blog.petitviolet.net

アラームの作り方

2014-03-06

QiitaAndroid

これが正しい方法かどうかわかりませんが、アラームとして機能したのでメモ

Android でアラームを鳴らすためには、

  1. アラーム時に起動するサービスを PendingIntent を使って指定する
  2. 指定されたタイミングで起動したサービスから sendBroadcast を利用してレシーバーを起こす
  3. 起こされたレシーバーからアラーム時に起動する Activity を Intent によって指定、起動

というプロセスでいけるようです。 めんどくさいですが。

サービスとレシーバーを利用するためには権限が必要なため、Manifest に記載する 必要な部分のみ書いています。

AndroidManifest.xml
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />

<application>
	<!-- MainActivityなど -->
	<receiver android:name="AlarmReceiver" >
		<intent-filter>
			<action android:name="MyAlarmAction"></action>
		</intent-filter>
	</receiver>

	<service android:name="MyAlarmService" ></service>

	<activity android:name="AlarmNotificationActivity" ></activity>
</application>

action に MyAlarmAction というものをセットしていますが、 これはサービスからレシーバーを起動する際に利用する識別子のようなものです。多分。

アラームの設定自体を行う MyAlarmManager.java は以下の通り

MyAlarmManager.java
public class MyAlarmManager {
	Context c;
	AlarmManager am;
	private PendingIntent mAlarmSender;

      private static final String TAG = MyAlarmManager.class.getSimpleName();

	public MyAlarmManager(Context c){
		// 初期化
		this.c = c;
		am = (AlarmManager)c.getSystemService(Context.ALARM_SERVICE);
		Log.v(TAG,"初期化完了");
	}

	public void addAlarm(int alarmHour, int alarmMinute){
		// アラームを設定する
		mAlarmSender = this.getPendingIntent();

		// アラーム時間設定
		Calendar cal = Calendar.getInstance();
		cal.setTimeInMillis(System.currentTimeMillis());
		// 設定した時刻をカレンダーに設定
		cal.set(Calendar.HOUR_OF_DAY, alarmHour);
		cal.set(Calendar.MINUTE, alarmMinute);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);

		// 過去だったら明日にする
		if(cal.getTimeInMillis() < System.currentTimeMillis()){
			cal.add(Calendar.DAY_OF_YEAR, 1);
		}
		Toast.makeText(c, String.format("%02d時%02d分に起こします", alarmHour, alarmMinute), Toast.LENGTH_LONG).show();

		am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), mAlarmSender);
		Log.v(TAG, cal.getTimeInMillis()+"ms");
		Log.v(TAG, "アラームセット完了");
	}

	public void stopAlarm() {
		// アラームのキャンセル
		Log.d(TAG, "stopAlarm()");
		am.cancel(mAlarmSender);
		spm.updateToRevival();
	}

	private PendingIntent getPendingIntent() {
		// アラーム時に起動するアプリケーションを登録
		Intent intent = new Intent(c, MyAlarmService.class);
		PendingIntent pendingIntent = PendingIntent.getService(c, PendingIntent.FLAG_ONE_SHOT, intent, PendingIntent.FLAG_UPDATE_CURRENT);
		return pendingIntent;
	}
}

PendingIntent の FLAG についてはhttp://y-anz-m.blogspot.jp/2011/07/androidappwidget-pendingintent-putextra.htmlが詳しいです。 アラームを更新するのか、あるいは前のままにするのか等、用途に合わせて設定して下さい。

getPendingIntent()で定義しているように、PendingIntent.getServiceで呼び出すサービスを指定します。 MyAlarmManager によって、アラームの時刻を設定したい Activity などからaddAlarm(hour, minute)で簡単にアラームをセットできます。

次にサービスを見ます。

MyAlarmService.java
public class MyAlarmService extends Service {
	private static final String TAG = MyAlarmService.class.getSimpleName();

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

	@Override
	public void onCreate() {
		Thread thr = new Thread(null, mTask, "MyAlarmServiceThread");
		thr.start();
		Log.v(TAG,"スレッド開始");
	}
	// アラーム用サービス
	Runnable mTask = new Runnable() {
		public void run() {
			// アラームを受け取るActivityを指定
			Intent alarmBroadcast = new Intent();
			// ここでActionをセットする(Manifestに書いたものと同じであれば何でもよい)
			alarmBroadcast.setAction("MyAlarmAction");
			// レシーバーへ渡す
			sendBroadcast(alarmBroadcast);
			// 役目を終えたサービスを止める
			MyAlarmService.this.stopSelf();
			Log.v(TAG,"サービス停止");
		}
	};
}

サービスからの BroadCast な Intent を受け取るレシーバー

AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
	@Override
	public void onReceive(Context context, Intent intent) {
		// アラームを受け取って起動するActivityを指定、起動
		Intent notification = new Intent(context, AlarmNortificationActivity.class);
		// 画面起動に必要
		notification.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		context.startActivity(notification);
	}
}

だんだんコードが減ってきて、言うことが無くなってきてます。

AlarmReceiver によって起こされる Activity

AlarmNotification.java
public class AlarmNortificationActivity extends Activity {
	private MediaPlayer mp;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.alarm_notification);

		// スクリーンロックを解除する
		// 権限が必要
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
				WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
				WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
				WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

		Toast.makeText(this, "アラーム!", Toast.LENGTH_SHORT).show();

	}

	@Override
	public void onStart() {
		super.onStart();
		Toast.makeText(getApplicationContext(), "アラームスタート!", Toast.LENGTH_LONG).show();
		// 音を鳴らす
		if (mp == null)
			// resのrawディレクトリにtest.mp3を置いてある
			mp = MediaPlayer.create(this, R.raw.test);
		mp.start();
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		stopAndRelaese();
	}

	private void stopAndRelaese() {
		if (mp != null) {
			mp.stop();
			mp.release();
		}
	}

	@Override
	protected void onResume() {
		super.onResume();
		alarmNowText = (TextView) findViewById(R.id.alarm_now_time);
		handler.sendEmptyMessage(WHAT);
		// mam.stopAlarm();
	}
}

これでalarm_notification.xmlが表示され、Toast が出るはずです。

意外とめんどくさいアラームのメモでした。

アラームを設定する際のベストプラクティスがよくわかっていないので、アドバイス頂けると嬉しいです。

from: https://qiita.com/petitviolet/items/89a0166f4167753d8844