在Android 7.0以上,在相机拍照 , 调用在对图片裁剪上,可能会碰到以下一些错误:
主要是由于在Android 7.0以后,用了Content Uri 替换了原本的File Uri,故在targetSdkVersion=24的时候,部分 “`Uri.fromFile()“` 方法就不适用了。 **File Uri 与 Content Uri 的区别** - File Uri 对应的是文件本身的存储路径 - Content Uri 对应的是文件在Content Provider的路径 所以在android 7.0 以上,我们就需要将File Uri转换为 Content Uri。具体转换方法如下:
开始写入标识 以及 函数值
protected static final int CHOOSE_PICTURE = 0;protected static final int TAKE_PICTURE = 1;private static final int CROP_SMALL_PICTURE = 2;private File tempFile;private Uri cropImageUri;
第一:首先我们设置 本地图库 与 相机的点击事件:
/*** 显示会话框,选择*/public void showChoosePicDialog(View view) {AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setTitle("设置头像");String[] items = { "选择本地照片", "拍照" };builder.setNegativeButton("取消", null);builder.setItems(items, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {switch (which) {case CHOOSE_PICTURE: // 选择本地照片Intent openAlbumIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);openAlbumIntent.setType("image/*");startActivityForResult(openAlbumIntent, CHOOSE_PICTURE);break;case TAKE_PICTURE: // 拍照takecamera();break;}}});ate().show();}
第二步: 对我们调用系统相机
/*** 相机7.0适配7.0 手机适配 文件存储地址*/private void takecamera() {String status= ExternalStorageState();if(status.equals(Environment.MEDIA_MOUNTED)){tempFile=new File(getExternalCacheDir(),getPhotoFileName());//SD卡的应用关联缓存目录try {ists()){tempFile.delete();}ateNewFile();} catch (Exception e) {Toast.makeText(InfomationActivity.this, "没有找到储存目录",Toast.LENGTH_LONG).show();}}else {Toast.makeText(InfomationActivity.this, "没有储存卡",Toast.LENGTH_LONG).show();}Intent cameraintent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);// 指定调用相机拍照后照片的储存路径Uri uri=null;if (Build.VERSION.SDK_INT >= 24) {uri = UriForFile(InfomationActivity.this, BuildConfig.APPLICATION_ID + ".myFileProvider", tempFile);}else {uri = Uri.fromFile(tempFile);}cameraintent.putExtra(MediaStore.EXTRA_OUTPUT, uri);startActivityForResult(cameraintent, TAKE_PICTURE);}//使用系统当前日期加以调整作为照片的名称private String getPhotoFileName() {Date date = new Date(System.currentTimeMillis());SimpleDateFormat dateFormat = new SimpleDateFormat("'IMG'_yyyyMMdd_HHmmss");return dateFormat.format(date) + ".jpg";}
第三步:返回调用回来的信息:
/*** 手机拍摄返回结果* @param requestCode* @param resultCode* @param data*/@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {ActivityResult(requestCode, resultCode, data);switch (requestCode) {case TAKE_PICTURE:if (resultCode == RESULT_OK) {Uri uri=null;if(Build.VERSION.SDK_INT >= 24) {uri = UriForFile(InfomationActivity.this,BuildConfig.APPLICATION_ID+".myFileProvider",tempFile);startPhotoZoom(uri);}else {uri = Uri.fromFile(tempFile);startPhotoZoom(uri);}}break;case CHOOSE_PICTURE:if (resultCode == RESULT_OK) {Data());}break;case CROP_SMALL_PICTURE:if(resultCode==RESULT_OK) {if (data != null) {try {Bitmap bp = BitmapFactory.decodeStream(getContentResolver().openInputStream(cropImageUri));circleIcon.setImageBitmap(bp);uploadPic(bp);} catch (FileNotFoundException e) {e.printStackTrace();}}}break;}}
第四步:手机图片裁切
/*** 7.0 适配7.0 以上手机 裁切图片* @param*/private void startPhotoZoom(Uri uri) {File CropPhoto=new File(getExternalCacheDir(),"crop.jpg");try{ists()){CropPhoto.delete();}ateNewFile();}catch(IOException e){e.printStackTrace();}cropImageUri=Uri.fromFile(CropPhoto);Intent intent = new Intent("com.android.camera.action.CROP");intent.setDataAndType(uri, "image/*");if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加这一句表示对目标应用临时授权该Uri所代表的文件}// 下面这个crop=true是设置在开启的Intent中设置显示的VIEW可裁剪intent.putExtra("crop", "true");intent.putExtra("scale", true);intent.putExtra("aspectX", 1);intent.putExtra("aspectY", 1);//输出的宽高intent.putExtra("outputX", 200);intent.putExtra("outputY", 200);intent.putExtra("return-data", false);intent.putExtra(MediaStore.EXTRA_OUTPUT, cropImageUri);intent.putExtra("outputFormat", Bitmap.String());intent.putExtra("noFaceDetection", true); // no face detectionstartActivityForResult(intent, CROP_SMALL_PICTURE);}
第五步:上传服务器 我这Retrofit+Rxjava上传上传不是File 而是 MultipartBody.Part body :
具体就 RequestBody
//创建RequestBody 封装file参数RequestBody fileBody = ate(MediaType.parse("multipart/form-data"), file);//创建RequestBody 设置类型等MultipartBody.Part requestBody = ateFormData("icon", Name(), fileBody);
/*** 上传到服务器* @param bitmap*/private void uploadPic(Bitmap bitmap) {// ... 可以在这里把Bitmap转换成file,然后得到file的url,做文件上传操作// 注意这里得到的图片已经是圆形图片了// bitmap是没有做个圆形处理的,但已经被裁剪了String imagePath = ImageWzqUtils.savePhoto(bitmap, ExternalStorageDirectory().getAbsolutePath(), String.valueOf(System.currentTimeMillis()));Log.e("imagePath", imagePath+"");if(imagePath != null){// 拿着imagePath上着imagePath上传了// Bitmap bm = BitmapFactory.decodeFile(imagePath);File file=new File(imagePath);OkHttpClient okHttpClient=new OkHttpClient();//创建RequestBody 封装file参数RequestBody fileBody = ate(MediaType.parse("multipart/form-data"), file);//创建RequestBody 设置类型等MultipartBody.Part requestBody = ateFormData("icon", Name(), fileBody);UpdatePic(requestBody);}}
这是因为拍照存储的文件,也需要以Content Uri的形式,故采用以下办法解决:
Step.1
修改l
&><provider
<!--Android中解决7.0权限FileUriPermission--><providerandroid:name="android.t.FileProvider"android:authorities="${applicationId}.myFileProvider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/file_paths" /></provider>
</application>
Step.2
在res/xml/下新建l文件
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="">
<root-path name="root" path="." /><files-path name="files" path="." /><cache-path name="cache" path="." /><external-path name="external" path="." /><external-files-path name="external_files" path="." /><external-cache-path name="external_cache" path="." /><external-path name="external_files" path="."/>
</paths>
另外我也b把7.0的FileUriPermissCompat这个也分享一下:
public class FileUriPermissionCompat {private static final String TAG = SimpleName();//此处需要改成l中申请的对应的provider的值private static final String AUTHORITIES = BuildConfig.APPLICATION_ID +".myFileProvider";/*** 是否需要适配7.0权限* @return*/public static boolean isNeedAdapt() {//24以上版本return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;}//适应Uri授权权限public static Uri adaptUriAndGrantPermission(Context context, Intent intent, File file) {Uri uri = adaptUri(context, file);if (uri == null) {return null;}grantUriPermission(context, intent, uri);return uri;}public static Uri adaptUri(Context context, File file) {if (context == null || file == null) {return null;}//网络路径的特殊处理,不需要7.0适配,但必须用parse()方法if (Path().startsWith("http")) {return Uri.Path());}Uri uri = null;try {if (isNeedAdapt()) {//需要7.0特殊适配;通过系统提供的FileProvider类创建一个content类型的Uri对象uri = UriForFile(context, AUTHORITIES, file);} else {//不需要适配uri = Uri.fromFile(file);}} catch (Exception e) {Log.e(TAG, "authorities value error, so can't convert uri !");e.printStackTrace();}return uri;}/*** 对第三方应用赋予对uri读写的权限* @param context* @param intent* @param saveUri 适配后的uri*/public static void grantUriPermission(Context context, Intent intent, Uri saveUri) {if (!isNeedAdapt()) {return;}if (context == null || intent == null || saveUri == null) {return;}//网络路径的特殊处理,不需要权限if (Scheme() != null && Scheme().startsWith("http")) {//不需要授权return;}//1、授权(系统相册、相机、裁剪时需要) -- 这种写法待分析List<ResolveInfo> resolveInfos = PackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);for (ResolveInfo resolveInfo : resolveInfos) {String packageName = resolveInfo.activityInfo.packageName;if (TextUtils.isEmpty(packageName)) {continue;}antUriPermission(packageName, saveUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);}//2、授权(安装apk时需要)intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);}/*** 取消URi权限* @param context* @param intent* @param saveUri*/public static void revokeUriPermission(Context context, Intent intent, Uri saveUri) {if (!isNeedAdapt()) {return;}if (context == null || intent == null || saveUri == null) {return;}//网络路径的特殊处理,不需要权限if (Scheme() != null && Scheme().startsWith("http")) {//不需要授权return;}try {vokeUriPermission(saveUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);} catch (Exception e) {e.printStackTrace();}}
目前也就这么多。搞定了7.0手机截图以及拍照适配。
本文发布于:2024-01-31 05:04:31,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170664867425751.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |