2011/08/07

[widget]RemoteViews

過去記事:2010/08/21 16:47
"view"は打ちやすいけど、"views"は打ちにくい。
いつも"w"を抜かしてしまう。
と、どうでもいい話はなしにしよう。
AppWidgetで残る大物は、RemoteViewsとPendingIntentだろう。
RemoteViewsを先にやろう。
あー、AppWidgetManagerってのもいるな。まあ、これは気分次第で。

AppWidgetのために何か描画させたい場合、普通のViewではなくRemoteViewsを使う。
RemoteViewsはViewから派生されたわけではない。ParcelableとFilterをimplementsしてはいるが、親クラスはいない(Objectね)。
特徴は、別プロセスから表示させることができる(can be displayed in another process)だろう。
何がどう"another process"なのかがよくわからん。
起動させるのはHomeアプリだから、この場合はHomeアプリプロセスを指しているのだろうか。
違う。訳が違う。
in another process、だから、別のプロセスで表示できる、となるのか。
別プロセスを立ち上げて、そこでRemoteViewsを表示させると言うことか?
psで見ると、AppWidgetの親はzygoteになっていた。USERはapp_XX(XXは数字)。そうなっているのは、emailやmms、inputmethodのsimejiなんかもだ。
起動直後(Homeには登録していない)

USER      PID   PPID  VSIZE  RSS     WCHAN    PC         NAME

root      1772  1     78708  11124 c0108254 afd0dc74 S zygoteapp_45    2151  1772  100056 12484 ffffffff afd0eb08 S jp.typepad.hirokuma.EjectSD



Homeアプリ表示(Homeには登録していない)app_45    2151  1772  100576 12408 ffffffff afd0eb08 S jp.typepad.hirokuma.EjectSD

ちょっと時間経過

app_45    2151  1772  100576 12388 ffffffff afd0eb08 S jp.typepad.hirokuma.EjectSDHome登録時のウィジェット一覧表示中app_45    2151  1772  100576 11428 ffffffff afd0eb08 S jp.typepad.hirokuma.EjectSDHome登録app_45    2151  1772  100576 11120 ffffffff afd0eb08 S jp.typepad.hirokuma.EjectSD

ちょっと時間経過app_45    2151  1772  100576 11292 ffffffff afd0eb08 S jp.typepad.hirokuma.EjectSDHomeにもう1つウィジェット登録app_45    2151  1772  100576 10924 ffffffff afd0eb08 S jp.typepad.hirokuma.EjectSD1回タップしてみたapp_45    2151  1772  100576 10924 ffffffff afd0eb08 S jp.typepad.hirokuma.EjectSD9個置いてみた。app_45    2151  1772  100576 10700 ffffffff afd0eb08 S jp.typepad.hirokuma.EjectSD
RSSってのが変化しているのでちょこちょこpsて見てみたが、RSSは常駐セットの大きさ、らしい。swapされてない物理メモリだとか。
PCはprogram count?
とにかく、増やしても違いが見えない。
これは単に、今回作ったウィジェットがそうだからなのかも。全部同じ見栄えであってほしいので、ウィジェットIDを管理していないのだ。
app_45は、数値だと10045みたいだ。
USER+α、という計算なのかな?

