最近开发新项目,头像上传问题因为一些问题浪费了一些时间,因为这个功能基本所有的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">
<!-- xml文件是唯一设置分享的目录 ,不能用代码设置
1.<files-path> getFilesDir() /data/data//files目录
2.<cache-path> getCacheDir() /data/data//cache目录
3.<external-path> Environment.getExternalStorageDirectory()
SDCard/Android/data/你的应用的包名/files/ 目录
4.<external-files-path> Context#getExternalFilesDir(String) Context.getExternalFilesDir(null).
5.<external-cache-path> Context.getExternalCacheDir().
-->
<!-- path :代表设置的目录下一级目录 eg:<external-path path="images/"
整个目录为Environment.getExternalStorageDirectory()+"/images/"
name: 代表定义在Content中的字段 eg:name = "myimages" ,并且请求的内容的文件名为default_image.jpg
则 返回一个URI content://com.example.myapp.fileprovider/myimages/default_image.jpg
-->
<!--当path 为空时 5个全配置就可以解决-->
<!--下载apk-->
<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, List<String> perms) {
switch (requestCode){
case RC_CAMERA_CODE:
//执行拍照
headPicUtils.takephoto();
break;
case RC_PHOTO_CODE:
headPicUtils.seletPhoto();
break;
}
}
//权限获取失败
@Override
public void onPermissionsDenied(int requestCode, List<String> 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的我觉得写得不错的文章