Android如何添加图片
一、目标
通过在文章中插入图片,实现图文混排的功能。
二、下载地址
神马笔记最新版本:【神马笔记Version1.1.0_beta.apk】
三、获取图片
有2种途径可以获取图片
- 拍照(创建新的照片)
- 照片图库(选择手机上的照片)
在Android平台,有2种方式可以用来实现这2种途径
- 调用第三方应用
- 编写拍照与图库代码,自己实现之
前者在功能上可能会遇到一些限制,但工作量小。
后者更加灵活,可以随意发挥,但工作量较大。虽然可以在Github上找到不错的实现方案,终归需要一些调试的事件。
神马笔记采用的是第一种方式——调用第三方应用。
四、调用第三方应用
Android通过startActivityForResult
调用地方应用,并且通过onActivityResult
处理返回结果。这2个方法分别存在于Activity
及Fragment
中。
Activity#startActivityForResult
Activity#onActivityResult
Fragment#startActivityForResult
Fragment#onActivityResult
1. 调用拍照应用
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. 调用照片图库应用
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;
}
五、优化调用过程
startActivityForResult
和onActivityResult
这2个接口通过requestCode
识别请求及结果。为了避免定义常量发送请求以及使用switch语法处理结果,采用面向对象的方法来优化调用过程。
1. 定义调用处理类
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. 定义调用管理类
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. 优化调用过程
- 调用第三方应用
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");
}
- 处理调用结果
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
requestResultManager.onActivityResult(requestCode, resultCode, data);
}
六、Final
通过调用第三方拍照及图库应用,可以快速实现文章中插入图片的功能。但是无法进一步操作第三方应用,使用灵活性较低。比如,调用图库应用添加某一相册下的图片,需要多次选择,无法记录最近一次使用的相册就颇为麻烦。