画像を取得できるかどうかは、残念ながら電話の製造元によって異なります。すべてのAndroidバージョンとすべてのメーカーはわずかに異なる動作をしているようです。URLが「データ」パラメーターとして結果に提供される場合もありますが(これが実行していることです)、空の場合もあります。それは完全に機能しましたが、RESULT_CANCELを返す電話を一度も手に入れました。
あらゆる種類の異なるフォールバックを実装する方法はないようです。これが私が現在私たちのプロジェクトの1つで使用している私のコードです。メンバー変数は、インテントパラメータとしてmTargetUri
指定した出力ファイル名に設定する必要があります。インテントを起動する直前に設定する必要があります。MediaStore.EXTRA_OUTPUT
mCaptureTime
Sytem.currentTimeMillis()
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
Log.v(LOG_TAG, "Camera intent succeeded");
}
else if (resultCode == RESULT_CANCELED) {
Log.i(LOG_TAG, "Camera intent aborted");
}
else {
Log.e(LOG_TAG, "Camera intent failed with result code: " + resultCode);
}
// Regardless of the resultCode we're going to check if a new photo has been
// created on the phone. At least on the Samsung Galaxy S3 the behavior
// could be observed that although the result code was "0" the camera app
// created two (!) files on the SD card.
// Image captured and saved to fileUri specified in the Intent
Uri targetUri = (data != null) ? data.getData() : null;
if (targetUri == null) {
Log.w(LOG_TAG, "Camera intent returned empty result.");
targetUri = mTargetUri;
}
if (targetUri != null) {
String targetFilePath = targetUri.getPath();
File targetFile = new File(targetFilePath);
if (targetFile.exists()) {
Log.i(LOG_TAG, "Image saved to: " + targetUri.toString());
// Fix for issue reported here: http://code.google.com/p/android/issues/detail?id=22822
// and here: http://code.google.com/p/android/issues/detail?id=19268
// We're following the proposed solution from https://stackoverflow.com/questions/8450539/
int rotation = -1;
long fileSize = targetFile.length();
Cursor mediaCursor = getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[] {
MediaStore.Images.ImageColumns.ORIENTATION,
MediaStore.MediaColumns.SIZE,
MediaStore.MediaColumns.DATA },
MediaStore.MediaColumns.DATE_ADDED + ">=?",
new String[] { String.valueOf(mCaptureTime/1000 - 1)},
MediaStore.MediaColumns.DATE_ADDED + " desc");
if ((mediaCursor != null) && (mCaptureTime != 0)) {
if (mediaCursor.moveToFirst()) {
do {
long size = mediaCursor.getLong(1);
Uri uri = Uri.parse(mediaCursor.getString(2));
// Extra check to make sure that we are getting the orientation from the proper file
if (size == fileSize && !uri.equals(targetUri.toString())) {
rotation = mediaCursor.getInt(0);
break;
}
} while (mediaCursor.moveToNext());
}
mediaCursor.close();
}
if (rotation == -1) {
// It seems that there has been no duplication and no rotation issue so far. This means we can
// add our newly created file to the media library.
// TODO
}
else {
// Looks like the picture already exists in the media library. This indicates we got a duplicate.
Log.w(LOG_TAG, "Duplicate image found for " + targetUri.toString() + " in media library. Deleting the copy.");
if (!targetFile.delete()) {
Log.e(LOG_TAG, "Failed to delete duplicate image.");
}
}
}
}
}
}
このコードは、Stackoverflowや他のサイトのさまざまなソースから発信されています。基本的な考え方は、
- 結果コード(
RESULT_OK
またはRESULT_CANCELED
)は、写真が撮影されてSDカードに保存されたかどうかを示すものではないため、無視してください。上記のコードは値をログに記録するだけですが、どのような場合でも続行します。
- 次に、インテント結果によって提供されたURIがあったかどうかを確認します。URIを取得した場合、それが実際に新しく撮影された写真を指していると想定するのが安全です。ただし、すべてが完全に成功したにもかかわらず、そのようなURIを取得することはできません。この場合を処理するには、カメラアクティビティに最初に提供したURI(
mTargetUri
)を使用して、そこに新しいファイルが見つかることを期待します。
- 一部の新しいデバイスでは、カメラアプリが自動的に新しい写真をメディアライブラリに追加し、で最初に指定した方法で2番目のコピー名を作成します
targetUri
。このアプローチの問題は、画像が重複してしまうことです。これに対処するために、次のStackoverflowの質問から派生したロジックに従います。ACTION_IMAGE_CAPTUREで撮影された画像は、一部の新しいデバイスではExifInterface.TAG_ORIENTATIONに対して常に1を返します。ここでは詳細については説明しませんが(リンクをたどって理解を深めるだけです)、基本的な考え方は、Androidメディアストアにクエリを実行し、タイムスタンプを比較して新しい写真が既に含まれているかどうかを確認することですmCaptureTime
(System.currentTimeMillis()
キャプチャインテントは元々開始されました)。
- メディアストアでエントリが見つかった場合は、重複を削除するだけです。
このロジックは、事実上すべてのAndroidデバイスですべての場合に機能するはずです。これまでのところ、追加の問題なしに、数十の異なるデバイスとAndroidバージョンでテストしました。