skimemo


skimemo - 日記/2013-08-18/WakeLockじゃなくてAlarmManagerを使って定期的な処理を継続する

_ WakeLockじゃなくてAlarmManagerを使って定期的な処理を継続する

バックグラウンドで処理を行いたい場合、Sleepしてしまうと処理が止まってしまうため、WakeLockを使うといいように書いてあったりします。
http://techbooster.org/android/application/4429/

私もSleep中に処理が止まってしまうのに悩んでいたので、「これだっ」と思って早速実装してみましたが、どうも一度寝てしまうと起きてくれません。
同じ事に悩んでいる人はいるらしく、検索しているとWakeLockはWake状態をLockするためのもので、SleepをWakeするためのものではない事が分かりました。
http://stackoverflow.com/questions/16450947/how-to-wake-the-android-device-from-deep-sleep-using-wake-lock

上記の記事ではAlarmManagerを使えとあり、試してみたところうまくいったので簡単にまとめてみます。

概要としては、ServiceからAlarmを仕掛け、Alarmが起動したらcallbackしてService内の処理を実行します。

まずはService内からAlarmを仕掛けます。

InfoTransferService.java*1

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 
 
 
 
-
|
-
!
|
|
|
|
!
 
 
-
|
|
|
|
!
 
 
-
|
-
!
-
!
-
!
|
!
 
-
-
|
|
|
|
|
|
-
!
!
-
|
-
!
|
|
|
!
-
|
!
-
|
-
!
private InfoTransferBroadcastReceiver ibr;
private Integer interval = 0;    // Interval
 
@Override
public void onCreate() {
        :(略)
    // AlarmのListener & broadcastを仕掛ける
    ibr = new InfoTransferBroadcastReceiver();
    IntentFilter alarmFilter = new IntentFilter();
    this.registerReceiver(ibr, alarmFilter);
    ibr.setListener(this);  // callback用のリスナー
        :(略)
}
 
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
        :(略)
    interval = Integer.parseInt(intent.getStringExtra("interval"));  // intervalをUIから受け取る例
    createTimer();    // intervalを受け取った後に実行
        :(略)
}
 
@Override
public void onDestroy() {
        :(略)
    // Alarmのキャンセル
    cancelTimer();
    // AlarmのListenerを外す
    ibr.removeListener();
    // Alarm用Broadcast解除
    unregisterReceiver(ibr);
        :(略)
}
 
// Alarmセット
private void createTimer() {
    Intent i = new Intent(this, InfoTransferBroadcastReceiver.class); // Receiverを呼び出すインテントを作成
    PendingIntent sender = PendingIntent.getBroadcast(this, 0, i, PendingIntent.FLAG_CANCEL_CURRENT); // 既存の仕掛けがあったらCancel
         
    long firstTime = SystemClock.elapsedRealtime();
    firstTime += interval*1000;  // 本当は、intervalがヘンな値だったら仕掛けないようにした方が良い
    AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE); // AlramManager取得
    // 繰り返し設定
    am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstTime, interval*1000, sender);
}
private void cancelTimer() { 
    Log.d(TAG,"cancelTimer");
    //タイマーのキャンセル処理
    Intent i = new Intent(this, InfoTransferBroadcastReceiver.class); // Receiverを呼び出すインテントを作成
    PendingIntent sender = PendingIntent.getBroadcast(this, 0, i, PendingIntent.FLAG_CANCEL_CURRENT); // 既存の仕掛けがあったらCancel
    AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE); // AlramManager取得
    am.cancel(sender);
}
/**
 * WakeUp時の処理。Receiverからcallbackで呼ばれる。
 */
public void wakeupAlarm() {
    Log.d(TAG,"wakeupAlarm");
    // 処理を書く
}

InfoTransferBroadcastReceiver.java

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
-
|
|
|
|
|
|
-
|
|
!
-
-
|
|
!
-
-
|
|
!
|
!
public class InfoTransferBroadcastReceiver extends BroadcastReceiver {
    
    static private InfoTransferBroadcastReceiverInterface listener = null;
    static final String TAG = "InfoTransferBroadcastReceiver";
 
    @Override
    public void onReceive(Context context, Intent intent)
    {
        Log.d(TAG,"onReceive");
        listener.wakeupAlarm();
    }
    // Listener set
    public void setListener( InfoTransferBroadcastReceiverInterface listener ){
        Log.d(TAG,"setListener");
        InfoTransferBroadcastReceiver.listener = listener;
    }
    // Listener delete
    public void removeListener(){
        Log.d(TAG,"removeListener");
        InfoTransferBroadcastReceiver.listener = null;
    }
 
}

InfoTransferBroadcastReceiverInterface.java

Everything is expanded.Everything is shortened.
  1
  2
  3
-
|
!
public interface InfoTransferBroadcastReceiverInterface extends EventListener {
    public void wakeupAlarm();
}

これでソースの実装は完了です。
しかし、実はここまで書いてもAlarmは起動してくれません。色々調べてみると、manifestファイルにReceiverの記述が必要なことが分かりました。

AndroidManifest.xml

  1
  2
  3

ここについうっかりandroid:process=":remote"とか書いてしまうと、Alarmで起動されるたびにlistenerがnullになってしまい、callbackできません。android:processはしていしないようにしましょう。


こんなのあるんですねー。
離れるとアラームで知らせてくれるそうです。
スマホに付けておいたらどこに行ったか分からなくならなくて良いかも。
でももっと小さくならないかな。

Category: [android] - 06:18:55


 


ソースは様々なサイトの記述を参考にさせていただいています(部分部分は結構そのままだったりします、ごめんなさい)。
でも大変助かっています、ありがとうございます。


 
Last-modified: 2013-08-18 (日) 07:50:56 (2663d)