Storing media URIs using Android SQLite

Published 01 July 2012 under android, how to

Whilst developing an Android app recently we came across a pitfall when storing media URIs inside a SQLite database.

The idea was to load media onto an external SD card and store links to that media inside our database. In order to do this we used the following intent to allow a user to choose an image:

public void chooseImage(View view) {
    Intent i = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    startActivityForResult(i, CHOOSE_IMAGE_REQ_CODE);

We grab the chosen image URI in onActivityResult():

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK && requestCode == CHOOSE_IMAGE_REQ_CODE) {
    imageURI = data.getData();
    Toast.makeText(getBaseContext(), "Added your chosen image", Toast.LENGTH_SHORT).show();

At which point we would save imageURI.toString() inside the database. We wrote some unit tests to cover this code and everything seemed to work nicely; we could retrieve the URI from the database and play the audio.

Unfortunately, things didn't go quite so swimmingly when we took the SD card out and put it back in: none of the audio clips we'd stored links to in our database could be found! It turns out that the media URIs change if the SD card is removed and put back in.

After much googling we found the following code snippet on StackOverflow which gets an absolute path from a URI. Storing the absolute path in the database gives the behaviour we expect i.e. taking out the SD card and replacing it without changing any files doesn't break anything.

private String getRealPathFromURI(Uri contentUri) {
    String[] proj = { MediaStore.Images.Media.DATA };
    Cursor cursor = managedQuery(contentUri, proj, null, null, null);
    if (cursor == null) {
      return contentUri.getPath();
    int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
    return cursor.getString(column_index);

This was the best solution we could find, but perhaps there's a nicer one...


blog comments powered by Disqus