Столбец ALBUM_ART устарел из API 29 и т. д., как получить путь?

В настоящее время мы получаем путь к обложке альбома, используя: MediaStore.Audio.AlbumColumns.ALBUM_ART, и успешно получаем путь, за исключением пикселя 3a (Android 10). После некоторых исследований ALBUM_ART стал устаревшим API 29 и выше, как показано: Здесь

В этой ссылке говорится: «У приложений может не быть разрешений файловой системы для прямого доступа к этому пути. Вместо того, чтобы пытаться открыть этот путь напрямую, приложения должны использовать ContentResolver#loadThumbnail для получения доступа».

Мои вопросы:
1) Я уже указываю в манифесте приложения разрешения на доступ к внешнему хранилищу (READ_EXTERNAL_STORAGE) и запрашиваю разрешение при навигации в приложении. Какие разрешения я должен предоставить, чтобы разрешить доступ к обложке альбома, чтобы получить путь?

2) Кажется, я не могу найти какой-либо контент в loadThumbnail в Интернете (и даже не в классе ContentResolver через код, пока я использую цель и компилирую SDK 29), если 1) это невозможно сделать, то как я могу использовать loadThumbnail и почему это не отображается в коде?

Заранее спасибо.


person Serge    schedule 20.09.2019    source источник
comment
Google объявила, что в рамках функции хранилища с заданной областью в Android Q, SAF (инфраструктура доступа к хранилищу) заменит обычные права доступа к хранилищу. Это означает, что даже если вы попытаетесь использовать разрешения на хранение, он предоставит доступ только к определенным типам файлов для файлов и путей к файлам, которые будут использоваться.   -  person Rj_Innocent_Coder    schedule 20.09.2019


Ответы (3)


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

Google объявила, что в рамках функции хранилища с заданной областью в Android Q, SAF (инфраструктура доступа к хранилищу) заменит обычные разрешения на хранение. Это означает, что даже если вы попытаетесь использовать разрешения на хранение, он предоставит доступ только к определенным типам файлов для файлов и путей к файлам, которые будут использоваться.

РЕДАКТИРОВАТЬ 2: после комментария @hetoan2 я снова просматриваю документацию и заметил, что ContentResolver является абстрактным, поэтому не может использовать ContentResolver.loadThumbnail() в качестве вызова метода. Это означает, что внутри действия вы также можете просто использовать следующее:

Bitmap albumArt = getContentResolver().loadThumbnail(uriOfFile, sizeOfAreaThatDisplaysThumbnail, cancellationSignalOrNull);
person Nikos Hidalgo    schedule 20.09.2019
comment
Я не думаю, что необходима перегрузка метода loadThumbnail в классе ContentResolver. Кроме того, стоит отметить, что объект Size, передаваемый методу loadThumbnail, должен иметь желаемый выходной размер растрового изображения обложки альбома (соответствующий любому представлению, в которое вы его загружаете). Кроме того, должен присутствовать резервный код для ‹ Q, который использует MediaStore, как ранее упоминалось в OP. - person hetoan2; 20.09.2019
comment
@hetoan2 мне тоже это показалось странным, но это был единственный способ увидеть этот метод в моей Android-студии. Что касается параметров, я не стал их много объяснять, так как в ОП уже есть ссылка на документацию, где они лучше всего объясняются. - person Nikos Hidalgo; 20.09.2019
comment
Нет ли другого способа без использования loadThumbnail? Что делать, если я использую инструменты сборки 28 (где нет loadThumbnail) и использую телефон с API 29? (Андроид 10) - person Serge; 25.09.2019
comment
@Serge, вы все равно можете использовать MediaStore, если версия сборки ниже 29 - person Nikos Hidalgo; 25.09.2019
comment
что ты имеешь в виду? я использую MediaStore.Audio.AlbumColumns.ALBUM_ART, но используя это на телефоне с API 29 Android 10, это не работает. - person Serge; 26.09.2019
comment
@Serge if (Build.VERSION.SDK_INT ›= Build.VERSION_CODES.Q) { // использовать . loadThumbnail} else {// использовать MediaStore.Audio.AlbumColumns.ALBUM_ART} - person Nikos Hidalgo; 26.09.2019
comment
Да, это нужно сделать, если вы используете API 29 в своем приложении, но что, если вы используете API 28 в своем приложении и хотите получить путь для ALBUM_ART на телефоне с API 29? Позвольте мне перефразировать мою проблему: я могу получить путь ALBUM_ART на любом телефоне, если у телефона версия Android меньше 29, однако он не получает путь (возвращает ноль) только при использовании телефона с версией Android 29. Итак мой вопрос в том, как я могу заставить его работать также на телефоне версии 29, не используя API 29 в моем приложении. - person Serge; 26.09.2019
comment
Я использую небольшой обходной путь, когда я могу получить изображение, выполнив следующие действия: используя этот uri:content://media/external/audio/albumart и добавляя к нему альбом, затем получая поток с помощью contentResolver.openInputStream(uri) и наконец, используя BitmapFactory.decodeStream (поток). Это работает, и я могу получить растровое изображение, но с помощью растрового изображения мне пришлось бы многое изменить в приложении, и что было бы действительно полезно, так это использовать путь, который должен предоставить ALBUM_ART. - person Serge; 26.09.2019
comment
@Serge Серж, я не знаю ни одного другого метода, который работал бы с API29. Тем не менее, я еще не сталкивался со сценарием, в котором мне нужно было бы использовать что-то еще. - person Nikos Hidalgo; 26.09.2019
comment
так что нет другого способа получить путь? loadThumbnail не возвращает путь, он возвращает растровое изображение, разве не должен быть способ получить путь даже для 29+? - person Serge; 26.09.2019
comment
@Serge не уверен, как указать путь вместо растрового изображения. Почему вам конкретно нужен путь, как вы его используете? возможно, есть более простая реализация без необходимости внесения многих изменений - person Nikos Hidalgo; 26.09.2019
comment
Мне нужен путь, потому что он отправляется на некоторые динамики (которые, в свою очередь, периодически отправляют обратно все свои метаданные, включая этот путь), затем приложение использует этот путь для получения обложки альбома. Возможны обходные пути, но они потребуют больших изменений в приложении. В идеале было бы иметь этот путь! странно, что вы не можете получить этот путь 29+, если это из-за разрешений (как говорится в документе, который я разместил выше), тогда у Android должен быть какой-то способ разрешить это в манифесте, чтобы мы могли получить этот путь. - person Serge; 27.09.2019
comment
Это странно. Мой проект находится в kotlin, и я не могу переопределить loadthumbnail, потому что для переопределения нет loadthumbnail. - person KMC; 09.10.2019
comment
@KMC, вы пытались вызвать его из ContentResolver (т.е. getContentResolver().loadThumbnail....)? - person Nikos Hidalgo; 09.10.2019
comment
@NikosHidalgo Я сделал, и нет loadThumbnail. - person KMC; 09.10.2019

Для кого-то еще, у кого здесь проблемы, это решение, которое сработало для меня:

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)
    }
}
person Rob    schedule 02.08.2020

попробуйте это, оно будет работать и загружаться с помощью 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);

Обновите Andriod Studio до последней версии 4.2.X и targetSdkVersion до 30.

person satishprattipati    schedule 06.10.2020