Created File对象, used to store the photo after taking the photo, the construction method has two parameters, the first one is to getExternalCacheDir()obtain the SD card 本应用的关联缓存目录, and after 6.0, the permission application is required to read and write other directories of the SD card.
By Uri方法converting the File object to the local real path, it is considered unsafe to directly use the local real path since 7.0, and FileUriExposedException will be reported. FileProvider is a special content provider that uses a mechanism similar to that of the content provider. To protect data, you can selectively share the encapsulated Uri with the outside,
To construct the Intent, first declare it as image capture, then specify the output address, and put it into the Uri real address we got
Call startActivityForResult() to start the activity, execute the callback interface, and take the picture successfully, you can call BitmapFactorythe decodeStream() method to parse the output_image.jpg picture into a Bitmap object, and then set it to the ImageView for display. Glide also works here. [Uri type forced to String type and then back to the path is wrong]
访问其他程序的数据, Xml manifest file to register our 内容提供器 1) android:exported="false", whether the current Activity can be started by another Application component: true is allowed to be started; false is not allowed to be started 2) Content Provider's grantUriPermissions attribute value is "true ", all data in the Provider can be authorized to access. But if it is set to "false", only the subset of data specified by this element can be authorized. 3) Meta-data sets the shared directory. If the path is empty, all the associated directories of the app can be shared.
The manifest file is added to the permission statement (the permission is still required to obtain the associated directory before version 4.4), as mentioned before, no dynamic permission application is required
Since both methods need to obtain the picture address and use it for display, encapsulate the two methods
privatefungetImagePath(uri: Uri?, selection: String?): String?{
var path: String?=null// 通过Uri和selection来获取真实的图片路径val cursor = contentResolver.query(uri!!,null, selection,null,null)if(cursor !=null){
if(cursor.moveToFirst()){
path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA))}
cursor.close()}return path
}privatefundisplayImage(imagePath: String?){
if(imagePath !=null){
val bitmap = BitmapFactory.decodeFile(imagePath)
picture.setImageBitmap(bitmap)}else{
Toast.makeText(this,"failed to get image", Toast.LENGTH_SHORT).show()}}
The two methods of version calling, starting from version 4.4, the selected picture in the album no longer returns the real Uri of the picture, but a packaged Uri, so if it is a mobile phone above version 4.4, this Uri needs to be parsed. If the returned Uri is of the document type, then take out the document id for processing, if not, then use the normal way to deal with it. In addition, if the authority of Uri is in media format, the document id needs to be parsed again, and the second half must be extracted by string splitting to get the real digital id. The retrieved id is used to construct a new Uri and conditional statement, and then these values are passed as parameters to the getImagePath() method, and the real path of the image can be obtained.
//4.4后 判断封装情况@TargetApi(19)privatefunhandleImageOnKitKat(data: Intent){
var imagePath: String?=nullval uri =data.data
Log.d("TAG","handleImageOnKitKat: uri is $uri")if(DocumentsContract.isDocumentUri(this, uri)){
// 如果是document类型的Uri,则通过document id处理val docId = DocumentsContract.getDocumentId(uri)if("com.android.providers.media.documents"== uri!!.authority){
val id = docId.split(":".toRegex()).toTypedArray()[1]// 解析出数字格式的idval selection = MediaStore.Images.Media._ID +"="+ id
imagePath =getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection)}elseif("com.android.providers.downloads.documents"== uri.authority){
val contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(docId))
imagePath =getImagePath(contentUri,null)}}elseif("content".equals(uri!!.scheme, ignoreCase =true)){
// 如果是content类型的Uri,则使用普通方式处理
imagePath =getImagePath(uri,null)}elseif("file".equals(uri.scheme, ignoreCase =true)){
// 如果是file类型的Uri,直接获取图片路径即可
imagePath = uri.path
}displayImage(imagePath)// 根据图片路径显示图片}privatefunhandleImageBeforeKitKat(data: Intent){
val uri =data.data
val imagePath =getImagePath(uri,null)displayImage(imagePath)}
After clicking, it will still report Permission deny. The reason is that Android 10 defines access to non-private areas and also adds a statement
Encode (get the time first and then fix the style) If you use the database to store the address of the picture, then use Glide to display it
View Results
The memory has indeed become larger, and access to the data file can be saved tangibly, pay attention to the path, the path will not be scanned by the album. Note that some of them have no images. The reason is that the File is generated first. If you cancel the photo, it will become that.
If you open the album, you can get the path, and the database is just fine.