SYSTEM_KDです。
(タイトル長すぎですね。。)
Androidアプリで、「カメラ」「ギャラリー」から画像を取得する際に、1つのChooserへまとめてユーザへ選択させる方法です。
先日ググってサクッと実装しようとしたのですが、いざ実装してみると、OSのバージョンで若干処理を分けたりしないといけかったり、上手くいかなかったりしたりしたので、まとめ。
やりたいこと
アプリで画像を扱うために、「画像」&「画像のパス」を取得したい。
ようは、これ。
実現方法
ググったところ、カメラを呼び出すIntentと、ギャラリーを呼び出すIntentを作成して、Chooserへ設定してやれば良いらしい。
ハマったポイント
カメラを呼び出すIntentを用意する際に、撮影情報保存用のファイルをgetContentResolver経由で用意すると、キャンセルした際に空のファイルが消えてくれない。(消えないというか、ギャラリーを表示したのに空ファイルができてしまうような気がする)
ギャラリーから選択する際に、OSのバージョンによってパスの取得方法が違う。
実装
やることは、「実現方法」の内容通りですが、ちょこちょこ小細工してます。
まずは、画像(写真)の取得・設定から
private Uri photoUri;
private static final int REQUEST_CHOOSER = 1000;
private static final int KITKAT_API_LEVEL = 19;
private void showCameraGallery() {
// カメラ起動のIntent作成 */
File pathExternalPublicDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
String filename = System.currentTimeMillis() + ".jpg";
File capturedFile = new File(pathExternalPublicDir, filename);
photoUri = Uri.fromFile(capturedFile);
Intent intentPhoto = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intentPhoto.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
// ギャラリー用のIntent作成 */
Intent intentGallery;
if (Build.VERSION.SDK_INT < KITKAT_API_LEVEL) {
intentGallery = new Intent(Intent.ACTION_GET_CONTENT);
intentGallery.setType("image/*");
} else {
intentGallery = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intentGallery.addCategory(Intent.CATEGORY_OPENABLE);
intentGallery.setType("image/jpeg");
}
Intent chooserIntent = Intent.createChooser(intentGallery, "Pickup");
// カメラ起動用のIntent を追加
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] {intentPhoto});
startActivityForResult(chooserIntent, REQUEST_CHOOSER);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_CHOOSER) {
if(resultCode != RESULT_OK) {
// キャンセル時
return ;
}
Uri resultUri = (data != null ? data.getData() : photoUri);
if(resultUri == null) {
// 取得失敗
return;
}
// ギャラリーへスキャンを促す
MediaScannerConnection.scanFile(
this,
new String[]{resultUri.getPath()},
new String[]{"image/jpeg"},
null
);
// 画像を設定
ImageView imageView = (ImageView)findViewById(R.id.imageView);
imageView.setImageURI(resultUri);
}
}
Chooserの表示から画像の取得・表示までの抜粋ですが、こんな感じになるかと思います。
ハマったポイントで上げた通り、カメラ画像を保存するファイルを「getContentResolver」経由で作成すると、空ファイルが残ってしまったので、「File」で用意して、「onActivityResult」で「ギャラリーへスキャンを促す」ようにしてます。
ギャラリーから選択する部分は、Kitkat以降とそれより前で、Actionを「Intent.ACTION_GET_CONTENT」「Intent.ACTION_OPEN_DOCUMENT」とわけてます。
画像のパスを取得する
続いて、画像のパスを取得する方法です。
public static String getImagePath(ContentResolver contentResolver, Uri uri) {
String retPath = "";
if(uri == null) return retPath;
File file = new File(uri.getPath());
if(file != null && file.exists()) {
return uri.getPath();
}
if(Build.VERSION.SDK_INT < 19) {
String[] columns = { MediaStore.Images.Media.DATA };
Cursor cursor = contentResolver.query(uri, columns, null, null, null);
cursor.moveToFirst();
retPath = cursor.getString(0);
cursor.close();
} else {
String id = DocumentsContract.getDocumentId(uri);
String selection = "_id=?";
String[] selectionArgs = new String[]{id.split(":")[1]};
Cursor cursor = contentResolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.MediaColumns.DATA},
selection, selectionArgs, null);
if (cursor.moveToFirst()) {
retPath = cursor.getString(0);
}
cursor.close();
}
return retPath;
}
「ContentResolver」と「Uri」を渡せば、パスを返却するようにしてます。
写真の場合は、「UriのgetPath()」でそのままとれるので、そのパスを利用。
ギャラリーから取得した画像の場合は、OSのバージョンによって呼び出すものを変えているので、取得方法をそれに沿って違ってます。
まとめ
一応、いまのところはこれで画像とパスはとれてそうなので、大丈夫かと思います。
今回、とってきた画像をそのままImageViewへ設定しており、写真の向きに合わせて回転するとかは含めてません。
カメラを呼び出すIntentを用意する際に、撮影情報保存用のファイルをgetContentResolver経由で用意すると、キャンセルした際に空のファイルが消えてくれない。(消えないというか、ギャラリーを表示したのに空ファイルができてしまうような気 ... 1カメラ.blogspot.com
返信削除