ある時間にアプリから通知して欲しいという場合がよくあります。目覚まし時計とかスケジュール系のアプリなど、これらの通知には時間を管理する AlarmManager 及びその関連APIを使います。
Android Studio 3.5.3 API 29 |
AlarmManager |
いきなりですが、アプリのオプションでアラームを鳴らしたいだけなら、Intentを使ったアラーム クロックを使うと簡単です。
また、setExactAndAllowWhileIdleをサービスを使って繰り返す方法もあります。
短時間の単純なタイマーや時間計測にはAlarmManagerではなく、Handlerを使うことが推奨されています。
For normal timing operations (ticks, timeouts, etc) it is easier and much more efficient to use Handler.
Ref: AlarmManager
https://developer.android.com/reference/android/app/AlarmManager.html
また、AlarmをBroadcastReceiver で受けるケースでは、ブロードキャストの制限事項 があります。
Android 8.0 を対象にしているアプリは、暗黙的なブロードキャストに対するブロードキャスト レシーバーをマニフェストで登録できなくなりました。
明示的な登録であれば大丈夫のようです。元々の理由が暗黙的BroadcastRecieverがたくさんあると関係ないアプリも毎回呼び出しを食らってリソース、消費電力の観点からよくないと言う理由からです。
また、AlarmManagerを使う上で、Dozeモードという低消費電力モードを考えないといけないのですが、API levelによって挙動が異なります。
つまり目覚まし時計を作ろうとした場合、このあたりをうまくやらないと時間通りにアラームが鳴りません。
[Android] Doze mode で AlarmManager の繰り返しアラームを実装するには AlarmManagerで繰り返しのアラーム機能を実装したいのですが、バックグラウンド実行制限があります。本来の機能として定期的なバックグラ... 2020-02-05 18:48 |
この他にタスクスケジュールを実行できるののとしてJobSchedulerやJobDispatcherなどがあります。
目次
1. AlarmManager
4. サンプルコード
5. サンプル動画
AlarmManager
このクラスを直接インスタンス化してはいけないようで
Context.getSystemService(Context.ALARM_SERVICE) を使います
1 | AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE); |
その後、例えば繰り返しのアラームメソッド set はこのように設定します
1 2 3 4 5 |
alarmManager.set( AlarmManager.RTC_WAKEUP, 5*1000, // 1sec = 1000 sender ); |
sender は PnedingIntent のインスタンスです。
これは単発アラームの例ですが、他にもメソッドがいくつもあります。
また、API levelによって様々追加されました。AlarmManager | Android Developers
API level 19: アラーム時間の精度が低いものが使えるようになる
API level 23: Dozeモードの導入でDoze中でも起動できるメソッドの追加
API level 24: Direct callbackが使えるメソッド
set: ワンショットのアラーム, API level 19 以降では低精度
1 2 3 4 |
//API level 1 set(int type, long triggerAtMillis, PendingIntent operation) |
set: 上記set に Direct callback が追加
1 2 3 4 5 |
//API level 24 set(int type, long triggerAtMillis, String tag, AlarmManager.OnAlarmListener listener, Handler targetHandler) |
setRepeating: 繰り返しアラーム
1 2 3 4 5 |
//API level 1 setRepeating(int type, long triggerAtMillis, long intervalMillis, PendingIntent operation) |
setInexactRepeating: 繰り返しアラーム、API level 19 以降では低精度
1 2 3 4 5 |
//API level 3 setInexactRepeating (int type, long triggerAtMillis, long intervalMillis, PendingIntent operation) |
setExact: setよりも正確なワンショットアラーム
1 2 3 4 |
//API level 19 setExact(int type, long triggerAtMillis, PendingIntent operation) |
setExact: 上記setExactに Direct Callback が追加
1 2 3 4 5 6 |
//API level 24 setExact (int type, long triggerAtMillis, String tag, AlarmManager.OnAlarmListener listener, Handler targetHandler) |
setAndAllowWhileIdle: setと同じだが low-power idleモードでも実行される。
1 2 3 4 |
//API level 23 setAndAllowWhileIdle (int type, long triggerAtMillis, PendingIntent operation) |
setExactAndAllowWhileIdle: setExactと同じだが low-power idleモードでも実行される。
1 2 3 4 |
//API level 23 setExactAndAllowWhileIdle (int type, long triggerAtMillis, PendingIntent operation) |
Doze中でも定期的にアラームを出にはこれらを使います。
setWindow: 設定したwindow内でアラームが実行
1 2 3 4 5 |
//API level 19 setWindow(int type, long windowStartMillis, long windowLengthMillis, PendingIntent operation) |
setWindow: 上記setWindowにDirect Callbackが追加
1 2 3 4 5 6 7 |
//API level 24 setWindow (int type, long windowStartMillis, long windowLengthMillis, String tag, AlarmManager.OnAlarmListener listener, Handler targetHandler) |
setAlarmClock: Dozeモードでもアラームを出してくれるようです。
1 2 3 |
// API level 21 setAlarmClock (AlarmManager.AlarmClockInfo info, PendingIntent operation) |
また、その他に
cancel
設定したアラームの取り消し
setTime
ミリ秒での時間設定
setTimeZone
タイムゾーンの設定
などがあります
また、アラームに関する定数が幾つかあります。例えば、
ELAPSED_REALTIME
スリープ時間を含んだブートアップからの経過時間
ELAPSED_REALTIME_WAKEUP
ELAPSED_REALTIME に加えて、実機スリープ中では wake up してくれる
RTC
時刻
RTC_WAKEUP
RTCに加えて実機スリープ中では wake up してくれる
PendingIntent
PendingIntent は作成した Intent をタイミングを見て他のアプリケーションに渡す場合に使います。
1 2 3 4 |
// Intent のインスタンス生成 Intent indent = new Intent(getApplicationContext(), AlarmBroadcastReceiver.class); // Broadcast にメッセージを送るための設定 PendingIntent pending = PendingIntent.getBroadcast(getApplicationContext(), 0, indent, 0); |
getBroadcastの第2引数は requestCode です。PendingIntent が1つの場合は0で大丈夫ですが複数ある時は、この requestCode を使って Receiver 側で切り分けます
Ref: PendingIntent
http://developer.android.com/reference/android/app/PendingIntent.html
BroadcastReceiver
PendingIntent からの Intent を受け取りるクラスを新しく作ります。そこでアラームを受けトーストします。
1 2 3 4 5 6 |
public class AlarmBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "Received ", Toast.LENGTH_LONG).show(); } } |
サンプルコード
これらの内容をふまえて実際にコードを組んでみましょう
WAKE_LOCK パーミッションとBroadcast の receiver を入れます。
AndroidManifest.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" .. <uses-permission android:name="android.permission.WAKE_LOCK"/> <application ... <activity ... </activity> <receiver android:name=".AlarmBroadcastReceiver" android:process=":remote" /> </application> </manifest> |
ボタンをタップしてアラームをセットするようにします
MainAcrivity.java
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 |
package your.package.name; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Intent; import android.view.View; import android.widget.Button; import android.widget.Toast; import java.util.Calendar; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 開始ボタン Button button = this.findViewById(R.id.button1); String str = "Alarm Start"; button.setText(str); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 時間をセットする Calendar calendar = Calendar.getInstance(); // Calendarを使って現在の時間をミリ秒で取得 calendar.setTimeInMillis(System.currentTimeMillis()); // 5秒後に設定 calendar.add(Calendar.SECOND, 5); //明示的なBroadCast Intent intent = new Intent(getApplicationContext(), AlarmBroadcastReceiver.class); PendingIntent pending = PendingIntent.getBroadcast( getApplicationContext(), 0, intent, 0); // アラームをセットする AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE); if(am != null){ am.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pending); Toast.makeText(getApplicationContext(), "Set Alarm ", Toast.LENGTH_SHORT).show(); } } }); } } |
アラームをBroadcastReceiver で受けます
AlarmBroadcastReceiver.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package your.package.name; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.widget.Toast; public class AlarmBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // toast で受け取りを確認 Toast.makeText(context, "Received ", Toast.LENGTH_LONG).show(); } } |
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center" tools:context=".MainActivity"> <Button android:id="@+id/button1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="50dp" android:textSize="18sp"/> </LinearLayout> |
サンプル動画
アラームを設定して開始
BroadcastReceiver で受け取るという簡単な例でした
次はアラームを通知できるようにしてみます
関連:
AlarmManagerをBroadcastRecieverと使う
Alarm を NotificationManager で通知する
Doze mode で AlarmManager の繰り返しアラームを実装するには
References:
AlarmManager | Android Developers
BroadcastReceiver | Android Developers
PendingIntent | Android Developers
誤字脱字、意味不明で分からにゃイ、
などのご意見はこちらから mailフォーム
ブックマークしておくと便利です
アプリ開発が上達するお勧め
アプリ開発を始めたけどわからないところがあり、誰かに聞きたいけど周りにはそんな人はいない…あるいは、会社で働いていて日中そんなに時間をとれないなど、オンラインのプログラミングスクールがいいでしょう。
オンラインスクールは色々ありますが、以下の3つはAndroidが学習できる老舗スクールです。
'JLPT' 카테고리의 다른 글
JDBCとは何でしょうか? (0) | 2021.07.05 |
---|---|
SQLite を使用してデータを保存する (0) | 2021.07.05 |
jQueryでjson使おうとるするも、「Uncaught TypeError~has no method ‘toJSON’」のエラー、ひとまず解決 (0) | 2021.07.05 |
NodejsでSlackにメッセージ投稿(2019年1月版) (0) | 2021.07.05 |
UML シーケンス図のフラグメントを使用した制御フローの記述 (0) | 2021.07.05 |
댓글