Подтвердить что ты не робот

Как проверить, доступен ли ресурс, указанный Ури?

У меня есть ресурс (музыкальный файл), указанный 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 для всех моих вариантов рингтонов... Любые другие идеи?

4b9b3361

Ответ 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());
    }