在做上一个项目时深深受到了图片上传的苦恼。图片上传主要分为两个部分,首先要获取图片,而获取图片可以分为从文件获取或者拍照获取。第二个部分才是上传图片,两个部分都是走了不少弯路。由于 Android 系统的碎片化比较严重,我们可能出现在第一台机子上能获取图片,但是换一个机子就不能获取图片的问题,并且在 Android6.0,7.0 之后也要做一定的适配,这样对于开发者来说,无疑很蛋疼。由于也是初学者,很多东西没有考虑到,适配起来也是有点难度的。
这几天也是从 github 上找到了一个库(地址在这 TakePhoto),经过简单的学习之后,发现用起来还是蛮简单的,并且在不同机型之间都能达到同样的效果。更重要的是可以根据不同配置达到不同的效果
接下来看下用法
一) 通过继承的方式
- voidtakeSuccess(TResult result);voidtakeFail(TResult result,Stringmsg);voidtakeCancel();
这种方法使用起来虽然简单,但是感觉定制性不高,必须继承指定的 Activity,而 有时我们已经封装好了 BaseActivity,不想再改了。有时候通过继承无法满足实际项目的需求。
二) 通过组装的方式去使用
- @Override
- public void onRequestPermissionsResult(intrequestCode, String[] permissions,int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);//以下代码为处理Android6.0、7.0动态权限所需TPermissionType type=PermissionManager.onRequestPermissionsResult(requestCode,permissions,grantResults);
- PermissionManager.handlePermissionsResult(this,type,invokeParam,this);
- }
- @OverridepublicTPermissionTypeinvoke(InvokeParaminvokeParam) {TPermissionType type=PermissionManager.checkPermission(TContextWrap.of(this),invokeParam.getMethod());
- if(TPermissionType.WAIT.equals(type)){this.invokeParam=invokeParam;
- }returntype;}
- /**
- * 获取TakePhoto实例
- * @return*/
- publicTakePhotogetTakePhoto(){if(takePhoto==null){
- takePhoto= (TakePhoto) TakePhotoInvocationHandler.of(this).bind(newTakePhotoImpl(this,this));
- }returntakePhoto;
- }
不仅可以对于参数自定义,也可以对于 UI 的自定义,比如自定义相册,自定义 Toolbar, 自定义状态栏,自定义提示文字,自定义裁切工具(需要使用自带的 TakePhoto 裁剪才行)。
支持从相册获取,也支持拍照,相关 Api
- * 从相机获取图片并裁剪
- *@paramoutPutUri 图片裁剪之后保存的路径
- *@paramoptions 裁剪配置
- */voidonPickFromCaptureWithCrop(Uri outPutUri, CropOptions options);/**
- * 从相册中获取图片并裁剪
- * @paramoutPutUri 图片裁剪之后保存的路径
- * @paramoptions 裁剪配置
- */
- voidonPickFromGalleryWithCrop(Uri outPutUri, CropOptions options);/**
- * 从文件中获取图片并裁剪
- * @paramoutPutUri 图片裁剪之后保存的路径
- * @paramoptions 裁剪配置
- */
- voidonPickFromDocumentsWithCrop(Uri outPutUri, CropOptions options);/**
- * 图片多选,并裁切
- * @paramlimit 最多选择图片张数的限制
- * @paramoptions 裁剪配置
- * */
- voidonPickMultipleWithCrop(intlimit, CropOptions options);
封装是对第二种方法的封装,主要参考了第一种的思想封装的。 关于 TakePhoto 的库代码全部封装到一个 TakePhotoUtil 工具类中,看代码:
- public class TakePhotoUtil implements TakePhoto.TakeResultListener,InvokeListener{
- private static finalString TAG = TakePhotoUtil.class.getName();privateTakePhoto takePhoto;privateInvokeParam invokeParam;privateActivity activity;privateFragment fragment;public TakePhotoUtil(Activity activity){this.activity = activity;
- }public TakePhotoUtil(Fragment fragment){this.fragment = fragment;
- }/**
- * 获取TakePhoto实例
- * @return*/
- publicTakePhotogetTakePhoto(){if(takePhoto==null){
- takePhoto= (TakePhoto) TakePhotoInvocationHandler.of(this).bind(newTakePhotoImpl(activity,this));
- }returntakePhoto;
- }public void onCreate(Bundle savedInstanceState){
- getTakePhoto().onCreate(savedInstanceState);
- }public void onSaveInstanceState(Bundle outState){
- getTakePhoto().onSaveInstanceState(outState);
- }public void onActivityResult(intrequestCode,intresultCode, Intent data){
- getTakePhoto().onActivityResult(requestCode, resultCode, data);
- }public void onRequestPermissionsResult(intrequestCode, String[] permissions,int[] grantResults) {
- PermissionManager.TPermissionType type=PermissionManager.onRequestPermissionsResult(requestCode,permissions,grantResults);
- PermissionManager.handlePermissionsResult(activity,type,invokeParam,this);
- }/**
- *
- * @paramresult
- */
- @Override
- public void takeSuccess(TResult result) {if(listener !=null){
- listener.takeSuccess(result);
- }// deleteCachePic();}@Override
- public void takeFail(TResult result, String msg) {if(listener !=null){
- listener.takeFail(result, msg);
- }// deleteCachePic();}@Override
- public void takeCancel() {if(listener !=null){
- listener.takeCancel();
- }
- }public void deleteCachePic(){
- File file=newFile(Environment.getExternalStorageDirectory(),"/takephoto/");if(!file.exists())return;
- File[] files = file.listFiles();for(File f: files) {
- f.delete();
- }
- }public interface TakePhotoListener{
- voidtakeSuccess(TResult result);voidtakeFail(TResult result, String msg);voidtakeCancel();
- }publicTakePhotoListener listener;public void setTakePhotoListener(SimpleTakePhotoListener listener){this.listener = listener;
- }public static class SimpleTakePhotoListener implements TakePhotoListener{
- @Override
- public void takeSuccess(TResult result) {
- }@Override
- public void takeFail(TResult result, String msg) {
- }@Override
- public void takeCancel() {
- }
- }@Override
- publicPermissionManager.TPermissionTypeinvoke(InvokeParam invokeParam) {
- PermissionManager.TPermissionType type=PermissionManager.checkPermission(TContextWrap.of(activity),invokeParam.getMethod());if(PermissionManager.TPermissionType.WAIT.equals(type)){this.invokeParam=invokeParam;
- }returntype;
- }/**
- *
- * @paramselect_type
- */
- public void takePhoto(Select_type select_type, SimpleTakePhotoListener listener){
- takePhoto(select_type,null, listener);
- }public void takePhoto(Select_type select_type, PhotoConfigOptions cropOptions, SimpleTakePhotoListener listener){if(takePhoto ==null){
- Toast.makeText(activity,"请先开启照片功能", Toast.LENGTH_SHORT).show();return;
- }
- setTakePhotoListener(listener);if(cropOptions ==null){
- cropOptions =newPhotoConfigOptions();
- }
- cropOptions.configCompress();//压缩配置cropOptions.configTakePhoto();//拍照配置File file=newFile(Environment.getExternalStorageDirectory(),"/takephoto/"+System.currentTimeMillis() +".jpg");if(!file.getParentFile().exists())file.getParentFile().mkdirs();
- Uri imageUri = Uri.fromFile(file);switch(select_type){casePICK_BY_SELECT://从相册获取
- if(cropOptions.limit >1){if(cropOptions.crop ==true){
- takePhoto.onPickMultipleWithCrop(cropOptions.limit, cropOptions.getCropOptions());
- }else{
- takePhoto.onPickMultiple(cropOptions.limit);
- }
- }if(cropOptions.chooseFromFile){if(cropOptions.crop ==true){
- takePhoto.onPickFromDocumentsWithCrop(imageUri, cropOptions.getCropOptions());
- }else{
- takePhoto.onPickFromDocuments();
- }
- }else{if(cropOptions.crop ==true){
- takePhoto.onPickFromGalleryWithCrop(imageUri, cropOptions.getCropOptions());
- }else{
- takePhoto.onPickFromGallery();
- }
- }break;casePICK_BY_TAKE://拍照获取
- if(cropOptions.crop ==true){
- takePhoto.onPickFromCaptureWithCrop(imageUri, cropOptions.getCropOptions());
- }else{
- takePhoto.onPickFromCapture(imageUri);
- }break;default:break;
- }
- }/**
- * 图片的裁剪配置选项内部类
- */
- public class PhotoConfigOptions{
- //裁剪配置
- private booleancrop =true;//是否裁剪
- private booleanwithWonCrop =true;//是否采用自带的裁剪工具,默认选取第三方的裁剪工具
- private booleancropSize =true;//尺寸还是比例
- //压缩配置
- private booleanuseOwnCompressTool =true;//使用自带的压缩工具
- private booleanisCompress =true;//是否压缩
- private booleanshowProgressBar =true;//显示压缩进度条
- // private
- private intmaxSize =102400;//选择图片配置
- private booleanuseOwnGallery =true;//选择使用自带的相册
- private booleanchooseFromFile =false;//从文件获取图片
- private intlimit =1;//选择最多图片的配置,选择多张图片会自动切换到TakePhoto自带相册
- //其它配置
- private booleansavePic =true;//选择完之后是否保存图片
- private booleancorrectTool =false;//纠正拍照的照片旋转角度
- private intheight =800;private intwidth =800;/**
- * 裁剪相关配置
- * @return*/
- publicCropOptionsgetCropOptions(){if(crop ==false)return null;
- CropOptions.Builder builder =newCropOptions.Builder();if(cropSize){
- builder.setOutputX(width).setOutputY(height);
- }else{
- builder.setAspectX(width).setAspectY(height);
- }
- builder.setWithOwnCrop(withWonCrop);//默认采用第三方配置
- returnbuilder.create();
- }/**
- * 图片压缩相关配置
- */
- public void configCompress(){if(isCompress ==false) {
- takePhoto.onEnableCompress(null,false);return;
- }
- CompressConfig config;if(useOwnCompressTool){
- config =newCompressConfig.Builder()
- .setMaxSize(maxSize)
- .setMaxPixel(width>height?width:height)
- .enableReserveRaw(savePic)
- .create();
- }else{
- LubanOptions options =newLubanOptions.Builder()
- .setMaxHeight(height)
- .setMaxWidth(maxSize)
- .create();
- config = CompressConfig.ofLuban(options);
- config.enableReserveRaw(savePic);
- }
- takePhoto.onEnableCompress(config, showProgressBar);
- }public void configTakePhoto(){
- TakePhotoOptions.Builder builder =newTakePhotoOptions.Builder();if(useOwnGallery){
- builder.setWithOwnGallery(true);
- }if(correctTool){
- builder.setCorrectImage(true);
- }
- takePhoto.setTakePhotoOptions(builder.create());
- }public void setCrop(booleancrop) {this.crop = crop;
- }public void setWithWonCrop(booleanwithWonCrop) {this.withWonCrop = withWonCrop;
- }public void setCropSize(booleancropSize) {this.cropSize = cropSize;
- }public void setUseOwnCompressTool(booleanuseOwnCompressTool) {this.useOwnCompressTool = useOwnCompressTool;
- }public void setCompress(booleancompress) {
- isCompress = compress;
- }public void setShowProgressBar(booleanshowProgressBar) {this.showProgressBar = showProgressBar;
- }public void setMaxSize(intmaxSize) {this.maxSize = maxSize;
- }public void setUseOwnGallery(booleanuseOwnGallery) {this.useOwnGallery = useOwnGallery;
- }public void setChooseFromFile(booleanchooseFromFile) {this.chooseFromFile = chooseFromFile;
- }public void setLimit(intlimit) {this.limit = limit;
- }public void setSavePic(booleansavePic) {this.savePic = savePic;
- }public void setCorrectTool(booleancorrectTool) {this.correctTool = correctTool;
- }public void setHeight(intheight) {this.height = height;
- }public void setWidth(intwidth) {this.width = width;
- }
- }/**
- * 照片获取方式, 从相册获取或拍照处理
- */
- public enumSelect_type{
- PICK_BY_SELECT, PICK_BY_TAKE
- }
- }
封装了一个 BaseTakePhotoActivity,里面的代码如下:
- protectedTakePhotoUtil takePhotoUtil;@Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- takePhotoUtil =newTakePhotoUtil(this);if(useTakePhoto()){
- takePhotoUtil.onCreate(savedInstanceState);
- }super.onCreate(savedInstanceState);
- }@Override
- protected void onSaveInstanceState(Bundle outState) {if(useTakePhoto()){
- takePhotoUtil.onSaveInstanceState(outState);
- }super.onSaveInstanceState(outState);
- }@Override
- protected void onActivityResult(intrequestCode,intresultCode, Intent data) {if(useTakePhoto()){
- takePhotoUtil.onActivityResult(requestCode, resultCode, data);
- }super.onActivityResult(requestCode, resultCode, data);
- }@Override
- public void onRequestPermissionsResult(intrequestCode, String[] permissions,int[] grantResults) {if(useTakePhoto()){
- takePhotoUtil.onRequestPermissionsResult(requestCode, permissions, grantResults);
- }super.onRequestPermissionsResult(requestCode, permissions, grantResults);
- }protected boolean useTakePhoto(){return false;
- }
其他对于业务的封装,可以再封装一个 BaseActivity,继承自 BaseTakePhotoActivity,这样就可以不影响 BaseActivity 的使用,如果我们在主 Activity 中使用获取图片的功能需要两步
- @Override
- protected boolean useTakePhoto() {return true;
- }
- takePhotoUtil.takePhoto(TakePhotoUtil.Select_type.PICK_BY_TAKE, new TakePhotoUtil.SimpleTakePhotoListener(){
- @Override
- public void takeSuccess(TResult result) {
- String s = result.getImage().getCompressPath();Bitmap bitmap = BitmapFactory.decodeFile(s);iv.setImageBitmap(bitmap);}
- });
takePhoto()的第一个参数是一个枚举类型的参数,分别为从相册获取和拍照获取,第二个参数为获取成功失败监听,有三个回调,由于有些回调不是必须的,所以对 Listener 做了一个适配,只需要回调想要的方法即可,获取成功之后就可以通过 TResult 封装的参数获取想要的图片以及图片地址。对于获取到的图片地址就可以做一些上传处理。
可以借助 okhttp3 实现上传功能
- MultipartBody.Builderbuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);RequestBody requestBody = RequestBody.create(MediaType.parse(MULTIPART_FORM_DATA), file);MultipartBody.Partpart = MultipartBody.Part.createFormData("dir", file.getName(), requestBody);builder.addPart(part);Request.Builderbuilder1 = new Request.Builder().url(url).post(builder.build());Request request = builder1.build();HttpUtils.client.newCall(request).enqueue(new Callback() {
- @Override
- public void onFailure(Call call, IOException e) {
- }
- @Override
- public void onResponse(Call call, Response response) throws IOException {
- if(response.isSuccessful()){
- final String s = response.body().string();((Activity)context).runOnUiThread(new Runnable() {
- @Override
- public void run() {
- }
- });}
- }
- });
大致代码如上
由于当时没有找到这个库,于是跑去问公司另一个做 Android 的,看了下他封装的代码,确实也是值得学习的,他的代码也是适配到了 Android7.0,贴下它的代码,方便以后学习:
- public classCameraUtil {private staticfinalintREQUEST_CAPTURE_CAMERA =1221;private staticfinalintREQUEST_CROP =1222;private staticfinalintREQUEST_OPEN_ALBUM =1223;private staticfinal String TAG ="Camera";private staticUri mCacheUri;private CameraUtil() {
- }
- @RequiresPermission(allOf = {Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA})public static void getImageFromCamera(Activity activity) {if(checkExternalStorageState(activity)) {
- activity.startActivityForResult(getImageFromCamera(activity.getApplicationContext()), REQUEST_CAPTURE_CAMERA);
- }
- }
- @RequiresPermission(allOf = {Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA})
- @Deprecatedpublic static void getImageFromCamera(Fragment fragment) {if(checkExternalStorageState(fragment.getContext())) {
- fragment.startActivityForResult(getImageFromCamera(fragment.getContext()), REQUEST_CAPTURE_CAMERA);
- }
- }private staticIntentgetImageFromCamera(Context context) {
- Intent getImageByCamera =newIntent(MediaStore.ACTION_IMAGE_CAPTURE);
- mCacheUri = getCachePhotoUri(context.getApplicationContext());
- getImageByCamera.putExtra(MediaStore.EXTRA_OUTPUT, mCacheUri);
- getImageByCamera.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
- grantUriPermission(context, getImageByCamera, mCacheUri);returngetImageByCamera;
- }private staticbooleancheckExternalStorageState(Context context) {if(TextUtils.equals(Environment.getExternalStorageState(), Environment.MEDIA_MOUNTED)) {return true;
- }
- Toast.makeText(context.getApplicationContext(),"请确认已经插入SD卡", Toast.LENGTH_LONG).show();return false;
- }
- @SuppressWarnings("ResultOfMethodCallIgnored")public staticFilegetCachePhotoFile() {
- File file =newFile(Environment.getExternalStorageDirectory(),"/lenso/cache/CameraTakePhoto"+ System.currentTimeMillis() +".jpg");if(!file.getParentFile().exists()) file.getParentFile().mkdirs();returnfile;
- }private staticUrigetCachePhotoUri(Context context) {returnFileProvider.getUriForFile(context, getAuthority(context), getCachePhotoFile());
- }private staticUrigetCachePhotoUri(Context context, File file) {returnFileProvider.getUriForFile(context, getAuthority(context), file);
- }public static void onActivityResult(Activity activity,intrequestCode,intresultCode, Intent data, OnActivityResultListener listener) {
- onActivityResult(activity,null, requestCode, resultCode, data, listener);
- }/**
- * getCachePhotoFile().getParentFile().getAbsolutePath()
- * @param dir
- * @return
- */
- public staticbooleandeleteDir(File dir) {if(dir !=null&& dir.isDirectory()) {
- String[] children = dir.list();for(inti =0; i < children.length; i++) {
- boolean success = deleteDir(newFile(dir, children[i]));if(!success) {return false;
- }
- }
- }returndir.delete();
- }public staticFilesaveBitmap(Bitmap bitmap) {
- File file = getCachePhotoFile();if(bitmap ==null|| bitmap.isRecycled())returnfile;
- FileOutputStream outputStream =null;try{
- outputStream =newFileOutputStream(file);
- bitmap.compress(Bitmap.CompressFormat.JPEG,100, outputStream);
- }catch(FileNotFoundException e) {
- e.printStackTrace();
- }finally{if(outputStream !=null)try{
- outputStream.close();
- }catch(IOException e) {
- e.printStackTrace();
- }
- bitmap.recycle();
- }returnfile;
- }public static void copy(File file, File point) {if(!file.exists())return;if(!point.getParentFile().exists()) point.getParentFile().mkdirs();
- BufferedInputStream inputStream =null;
- BufferedOutputStream outputStream =null;try{
- inputStream =newBufferedInputStream(newFileInputStream(file));
- outputStream =newBufferedOutputStream(newFileOutputStream(point));byte[] buff =new byte[1024*1024*2];intlen;while((len = inputStream.read(buff)) != -1) {
- outputStream.write(buff,0, len);
- outputStream.flush();
- }
- }catch(FileNotFoundException e) {
- e.printStackTrace();
- }catch(IOException e) {
- e.printStackTrace();
- }finally{
- closeStream(inputStream);
- closeStream(outputStream);
- }
- }private static void closeStream(Closeable closeable) {if(closeable !=null)try{
- closeable.close();
- }catch(IOException e) {
- e.printStackTrace();
- }
- }public static void onActivityResult(Activity activity, CropOption crop,intrequestCode,intresultCode, Intent data, OnActivityResultListener listener) {if(resultCode == Activity.RESULT_CANCELED)return;
- Uri uri;switch(requestCode) {caseREQUEST_OPEN_ALBUM:
- uri = data.getData();if(uri !=null) {
- mCacheUri = getCachePhotoUri(activity);
- copy(newFile(getRealFilePath(activity, uri)),newFile(getRealFilePath(activity, mCacheUri)));
- }else{
- Bitmap bitmap = data.getParcelableExtra("data");
- File file = saveBitmap(bitmap);
- mCacheUri = getCachePhotoUri(activity, file);
- }caseREQUEST_CAPTURE_CAMERA:
- uri = mCacheUri;if(listener !=null) {
- listener.requestCaptureCamera(getRealFilePath(activity, uri),null);
- }if(crop ==null)return;
- crop.setSource(uri);
- Intent intent = crop.create();
- grantUriPermission(activity, intent, crop.getOutput());
- activity.startActivityForResult(intent, REQUEST_CROP);break;caseREQUEST_CROP:if(listener !=null&& data !=null)
- {
- listener.requestCrop(getRealFilePath(activity, mCacheUri), (Bitmap) data.getParcelableExtra("data"));
- }break;
- }
- }
- @RequiresPermission(allOf = {Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE})public static void getImageFromAlbum(Activity activity) {
- Intent intent =newIntent(Intent.ACTION_PICK);
- intent.setType("image/*");//相片类型activity.startActivityForResult(intent, REQUEST_OPEN_ALBUM);
- }
- @RequiresPermission(allOf = {Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE})
- @Deprecatedpublic static void getImageFromAlbum(Fragment fragment) {
- Intent intent =newIntent(Intent.ACTION_PICK);
- intent.setType("image/*");//相片类型fragment.startActivityForResult(intent, REQUEST_OPEN_ALBUM);
- }public interfaceOnActivityResultListener {voidrequestCaptureCamera(String path, Bitmap bitmap);voidrequestCrop(String path, Bitmap bitmap);
- }/**
- * Try to return the absolute file path from the given Uri
- *
- * @param context context
- * @param uri uri
- * @return the file path or null
- */
- public staticStringgetRealFilePath(final Context context, final Uri uri) {if(null== uri)return null;
- String path = uri.toString();if(path.startsWith("content://"+ getAuthority(context) +"/rc_external_path"<
来源: http://blog.csdn.net/qq_18242391/article/details/72302982