2013年1月23日水曜日

Androidで画像のファイルパスからURIを得るには?

AndroidでDownloadManagerを使って画像をダウンロードして、DownloadManagerにクエリをかけると、DownloadManager.COLUMN_LOCAL_URI列から「file:///storage/emulated/0/Pictures/xxxx.png」などというファイルパスのURIを得られる。

この画像をギャラリーなどの他の適当なアプリで開きたいので、このようにしたい。

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setType("image/*");
intent.setData(uri);

しかし、このsetData(uri)のURIの形式は「file:」ではなく「content:」でなければならないので、この形式に何とか変換したい。

API Level 11以降の対応で良ければDownloadManager.getUriForDownloadedFile(long id)で取得できそうだけど、API Level 10では使えない。

そこで、こうする。

/**
 * @param context
 * @param srcUri 外部ストレージにある画像のURI file://.... 形式
 * @return 変換されたURI content://media/external/images/media/[ID(数字)] 形式
 */
public static Uri fileUri2contentUri(Context context, Uri srcUri) {
  Uri uri = null;
  Uri baseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
  String[] proj = { BaseColumns._ID };
  String sel = MediaStore.Images.ImageColumns.DATA + " LIKE ?";
  String[] selArgs = new String[] { srcUri.getPath() };
  ContentResolver cr = context.getContentResolver();
  try {
    Cursor cur = cr.query(baseUri, proj, sel, selArgs, null);
    cur.moveToFirst();
    int cidx = cur.getColumnIndex(proj[0]);
    long id = cur.getLong(cidx);
    cur.close();
    uri = Uri.parse(baseUri.toString() + "/" + id);
  } catch (Exception e) {
    Log.v("fileUri2contentUri", "file://からcontent://形式変換中にエラー", e);
  }
  return uri;
}

上の「file:」形式のURIをこのメソッドに渡してやると「content://media/external/images/media/数字」という形式のURIに変換される。

追記13.01.28:Nexus7ではダウンロードマネージャで画像をダウンロードすると比較的早く(500msec以下)で自動的にファイルのスキャンが行われてURIを得られるようになるけれど、Galaxy Tabではぜ~んぜん行われないことが分かった。

結局、MediaScannerConnection.scanFile()を使うのが無難だと思う。API Level 11以上ならDownloadManager.getUriForDownloadedFile()とかDownloadManager.Request.allowScanningByMediaScanner()とかあるので楽勝なのだけど、API Level 10以上を目指すなら、個人的にはこの方法がベストということになっている。

琴線探査: Androidのダウンロードマネージャで画像をダウンロードして完了を通知し、その通知をタップしたらその画像をギャラリーで開くには?