android - 在 Android Q 上使用 Glide 显示来自具有 "content://"方案的 URI 的图像

标签 android android-glide android-contentresolver mediastore android-10.0

之前有人问过有关 Android Q 和 Glide 的问题,但我无法将它们全部放在一起,所以我希望有人愿意提供帮助。

我正在将从云端 (Firebase) 下载的图像、从图库中选择的图像或用相机拍摄的图像保存到本地存储。我曾经将其保存在应用程序的文件夹中,并且可以将其添加到图库中,但对于 Android Q,这不再可能了。因此,我更改了我的应用程序以使用 MediaStore 和 ContentResolver 来访问文件并保存它。文件保存在 MediaStore.Images.Media.EXTERNAL_CONTENT_URIPictures 目录中。

存储处理程序:

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

它将文件保存到存储中,可以通过Android Studio中的设备资源管理器看到。它还会上传到云端并可以从那里查看(如果它是新文件)。但是当我尝试使用 Glide 将其加载到 ImageView 中时,它给了我一个错误:java.lang.UnsupportedOperationException: Unknown or unsupported URL: content:// 。我似乎不明白为什么。它曾经可以工作,并且 URI 应该是正确的,因为它也可以在其他地方使用(上传文件、保存文件等)并且可以工作。 Glide/我的代码有什么问题?

完整错误:

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)

最佳答案

您的getUriFromContentResolver()是错误的。查询 _ID,然后使用 ContentUris.withAppishedId() 组装要使用的 Uri

例如,在this sample app中来自this book ,我使用:

  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
    }

其中 PROJECTIONQUERY 是:

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

其中集合是:

  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

(就我而言,我正在查询视频;您可以使用 MediaStore.Images 代替)

关于android - 在 Android Q 上使用 Glide 显示来自具有 "content://"方案的 URI 的图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59716014/

相关文章:

android - 如何在 Flutter 中获取 GPS 时间?

android - Glide 库在 AsyncTask.doInBackground 中停止

android - 从 Glide 库中的缓存中删除图像

android - Glide 会自动防止重复调用吗?

android - MissingPluginException(在 channel plugins.flutter.io/firebase_core 上找不到方法 Firebase#initializeCore 的实现) Release模式

java - 删除布局中按/触摸时的深色高光

android - 对“允许模拟位置”的内容解析器进行两次检查,提供不同的结果

Android:根据电话号码搜索联系人

android - ContentDescriptor 在实例化时抛出 NullPointerException

android - 是否可以将 iOS db 文件用于 Android 项目?