Androidでカメラを使うアプリを作成ー機能追加

前回作成したセルフタイマー専用カメラに機能追加。(ソース)

  • 外部メモリへの保存
  • メディアスキャナーへ画像を登録
  • オートフォーカス
  • 画像表示画面でGalleryによる画像選択を可能に。
  • 画像削除機能

外部メモリへの保存

まず、 Environment.getExternalStorageState() で外部メモリが使用可能か否かを判定。

        String state = Environment.getExternalStorageState();
        if (!Environment.MEDIA_MOUNTED.equals(state)) {
            return false;
        }

Environment.getExternalStorageDirectory() で外部メモリへのパスを取得。

    	File directory = Environment.getExternalStorageDirectory();

データは、外部メモリ内の “Android/data/<パッケージ名>” というフォルダに保存しないといけないようなので、そのフォルダがなければ作成(mkdirs)する。

    	File directory = Environment.getExternalStorageDirectory();
    	String dirpath = "Android/data/" + pkgname + "/files";
    	File subdirectory = new File(directory, dirpath);
    	if(subdirectory.exists() == false) {
        	subdirectory.mkdirs();
    	}

BufferedOutputStream を開いて書き込む。

    	File f = new File(subdirectory.getPath(), filename);
    	OutputStream out = new BufferedOutputStream(new FileOutputStream(f));
	out.write(data);

メディアスキャナーへ画像を登録

MediaScannerConnectionで画像ファイルを登録すると、内蔵の画像ビューアーなどで画像が見れるようになる。このとき、サムネイルも作ってくれる。

MediaScannerConnectionのインスタンス作成時に、MediaScannerConnection.MediaScannerConnectionClient のインタフェースの参照が必要。今回はActivity本体にこのインタフェースを実装した。

スキャンを開始する前に connect() を呼び出す。完了すると onMediaScannerConnected() が呼び出される。パスを指定して scanFile() を呼び出し、スキャンしたらすぐにdisconnect している。この使い方が正しいのか、よくわからないが、とりあえず機能しているように見える。

    public void onMediaScannerConnected () {
        if(mMsc.isConnected()) {
            mMsc.scanFile(mScanPath, null);
            mMsc.disconnect();
        }
    }

スキャンが完了すると、onScanCompleted (String, Uri) が呼び出される。スキャンしたファイルのパスとURIが取得できるが、今回はどちらもつかわないので、ここでは何もしていない。

オートフォーカス

Camera の autoFocus (Camera.AutoFocusCallback) を呼び出すと、オートフォーカスができたタイミングで AutoFocusCallback の onAutoFocus (boolean, Camera) が呼び出される。この中で、Camera の takePicture () を呼び出すだけでよかった。takePicture() を呼び出すところは既にできていたので、実質、追加したのは2行だけ。

        mCam.autoFocus(new Camera.AutoFocusCallback() { //追加
            @Override
            public void onAutoFocus(boolean success, Camera camera) { //追加
                camera.takePicture(null, null, new Camera.PictureCallback() { //ここは同じ
                    @Override
                    public void onPictureTaken(byte[] data, Camera camera) {
           /* 省略。ここでデータを保存した後、startPreview を呼び出す */
                    }
                });        
            } //追加
        }); //追加

画像表示画面でGalleryによる画像選択を可能に

下のサムネイルから画像を選択

最初はApiDemo の ImageSwitcher + Gallery の組み合わせをそのまま使うつもりだったが、イメージを2つ用意しないといけない為か、メモリ不足で落ちることが多かったので、ImageSwitcher はやめて、普通の ImageView に変更。

Gallery の詳しい説明は

ApiDemo の ImageSwitcher のコードは

また、この修正の過程で ImageView.setImageURI() の使い方が判明。実は、前回からこのメソッドを使って画像を表示させようとしていたが、うまくいかず、結局自分で Bitmap を作成することにしたのだが、前回は

        Uri uri = Uri.fromFile(new File(path));
        imgView.setImageURI(uri);

のように、Uri.fromFile() から作成した Uri を使っていたが、だめだった。しかし、今回改めて調べたところ、下のように Uri.parse() を使えば表示できるとの情報があり、ためしてみると、表示できた!(・・・何が違うんだ!)

        Uri uri = Uri.parse(path);
        imgView.setImageURI(uri);

しかし、結局 setImageUri() では表示が遅くなるので、自分で Bitmap を作成する方法に戻してしまった。きっと、setImageUri() ではファイルのフルサイズのイメージを作成してしまうので、遅いのかもしれない。(自分で Bitmap を作成するときは、画面の大きさに合わせて縮小している。)

画像削除機能

画像を表示しているときに、その画像を削除できる機能を追加。メニューボタンからとコンテキストメニューから呼び出せる。

コンテキストメニューの使い方

また、画像を削除した際も、メディアスキャナーに登録すると、サムネイルを削除してくれる。これを行わないと、内蔵の画像ビュアーには「壊れた画像」的に表示が残ってしまう。

問題点

  • スクリーンロックがかかると、必ず再起動してしまう。
    • OnResume ではなく、OnCreate が呼び出されてしまう。変数もみな初期化されている。そのせいで、画像表示中にロックされると、カメラに戻ってしまう。なぜ?
  • ロックから戻るときの不具合が多い。
    • カメラのインスタンス取得に失敗し、プレビュー表示ができていなかったり、落ちてしまったりする。
  • Activityの分割
    • Activityをカメラと画像表示で分けた方がいいのかもしれない。

1件のフィードバック to “Androidでカメラを使うアプリを作成ー機能追加”

  1. Picasaに画像をアップする(Android) « スマホアプリの自習帳 Says:

    […] このサンプルを参考に、アプリを作成してみた(ソースはこちら)。以前作った、Intent でカメラを起動させるアプリにこの送信機能を追加する。 […]

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください