« 抜き色が倒せない | メイン | Windows で Android のソースコードを取得する »

2011年01月27日

Android:: 止まらないウィジェットを作る

    

Android は、メモリが少なくなってくると動作しているアプリを停止させてメモリを空ける。
これはサービスも同じで、ウィジェットを更新するために動かしているサービスも止められてしまうことがある(いっぱい立ち上げると止められる)。
また、Android はいろいろと立ち上がっていると動作が遅くなるし電池食うしであんまりいいことないので、タスクキル系のアプリが一般的になっていて、そのようなアプリでもサービスが止められてしまう。
システムがサービスを停止させた場合、メモリに余裕が出来るとシステムが再度起動してくれるが、タスクキル系のアプリで止められた時はそうではないようだ。
Service.setForeground(true) を使うとシステムにキルされづらくなるというのは、2.1 で意味のないメソッドとなったよう。
AlarmManager で定期的に処理するというのもユーザーに停止させられた場合は無意味になるし、あんまり無駄な処理をすると電池を食う原因となる。

完全に停止させられないようにする方法は見付からなかった(停止不可に出来ると、そのようなアプリがいっぱい起動されたらどうしようもなくなるので、停止できないようにするのは無理ではないかと思われる)。
そこで、動作させ続ける必要があるウィジェットを探して入れて、タスクキル系のアプリで殺しても少ししてみたらまた起動しているものがあることに気付いた。
何かしたら時々システムから起こしてもらえるようになる方法がある?
この方法である程度回避することが出来そうだ。

探すと android.intent.action.SCREEN_ON が該当しそうだと思ったが、これは BroadcastReceiver を登録しないと受けられない。
プロセスが終了していると、BroadcastReceiver は無効になるので意味がなく、起動はしてもらえない。
AndroidManifest.xml に書いて受けられるインテントが必要。
この用途で探すと android.intent.action.USER_PRESENT が見付かった。
これはデバイスが起動した時 ( ユーザーがロックを解除した時 ) にシステムから送られる。
プロセスが停止していても起こしてもらえる。
スマートフォンでは、スクリーンの ON/OFF はよくする動作なので、スクリーン ON した時に起動させてもらえれば、実用上あんまり停止しているようには見えないはず。

AppWidgetProvider で android.intent.action.USER_PRESENT を受けるように AndroidManifest.xml に書いて、AppWidgetProvider::onReceive でインテントが android.intent.action.USER_PRESENT ならサービスを起動するようにすれば OK。
その時、AppWidgetID は不明なので、AppWidgetID は ContentProvider 等で保存するようにしておく。
SharedPreferences ではなく、ContentProvider なのはウィジェットは複数配置される可能性があるから、ContentProvider の方が都合がよい。
ウィジェットの更新に AppWidgetID が必要な時と必要でない時があるので、単純にウィジェットが今ホームに置かれているかどうか判定するだけなら、単に SharedPreferences で数をカウントすればいいので、ContentProvider は要らない。

また、USER_PRESENT で起こされた時以外 ( システムから起こされた時 ) のためにも何かしら保存しておく必要がある。
一度プロセスが停止させられると変数等はクリアされてしまうのと、システムから起動された時は Service::onStart は呼ばれず、Service::onCreate までしか呼ばれないので、Service::onCreate が呼ばれた時に既にウィジェットが今ホームに置かれているかどうかの判定が必要になる ( 通常のユーザー操作でホームに配置された時と識別出来る必要がある )。

AppWidgetID が必要になるケースは、ウィジェットごとに何かしら表示を設定出来るケースとウィジェットのクリックが必要な時。



投稿者 Takenori : 2011年01月27日 23:32




comments powered by Disqus
Total : Today : Yesterday : なかのひと