MediaScannerConnectionを使って画像をギャラリーに反映させる


アプリ内で保存した画像をギャラリーに反映させる方法を説明します。

カメラアプリや画像加工アプリを作成してSDカードなどのストレージに画像ファイルを保存した場合、そのままではギャラリーアプリからその画像を確認することができません。

今回の記事の方法でその画像ファイルをギャラリーの反映させることができます。

カメラアプリを作成したい場合や、SDカードに保存する場合は以下の記事が参考になります。

それでは続きでサンプルソースと共に説明します。

MediaScannerConnection

MediaScannerConnectionクラスはMediaScannerServiceと接続する役割を持ち、メディアファイルをMediaContent Providerに登録することができます。

このMediaScannerConnectionクラスのメソッドであるMediaScannerConnection#scanFileを使うことで任意の画像ファイルをMediaContent Providerに登録し、ギャラリーに反映させることができます。

scanFileメソッドはAPIレベル1から存在します。APIレベル8から同じscanFileという名前ですが、引き数が異なるものが追加されました。

APIレベル8で追加されたメソッドの方が呼び出しが簡単&複数のファイを指定することができて便利です。

最近の端末はAndroid2.2以上が多いのでまずはAPIレベル8で追加された方のscanFileメソッドを説明します。

scanFileメソッド(APIレベル8)

  • static void scanFile(Context context, String[] paths, String[] mimeTypes, MediaScannerConnection.OnScanCompletedListener callback)

定義を見てもらえば分かりますが、クラスメソッドなのでMediaScannerConnectionクラスのインスタンスを生成する必要がありません(後述するAPIレベル1からのscanFileメソッドはインスタンスメソッド)。

第2引数にギャラリーに反映させたいファイルのパスを、第3引数に対象とするメディアの種類のMineTypeを指定します。共に配列ですので複数指定することができます。

※第3引数のMimeTypeはnullを指定することも可能で、その場合は拡張子からタイプを推測してくれます。

MediaScannerConnection.OnScanCompletedListenerは1つのメソッドだけを持ったインタフェースです。スキャンが終わった際に呼ばれます。

  • abstract void onScanCompleted(String path, Uri uri)

以下のサンプルではSDカード直下のrotate.jpgをスキャンしてギャラリーに反映させています。

1
2
3
4
5
6
String[] paths = {Environment.getExternalStorageDirectory().toString()+ "/rotate.jpg"};
String[] mimeTypes = {"image/jpeg"};
MediaScannerConnection.scanFile(getApplicationContext(),
                                paths,
                                mimeTypes,
                                mScanCompletedListener);
1
2
3
4
5
6
7
OnScanCompletedListener mScanCompletedListener = new OnScanCompletedListener() {
    @Override
    public void onScanCompleted(String path, Uri uri) {
        Log.d("MediaScannerConnection", "Scanned " + path + ":");
        Log.d("MediaScannerConnection", "-> uri=" + uri);
    }
};

上記のサンプルを実行してスキャンした際のログです。

onScanCompletedのpathにはスキャンしたファイルのパス、uriにはContentProviderのURIが入ります。URIがnullの場合はスキャンに失敗したということを表します。

scanFileメソッド(APIレベル1)

  • void scanFile(String path, String mimeType)

次にAPIレベル1から使えるscanFileメソッドです。こちらはインスタンスメソッドなのでまずはMediaScannerConnectionクラスのインスタンスを生成する必要があります。

コンストラクタの第2引数にはMediaScannerConnectionClientクラスを指定します。

このMediaScannerConnectionClientクラスには

  • onScanCompleted
  • onMediaScannerConnected

が定義されており、それぞれスキャンが完了した時、MediaScannerServiceへの接続が完了した時に呼び出されます。

ギャラリーへの反映の手順は手順は以下の通りです。

  1. MediaScannerConnectionクラスのインスタンスの生成
  2. MediaScannerServiceへ接続
  3. MediaScannerServiceへ接続が完了したらscanFileメソッドでスキャンを指示
  4. スキャンが完了したらMediaScannerServiceへ接続への接続を解除する

MediaScannerConnectionクラスのインスタンスの生成とMediaScannerConnection#connectでMediaScannerServiceへ接続を実施

1
2
3
mMediaScannerConnection = new MediaScannerConnection(getApplicationContext(),
                                                    mScannerConnectionCluent);
mMediaScannerConnection.connect();

接続完了時に呼ばれるMediaScannerConnectionClient#onMediaScannerConnectedでMediaScannerConnection#scanFileを実行する。APIレベル8で追加されたscanFileと異なりは入れるではなく、1つのファイルしか指定することができません。

※第3引数のMimeTypeはnullを指定することも可能で、その場合は拡張子からタイプを推測してくれます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
MediaScannerConnectionClient mScannerConnectionCluent = new MediaScannerConnectionClient() {
    @Override
    public void onScanCompleted(String path, Uri uri) {
        Log.d("MediaScannerConnection", "Scanned " + path + ":");
        Log.d("MediaScannerConnection", "-> uri=" + uri);
        mMediaScannerConnection.disconnect();
    }
 
    @Override
    public void onMediaScannerConnected() {
        Log.d("MediaScannerConnection", "onMediaScannerConnected ");
        String path = Environment.getExternalStorageDirectory().toString()+ "/rotate.jpg";
        String mimeType = "image/jpeg";
        mMediaScannerConnection.scanFile(path, mimeType);
    }
};

補足

「今回は画像ファイルをスキャンし、ギャラリーに反映させるためにMediaScannerConnectionクラスを利用したけど、音声ファイルなども同様にスキャンしてContentProviderに登録することが可能だよ。」