Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if resource pointed by Uri is available?

Tags:

android

uri

I have resource (music file) pointed by Uri. How can I check if it is available before I try to play it with MediaPlayer?

Its Uri is stored in database, so when the file is deleted or on external storage that is unmounted, then I just get exception when I call MediaPlayer.prepare().

In above situation I would like to play systems default ringtone. I could of course do that after I catch above exception, but maybe there is some more elegant solution?

edit: I forgot to mention that music files Uri's are actually acquired by using RingtonePreference. This means that I can get Uri pointing to ringtone on Internal Storage, External Storage or to default systems ringtone.

Uri's examples are:

  • content://settings/system/ringtone - for choosing default ringtone
  • content://media/internal/audio/media/60 - for ringtone on Internal Storage
  • content://media/external/audio/media/192 - for ringtone on External Storage

I was happy with proposed "new File(path).exists() method, as it saved me from mentioned exception, but after some time I noticed that it returns false for all of my ringtone choices... Any other ideas?

like image 680
Koger Avatar asked Oct 04 '11 09:10

Koger


People also ask

How do I check if URI exists?

file. Files; boolean exists = Files. exists(Paths. get(URI));

How do I get Uri resources?

Occasionally however, you will need to get the actual URI of a resource. All you need to do is replace the package name with your app's package name, as defined in the manifest, and the resource ID of the resource you would like to use. Uri resourceURI = Uri. parse("android.

What is a URI in Android Studio?

A Uniform Resource Identifier (URI) is a compact sequence of characters that identifies an abstract or physical resource.


2 Answers

The reason the proposed method doesn't work is because you're using the ContentProvider URI rather than the actual file path. To get the actual file path, you have to use a cursor to get the file.

Assuming String contentUri is equal to the content URI such as 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  } 

I haven't used this method with sound files or internal storage, but it should work. The query should return a single row directly to your file.

like image 104
DeeV Avatar answered Oct 11 '22 12:10

DeeV


I too had this problem - I really wanted to check if a Uri was available before trying to load it, as unnecessary failures would end up crowding my Crashlytics logs.

Since the arrival of the StorageAccessFramework (SAF), DocumentProviders, etc., dealing with Uris has become more complicated. This is what I eventually used:

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 } 

If someone has a more elegant -- or correct -- alternative, please do comment.

like image 27
jules Avatar answered Oct 11 '22 14:10

jules