RemoteViewsのコンストラクタは2つあるが、今回使っているのはpackageNameとlayoutIdをとる方。
これは単にメンバ変数に代入するだけで終わっている。
クリックイベントを受けとってもらうPendingIntentを登録するメソッドのsetOnClickPendingIntent()も、内部で保持するだけ。
内部のActionリストに追加するだけなのだ。
コンストラクタで登録したパッケージ名とレイアウトIDはいつ使うのか?
apply()が一番それっぽく使っているようだ。
apply()関係のメソッドがいくつかあるが、呼ぶと例外を投げるらしい。
システムから呼び出されることを前提にしているのだろうか?
うーん、何一つ疑問が解決しない・・・。
ウィジェットの起動はActivityManagerが行っているようなので、そこから見ていくか。
ログはamのもののようだ。services/java/com/android/server/am/ActivityManagerService.java。
まあ、そういうものか。
プロセス起動は、zygoteが行っている。
これは、Homeアプリがウィジェットとして使おうと使うまいと、関係がない。
では、Homeアプリに9つAppWidgetを登録したときの起動時logcatを見てみよう。
I/ActivityManager( 1868): Start proc jp.typepad.hirokuma.EjectSD for broadcast jp.typepad.hirokuma.EjectSD/.EjectSD: pid=2137 uid=10045 gids={}
V/EjectSD ( 2137): onReceive:android.appwidget.action.APPWIDGET_ENABLED
V/EjectSD ( 2137): onReceive:android.appwidget.action.APPWIDGET_UPDATE
V/EjectSD ( 2137): onUpdate
D/EjectSD ( 2137): getClickRemoteView
V/EjectSD ( 2137): updateIcon
D/EjectSD ( 2137): getClickRemoteView
V/EjectSD ( 2137): updateIcon
D/EjectSD ( 2137): getClickRemoteView
V/EjectSD ( 2137): updateIcon
D/EjectSD ( 2137): getClickRemoteView
V/EjectSD ( 2137): updateIcon
D/EjectSD ( 2137): getClickRemoteView
V/EjectSD ( 2137): updateIcon
D/EjectSD ( 2137): getClickRemoteView
V/EjectSD ( 2137): updateIcon
D/EjectSD ( 2137): getClickRemoteView
V/EjectSD ( 2137): updateIcon
D/EjectSD ( 2137): getClickRemoteView
V/EjectSD ( 2137): updateIcon
D/EjectSD ( 2137): getClickRemoteView
V/EjectSD ( 2137): updateIcon

V/EjectSD ( 2137): onReceive:android.intent.action.MEDIA_MOUNTED
D/EjectSD ( 2137): mount
D/EjectSD ( 2137): getClickRemoteView
これだけ見てもわからないと思うが・・・。
最初の1行は、起動。
次にintentとしてENABLED、続いてUPDATEが来ているので、処理している。
実装しているのはonUpdate()で、こんなことをしている。
final int APP_NUM = appWidgetIds.length;
for(int i=0; i<APP_NUM; i++) {
 RemoteViews remoteView = getClickRemoteView(context);
 updateIcon(remoteView);
 appWidgetManager.updateAppWidget(appWidgetIds[i], remoteView);
}

引数でappWidgetIds[]が渡されるので、それぞれにRemoteViewsを生成し(中でnewを呼び、クリック時のインテントを登録している)、アイコンを描画し、反映させている。
9つ分やっているのは、ここだったのだ。
自分で思いついたわけではなく、どこかのサイトからもらってきた処理だが、そういう意味があったのだな。
では、アイコンをタップしたときのlogcatも見ておこう。
V/EjectSD ( 2137): onReceive:jp.typepad.hirokumaEjectSD.WIDGET_CONTROL
D/EjectSD ( 2137): click
D/EjectSD ( 2137): getClickRemoteView
V/EjectSD ( 2137): onReceive:android.intent.action.MEDIA_EJECT
V/EjectSD ( 2137): onReceive:android.intent.action.MEDIA_UNMOUNTED
D/EjectSD ( 2137): umount
D/EjectSD ( 2137): getClickRemoteView

先頭部分がタップ時のintent受信。
ログに出てこないが、ここでMountServiceに対してmount/umount要求を投げている。
要求が帰ってくるまでの間、アイコンを変化させるためにRemoteViewsを作成し、アイコンをセットしている。
アイコンの変更は、こんな処理。
remoteView.setImageViewResource(R.id.ImageView, R.drawable.icon);
remoteViewはRemoteViewsのインスタンスね。
レイアウトXMLでImageViewという名前のImageViewを置いているので、それをiconというリソースにします、というだけだ。
実は、これがわからずに調べ回っていたのだ。View関係だからRemoteViewsの説明を見ればいいのだろうけど、思いつかなかったのだよ。
その後ここでやっているのは、onUpdate()と違ってこんなことになっている。
ComponentName thisWidget = new ComponentName(context, EjectSD.class);
AppWidgetManager.getInstance(context).updateAppWidget(thisWidget, remoteView);

これもどこかからもらってきた処理だ。
しかし、これも処理がわからずに困っていたのだよ。
後半はUNMOUNTEDとなったintentを受信しての処理だ。
やっていることはタップ時とほとんど同じ。
アイコンを変更させ、updateAppWidget()している。
久しぶりにAndroid関係の本を購入。
「AndroidSDK開発のレシピ」。
カバーはいりません、と言ったつもりなのに、されてしまった。。
何となく悔しい。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。

注: コメントを投稿できるのは、このブログのメンバーだけです。