一、前言
好多APP都有上传图片的功能,无聊是调起相册还是拍照,都必须要在activity的onActivityResult回调方法处理,实现起来比较繁琐。至此对其进一步封装。使用起来更加简单。
二、直接上源码:
GitHub源码
1、首先创建一个PicOptions,作用是配置相关信息
public class PicOptions {
private boolean isCrop;//是否裁剪
private int cropWidth;//裁剪宽度
private int cropHeight;//裁剪高度
private String providerAuthority;//7.0以上访问sdcard需要用到
private File cacheFile;//缓存文件
private PicOptions(Builder builder) {
isCrop = builder.isCrop;
cropWidth = builder.cropWidth;
cropHeight = builder.cropHeight;
providerAuthority = builder.providerAuthority;
cacheFile = builder.cacheFile;
}
public boolean isCrop() {
return isCrop;
}
public int getCropWidth() {
return cropWidth;
}
public int getCropHeight() {
return cropHeight;
}
public String getProviderAuthority() {
return providerAuthority;
}
public File getCacheFile() {
return cacheFile;
}
public static Builder beginBuilder() {
return new Builder();
}
public static class Builder {
private boolean isCrop = false;
private int cropWidth = 0;
private int cropHeight = 0;
private String providerAuthority;
private File cacheFile;
public Builder setCrop(boolean crop) {
isCrop = crop;
return this;
}
public Builder setCropWidth(int cropWidth) {
this.cropWidth = cropWidth;
return this;
}
public Builder setCropHeight(int cropHeight) {
this.cropHeight = cropHeight;
return this;
}
public Builder setProviderAuthority(String providerAuthority) {
this.providerAuthority = providerAuthority;
return this;
}
public Builder setCacheFile(File cacheFile) {
this.cacheFile = cacheFile;
return this;
}
public PicOptions build() {
if (this.cacheFile == null) {
throw new IllegalArgumentException("cacheFile no found...");
}
return new PicOptions(this);
}
}
}
2、回调接口PicListener
public interface PicListener {
void onTakePicSuccess(Uri uri);//成功
void onTakePicFail();//失败
}
3、管理器PicManager
public class PicManager {
private final String TAG = "PicManager";
private final int REQUEST_CODE_CAMERA = 1009;//拍照
private final int REQUEST_CODE_PICTURE = 1008;//相册
private final int REQUEST_CODE_CUT_PIC = 1007;//裁剪
private final String REQUEST_TYPE = "requestType";
private PicOptions picOptions;
private PicListener listener;
public PicManager setPicOptions(PicOptions picOptions) {
this.picOptions = picOptions;
return this;
}
public PicManager setListener(PicListener listener) {
this.listener = listener;
return this;
}
public void takeCamera(Context context) {
startPicActivity(context, REQUEST_CODE_CAMERA);
}
public void takePhotoAlbum(Context context) {
startPicActivity(context, REQUEST_CODE_PICTURE);
}
private void startPicActivity(Context context, int type) {
Intent intent = new Intent(context, PicActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(REQUEST_TYPE, type);
context.startActivity(intent);
}
public void behavior(Activity activity, Intent intent, Bundle savedInstanceState) {
if (intent == null) {
YLogUtil.INSTANCE.eTag(TAG, "behavior intent is null");
onDestroy(activity);
return;
}
if (intent.getExtras() == null) {
YLogUtil.INSTANCE.eTag(TAG, "behavior extras is null");
onDestroy(activity);
return;
}
if (savedInstanceState == null) {
int requestType = intent.getExtras().getInt(REQUEST_TYPE);
if (requestType == REQUEST_CODE_CAMERA) {
executeCamera(activity);
} else if (requestType == REQUEST_CODE_PICTURE) {
executePhotoAlbum(activity);
}
}
}
private void executeCamera(Activity context) {
String providerAuthority = context.getPackageName() + ".FileProvider";
if (null != picOptions.getProviderAuthority() && !picOptions.getProviderAuthority().isEmpty()) {
providerAuthority = picOptions.getProviderAuthority();
}
Uri imageUri;
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// 判断版本大于等于7.0
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
try {
imageUri = FileProvider.getUriForFile(context, providerAuthority, picOptions.getCacheFile());
} catch (Exception e) {
e.printStackTrace();
imageUri = Uri.fromFile(picOptions.getCacheFile());
}
// 给目标应用一个临时授权
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
imageUri = Uri.fromFile(picOptions.getCacheFile());
}
// 指定调用相机拍照后照片的储存路径
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
context.startActivityForResult(intent, REQUEST_CODE_CAMERA);
}
private void executePhotoAlbum(Activity context) {
Intent intent = new Intent(Intent.ACTION_PICK, null);
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
"image/*");
context.startActivityForResult(intent, REQUEST_CODE_PICTURE);
}
private void crop(Activity context, Uri uri) {
YLogUtil.INSTANCE.iFormatTag(TAG, "crop uri:%s", uri);
Intent intent = new Intent("com.android.camera.action.CROP");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
intent.setDataAndType(uri, "image/*");
// crop为true是设置在开启的intent中设置显示的view可以剪裁
intent.putExtra("crop", "true");
// aspectX aspectY 是宽高的比例
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
// outputX,outputY 是剪裁图片的宽高
intent.putExtra("outputX", picOptions.getCropWidth());
intent.putExtra("outputY", picOptions.getCropHeight());
intent.putExtra("return-data", false);
// intent.putExtra(MediaStore.EXTRA_OUTPUT,
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(picOptions.getCacheFile()));
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true); // no face detection
context.startActivityForResult(intent, REQUEST_CODE_CUT_PIC);
}
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
if (listener == null || (requestCode != REQUEST_CODE_CAMERA && requestCode != REQUEST_CODE_PICTURE && requestCode != REQUEST_CODE_CUT_PIC)) {
YLogUtil.INSTANCE.eTag(TAG, "onActivityResult Unknown requestCode or listener is null");
onDestroy(activity);
return;
}
if (resultCode != android.app.Activity.RESULT_OK) {
YLogUtil.INSTANCE.eTag(TAG, "onActivityResult--cancel--resultCode", resultCode);
onDestroy(activity);
return;
}
switch (requestCode) {
case REQUEST_CODE_CAMERA:
YLogUtil.INSTANCE.iTag(TAG, "onActivityResult camera");
scanFile(activity, picOptions.getCacheFile().getAbsolutePath(), picOptions.isCrop());
break;
case REQUEST_CODE_PICTURE:
if (data == null || data.getData() == null) {
YLogUtil.INSTANCE.eTag(TAG, "onActivityResult picture data is null ");
listener.onTakePicFail();
onDestroy(activity);
return;
}
YLogUtil.INSTANCE.iTag(TAG, "onActivityResult picture");
if (picOptions.isCrop()) {
crop(activity, data.getData());
} else {
YLogUtil.INSTANCE.iFormatTag(TAG, "onActivityResult picture callback uri:%s", data.getData());
listener.onTakePicSuccess(data.getData());
onDestroy(activity);
}
break;
case REQUEST_CODE_CUT_PIC:
YLogUtil.INSTANCE.iTag(TAG, "onActivityResult crop");
scanFile(activity, picOptions.getCacheFile().getAbsolutePath(), false);
break;
}
}
private void scanFile(final Activity activity, String path, final boolean isCrop) {
MediaScannerConnection.scanFile(activity, new String[]{path}, new String[]{"image/jpeg"}, new MediaScannerConnection.OnScanCompletedListener() {
@Override
public void onScanCompleted(String path, final Uri uri) {
HandlerUtil.INSTANCE.runOnUiThread(new Runnable() {
@Override
public void run() {
if (isCrop) {
crop(activity, uri);
} else {
YLogUtil.INSTANCE.iFormatTag(TAG, "scanFile camera or crop callback uri:%s", uri);
listener.onTakePicSuccess(uri);
onDestroy(activity);
}
}
});
}
});
}
/**
* 摧毁本库的 PicActivity
*/
private void onDestroy(Activity activity) {
if (activity != null) {
activity.finish();
}
}
}
4、Pic
public class Pic {
private PicManager picManager;
private Pic() {
picManager = new PicManager();
}
public static synchronized Pic getInstance() {
return PicHolder.instance;
}
private static class PicHolder {
private static final Pic instance = new Pic();
}
public PicManager getPicManager() {
return picManager;
}
}
5、真正调起拍照或相册的activity,PicActivity
public class PicActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//不接受触摸屏事件
getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
Pic.getInstance().getPicManager().behavior(this, getIntent(), savedInstanceState);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Pic.getInstance().getPicManager().onActivityResult(this, requestCode, resultCode, data);
}
}
6、注册PicActivity到manifest
7、示例:
调起摄像头
Pic.getInstance().picManager.setPicOptions(getPicOptions()).setListener(listener).takeCamera(context)
调起相册
Pic.getInstance().picManager.setPicOptions(getPicOptions()).setListener(listener).takePhotoAlbum(context)
private PicOptions getPicOptions(){
File cacheFile = File(FileUtils.getSdcardPath(), TimeUtil.nowTimeStr + ".jpg");
return PicOptions.beginBuilder()
.setCacheFile(cacheFile)
.setCrop(checkBox.isChecked)
.setCropHeight(200)
.setCropWidth(200)
.build();
}