I have an ImageView. When you click on a ImageView, it will open gallery and you pick up a image and show it on ImageView. I have a condition that when I close my app and then I open it, the image will retain there . So for that, I am storing image Uri on sharedprefrence. And on opening the application i am retrieving the same Uri and tries to display the image on imageView.
However in some phones - image appears perfect like Mi(Lollipop), Samsung(KitKat) but it doesn't appear in phones like - Motorola(Marshmallow) ,One Plus One (Marshmallow). Any idea why it's happening ? Here is my code
For picking up an image i am using
Intent intent=new Intent();intent.setType("image/*"); intent.setAction(Intent.ACTION_GET_CONTENT); startActivityForResult(Intent.createChooser(intent, "Select Picture"), Constants.SELECT_PICTURE);
And on OnActivityResult() code is
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(requestCode==Constants.SELECT_PICTURE && resultCode==RESULT_OK && null!=data) { Uri uri=data.getData(); Picasso.with(UsersProfileActivity.this) .load(uri) .centerCrop() .resize(200,200) .into(img_photo); // This profile image i am storing into a sharedpreference profile_image=uri.toString(); }
And while retrieving from sharedprefrence I convert String to uri by using Uri.parse(profile_image)
However if I notice, uri returns for different android phone is as follows
Mi(Lollipop)- Uri=content://media/external/images/media/12415 samsung(KitKat)-Uri=content://media/external/images/media/786 Motorola(Marshmallow)- Uri=content://com.android.providers.media.documents/document/image%3A30731 One Plus One (Marshmallow)- Uri=content://com.android.providers.media.documents/document/image%3A475
Hence when uri content is -content://media/external/images/media/ is display image on ImageView Perfect and in other cases it is not
10 Answers
Answers 1
Try this
I developed and tested
and working on
- Lenovo K3 Note(Marshmallow)
- Motorola(Lollipop)
- Samsung(KitKat)
In your MainActivity.java
add
profilePicture = (ImageView)findViewById(R.id.imgProfilePicture); sharedPreferences = getSharedPreferences(getString(R.string.app_name)+"_ProfileDetails",MODE_PRIVATE); // get uri from shared preference String profilePicUri = sharedPreferences.getString("profilePicUrl",""); // if uri not found if (profilePicUri.equalsIgnoreCase("")){ // code for open gallery to select image Intent intent; if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){ intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); }else{ intent = new Intent(Intent.ACTION_GET_CONTENT); } intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.setType("image/*"); startActivityForResult(Intent.createChooser(intent, "Select Picture"), SELECT_PICTURE_CONSTANT); }else{ try{ final int takeFlags = (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); // Check for the freshest data. getContentResolver().takePersistableUriPermission(Uri.parse(profilePicUri), takeFlags); // convert uri to bitmap Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), Uri.parse(profilePicUri)); // set bitmap to imageview profilePicture.setImageBitmap(bitmap); } catch (Exception e){ //handle exception e.printStackTrace(); } }
Now Handle onActivityResult
.
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == SELECT_PICTURE_CONSTANT && resultCode == RESULT_OK && null != data) { Uri uri = data.getData(); // This profile image i am storing into a sharedpreference SharedPreferences.Editor editor = sharedPreferences.edit(); // save uri to shared preference editor.putString("profilePicUrl",uri.toString()); editor.commit(); profilePicture.setImageURI(uri); } }
In your Manifest
file add permission
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Note:
Assuming
you added code for take permission
for Marshmallow
Result Uri
lenovo K3 Note: content://com.android.externalstorage.documents/document/primary%3ADCIM%2FCamera%2FIMG_20160606_212815.jpg
samsung: content://com.android.providers.media.documents/document/image%3A2086
motorola: content://com.android.providers.media.documents/document/image%3A15828
Answers 2
You need to request the permission to read external storage to user at runtime for Android 6+
https://developer.android.com/training/permissions/requesting.html#perm-check
Hope this helps.
Answers 3
Maybe you can handle it by converting URI to real path first.
public String getRealPathFromURI(Context context, Uri contentUri) { Cursor cursor = null; try { String[] proj = { MediaStore.Images.Media.DATA }; cursor = context.getContentResolver().query(contentUri, proj, null, null, null); int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); return cursor.getString(column_index); } finally { if (cursor != null) { cursor.close(); } } }
And your onActivityResult should looks like this
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(requestCode==Constants.SELECT_PICTURE && resultCode==RESULT_OK && null!=data) { Uri uri=data.getData(); String imagePath = getRealPathFromURI(getApplicationContext(), uril); Picasso.with(UsersProfileActivity.this).load(imagePath).centerCrop().resize(200,200).into(img_photo); profile_image = imagePath; }
Answers 4
I have managed to do this in the past. Instead of storing it in SharePreferences, I save it in the Bundle when onSaveInstanceState(Bundle) get called by: bundle.putParcelable(SOME_KEY, uri). You can do this because Uri implements Parcelable. After that, check for this uri in the Bundle passed in onCreate(). Code:
public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); if (savedInstanceState != null){ loadImage((Uri)saveInstanceState.getParcelable(SOME_KEY)) } } public void onSaveInstanceState(Bundle bundle){ bundle.putParcelable(SOME_KEY, uri) }
P/S: I guess the problem of storing the uri in SharePreference is encoding/decoding Uri.
Answers 5
Quoting from 4.4 API overview:
'On previous versions of Android, if you want your app to retrieve a specific type of file from another app, it must invoke an intent with the ACTION_GET_CONTENT action. This action is still the appropriate way to request a file that you want to import into your app. However, Android 4.4 introduces the ACTION_OPEN_DOCUMENT action, which allows the user to select a file of a specific type and grant your app long-term read access to that file (possibly with write access) without importing the file to your app.'(emphasis added)
To allow your app to retrieve previously-selected images, just change the action from ACTION_GET_CONTENT to ACTION_OPEN_DOCUMENT (solution confirmed working on Nexus 7 2013).
Intent intent = new Intent(); intent.setType("image/*"); String action = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT ? Intent.ACTION_OPEN_DOCUMENT : Intent.ACTION_GET_CONTENT; intent.setAction(action); startActivityForResult(Intent.createChooser(intent, "Select Picture"), Constants.SELECT_PICTURE);
Answers 6
You can Easily convert URI to Bitmap:
ParcelFileDescriptor parcelFileDescriptor = context.getContentResolver().openFileDescriptor(selectedFileUri, "r"); FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor(); Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor); parcelFileDescriptor.close();
And then set in to Imageview: imgview.setImageBitmap(image);
Hope this will help you.
Answers 7
Could be a Picasso versioning issue. They fixed something with loading large images in version 2.5.0 (2.4.0...?), which isn't available via the repositories yet.
You'll need to manually include the nightly snapshot of Picasso, and that will likely fix your issue. It did for me.
Answers 8
Pass your URI in this method it will return a String and than convert it into Bitmap
String path = getPath(getApplicationContext(), uri); Bitmap bitmap = BitmapFactory.decodeFile(path); imageView.setImageBitmap(bitmap); public static String getPath(final Context context, final Uri uri) { // DocumentProvider if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri)) { if (isExternalStorageDocument(uri)) {// ExternalStorageProvider final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; String storageDefinition; if ("primary".equalsIgnoreCase(type)) { return Environment.getExternalStorageDirectory() + "/" + split[1]; } else { if (Environment.isExternalStorageRemovable()) { storageDefinition = "EXTERNAL_STORAGE"; } else { storageDefinition = "SECONDARY_STORAGE"; } return System.getenv(storageDefinition) + "/" + split[1]; } } else if (isDownloadsDocument(uri)) {// DownloadsProvider final String id = DocumentsContract.getDocumentId(uri); final Uri contentUri = ContentUris.withAppendedId( Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); return getDataColumn(context, contentUri, null, null); } else if (isMediaDocument(uri)) {// MediaProvider final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; Uri contentUri = null; if ("image".equals(type)) { contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; } else if ("video".equals(type)) { contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; } else if ("audio".equals(type)) { contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; } final String selection = "_id=?"; final String[] selectionArgs = new String[]{ split[1] }; return getDataColumn(context, contentUri, selection, selectionArgs); } } else if ("content".equalsIgnoreCase(uri.getScheme())) {// MediaStore (and general) // Return the remote address if (isGooglePhotosUri(uri)) return uri.getLastPathSegment(); return getDataColumn(context, uri, null, null); } else if ("file".equalsIgnoreCase(uri.getScheme())) {// File return uri.getPath(); } return null; }
Answers 9
I also run into something like this earlier and found a useful helper class which gives you the file's exact location. Here is the link.
You can use the methods like FileUtils.getPath(context, uri) or FileUtils.getFile(context, uri) to get the file. Then just use it like this:
Picasso.with(UsersProfileActivity.this) .load(Uri.fromFile(file)) .centerCrop() .resize(200,200) .into(img_photo);
Hope this helps.
Answers 10
Just not 100% sure if I get the question. If certain images cannot be shown in the imageView (even before closing and restarting the app) then the issue is with Picasso is being able to handle the contents from certain providers. I am not getting the sense that this is the case, but if it is, then you might want to consider filing a bug/RFE for that library. On the other hand, if Picasso is correctly showing the image for a given Uri, but not after Uri_org -> String -> Uri_regen conversion then it means that Uri_org is not the same as Uri_regen. You can (temporarily) add a couple of lines your code to convert the String back to Uri and put a breakpoint just after and compare the two Uri's. That should give you a clue as to how things are going wrong.
profile_image=uri.toString(); //add the next few lines for debugging purposes only; remove them later Uri uri2 = Uri.parse(profile_image) if (!uri.equals(uri2) //add a breakpoint on the next line Log.d("Uri mismatch), "Ouch"); //remove the lines after you are done with debugging
If you are not hitting the breakpoint, then move the breakpoint back to the "if" statement and visually check the two Uri's (which almost certainly will be the same, otherwise you would have had hit the breakpoint, but this would help checking the debug code itself). If the Uri's are the same then somehow the String preference is not being preserved correctly for some reason. In that case make a note of the original Uri and add a breakpoint on the line that converts the String back to Uri:
Uri uri = Uri.parse(profile_image) //profile_image is retrieved from sharedpreferences
If the previous experiment worked, it should be working again here unless the profile_image is different. Either way you should get pointers as to where the issue is.
Good luck!
0 comments:
Post a Comment