Display image from URI with "content://" scheme with Glide on Android Q

TruffelNL

Questions around Android Q and Glide have been asked before but I'm not able to put them all together, so I hope someone is willing to help.

I'm saving images, downloaded from the cloud(Firebase) or chosen from gallery or taken with the camera, to local storage. I used to save it in the app's folder and could add it to the gallery, but with Android Q that is not possible anymore. So I changed my app to use the MediaStore and ContentResolver to access files and save it. Files are saved in the Pictures directory of MediaStore.Images.Media.EXTERNAL_CONTENT_URI.

StorageHandler:

public Uri createUriForFile(String fileName, String parentId)
{
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
    {
        Uri uriFromContentResolver = getUriFromContentResolver(fileName);
        if(uriFromContentResolver != null)
        {
            return uriFromContentResolver;
        }else
        {
            ContentResolver resolver = baseActivity.getApplicationContext().getContentResolver();
            ContentValues contentValues = new ContentValues();
            contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
            contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/jpg");
            contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, EXTERNAL_PICTURE_RELATIVE_PATH);
            return resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
        }
    }else {
        File pictureFile  = new File( EXTERNAL_PICTURE_STORAGE_DIR.getAbsolutePath() + File.separator + parentId + File.separator + fileName );
        checkAndCreatePictureDir(parentId);
        return FileProvider.getUriForFile(baseActivity, baseActivity.getApplicationContext().getPackageName() + ".fileprovider", pictureFile);
    }
}

public Uri getUriFromContentResolver(String fileName)
{
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
    {
        ContentResolver resolver = baseActivity.getApplicationContext().getContentResolver();

        Cursor queryCursor = resolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{MediaStore.Images.Media.DISPLAY_NAME,
                        MediaStore.Images.Media.RELATIVE_PATH}, MediaStore.Images.Media.DISPLAY_NAME + "=? ",
                new String[]{fileName}, null);

        if (queryCursor != null && queryCursor.moveToFirst())
        {
            Uri content = MediaStore.Images.Media.EXTERNAL_CONTENT_URI.buildUpon().appendEncodedPath(queryCursor.getString(queryCursor.getColumnIndex(MediaStore.Images.Media.RELATIVE_PATH)))
                    .appendPath(queryCursor.getString(queryCursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME))).build();
            return content;
        } else
        {
            return null;
        }
    }else
    {
        return null;
    }

It saves the file to the storage, it can be seen with the Device Explorer in Android Studio. It is also uploaded to the cloud and can be viewed from there(if it is a new file). But when I'm trying to load it into a ImageView with Glide, it gives me an error: java.lang.UnsupportedOperationException: Unknown or unsupported URL: content://. And I can't seem to figure out why. It used to work and the URI should be correct as it is used on other places as well(uploading the file, saving the file, etc.) and it works. What is the problem with Glide/my code?

Full error:

E/GlideExecutor: Request threw uncaught throwable
java.lang.UnsupportedOperationException: Unknown or unsupported URL: content://media/external/images/media/Pictures/**AppName**/IMG20200112164646.jpg
    at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:172)
    at android.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:151)
    at android.content.ContentProviderProxy.openTypedAssetFile(ContentProviderNative.java:705)
    at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1687)
    at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1503)
    at android.content.ContentResolver.openInputStream(ContentResolver.java:1187)
    at com.bumptech.glide.load.data.StreamLocalUriFetcher.loadResourceFromUri(StreamLocalUriFetcher.java:85)
    at com.bumptech.glide.load.data.StreamLocalUriFetcher.loadResource(StreamLocalUriFetcher.java:60)
    at com.bumptech.glide.load.data.StreamLocalUriFetcher.loadResource(StreamLocalUriFetcher.java:15)
    at com.bumptech.glide.load.data.LocalUriFetcher.loadData(LocalUriFetcher.java:44)
    at com.bumptech.glide.load.engine.SourceGenerator.startNext(SourceGenerator.java:62)
    at com.bumptech.glide.load.engine.DecodeJob.runGenerators(DecodeJob.java:302)
    at com.bumptech.glide.load.engine.DecodeJob.runWrapped(DecodeJob.java:272)
    at com.bumptech.glide.load.engine.DecodeJob.run(DecodeJob.java:233)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(Thread.java:919)
    at com.bumptech.glide.load.engine.executor.GlideExecutor$DefaultThreadFactory$1.run(GlideExecutor.java:446)
CommonsWare

Your getUriFromContentResolver() is wrong. Query for the _ID, then use ContentUris.withAppendedId() to assemble the Uri to use.

For example, in this sample app from this book, I use:

  suspend fun getLocalUri(filename: String): Uri? =
    withContext(Dispatchers.IO) {
      val resolver = context.contentResolver

      resolver.query(collection, PROJECTION, QUERY, arrayOf(filename), null)
        ?.use { cursor ->
          if (cursor.count > 0) {
            cursor.moveToFirst()
            return@withContext ContentUris.withAppendedId(
              collection,
              cursor.getLong(0)
            )
          }
        }

      null
    }

where PROJECTION and QUERY are:

private val PROJECTION = arrayOf(MediaStore.Video.Media._ID)
private const val QUERY = MediaStore.Video.Media.DISPLAY_NAME + " = ?"

and where collection is:

  private val collection =
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) MediaStore.Video.Media.getContentUri(
      MediaStore.VOLUME_EXTERNAL
    ) else MediaStore.Video.Media.EXTERNAL_CONTENT_URI

(in my case, I am querying videos; you would use MediaStore.Images instead)

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

How to get actual path of image from Uri in Android Q?

Getting run-time error 'image uri must be of the content scheme type' in Android Code

How to copy file from app-specific folder (file:// scheme) to MediaStore Images collection (content:// scheme) in Android Q?

Not able to display gif from local uri using glide

Android: Getting a file URI from a content URI?

Display multiple image with Glide

Android: Glide not showing large image from URL

How to show image from server into Glide in android

Display an image using Glide in Android. Can't see anything

Show image from Data URI scheme on Java panel

Display image using Glide and Retrofit from local computer memory

display an image retrieved from its URI

i use Glide for my image display in android studio but how can i implement Glide to my listview?

Android: Getting image bitmap from third party app (e.g. WhatsApp) via content:// URI

How can I convert a file Uri scheme into content Uri scheme?

No image from glide in Firestore

Android get EXIF data from content URI

Get content uri from file path in android

Create File object from Android content URI

How to display image having fixed Uri in Image View in android

How set image into ImageView using Glide and a URI?

Glide load local image by Uri.

Android Q: Get image from gallery and process it

Android glide: crop - cut off X pixels from image bottom

Get real path from Uri - DATA is deprecated in android Q

Unable to load video thumbnail from Uri in android Q

Android Glide download before display

Android set image from URI on ImageView

display image from android database