ALBUM_ART列在API 29中已被弃用,如何获取路径?

11

目前我们正在使用MediaStore.Audio.AlbumColumns.ALBUM_ART来获取专辑封面的路径,除了Pixel 3a(Android 10)外,我们已经成功获取到了路径。 经过一些研究,ALBUM_ART在API 29及以上版本中已成为不建议使用的API,如下所示:这里

链接中写道:“应用程序可能没有文件系统权限直接访问该路径。 应用程序应使用ContentResolver#loadThumbnail来获得访问权限,而不是尝试直接打开此路径。”

我的问题是:
1)我已经在应用程序清单中声明了外部存储器访问权限(READ_EXTERNAL_STORAGE),并在应用内部请求了权限。 我需要提供哪些权限以允许访问专辑封面以获取路径?

2)我似乎找不到有关loadThumbnail的任何内容(甚至在使用目标和编译SDK 29的代码中也找不到ContentResolver类),如果无法完成1),那么我该如何使用loadThumbnail,为什么它没有显示在代码中?

谢谢您提前。


1
作为 Android Q 上的范围存储功能的一部分,谷歌宣布 SAF(存储访问框架)将替换普通存储权限。这意味着即使您尝试使用存储权限,它也只会授予对特定类型的文件的访问权限,以供 File 和文件路径使用。 - Rohit Chauhan
3个回答

6
为使用ContentResolver方法,请确保已安装最新的SDK和相关工具,并在您的代码中首先实例化ContentResolver对象,然后按照需求使用它:
public class MainActivity extends AppCompatActivity {
    public ContentResolver resolver;
    Bitmap albumArt;
    Size size;
    Uri uriOfItem;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        resolver = new ContentResolver(this) {
            @NonNull
            @Override
            public Bitmap loadThumbnail(@NonNull Uri uri, @NonNull Size size, @Nullable CancellationSignal signal) throws IOException {
                return super.loadThumbnail(uri, size, signal);
            }
        };
        //uriOfItem = uri of your file
        size = new Size(100, 100);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            try {
                albumArt = resolver.loadThumbnail(uriOfItem, size, null);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

编辑:关于你的第一个问题,如果 @Rj_Innocent_Coder 不介意我在这里引用他的评论:

作为 Android Q 上 scoped-storage 功能的一部分,谷歌宣布 SAF(存储访问框架)将取代普通的存储权限。这意味着即使您尝试使用存储权限,它也只会授予对特定类型的文件的访问权限,以供 File 和 file-path 使用。

编辑 2:在 @hetoan2 的评论后,我再次检查了文档,发现 ContentResolver 是抽象的,因此不能使用 ContentResolver.loadThumbnail() 作为方法调用。 这意味着在活动中,您也可以简单地使用以下内容:

Bitmap albumArt = getContentResolver().loadThumbnail(uriOfFile, sizeOfAreaThatDisplaysThumbnail, cancellationSignalOrNull);

我认为在ContentResolver类中重载loadThumbnail方法是不必要的。此外,值得注意的是,传递给loadThumbnail方法的Size对象应该是Album Art位图的所需输出大小(与您加载它的任何视图匹配)。另外,在< Q的情况下,应该存在回退代码,使用先前由OP提到的MediaStore。 - hetoan2
@Serge 我不知道在API29上还有其他可行的方法。话虽如此,我还没有遇到过需要使用其他方法的情况。 - Nikos Hidalgo
1
我需要这个路径,因为它将被发送到一些扬声器(然后周期性地返回所有元数据,包括此路径),应用程序随后使用此路径获取专辑封面。虽然有可能的解决方法,但这些需要对应用程序进行大量更改。理想情况下是要有这个路径!如果不能获取这个路径29+,那么这可能是由于权限问题(正如我在上面发布的文档中所说),那么Android应该有一种方式在清单中允许此操作,以便我们可以获得该路径。 - Serge
这很奇怪。我的项目是用 Kotlin 编写的,但我无法覆盖 loadthumbnail 方法,因为它不存在需要被覆盖的地方。 - KMC
@KMC 你尝试过从ContentResolver中调用它吗(即getContentResolver().loadThumbnail....)? - Nikos Hidalgo
显示剩余10条评论

1

试一下这个,它可以使用Glide ImageView加载并运行。

int thumbColumn = audioCursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns._ID);
   int _thumpId = audioCursor.getInt(thumbColumn);
   imgFilePath = "content://media/external/audio/albumart/"+_thumpId;  
   audioCursor.moveToPosition(i);
  Glide.with(getContext()).load(imgFilePath).placeholder(R.drawable.missed).into(tracksAlbumArt);

更新 Android Studio 至最新版本 4.2.X,并将 targetSdkVersion 升级至 30。


1

对于其他遇到问题的人,这是对我有效的解决方案:

if(android.os.Build.VERSION.SDK_INT >= 29)
{
    val album = "Name Of Album"
    val artist = "Name of Artist"
    // Determine album ID first
    val cursor = context.contentResolver.query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
                MediaStore.Audio.Albums.ALBUM_ID,
                "${MediaStore.Audio.Albums.ALBUM} = '$album' AND 
                 ${MediaStore.Audio.Albums.ARTIST} = '$artist'"
                 ,null,null)
    val uri = if(cursor != null && cursor.count > 0)
    {
        cursor.moveToFirst()
        ContentUris.withAppendedId(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, cursor.getString(0).toLong())
    }
    else
    {
        // Dummy URI that will not return an image
        // If you end up here, the album is not in the DataStore
        MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI
    }
    val bm = try
    {
        // Set size based on size of bitmap you want returned
        context.contentResolver.loadThumbnail(uri, Size(50,50), null)
    }
    catch(e: java.lang.Exception)
    {
        // Return default image indicating no image available from DataStore
        BitmapFactory.decodeResource(context.resources, R.drawable.no_image)
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接