Android如何添加图片

Android如何添加图片

一、目标

通过在文章中插入图片,实现图文混排的功能。

二、下载地址

神马笔记最新版本:【神马笔记Version1.1.0_beta.apk

三、获取图片

有2种途径可以获取图片

  1. 拍照(创建新的照片)
  2. 照片图库(选择手机上的照片)

在Android平台,有2种方式可以用来实现这2种途径

  1. 调用第三方应用
  2. 编写拍照与图库代码,自己实现之

前者在功能上可能会遇到一些限制,但工作量小。

后者更加灵活,可以随意发挥,但工作量较大。虽然可以在Github上找到不错的实现方案,终归需要一些调试的事件。

神马笔记采用的是第一种方式——调用第三方应用

四、调用第三方应用

Android通过startActivityForResult调用地方应用,并且通过onActivityResult处理返回结果。这2个方法分别存在于ActivityFragment中。

  • Activity#startActivityForResult

  • Activity#onActivityResult

  • Fragment#startActivityForResult

  • Fragment#onActivityResult

1. 调用拍照应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public boolean request() {
SoftInputUtils.hide(context);

Uri imageUri;
{
File file = target.getFile();
file.getAbsoluteFile().getParentFile().mkdirs();

imageUri = UriUtils.fromFile(context, file);
}

Intent intent = new Intent();
{
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
}

try {

parent.startActivityForResult(intent, requestCode);

return true;
} catch (Exception e) {
e.printStackTrace();
}

return false;
}

2. 调用照片图库应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public boolean request() {
SoftInputUtils.hide(context);

Intent intent = new Intent(Intent.ACTION_PICK, null);
intent.setDataAndType(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
"image/*");
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);

try {
parent.startActivityForResult(intent, requestCode);

return true;
} catch (Exception e) {

}

return false;
}

五、优化调用过程

startActivityForResultonActivityResult这2个接口通过requestCode识别请求及结果。为了避免定义常量发送请求以及使用switch语法处理结果,采用面向对象的方法来优化调用过程。

1. 定义调用处理类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public abstract class BaseRequestDelegate implements BiConsumer<Integer, Intent> {

private static int COUNTER = 1;

protected int requestCode;

protected Fragment parent;
protected Activity context;

public BaseRequestDelegate(Fragment f) {
this.context = f.getActivity();
this.parent = f;

this.requestCode = COUNTER;

{
int counter = COUNTER;
++counter;
counter %= 1000;
COUNTER = counter;
}
}

public int getRequestCode() {
return requestCode;
}

public abstract boolean request();

public abstract void accept(Integer resultCode, Intent data);
}

BaseRequestDelegate会自动产生requestCode,避免定义常量。这里使用了是COUNTER的方式,每次创建一个新的请求,计数器累加1作为下一次的requestCode,并且限定在1000以内。

BaseRequestDelegate封装了2个方法request用与发送请求,以及accept用于处理结果。

2. 定义调用管理类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class RequestResultManager {

HashMap<Integer, BiConsumer<Integer, Intent>> map;

public RequestResultManager() {
this.map = new HashMap<>();
}

public void onActivityResult(int requestCode, int resultCode, Intent data) {
BiConsumer delegate = map.remove(requestCode);
if (delegate != null) {
delegate.accept(resultCode, data);
}
}

public void request(BaseRequestDelegate delegate) {
boolean result = delegate.request();
if (result) {
map.put(delegate.getRequestCode(), delegate);
}
}

}

RequestResultManager负责管理BaseRequestDelegate,通过request方法发送请求。在onActivityResult处理结果。

3. 优化调用过程

  • 调用第三方应用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void requestInsertion() {

MenuItemClickListener listener = new MenuItemClickListener();

{

listener.put(R.id.menu_insert_paragraph, e ->
new ParagraphInsertion(insertionCallback).execute()
);

listener.put(R.id.menu_camera, e -> {
CameraDelegate delegate = new CameraDelegate(this, insertionCallback);
requestResultManager.request(delegate);
});

listener.put(R.id.menu_photo, e -> {
PhotoDelegate delegate = new PhotoDelegate(this, insertionCallback);
requestResultManager.request(delegate);
});

}

PopupMenuDialogFragment dialogFragment = new PopupMenuDialogFragment();
dialogFragment.setTheme(R.style.DialogDimTheme);
dialogFragment.setMenuResource(R.menu.menu_compose_insertion);
dialogFragment.setOnMenuItemClickListener(listener);
dialogFragment.showNow(getFragmentManager(), "insertion");
}
  • 处理调用结果
1
2
3
4
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
requestResultManager.onActivityResult(requestCode, resultCode, data);
}

六、Final

通过调用第三方拍照及图库应用,可以快速实现文章中插入图片的功能。但是无法进一步操作第三方应用,使用灵活性较低。比如,调用图库应用添加某一相册下的图片,需要多次选择,无法记录最近一次使用的相册就颇为麻烦。