Androidで定期的にバックグラウンド処理する場合、従来はPARTIAL_WAKE_LOCKなWakeLockを使う必要がありました。
AlarmManagerでタイマーを仕掛け、タイマーで起こされたBroadcastReceiverがWakeLockでCPUをスリープしないようにしてからServiceを呼んで、Serviceでバックグラウンド処理をし、完了したらBroadcastReceiverが持っているWakeLockを解除してCPUがスリープできるようにする、という流れです。
ここでWakeLockが若干面倒なので処理を簡素化するためにできたのがWakefulBroadcastReceiverです。
公式のトレーニングにも説明が載っています。
WakefulBroadcastReceiverからstartWakefulService()でServiceを起動し、Serviceは処理が済んだらWakefulBroadcastReceiver.completeWakefulIntent()を呼ぶ。
その間はCPUがスリープしないと。
完璧です。
そう思って僕も早速これに置き換えましたが、どうもServiceの処理に時間がかかってしまいます。
もともと2分くらいなのですが、10分とか1時間とかかかっているケースもあります。ただ充電中(開発者オプションで画面付けっぱなし)は2分くらいで済んでいます。
どうも、CPUがスリープしてしまっているように思えます。が、そんなハズはとWakefulBroadcastReceiverのソースを読んでみたところ・・・
wl.acquire(60*1000);
60秒でタイムアウトだそうで。
今回のケースではアウトです。
本当にありがとうございました。
--- 20151029追記 ---
今回はWakefulBroadcastReceiverを取り込んで対処しました。
ソースを自分のプロジェクトにコピペしてpackageとタイムアウト値を変更して使いました。
Apache 2.0なライセンスなので、そこら辺はちゃんとしないといけないですね。
2015年10月28日水曜日
2015年10月27日火曜日
[解決]BOOT_COMPLETEDで起動しない機種があるときはintent-filterに誤りがあるかも
AndroidManifestにこう書いていたら、Zenfone5の電源投入時にonReceiveが呼ばれませんでした。
<receiver android:name=".BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name=".BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
・・・というか、このやり方なら「電源投入時に起動する」という設定を覚えておく必要がないのですね。
<receiver android:name=".BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
カテゴリ指定を取ってこう書いたらonReceiveが呼ばれるようになりました。
<receiver android:name=".BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
公式のトレーニングにもそう書いてありますね。
しかも最初は呼ばれない(enabled="false")ようにして、ユーザが明示的にONしたときにPackageManager経由で有効にする、というのが正しいやり方のようです。
・・・というか、このやり方なら「電源投入時に起動する」という設定を覚えておく必要がないのですね。