[Android] Camera で撮影、Intentで簡単にやりましょ

本格的なカメラアプリであれば別ですが、オプション的に画像をカメラで撮って使いたい場合はIntentを使うことで「比較的」簡単にできます。

android.os.FileUriExposedException というエラーになった場合は、API24からはUriをfile://xxx という使い方ができない理由によるものかもしれません。またExternal Storageを使う方法を後半で紹介しています。

device 2016 07 30 112639 170x300 - [Android]  Camera で撮影、Intentで簡単にやりましょ
device 2016 07 30 112725 170x300 - [Android]  Camera で撮影、Intentで簡単にやりましょ

 

Android Studio 3.1.3
Android 8.1.0

 



ACTION_IMAGE_CAPTURE

 
Intentを使うやり方は端末内のカメラアプリ、デフォルトで1つは入っていますから、それらを呼び出して撮影と保存をやってもらおうというあなた任せの機能です。(楽)

Android 8.1.0からこのあたりの挙動が変わったように思います。まだバグ?なのか改善?なのか不明です。対策をしてしばらく様子を見ることにします。

 

 

シンプルなカメラ起動

 
これは、emulatorでの簡単なカメラテストです。emulatorの「Advanced Settings」からCameraのfront, backの設定をEmulatedにしておきます。
 
intent camera a01 450x290 - [Android]  Camera で撮影、Intentで簡単にやりましょ
 
Intentで飛ばして間接的にカメラを起動させるのでAndroid6.0からのRuntime Permissionに引っかかりません。
またこの段階では撮った写真を保存するところまではやっていません。
 
MediaStore.ACTION_IMAGE_CAPTURE
をIntentで設定します。
 

 
Intentで飛ばしたので結果を受け取るためにonActivityResultを使います。

 
上記内容をまとめると

MainActivity.java

 
activity_main.xml

 
リソース
strings.xml

 
これでアプリを起動するとエミュレートされた画像が表示されます。中央のボタンで撮影
 
camera intent 01 - [Android]  Camera で撮影、Intentで簡単にやりましょ
 
撮影したあとはチェック「✔︎」をクリックすると画像が表示されます。
 
camera intent 02 - [Android]  Camera で撮影、Intentで簡単にやりましょ
 
ただし、これはサムネイル程度のとても小さい画像です。ここでは拡大するようにしていますが、emulatorでは(90 x 160pix)しかありません、また端末によっては画像が回転しているケースもあります。
また、Webcam0はPCのカメラですが、これもサムネイルサイズです。

 

外部ストレージ領域に保存してカメラ画像を取得

 
ある程度大きい画像で表示したい場合は画像をファイルとしてExternal Strage、外部ストレージに保存し、その画像を表示させます。外部ストレージとはSDカードや端末内部のパブリックなメモリ領域をさし、フォトやギャラリーなどの写真が保存されるとことです。
 
また、外部ストレージ領域を使いますので「WRITE_EXTERNAL_STORAGE」のPermissionを追加します。これはAndroid 6.0 Runtime Permission の dangerous permissionに該当するため、ユーザーに許可を求める必要があります。(やっぱりPermission Checkが必要になるのか…)
Runtime Permission, Android 6.0 からの変更
 
更に、API24からはUriをfile://xxx という使い方ができなくなったためFileProviderを使います。
https://inthecheesefactory.com/blog/how-to-share-access-to-file-with-fileprovider-on-android-nougat
 
FileProvide
アプリ間でのデータ共有を可能にしたContentProviderがありますが、それを簡単にしたサブクラスです。
このアプリとフォトアプリのデータ共有です(デフォルトのカメラアプリが撮影画像をフォトアプリで引き出せる共有メモリ領域に保存しているので)
 
FileProvider tag を AndroidManifestに追加します。
 
AndroidManifest.xml

 
android:authoritiesはアプリのパッケージ名+fileprovider
android:resource=”@xml/provider_paths”
ではファイルを渡すための共有ディレクトリーを設定します。
 
res¥xml¥provider_paths.xml ファイルを作って以下のように記述します。
 
camera intent 03 - [Android]  Camera で撮影、Intentで簡単にやりましょ
 
provider_paths.xml

 
あとは、Uri.fromFileの変更です。getUriForFile()からUriを取得します。
getUriForFile(Context context, String authority, File file)
authority はAndroidManifestで設定した
android:authorities=”${applicationId}.fileprovider”
になります。
 

 

サンプルコード

 
これでまとめると
MainActivity.java

 
レイアウト、リソースは前と同じです。

activity_main.xml

 
strings.xml

 
provide_paths.xml

 
AndroidManifest.xml
 

アンドロイドのデータベースへ登録

 
この方法では一旦画像を保存しているので、その画像は通常はデフォルトで端末に入っているギャラリーやフォトなどのアプリで表示できます。ただこれはすぐには反映されないので画像を撮ってすぐギャラリーで確認しても写真が無いこともあります。

アンドロイドのデータベースへ登録することでこれは解消します。
上記のコードで、registerDatabase(String file)を以下のように追加します。

 
device 2016 07 30 112639 170x300 - [Android]  Camera で撮影、Intentで簡単にやりましょ
 
device 2016 07 30 112725 170x300 - [Android]  Camera で撮影、Intentで簡単にやりましょ
emulatorでは回転しなくなったようです。Nexus 5Xでは一度回転して戻ったりします。これを回避するためにconfigChangesの設定をしておきます。画面の回転
 
AndroidManifest.xml

 
Logを入れてIntentでカメラアプリを呼び出した場合のstatusを見てみたいと思います。

 
onStop()で止まったままで、onDestroy()までは行っていない様子がわかります。
再開はonRestart()からです。この動きはActivityのライフサイクルが参考になります。
 

 
API23まではこれでできました。簡単な方法として、

とすれば今の所、継続して使用できます。
MainActivity.java

 
レイアウトファイルは前と同じですが、
ManifestにはPermissionを追加します。
AndroidManifext.xml

 

 
References:
Camera API | Android Developers
実行時のパーミッション リクエスト | Android Developers
FileProvider | Android Developers
Setting Up File Sharing | Android Developers

誤字脱字、意味不明で分からにゃイ、
などのご意見はこちらから mailフォーム

ブックマークしておくと便利です このエントリーをはてなブックマークに追加


 


ページのトップへ戻る




シェアする

  • このエントリーをはてなブックマークに追加

フォローする