[Android Tips] ホーム画面などで AlertDialog を表示する
はじめに
今回は LINE の通知のような、ホーム画面などでダイアログを表示するサンプルを実装してみたいと思います。
この実装のポイントは以下の通りです。
- アプリ本体の Activity から IntentService を呼び出す
- IntentService で数秒経ってから BroadcastReceiver に送る
- BroadcastReceiver から DialogFragment を表示する Activity を起動
- DialogFragement を使うので FragmentActivity から起動させる
- FragmentActivity をテーマを使って透過させることで Dialog だけ見えるようにする
- FragmentActivity をアプリ本体の Activity とは別タスクで起動させる
なお、以下よりアプリ本体側の Activity を MainActivity、Dialog を表示する Activity を AlertDialogActivity と呼びます。
IntentService と BroadcastReceiver を呼び出す
まずは MainActivity から IntentService を呼び BroadcastReceiver を呼び出すところまで実装します。IntentService はアプリの処理をバックグラウンドで行うために使うクラスです。ここでは1秒待機させる処理を実行させましょう (その間にホーム画面に戻り、通知を表示させる…という確認をしたいので)。onHandleIntent() は IntentService が呼び出されたときに実行されるメソッドなので、このときに数秒待機させる処理を行ったあと BroadcastReceiver を呼び出す処理を行います。
TimerIntentService.java
package jp.classmethod.android.sample.dialogonhome; import android.app.IntentService; import android.content.Intent; import android.os.Handler; import android.os.SystemClock; public class TimerIntentService extends IntentService { public TimerIntentService(String name) { super(name); } public TimerIntentService() { super("TimerIntentService"); } @Override protected void onHandleIntent(Intent data) { SystemClock.sleep(5000); Intent intent = new Intent(); intent.setAction("TIMER_FINISHED"); sendBroadcast(intent); } }
ここではアクションを TIMER_FINISHED としました。
次に BroadcastReceiver を実装します。BroadcastReceiver はさまざまなイベント(アクション)を受け取るためのクラスです。このクラスで TIMER_FINISHED というイベントが発生したときに呼び出されるようにします。アクション名との紐付けは後述する AndroidManifest 内で定義します。ということでまずはクラスの実装です。
TimerReceiver.java
package jp.classmethod.android.sample.dialogonhome; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; public class TimerReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent data) { Intent intent = new Intent(context, AlertDialogActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); try { pendingIntent.send(); } catch (PendingIntent.CanceledException e) { e.printStackTrace(); } } }
アクションを受け取るときに onReceive() メソッドが呼び出されるので、このときに AlertDialogActivity を起動するようにします。AlertDialogActivity の実装は次項で解説します!
ここまでで IntentService と BroadcastReceiver の実装が終わりました。あとはこのクラスをそれぞれ AndroidManifest で定義しましょう。
<service android:name=".TimerIntentService" /> <receiver android:name=".TimerReceiver"> <intent-filter> <action android:name="TIMER_FINISHED" /> </intent-filter> </receiver>
ここまでできたらあとは MainActivity で IntentService を呼び出すようにします。
MainActivity.java
package jp.classmethod.android.sample.dialogonhome; import android.content.Intent; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.view.View; public class MainActivity extends Activity { private final MainActivity self = this; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.post).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { startService(new Intent(self, TimerIntentService.class)); } }); } }
これで MainActivity のボタンをタップしたら IntentService が実行され、処理完了後に BroadcastReceiver に通知してくれるところまで実装が終わりました!次はダイアログを表示するところの実装です!
AlertDialog を表示する Activity の実装
まずは Fragment から実装しましょう。といっても今回は特にカスタマイズとかはせず DialogFragment を継承したとってもシンプルな Fragment になっています。Dialog が閉じるタイミングでその Dialog を表示した Activity を finish してしまうところがポイントです。
AlertDialogFragment.java
package jp.classmethod.android.sample.dialogonhome; import android.app.AlertDialog; import android.app.Dialog; import android.os.Bundle; import android.support.v4.app.DialogFragment; public class AlertDialogFragment extends DialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); Dialog dialog = builder.setTitle("通知").setMessage("").create(); dialog.setCanceledOnTouchOutside(true); return dialog; } @Override public void onStop() { super.onStop(); getActivity().finish(); } }
次にこの DialogFragment を表示する Activity を実装します。
AlertDialogActivity.java
package jp.classmethod.android.sample.dialogonhome; import android.os.Bundle; import android.support.v4.app.FragmentActivity; public class AlertDialogActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); AlertDialogFragment fragment = new AlertDialogFragment(); fragment.show(getSupportFragmentManager(), "alert_dialog"); } }
この Activity は実際には表示させたくないので、透過させましょう。android:Theme.Translucent を継承すると透過させることもできますが、AlertDialog のスタイルが 2 系のものになってしまうので android:Theme.Holo を継承しつつカスタマイズします。
<style name="Translucent" parent="android:Theme.Holo.Light"> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:colorBackgroundCacheHint">@null</item> <item name="android:windowIsTranslucent">true</item> <item name="android:windowAnimationStyle">@android:style/Animation</item> <item name="android:windowNoTitle">true</item> <item name="android:windowContentOverlay">@null</item> </style>
あとはこの Activity の android:launchMode を singleInstance にします。こうすることで MainActivity と同タスクで起動することはありません (別タスクで起動するのでバックキーをタップしても MainActivity に戻ることがない) 。
<activity android:name=".AlertDialogActivity" android:theme="@style/Translucent" android:launchMode="singleInstance"> </activity>
以上で実装完了です。あとは実行すると以下のようにホーム画面に居てもどこに居ても AlertDialog で通知してくれます!
まとめ
ということで AlertDialog をホーム画面で表示する実装でした。では来期もよろしくお願いします!