- Date: Sun 22 12 2013
- Category: Android
- Response: Comment 0 Trackback 0
指定時間に処理を実行する : AlarmManager
Android では指定された時間、または、一定時間毎に処理を実行するために AlarmManager が用意されています。
例えば、10秒毎にサービスを実行するには以下のように記述します。
■ AlarmManager の注意点
①AlarmManager の実行周期が長いと時間が遅れる(数時間で2~3分?)
②AlermManager は cancel しなくても以下の時に終了する
・デバイスの電源をオフにする(再起動する)
・アプリをアップデートする
・アプリをアンインストールする
この問題は BroadcastReceiver クラスを使い、再実行することで回避することが出来ます。
①の時間が遅れる問題は時間が自動設定されているときに発生するので、システム時間が変更された時に発生する broadcast を受け取るようにします。
②はデバイス起動時とアプリ更新時に発生する broadcast を受け取ってください。アンインストール時はアプリ自体がなくなるので指定する必要はありません。
そして、アプリ更新時には <data android:scheme="package" /> が必要です。<data> タグに android:path を指定することで自身のアプリのみを対象にできる…らしいのですが android:path を指定しても他のアプリ更新時に broadcast が投げられてしまいました。BroadCast クラス側で path のチェックをする必要があるようです。
(HTC J ISW13HT で確認)
以上を踏まえ、10秒毎にログを出力する簡単なアプリを作ってみました。
AlermManager のON/OFFの管理は行っていません。アプリが1度でも起動したら常にONになります。
なお、Android 3.1 (API12 / Haneycomb) 以降、アプリが1度も実行されていない場合は STOP 状態となり broadcast も受け取りません。そのためインストール時に自動で開始させることはできません。なので「1度でも起動したら」という表記を用いています。
SampleService.java
SampleActivity.java
SampleBroadcastReceiver.java
AndroidManifest.xml
■参考サイト
Y.A.M の 雑記帳 - AlarmManager
素人のアンドロイドアプリ開発日記 - AlarmManagerを使う場合の注意点
rokuta96のAndroidアプリ開発 - アラーム3
kino's blog - Android Service を自動的に再起動する方法
例えば、10秒毎にサービスを実行するには以下のように記述します。
// 実行するサービスを指定する
PendingIntent pendingIntent = PendingIntent.getService(context, 0,
new Intent(context, SampleService.class),
PendingIntent.FLAG_UPDATE_CURRENT);
// 10秒毎にサービスの処理を実行する
AlarmManager am = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(), 10 * 1000, pendingIntent);
■ AlarmManager の注意点
①AlarmManager の実行周期が長いと時間が遅れる(数時間で2~3分?)
②AlermManager は cancel しなくても以下の時に終了する
・デバイスの電源をオフにする(再起動する)
・アプリをアップデートする
・アプリをアンインストールする
この問題は BroadcastReceiver クラスを使い、再実行することで回避することが出来ます。
①の時間が遅れる問題は時間が自動設定されているときに発生するので、システム時間が変更された時に発生する broadcast を受け取るようにします。
<receiver
android:name=".SampleBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.TIMEZONE_CHANGED" />
<action android:name="android.intent.action.TIME_SET" />
<action android:name="android.intent.action.DATE_CHANGED" />
</intent-filter>
</receiver>
②はデバイス起動時とアプリ更新時に発生する broadcast を受け取ってください。アンインストール時はアプリ自体がなくなるので指定する必要はありません。
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />起動時に broadcast を受け取るには android.permission.RECEIVE_BOOT_COMPLETED 権限が必要です。
<receiver
android:name=".SampleBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<data
android:path="jp.inujirushi.android.sample"
android:scheme="package" />
</intent-filter>
</receiver>
そして、アプリ更新時には <data android:scheme="package" /> が必要です。<data> タグに android:path を指定することで自身のアプリのみを対象にできる…らしいのですが android:path を指定しても他のアプリ更新時に broadcast が投げられてしまいました。BroadCast クラス側で path のチェックをする必要があるようです。
(HTC J ISW13HT で確認)
以上を踏まえ、10秒毎にログを出力する簡単なアプリを作ってみました。
AlermManager のON/OFFの管理は行っていません。アプリが1度でも起動したら常にONになります。
なお、Android 3.1 (API12 / Haneycomb) 以降、アプリが1度も実行されていない場合は STOP 状態となり broadcast も受け取りません。そのためインストール時に自動で開始させることはできません。なので「1度でも起動したら」という表記を用いています。
SampleService.java
package jp.inujirushi.android.sample;
import android.app.AlarmManager;
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
import android.util.Log;
public class SampleService extends IntentService {
private static final String TAG = "SampleService";
public SampleService() {
super(TAG);
}
@Override
protected void onHandleIntent(Intent intent) {
Log.d(TAG, "time:" + SystemClock.elapsedRealtime());
}
/**
* サービスを処理する AlarmManager を開始する。
*
* @param context
*/
public static void startAlarm(Context context) {
// 実行するサービスを指定する
PendingIntent pendingIntent = PendingIntent.getService(context, 0,
new Intent(context, SampleService.class),
PendingIntent.FLAG_UPDATE_CURRENT);
// 10秒毎にサービスの処理を実行する
AlarmManager am = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(), 10 * 1000, pendingIntent);
}
}
SampleActivity.java
package jp.inujirushi.android.sample;
import android.app.Activity;
import android.os.Bundle;
public class SampleActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
// AlarmManager を開始する
SampleService.startAlarm(getApplicationContext());
}
}
SampleBroadcastReceiver.java
package jp.inujirushi.android.sample;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class SampleBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// 他のアプリ更新時は対象外とする
if (intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED)) {
if (!intent.getDataString().equals(
"package:" + context.getPackageName())) {
return;
}
}
// AlarmManager を開始する
SampleService.startAlarm(context);
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?><receiver> タグにある android:process=":remote" は別プロセスで起動する場合に指定します。必須ではありません。
<manifest package="jp.inujirushi.android.sample"
android:versionCode="1"
android:versionName="1.0" xmlns:android="http://schemas.android.com/apk/res/android">
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".SampleActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".SampleBroadcastReceiver"
android:process=":remote" >
<intent-filter>
<action android:name="android.intent.action.TIMEZONE_CHANGED" />
<action android:name="android.intent.action.TIME_SET" />
<action android:name="android.intent.action.DATE_CHANGED" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<data
android:path="jp.inujirushi.android.sample"
android:scheme="package" />
</intent-filter>
</receiver>
<service android:name=".SampleService"></service>
</application>
</manifest>
■参考サイト
Y.A.M の 雑記帳 - AlarmManager
素人のアンドロイドアプリ開発日記 - AlarmManagerを使う場合の注意点
rokuta96のAndroidアプリ開発 - アラーム3
kino's blog - Android Service を自動的に再起動する方法
スポンサーサイト