Изображение 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 я преобразовываю String в 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 -content://media/external/images/media/- это изображение на ImageView Perfect, а в других случаях это не

Ответ 1

Попробуйте

Я разработал и tested и работал над

  • Примечание Lenovo K3 (Зефир)
  • Motorola (Lollipop)
  • 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);
    }
}

В вашем файле Manifest добавьте 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

Ответ 2

Я думаю, что проблема с 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 для поиска точного пути к файлу. Это самый простой способ справиться с проблемой, как вы определили. Пожалуйста, дайте мне знать, если вам нужна дополнительная помощь:)

Ответ 3

Цитата из 4.4 Обзор API:

'В предыдущих версиях Android, если вы хотите, чтобы ваше приложение извлекало определенный тип файла из другого приложения, оно должно вызывать намерение с действием ACTION_GET_CONTENT. Это действие по-прежнему является подходящим способом запроса файла, который вы хотите импортировать в ваше приложение. Однако Android 4.4 представляет действие ACTION_OPEN_DOCUMENT, которое позволяет пользователю выбрать файл определенного типа и предоставить вашему приложению долгосрочный доступ для чтения к этому файлу (возможно, с доступом для записи) без импорта файла к вашему приложению "(выделено мной)

Чтобы ваше приложение могло получать ранее выбранные изображения, просто измените действие с ACTION_GET_CONTENT на 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);

Ответ 4

Передайте свой URI в этом методе, он вернет String и преобразует его в 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;
}

Ответ 6

Возможно, вы справитесь с этим, сначала конвертируя 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;  

    }

Ответ 7

Мне это удалось в прошлом. Вместо сохранения в SharePreferences я сохраняю его в Bundle, когда onSaveInstanceState (Bundle) получает вызов: bundle.putParcelable(SOME_KEY, uri). Вы можете сделать это, потому что Uri реализует Parcelable. После этого проверьте этот uri в Bundle, который был передан в 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.

Ответ 8

Вы можете легко конвертировать URI в Bitmap:

ParcelFileDescriptor parcelFileDescriptor =
                context.getContentResolver().openFileDescriptor(selectedFileUri, "r");
        FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
        Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);


        parcelFileDescriptor.close();

И затем перейдите в Imageview: imgview.setImageBitmap(изображение);

Надеюсь, это поможет вам.

Ответ 9

Может быть проблема с версией Пикассо. Они исправили что-то с загрузкой больших изображений в версии 2.5.0 (2.4.0...?), Которая еще не доступна через репозитории.

Вам нужно будет вручную включить ночной снимок Picasso, и это, скорее всего, исправит вашу проблему. Это было для меня.

Ответ 10

Я также сталкивался с чем-то подобным ранее и нашел полезный вспомогательный класс, который дает вам точное местоположение файла. Вот ссылка .

Вы можете использовать методы, такие как FileUtils.getPath(context, uri) или FileUtils.getFile(context, uri), чтобы получить файл. Тогда просто используйте его так:

 Picasso.with(UsersProfileActivity.this)
         .load(Uri.fromFile(file))
         .centerCrop()
         .resize(200,200)
         .into(img_photo);

Надеюсь, что это поможет.

Ответ 11

Просто не уверен на 100%, если я получу вопрос. Если определенные изображения не могут быть показаны в imageView (даже до закрытия и перезапуска приложения), проблема связана с тем, что Picasso может обрабатывать содержимое определенных поставщиков. Я не понимаю, что это так, но если это так, то вы можете захотеть зарегистрировать ошибку /RFE для этой библиотеки. С другой стороны, если Picasso правильно показывает изображение для данного Uri, но не после Uri_org → String → Uri_regen, то это означает, что Uri_org не совпадает с Uri_regen. Вы можете (временно) добавить пару строк своего кода, чтобы преобразовать String обратно в Uri и сразу же поставить точку останова и сравнить два Uri's. Это должно дать вам понять, как все идет не так.

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 одинаковы, то почему-то предпочтение String по какой-то причине не сохраняется правильно. В этом случае запишите оригинал Uri и добавьте точку останова на линии, которая преобразует строку обратно в Uri:

Uri uri = Uri.parse(profile_image) //profile_image is retrieved from sharedpreferences

Если предыдущий эксперимент сработал, он должен снова работать здесь, если профиль profile_image не отличается. В любом случае вы должны получить указатели относительно того, где проблема.

Удачи!