RemoteViews.setImageViewBitmap によるウィジェットの画像更新に失敗する


これまた嵌ったのでメモ。


ウィジェットアプリを作っていたのだが、ウィジェットの更新がうまくいかなくて嵌ってた。
RemoteViews.setImageViewResource や RemoteViews.setTextViewText を使っての更新はうまくできていた。でも、ウィジェット全体を自分で描画したかったので RemoteViews.setImageViewBitmap を使ったコードに差し替えたとたん、ウィジェットの更新処理がうまく動かなくなった。ウィジェットの背景だけは描画されるのだが、その後にされるはずのビットマップ描画処理が実行されない模様。
そこでいろいろググってみたところ、どうも以下のような原因で失敗するらしいことがわかった。


・RemoteViews.setImageViewBitmap 実行時、扱う画像サイズが大きかったりすると、"!!! FAILED BINDER TRANSACTION !!!"エラーログが出て、更新処理が失敗する


参考:「RemoteViewsの仕組み」
http://blog.livedoor.jp/exiashio/archives/cat_100617.html


要は、RemoteViews は間接的にウィジェット画面を更新する仕組みなので、set系関数を呼ぶ度に内部で対応する action がメモリに積まれていくが、これがある規定のメモリ量を超えると(?)、"!!! FAILED BINDER TRANSACTION !!!"が吐かれ、そこで更新処理が失敗するらしい。特に setImageViewBitmap は画像そのものをメモリに積むようで、画像自体が大きいモノだったりすると、あっさりエラーになってしまう模様。
私の環境では、400x500の画像をベースに加工してエラーになっていたので、画像サイズを 200x250 と小さくしてみたら、更新が成功するようになった。


※ 実際にエラー分岐するあたりをフレームワークのソースで調べてみようと思ったのだが、エラー分岐箇所に辿り着けず断念。エラーをログ出力しているところは見つかるが(2.2だと、core/jni/android_util_Binder.cpp:545)、その流れを作るエラー設定部分が辿れない。BR_FAILED_REPLY というエラー定義値をどこかで設定する箇所があるはずなんだけど、それが見つけられなかった。