前回作成したセルフタイマー専用カメラに機能追加。(ソース)
- 外部メモリへの保存
- メディアスキャナーへ画像を登録
- オートフォーカス
- 画像表示画面で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をカメラと画像表示で分けた方がいいのかもしれない。

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