nexus7 AIR3.4 for Android: CameraRoll UncaughtErrorEvent
Android 端末 nexus7 のカメラロール周りの動作にて、二点ほどキャッチできないエラーが発生する事を確認。nexus7 に限ったことではないのかもしれませんが、以下に状況を記述します。
前提
nexus7 では、以下のプロパティはどちらも true を返します。
・CameraRoll.supportsBrowseForImage
(カメラロールから画像を取得できるかどうかの判別用プロパティ)
・CameraRoll.supportsAddBitmapData
(カメラロールへ画像を保存する事が可能かどうかの判別用プロパティ)
問題点1 ギャラリー内 Google+ に投稿された画像を選択するとエラー
nexus7 端末設定内にて Google アカウントがひもづけられているせいか、Android のギャラリーを開くと Google+ で投稿した画像を閲覧する事ができます。CameraRoll.browseForImage メソッドから、この Google+ 投稿画像データを Loader.loadFilePromise メソッドで読み込もうとすると、以下のエラーが発生します。
CameraRoll.browseForImage -> Google+ image -> Loader.loadFilePromise Error #2044: Unhandled IOErrorEvent:. text=Error #2032: Stream Error.
端末には存在しないネットワーク上の画像データを読み込もうとするのだから、エラーが発生しているのだろうと思います。端末に保存されているギャラリー内の画像では、上記エラーは発生しません。
問題点2 カメラロール(ギャラリー)へ画像を保存しようとするとエラー
前提で挙げました、nexus7 では CameraRoll.supportsAddBitmapData が true なのだから CameraRoll.addBitmapData メソッドでの保存は問題なく行われそうですが、以下のエラーが発生してしまいます。
CameraRoll.addBitmapData Error #2044: Unhandled ErrorEvent:. text=Error #2038: File I/O Error.
nexus7 では 背面カメラが無く CameraUI クラスにてカメラアプリ呼び出しが不可という事もあり、「カメラロール」の判定が少々おかしいのかもしれません。
対処
上記二つの問題から発生する ErrorEvent は AIR で意図されていない動作なのかどうか、try catch でキャッチできないようです。グローバルエラーをキャッチするための UncaughtErrorEvent.UNCAUGHT_ERROR ハンドルでは探知できたので、そちらでなんとか対処することに。
loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, onUncaughtError); private function onUncaughtError(event:UncaughtErrorEvent):void { … }
AIR のバージョンは 3.4 で検証しましたが、バージョンが異なれば別の動作になる可能性もあります。また、今後のバージョアップで上記問題が解決する可能性もあります。
追記1
検索して調べてみたところ、Android 端末と Google アカウントを同期することで、Android ギャラリー内に Picasa ウェブアルバムの画像データが表示されることがわかりました。nexus7 以外の Android スマートフォン端末で試してみると、CameraRoll.browseForImage から Google+ の画像データ読込みではやはりエラーが発生しますが、意図可能なエラーとなりました。以下の記述で探知できます。
cameraRoll = new CameraRoll(); cameraRoll.addEventListener(ErrorEvent.ERROR, onError); cameraRoll.browseForImage(); private function onError(event:ErrorEvent):void { … }
エラー処理を色々と切り分けて作成する必要がありそうです。
追記2
カメラロールへの保存に関するエラーは、nexus7 でも以下の記述によってハンドリング可能な事がわかりました。
cameraRoll = new CameraRoll(); cameraRoll.addEventListener(ErrorEvent.ERROR, onError); cameraRoll.addBitmapData(bitmapdata); private function onError(event:ErrorEvent):void { … }
残るは、nexus7 でギャラリーに表示される Picasa の画像読み込み時のエラーがハンドリングできない問題のみとなります。
追記3 問題解決
MediaPromise.file プロパティを調査する事により、ギャラリーから選択されたファイルがアプリケーションにアクセス可能かどうか判断可能なことが判明。
MediaPromise.file プロパティ説明ページより
基礎となるデータソースがファイルベースで、ファイルからアプリケーションにアクセス可能な場合、このプロパティは File オブジェクトを表します。それ以外の場合、プロパティは null です。
以上から、nexus7 を考慮したカメラロール(ギャラリー)からの Picasa データ読み込み対応版処理は以下となります。
cameraRoll = new CameraRoll(); cameraRoll.addEventListener(MediaEvent.SELECT, onSelectImage); cameraRoll.addEventListener(Event.CANCEL, onCansel); cameraRoll.addEventListener(ErrorEvent.ERROR, onError); cameraRoll.browseForImage(); private function onError(event:ErrorEvent):void { //通常スマホ用エラー処理 } private function onSelectImage(event:MediaEvent):void { var mediaPromise:MediaPromise = event.data; if(!mediaPromise.file){ //nexus7 用 Error処理 return; } loader = new Loader(); loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onMediaPromiseLoaded); loader.addEventListener(IOErrorEvent.IO_ERROR, onIOError); loader.loadFilePromise(mediaPromise); }
補足
API リファレンスには書かれていませんが、CameraRoll.addBitmapData でのカメラロールへのデータ保存後は Event.COMPLETE イベントが発行される模様。
よって、保存が完了したか、もしくはエラーが発生したかを調査するためには以下のように記述すればよしとなります。
cameraRoll = new CameraRoll(); cameraRoll.addEventListener(Event.COMPLETE, onComplete); cameraRoll.addEventListener(ErrorEvent.ERROR, onError); cameraRoll.addBitmapData(bitmapdata); private function onComplete(event:Event):void { … } private function onError(event:ErrorEvent):void { … }