Как проверить, доступен ли ресурс, указанный Ури?
У меня есть ресурс (музыкальный файл), указанный Uri. Как я могу проверить, доступно ли это до того, как я попытаюсь воспроизвести его с помощью MediaPlayer?
Его Uri хранится в базе данных, поэтому, когда файл удален или на внешнем хранилище, которое размонтировано, я просто получаю исключение, когда я вызываю MediaPlayer.prepare().
В приведенной выше ситуации я хотел бы играть в стандартную мелодию для систем. Я мог бы, конечно, сделать это после того, как поймаю выше исключения, но может быть, есть еще более элегантное решение?
изменить:
Я забыл упомянуть, что музыкальные файлы Uri фактически приобретены с помощью RingtonePreference. Это означает, что я могу заставить Uri указывать на мелодию звонка на внутреннем хранилище, внешнем хранилище или на стандартную систему рингтонов.
Примеры Uri:
- content://settings/system/ringtone - для выбора мелодии звонка по умолчанию
- content://media/internal/audio/media/60 - для мелодии звонка во внутреннем хранилище
- content://media/external/audio/media/192 - для рингтона на внешнем хранилище
Я был доволен предложенным "новым методом File (путь).exists(), поскольку он спас меня от упомянутого исключения, но через некоторое время я заметил, что он возвращает false для всех моих вариантов рингтонов...
Любые другие идеи?
Ответы
Ответ 1
Причина, по которой предложенный метод не работает, заключается в том, что вы используете URI ContentProvider
, а не фактический путь к файлу. Чтобы получить фактический путь к файлу, вы должны использовать курсор для получения файла.
Предполагая, что String contentUri
равно URI содержимого, например content://media/external/audio/media/192
ContentResolver cr = getContentResolver();
String[] projection = {MediaStore.MediaColumns.DATA}
Cursor cur = cr.query(Uri.parse(contentUri), projection, null, null, null);
if (cur != null) {
if (cur.moveToFirst()) {
String filePath = cur.getString(0);
if (new File(filePath).exists()) {
// do something if it exists
} else {
// File was not found
}
} else {
// Uri was ok but no entry found.
}
cur.close();
} else {
// content Uri was invalid or some other error occurred
}
Я не использовал этот метод со звуковыми файлами или внутренним хранилищем, но он должен работать. Запрос должен возвращать одну строку непосредственно в ваш файл.
Ответ 2
Как и в случае с Kitkat, вы можете, и вы должны, сохранить URI, которые ваше приложение использует, если необходимо. Насколько я знаю, существует ограничение на 120 URI, которое вы можете сохранить для каждого приложения, поэтому вам нужно максимально использовать эти ресурсы.
Лично я бы не имел дело с прямыми путями в этом случае, а скорее проверял, сохраняется ли постоянный URI, поскольку, когда ресурс (файл) удаляется с устройства, ваше приложение теряет права на этот URI, поэтому делает эту проверку как просто, как показано ниже:
getContext().getContentResolver().getPersistedUriPermissions().forEach( {element -> element.uri == yourUri});
Между тем вам не нужно будет проверять разрешения URI, если устройство находится ниже уровня Kitkat API.
Обычно при чтении файлов из URI вы собираетесь использовать ParcelFileDescriptor
, поэтому он будет метаться, если файл не доступен для этого конкретного URI, поэтому вы должны обернуть его блоком try/catch
.
Ответ 3
Попробуйте выполнить такую функцию, как:
public static boolean checkURIResource(Context context, Uri uri) {
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
return (cursor != null && cursor.moveToFirst());
}