web-dev-qa-db-ja.com

一部のAndroidデバイスのImageViewで画像URIが画像を表示しない

ImageViewがあります。 ImageViewをクリックすると、ギャラリーが開き、画像を取得してImageViewに表示します。アプリを閉じてから開くと、画像がそこに保持されるという条件があります。そのために、私はsharedUrfrenceにイメージUriを格納しています。アプリケーションを開くと、同じ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.parse(profile_image)を使用して文字列をURIに変換します

しかし、気づいたら、異なるAndroid電話に対してuriが次のように戻ります

_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に画像が表示され、それ以外の場合は表示されません。

14
abh22ishek

これを試してください

私は開発し、testedと取り組んでいます

  1. レノボK3ノート(マシュマロ)
  2. モトローラ(ロリポップ)
  3. サムスン(キットカット)

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();
        }
    }

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);
    }
}

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" />

注:

AssumingMarshmallowtake permissionのコードを追加しました

結果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

15
Pramod Waghmare

画像ファイルの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
Neo

引用 4.4 APIの概要

'以前のバージョンのAndroidでは、アプリで別のアプリから特定の種類のファイルを取得する場合、ACTION_GET_CONTENTアクションを使用してインテントを呼び出す必要があります。このアクションは、アプリにimportしたいファイルをリクエストするための適切な方法です。ただし、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);
2
Kai

このメソッドにURIを渡すと、文字列が返され、ビットマップに変換されます。

  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;
}
1
Tanveer Bulsari

私は以前にもこのようなものに遭遇し、ファイルの正確な場所を提供する便利なヘルパークラスを見つけました。これが link です。

FileUtils.getPath(context、uri)やFileUtils.getFile(context、uri)などのメソッドを使用してファイルを取得できます。次に、次のように使用します。

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

お役に立てれば。

0
Siddharth jain

質問があった場合、100%確実ではありません。特定の画像をimageViewに表示できない場合(アプリを閉じて再起動する前でも)、問題はピカソが特定のプロバイダーからのコンテンツを処理できることです。私はこれが事実であるという意味を理解していませんが、もしそうであれば、そのライブラリのバグ/ RFEの提出を検討することをお勧めします。一方、ピカソが特定のUriの画像を正しく表示しているが、Uri_org-> String-> Uri_regen変換の後ではない場合、Uri_orgはUri_regenと同じではないことを意味します。 (一時的に)コードに数行を追加して文字列をUriに変換し直し、直後にブレークポイントを置いて2つの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」ステートメントに戻し、2つのUriを視覚的に確認します(ほとんどの場合同じですが、そうでない場合はブレークポイントに達したはずですが、これはデバッグの確認に役立ちます)コード自体)。 Uriが同じである場合、なんらかの理由で文字列設定が正しく保存されていません。その場合は、元のUriをメモし、文字列をUriに戻す行にブレークポイントを追加します。

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

前の実験が機能した場合、profile_imageが異なる場合を除き、ここで再び機能するはずです。どちらの方法でも、問題の場所に関するポインタを取得する必要があります。

幸運を!

0
Kaamel

多分あなたは最初に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;  

    }
0
ikhsanudinhakim

ピカソのバージョン管理の問題である可能性があります。彼らはバージョン2.5.0(2.4.0 ...?)で大きな画像をロードすることで何かを修正しましたが、これはまだリポジトリからは利用できません。

ピカソの毎晩のスナップショットを手動で含める必要があります。これで問題が解決する可能性があります。それは私のためにした。

0
Marc DiMillo

URIをビットマップに簡単に変換できます。

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


        parcelFileDescriptor.close();

次に、Imageviewに設定します。imgview.setImageBitmap(image);

これがお役に立てば幸いです。

0

Android 6+の実行時にユーザーに外部ストレージを読み取る権限をリクエストする必要があります

https://developer.Android.com/training/permissions/requesting.html#perm-check

お役に立てれば。

0
Vlad

私は過去にこれをなんとかしてきました。 SharePreferencesに保存する代わりに、onSaveInstanceState(Bundle)がbundle.putParcelable(SOME_KEY、uri)から呼び出されたときにBundleに保存します。 UriがParcelableを実装しているため、これを行うことができます。その後、onCreate()で渡されたバンドルでこのURIを確認します。コード:

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のエンコード/デコードにあると思います。

0
Tin Tran

単純な修正は、ファイルパスの先頭に「file://」を追加するだけです。たとえば、{{uri: "/path/to/file"}}{{uri: "file:///path/to/file"}}に変更すると、どのプラットフォームでも機能します。

0
Benjamin