introduce
FileProvider is the recommended way to get file Uri in Android and will replace the Uri.fromFile() method
old-fashioned problem
In Android 7.0 version, directly obtaining Uri from the file in the internal storage will cause the program to crash. The relevant code is as follows:
Uri uri = Uri.fromFile (file);
If you run it, you will get an error:
The solution is to introduce FileProvider
Use of FileProvider
Now, I will show you the usage of FileProvider step by step
statement
We first need to declare a FileProvider child node under the application node in the manifest file
<provider android:authorities="com.example.songzeceng.myFileProvider" android:name="android.support.v4.content.FileProvider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/updatepath"></meta-data> </provider>
The properties and nodes inside are explained as follows:
provider: indicates that this is a provider
The name of android:authorities:provider, like this attribute of ContentProvider, is the identity of this provider
android:name: fixed, to use FileProvider, it must be declared as in the code
android:exported: whether to export, must be false
android:grantUriPermissions: Whether to be granted uri permission, must be true
<meta-data>: Attributes visible to external applications of this provider, a path must be declared, indicating the shared directory
android:name: The name of the shared directory, fixed hard-coded
android:resource: The xml file corresponding to the path, this should create a new corresponding xml file in the res directory
Create share xml file
Now we have to create an xml file corresponding to the android:resource tag mentioned above --> xml/updatepath.xml
<?xml version="1.0" encoding="utf-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android"> <paths> <files-path path="files" name="files" /> <cache-path path="files" name="cache" /> <external-path path="files" name="external" /> <external-files-path path="files" name="externalfiles"/> <!-- This tag requires support 25.0.0 or above to use --> <external-cache-path path="files" name="externalcache"/> </paths> </resources>
The labels file-path and cache-path represent a directory in the phone memory, the path attribute is a subdirectory under this directory, and the name attribute is a pseudonym, which will replace the absolute path of the path directory
The paths corresponding to the sub-tags involved in the figure are as follows:
subtab | The absolute path corresponding to the subtag (without path) | The absolute path corresponding to the subtag (plus path) | pseudonym |
files-path | The files directory under the app's private storage area (context.getFilesDir()) |
files directory plus path (context.getFilesDir()/files) |
files |
cache-path | The cache directory under the app's private directory (context.getCacheDir()) |
private cache directory plus path
(context.getCacheDir()/files)
cacheexternal-path external stub directory (Environment.getExternalStorageDirectory()) external stub directory plus path (Environment.getExternalStorageDirector()/files)externalexternal-files
-path
The file directory under the external stub directory
(context.getExternalFilesDir())
file directory plus path
(context.getExternalFilesDir()/files)
externalfiles
external-cache
-path
Cache directory under external stub directory
(context.getExternalCacheDir())
cache directory plus path
(context.getExternalCacheDir()/files)
externalcachesThe final result is the shared directory obtained by the external app, not a path, but a pseudonym
Moreover, each time a shared directory is added, a corresponding sub-tag must be added.
For example, if I add a new shared directory, which is a folder under the external stub directory, I add a subtag as follows:
<external-path name = "fp_pictures" path = "/Pictures/dongqiudi/"></external-path>
just fine
Use FileProvider to get file Uri
code show as below:
String path = Environment.getExternalStorageDirectory().getPath() + "/Pictures/dongqiudi/1523624189281.jpg"; File file = new File(path); if (file.exists()) { Uri uri = FileProvider.getUriForFile(MainActivity.this, "com.example.songzeceng.myFileProvider", file); Log.i(TAG, "uri:" + uri.toString()); }
The code is very simple, but in order to prevent errors, I judged whether the file exists (what happens if it does not exist, I have not tried it)
result
As you can see, it does replace the shared directory path we specified with the pseudonym fp_pictures. This uri is different from the previous path uri, but it does not affect the use, and it will still find our file correctly.
Epilogue
This example is just a verification, to see if the FileProvider parses and converts the file uri correctly, and whether the program crashes, and finds that everything is normal, then we can use the newly generated uri according to our own business.