如何检查Uri指向的资源是否可用?

Kog*_*ger 14 android uri

我有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 - 用于外部存储上的铃声

我对提议的"新文件(路径).exists()方法很满意,因为它将我从提到的异常中保存下来,但过了一段时间后我注意到它为我的所有铃声选择返回false ...还有其他想法吗?

Dee*_*eeV 23

提出的方法不起作用的原因是因为您使用的是ContentProviderURI而不是实际的文件路径.要获取实际文件路径,必须使用游标来获取文件.

假设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 
}
Run Code Online (Sandbox Code Playgroud)

我没有将此方法用于声音文件或内部存储,但它应该可以工作.查询应该将单行直接返回到您的文件.

  • 不幸的是,它不适用于 content://settings/system/ringtone Uri,但这很合乎逻辑,我可以解决 (2认同)

nkm*_*uri 8

尝试使用如下函数:

public static boolean checkURIResource(Context context, Uri uri) {
    Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
    boolean doesExist= (cursor != null && cursor.moveToFirst());
    if (cursor != null) {
        cursor.close();
    }
    return doesExist;
}
Run Code Online (Sandbox Code Playgroud)

  • 你应该关闭光标 (3认同)

jul*_*les 8

我也有这个问题 - 我真的想在尝试加载之前检查 Uri 是否可用,因为不必要的失败最终会挤满我的 Crashlytics 日志。

由于StorageAccessFramework(SAF)、DocumentProviders等的到来,处理Uris变得更加复杂。这是我最终使用的:

fun yourFunction() {

    val uriToLoad = ...

    val validUris = contentResolver.persistedUriPermissions.map { uri }

    if (isLoadable(uriToLoad, validUris) != UriLoadable.NO) {
        // Attempt to load the uri
    }
}

enum class UriLoadable {
    YES, NO, MAYBE
}

fun isLoadable(uri: Uri, granted: List<Uri>): UriLoadable {

    return when(uri.scheme) {
        "content" -> {
            if (DocumentsContract.isDocumentUri(this, uri))
                if (documentUriExists(uri) && granted.contains(uri))
                    UriLoadable.YES
                else
                    UriLoadable.NO
            else // Content URI is not from a document provider
                if (contentUriExists(uri))
                    UriLoadable.YES
                else
                    UriLoadable.NO
        }

        "file" -> if (File(uri.path).exists()) UriLoadable.YES else UriLoadable.NO

        // http, https, etc. No inexpensive way to test existence.
        else -> UriLoadable.MAYBE
    }
}

// All DocumentProviders should support the COLUMN_DOCUMENT_ID column
fun documentUriExists(uri: Uri): Boolean =
        resolveUri(uri, DocumentsContract.Document.COLUMN_DOCUMENT_ID)

// All ContentProviders should support the BaseColumns._ID column
fun contentUriExists(uri: Uri): Boolean =
        resolveUri(uri, BaseColumns._ID)

fun resolveUri(uri: Uri, column: String): Boolean {

    val cursor = contentResolver.query(uri,
            arrayOf(column), // Empty projections are bad for performance
            null,
            null,
            null)

    val result = cursor?.moveToFirst() ?: false

    cursor?.close()

    return result
}
Run Code Online (Sandbox Code Playgroud)

如果有人有更优雅或正确的替代方案,请发表评论。


man*_*521 5

对于那些仍在寻找解决方案的人[截至 2020 年 12 月,工作完美]并且在所有边缘情况下都按预期运行,解决方案如下:

boolean bool = false;
        if(null != uri) {
            try {
                InputStream inputStream = context.getContentResolver().openInputStream(uri);
                inputStream.close();
                bool = true;
            } catch (Exception e) {
                Log.w(MY_TAG, "File corresponding to the uri does not exist " + uri.toString());
            }
        }
Run Code Online (Sandbox Code Playgroud)

如果与 URI 对应的文件存在,那么您将有一个可以使用的输入流对象,否则将引发异常。

如果文件确实存在,请不要忘记关闭输入流。

笔记:

DocumentFile sourceFile = DocumentFile.fromSingleUri(context, uri);
boolean bool = sourceFile.exists();
Run Code Online (Sandbox Code Playgroud)

上面的 DocumentFile 代码行确实处理了大多数边缘情况,但我发现,如果以编程方式创建文件并将其存储在某个文件夹中,则用户然后访问该文件夹并手动删除该文件(在应用程序运行时) ),DocumentFile.fromSingleUri 错误地表示该文件存在。