最近开发新项目,头像上传问题因为一些问题浪费了一些时间,因为这个功能基本所有的APP都有,所以决定写个工具类,并说明一下我在写这个功能的时候遇到的问题,这也是我的第一篇个人博客
话不多说,步入正题
关键是Android7.0以后,获取Uri权限发生了变化,过去是Uri uri=Uri.fromfile(file), 现在是FileProvider.getUriForFile()
先来说一些解决步骤
1.在res文件夹下面建立资源文件夹file_path(资源文件夹名字随便取) //注意每个path代表的不同的路径,后面我会说为什么
xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path path="." name="sdcard_files" />
paths>
2.在清单文件中注册Provider
<provider android:name="android.support.v4.content.FileProvider" android:authorities="(包名,其实可以自定义,我用包名)xxx.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/> provider>3.准备工作做好了,现在就开始写代码了
一.Android6.0以后的动态权限准备,可以用原生获取,我用的EasyPermissions
用法也很简单,我就说一下基本用法,想要了解具体用法的可以看最后的链接
在build.gladle中添加
dependencies { compile 'pub.devrel:easypermissions:1.0.1'}
代码用法:
final int RC_CAMERA_CODE=998;//相机权限申请 final int RC_PHOTO_CODE=997;//相册权限申请
case R.id.tv_takephoto_id://拍照 String[] perms={Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}; if (EasyPermissions.hasPermissions(this,perms)){ //直接调用工具类实现拍照、 headPicUtils.takephoto(); }else{ //申请拍照需要的权限 EasyPermissions.requestPermissions(this,"拍照需要摄像头权限",RC_CAMERA_CODE,perms); } photoPopWindow.dissmiss(); break; case R.id.tv_gallery_id://从相册选择 String[] perm={Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE}; if (EasyPermissions.hasPermissions(this,perm)){ headPicUtils.seletPhoto(); }else{ EasyPermissions.requestPermissions(this,"读取相册需要读取SD卡权限",RC_PHOTO_CODE,perm); } break;
//回调方法
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); EasyPermissions.onRequestPermissionsResult(requestCode,permissions,grantResults,this); } //权限获取成功 @Override public void onPermissionsGranted(int requestCode, Listperms) { switch (requestCode){ case RC_CAMERA_CODE: //执行拍照 headPicUtils.takephoto(); break; case RC_PHOTO_CODE: headPicUtils.seletPhoto(); break; } } //权限获取失败 @Override public void onPermissionsDenied(int requestCode, List perms) { switch (requestCode){ case RC_CAMERA_CODE: ToastUtils.showToast(this,"拍照权限获取失败"); break; case RC_PHOTO_CODE: ToastUtils.showToast(this,"相册读取权限获取失败"); break; } }
//工具类方法
/** * Created by 李浩 on 2018/6/8. * 适配7.0以上的头像更替功能 * 剪切用到了UCrop,并且用到了EasyPermissions做动态权限申请 * * 重点注意:path的路径需要和file_path中的path属性一致 */ public class HeadPicUtils { //图片的存储路径,注意这里的路径需要和file_path文件中的一致,不然会出现midirs失败的问题
final public static String path= Environment.getExternalStorageDirectory()+"/yixiuPro/photos/"; final public static String authoritys="com.jiankangli.knowledge.jiankang_yixiupro.fileprovider"; public static File file; Activity context; final int OPEN_CAMERA_CODE=112; final int OPEN_PHOTOALBUM_CODE=113; public HeadPicUtils(Activity context){ this.context=context; } //拍照 //Android 7.0以上的拍照 public void takephoto(){ //存储对象 file = new File(path,System.currentTimeMillis()+".png"); if (!file.getParentFile().exists()){ file.getParentFile().mkdirs(); } Intent intent=new Intent(MediaStore.ACTION_IMAGE_CAPTURE); Uri imguri=getFileProviderUri(); if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){//7.0以上 //临时授权 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); } intent.putExtra(MediaStore.EXTRA_OUTPUT,imguri); context.startActivityForResult(intent,OPEN_CAMERA_CODE); } //相册 public void seletPhoto() { if (hasSdcard()){ Intent mOpenGalleryIntent=new Intent(Intent.ACTION_PICK); mOpenGalleryIntent.setType("image/*"); context.startActivityForResult(mOpenGalleryIntent,OPEN_PHOTOALBUM_CODE); }else{ ToastUtils.showToast(context,"设备没有SD卡"); } } //7.0以上的地址获取Uri public Uri getFileProviderUri(){ Uri uri; if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){ uri= FileProvider.getUriForFile(context,authoritys,file); }else{ uri=Uri.fromFile(file); } return uri; } //剪切方法,我用到了Ucorp,具体用法看文章末尾的链接 public void cropRawPhoto(Uri uri) { // 修改配置参数(我这里只是列出了部分配置,并不是全部) UCrop.Options options = new UCrop.Options(); // 修改标题栏颜色 options.setToolbarColor(context.getResources().getColor(R.color.colorPrimary)); // 修改状态栏颜色 options.setStatusBarColor(context.getResources().getColor(R.color.colorPrimaryDark)); // 隐藏底部工具 options.setHideBottomControls(true); // 图片格式 options.setCompressionFormat(Bitmap.CompressFormat.PNG); // 设置图片压缩质量 options.setCompressionQuality(100); // 是否让用户调整范围(默认false),如果开启,可能会造成剪切的图片的长宽比不是设定的 // 如果不开启,用户不能拖动选框,只能缩放图片 options.setFreeStyleCropEnabled(true); Uri desUri=Uri.fromFile(new File(path,System.currentTimeMillis()+".png")); Log.i("TAG", "desUri: "+desUri); Log.i("TAG", "uri: "+uri); // 设置源uri及目标uri UCrop.of(uri,desUri) // 长宽比 .withAspectRatio(1, 1) // 图片大小 .withMaxResultSize(200, 200) // 配置参数 .withOptions(options) .start(context); } //验证是否有SD卡 public static boolean hasSdcard(){ String state = Environment.getExternalStorageState(); if(state.equals(Environment.MEDIA_MOUNTED)){ return true; }else{ return false; } } }
在Activity中的回调方法
final int OPEN_CAMERA_CODE=112; final int OPEN_PHOTOALBUM_CODE=113;
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == UCrop.RESULT_ERROR){ ToastUtils.showToast(this,"图片剪裁失败"); return; } if (resultCode == RESULT_OK) { switch (requestCode) { case OPEN_CAMERA_CODE://拍照 //开始裁剪功能 headPicUtils.cropRawPhoto(headPicUtils.getFileProviderUri()); break; case OPEN_PHOTOALBUM_CODE: headPicUtils.cropRawPhoto(data.getData()); break; case UCrop.REQUEST_CROP: //显示出来,并提交服务器 Uri Cropuri=UCrop.getOutput(data); Log.i("TAG", "onActivityResult: "+Cropuri); Bitmap bitmap=BitmapFactory.decodeFile(Cropuri.getPath()); fileImage.setImageBitmap(bitmap); File file=new File(Cropuri.getPath()); //提交服务器 //submithead(file);//这步不用看,自己去上传 break; } } }
大概就是这些了,最后放出UCrop 和EasyPermissions的我觉得写得不错的文章EasyPermissions:https://blog.csdn.net/hexingen/article/details/78504814
UCrop:https://blog.csdn.net/little_soybean/article/details/52460222
第一次写博客,排版有点乱,大家有问题,可以在下面留言,我会在第一时间回复的