因为在Android7.0上,google使用了新的权限机制,因此致使在调用相机的时候,若是传递的URI为”file://”类型,的系统会抛出FileUriExposedException
这个错误.具体堆栈信息以下:css
android.os.FileUriExposedException: file:///storage/emulated/0/Android/data/***/files/Cache/30001748.jpg exposed beyond app through ClipData.Item.getUri()
at android.os.StrictMode.onFileUriExposed(StrictMode.java:1799)
at android.net.Uri.checkFileUriExposed(Uri.java:2346)
at android.content.ClipData.prepareToLeaveProcess(ClipData.java:832)
at android.content.Intent.prepareToLeaveProcess(Intent.java:8923)
at android.content.Intent.prepareToLeaveProcess(Intent.java:8908)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1519)
at android.app.Activity.startActivityForResult(Activity.java:4288)
...
at android.view.View.performClick(View.java:5611)
at android.view.View$PerformClick.run(View.java:22276)
at android.os.Handler.handleCallback(Handler.java:754)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:160)
at android.app.ActivityThread.main(ActivityThread.java:6139)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:874)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:764)
解决URI
原本是直接经过Uri.fromFile(file)
获取的uri,而后经过Intent
传出,在Android7.0及以上版本能够采用以下方式获取urijava
// 中间的参数 authority 能够随意设置.
Uri uri = FileProvider.getUriForFile(context,"org.diql.fileprovider", file);
经过这个方法,系统会产生一个临时的uri来进行替换掉原始的uri.android
在AndroidManifest.xml
中配置markdown
<provider android:name="android.support.v4.content.FileProvider" android:authorities="org.diql.fileprovider" //这里就是1中的参数 authority android:exported="false" android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
</provider>
在res
中建立相应的文件来让系统最终生成相应的的uri.
在res
的如2中的路径新建对应的文件,这里就是res->xml->file_paths.xml
.其中’file_paths.xml’文件的内容以下app
<?xml version="1.0" encoding="utf-8"?>
<resource xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="cache" path="Cache/" /> //这里的"Cache/"就是问题中抛出异常的那个路径
</resource>
原本觉得问题就此解决了,可是又产生了下面的问题ide
java.lang.RuntimeException: Unable to start activity ComponentInfo{.../....EditInfoActivity}: java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/.../files/Cache/30001748.jpg
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2680)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2741)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1492)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:160)
at android.app.ActivityThread.main(ActivityThread.java:6139)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:874)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:764)
...
明明这个路径对应的文件是存在的,为何会找不到呢,感受到确定是路径配置那里出问题,通过查找资料,才发现file_paths.xml
中配置的external-path
是以下做用:oop
该方式提供在外部存储区域根目录下的文件。它对应Environment.getExternalStorageDirectory返回的路径:eg:”/storage/emulated/0”;google
而external-files-path
的做用是我须要的这种路径即:spa
该方式提供在应用的外部存储区根目录的下的文件。它对应Context#getExternalFilesDir(String) Context.getExternalFilesDir(null)返回的路径。eg:”/storage/emulated/0/Android/data/com.jph.simple/files”。.net
将这个修改好以后就一切大工告成了.