After Android 4.4 and 7.0 access to albums and crop related issues

After Android4.4

We know that after android4.4, if the following code directly accesses the system gallery

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");

The obtained Uri is no longer a Uri of type content://media/, but a Uri of type conten://…provider/.

Format returned before Android 4.4

You can see that the previous return Uri is like this

You can see that the previous return Uri is like this

Return format after Android4.4

We see that the format has changed. If we still want to directly access this Uri, crop it and save it back to this Uri, the app will crash. There are already many solutions on the Internet, so I won't say more here, the reason is that I don't recommend using this method to get the picture Uri after 4.4, let's talk about why

We see that the format has changed.  If we still want to directly access this Uri, crop it and save it back to this Uri, the app will crash.  There are already many solutions on the Internet, so I won't say more here, the reason is that I don't recommend using this method to get the picture Uri after 4.4, let's talk about why

reason

In fact, the Uri accessed by the above methods after 4.4 may also be of the previous content://media/ type, such as the 5.1 system of Meizu MX5, so if we want to get the real path of the picture, we need to use the api version greater than or equal to 19. Judgment, using different methods. If the following access method is used, before 7.0, only content://media/ type Uri will be returned.

Intent intent = new Intent(Intent.ACTION_PICK); 
intent.setDat(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);

If it is the Uri of content://media/, then we can get the real path in the following way

public String changeToPath(Uri uri){
        String[] proj = { MediaStore.Images.Media.DATA };
        //sdk<=11,cursor = manageQuery(uri,proj,null,null,null)
        CursorLoader loader = new CursorLoader(this,uri,proj,null,null,null);
        Cursor cursor = loader.loadInBackground();
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        Log.w("changtoUri",cursor.getString(column_index));
        return cursor.getString(column_index);
    }

So what about after 7.0? And why not use the first method of accessing the gallery?


Because if it is after 7.0, although the Uri returned by ACTION_PICK is no longer a content://media/ type Uri, we can still use the above-mentioned changToPath method to obtain the real path without having to use different methods according to different Uri . So what about the Uri returned by 7.0ACTION_PICK? Is such that

write picture description here
The picture is not clear, probably this type

content://com.google.android.apps.photos.contentprovider/-1/1/content://media/external/file/95/ORIGINAL/NONE/998221584 typ=image/* (has extras)

For the first method, it is obtained by using different methods, and there are many examples on the Internet.

still have a question

It is the problem of app crash. After my verification, I found that before 7.0, we could not use the access to the gallery. Generally speaking, the stored URIs are content://meida/ class Uri and file:// class Uri (ie Uri.fromFile(file)), so when we access the content://...provider obtained by calling Intent.getData() after accessing the image using the first method, the clipped image cannot be written, so this is also recommended. The reason for the second method is that before 7.0, the Uri of the class conten://media/ is returned. If 7.0 is of the provider class, just use the above changToPath() to convert it to the real path and then use it

File file = new File(changeToUrl(data.getData()));
 intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(file));

It's ok. Of course, you can also use the first method for different return results, but I think it's a little more troublesome.

say 7.0

6.0 has more dynamic permission management, while 7.0 directly thinks that Uri.fromFile(file) is unsafe, and an exception will be thrown if used directly. So what to do, use FileProvider. There are also many examples on the Internet. I will show the steps
1. Register our provider in AndroidManifest.xml
2. Create a new paths.xml in the res/xml/ directory with any name
3. Use FileProvider.getUriForFile() in the code

write picture description here

write picture description here

write picture description here

If the uri of data.getDtat() is of the provider class, it will crash directly. If it is 7.0, it can be cropped, but when the crop is saved and saved, it will crash again. To save it back, intent3.putExtra(MediaStore. EXTRA_OUTPUT, uri) This uri can only be the fileUri of the Uri.fromFile(file) class, not even the content://media/ class that was available before ! In 7.0, it is very troublesome for us to call the camera to take pictures. The process is as follows:


1. Use FileProvider to obtain a uri to store the captured picture
2. Call the system cropping function, that is

Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndtype(uri,"image/*")
intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile)
intent3.putExtra(MediaStore.EXTRA_OUTPUT,mUri)

Note that at this time, the uri cannot be obtained by our FileProvider.getUriForFile(), this is the Uri of the custom private class, which is inaccessible, and the selection of the gallery returns is only readable , which is the same after 4.4, but cannot It is the uri of the custom FilerProvider, so we need to change the uri. You can use the following method to convert it into the content://media/ class. This is what I collected on the Internet.

 public Uri getImageContentUri(Context context, File imageFile) {
        String filePath = imageFile.getAbsolutePath();
        Cursor cursor = context.getContentResolver().query(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                new String[] { MediaStore.Images.Media._ID },
                MediaStore.Images.Media.DATA + "=? ",
                new String[] { filePath }, null);

        if (cursor != null && cursor.moveToFirst()) {
            int id = cursor.getInt(cursor
                    .getColumnIndex(MediaStore.MediaColumns._ID));
            Uri baseUri = Uri.parse("content://media/external/images/media");
            return Uri.withAppendedPath(baseUri, "" + id);
        } else {
            if (imageFile.exists()) {
                ContentValues values = new ContentValues();
                values.put(MediaStore.Images.Media.DATA, filePath);
                return context.getContentResolver().insert(
                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
            } else {
                return null;
            }
        }
    }

After the conversion is completed, the uri in putExtra(… , uri) still needs to be changed to the file:// class, that is, Uri.fromFile(file), so we can call the above changToPath() to get what we just got with getImageContenturi(). The content://media/ class is converted to the real path, and then the file is obtained, and then the file class uri is obtained, so that the cropped picture can be saved back!

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325719248&siteId=291194637