Uri изображения не отображает изображения в ImageView на некоторых устройствах android
у меня есть ImageView. Когда вы нажимаете на ImageView, он открывает галерею, и вы выбираете изображение и показываете его на ImageView. У меня есть условие, что когда я закрываю свое приложение, а затем открываю его, изображение сохранится там . Поэтому для этого я сохраняю Uri изображения на sharedprefrence. И при открытии приложения я получаю тот же Uri и пытается отобразить изображение на imageView.
однако в некоторых телефонах-изображение выглядит идеально, как Mi (Lollipop), Samsung (KitKat) но это не отображается в телефонах типа-Motorola (Marshmallow) ,One Plus One (Marshmallow). Есть идеи, почему это происходит ? Вот мой код
для сбора изображения, которое я использую
Intent intent=new Intent();intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select Picture"), Constants.SELECT_PICTURE);
и на onActivityResult () код
@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();
}
и при извлечении из sharedprefrence я конвертирую строку в uri с помощью Uri.parse(profile_image)
однако, если я замечу, uri возвращается для разных телефонов android следующим образом
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
следовательно, когда содержимое uri is-content: / / media / external/images/ media / is отображение изображения на ImageView идеально, а в других случаях это не
11 ответов
попробуй такое
я разработал и tested
и работает на
- Lenovo K3 Примечание (Зефир)
- Motorola (Леденец)
- Samsung (KitKat)
в своем MainActivity.java
добавить
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();
}
}
Теперь Ручка 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);
}
}
в своем Добавить 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" />
Примечание:
Assuming
вы добавили код take permission
на Marshmallow
результат Uri
lenovo K3 Примечание: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
Я думаю, что проблема с uri файла изображения, я использую класс для получения точного URI, и он протестирован и работает на всех версиях.
package fandooo.com.fandooo.util;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
public class ImageFilePath {
/**
* Method for return file path of Gallery image
*
* @param context
* @param uri
* @return path of the selected image file from gallery
*/
public static String getPath(final Context context, final Uri uri) {
// check here to KITKAT or new version
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/"
+ split[1];
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
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);
}
// MediaProvider
else if (isMediaDocument(uri)) {
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);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context
* The context.
* @param uri
* The Uri to query.
* @param selection
* (Optional) Filter used in the query.
* @param selectionArgs
* (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
public static String getDataColumn(Context context, Uri uri,
String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = { column };
try {
cursor = context.getContentResolver().query(uri, projection,
selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri
.getAuthority());
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri
.getAuthority());
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri
.getAuthority());
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri
.getAuthority());
}
}
используйте getPath, чтобы найти точный путь к файлу. Это простой способ справиться с проблемой, как вы определили. Пожалуйста, попробуйте и дайте мне знать, если вам нужна дополнительная помощь :)
цитирую 4.4 обзор API:
'в предыдущих версиях Android, Если вы хотите, чтобы ваше приложение, чтобы получить определенный тип файла из другого приложения, он должен вызвать намерение с ACTION_GET_CONTENT действие. Это действие по-прежнему является подходящим способом запроса файла, который вы хотите импорт в вашем приложении. Тем не менее, Android 4.4 вводит ACTION_OPEN_DOCUMENT действие, которое позволяет пользователю выберите файл определенного типа и предоставьте вашему приложению долгосрочный доступ для чтения к этому файлу (возможно, с доступом на запись) без импорта файла в приложение.(подчеркнуто)
чтобы ваше приложение могло извлекать ранее выбранные изображения, просто измените действие с ACTION_GET_CONTENT to ACTION_OPEN_DOCUMENT (решение подтвердило работу на 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);
передайте свой URI в этом методе, он вернет строку и преобразует ее в 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;
}
вам нужно запросить разрешение на чтение внешнего хранилища пользователю во время выполнения для Android 6+
https://developer.android.com/training/permissions/requesting.html#perm-check
надеюсь, что это помогает.
возможно, вы можете справиться с этим, сначала преобразовав URI в реальный путь.
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();
}
}
}
и ваш onActivityResult должен выглядеть так
@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;
}
мне удалось сделать это в прошлом. Вместо того, чтобы хранить его в SharePreferences, я сохраняю его в пакете, когда onSaveInstanceState(Bundle) вызывается: bundle.putParcelable (SOME_KEY, uri). Вы можете сделать это, потому что Uri реализует Parcelable. После этого проверьте этот uri в пакете, переданном в onCreate (). Код:
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: Я думаю, проблема хранения uri в SharePreference заключается в кодировании / декодировании Uri.
вы можете легко конвертировать URI в Bitmap:
ParcelFileDescriptor parcelFileDescriptor =
context.getContentResolver().openFileDescriptor(selectedFileUri, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close();
а затем установите в Imageview: imgview.setImageBitmap(изображения);
надеюсь, это поможет вам.
может быть проблема с версиями Пикассо. Они исправили что-то с загрузкой больших изображений в версии 2.5.0 (2.4.0...?), который еще не доступен через репозитории.
вам нужно будет вручную включить ночной снимок Пикассо, и это, вероятно, исправит вашу проблему. Для меня-да.
Я также столкнулся с чем-то подобным ранее и нашел полезный вспомогательный класс, который дает вам точное местоположение файла. Вот это ссылке.
вы можете использовать такие методы, как FileUtils.getPath (контекст, uri) или FileUtils.getFile (context, uri), чтобы получить файл. Тогда просто используйте его так:
Picasso.with(UsersProfileActivity.this)
.load(Uri.fromFile(file))
.centerCrop()
.resize(200,200)
.into(img_photo);
надеюсь, что это помогает.
просто не на 100% уверен, если я получу вопрос. Если определенные изображения не могут быть показаны в imageView (даже до закрытия и перезапуска приложения), то проблема в том, что Picasso может обрабатывать содержимое от определенных поставщиков. Я не понимаю, что это так, но если это так, то вы можете рассмотреть возможность подачи ошибки/RFE для этой библиотеки. С другой стороны, если Picasso правильно показывает изображение для данного Uri, но не после Uri_org - > String - > Uri_regen преобразование тогда это означает, что Uri_org не то же самое, что Uri_regen. Вы можете (временно) добавить пару строк кода, чтобы преобразовать строку обратно в Uri и поставить точку останова сразу после и сравнить два Uri. Это должно дать вам ключ к тому, как все идет не так.
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 " и визуально проверьте два Uri (которые почти наверняка будут одинаковыми, иначе у вас было бы нажмите точку останова,но это поможет проверить сам код отладки). Если URI такие же, то строки предпочтение не правильно сохранился почему-то. В этом случае запишите исходный Uri и добавьте точку останова в строке, которая преобразует строку обратно в Uri:
Uri uri = Uri.parse(profile_image) //profile_image is retrieved from sharedpreferences
Если предыдущий эксперимент работал, он должен снова работать здесь, если profile_image не отличается. В любом случае вы должны получить указатели на то, где проблема есть.
удачи!