ステータス通知(Notification)を変化させる


Notificationを使ってステータス通知するではステータスへメッセージを表示するための方法を紹介しました。今回は、応用としてステータス通知をアニメーションさせる方法を紹介します。
Notificationでは時間差でIntentを発行するPendingIntentも利用しています。AppWidgetの作成(2) + PendingIntentも参考にどうぞ。

ステータスに♪表示 ステータス通知(♪) ステータス通知(▲)

アプリケーションの構成

ステータスバー(通知バー)でアニメーションさせるためにServiceを利用しています。

  • Notificationを押下したときに呼び出されるActivity
  • NotificationをアニメーションさせるService

Serviceを使うことで、Activityが終了した後もステータス通知を定期的に変えることができます
別の利点として、Serviceはスレッドなどと異なり、Binderによるプロセス間通信が用意されています。
表示を中止するなど細かな制御が可能です。(Serviceは、また別の機会に取り上げたいと思います)。

AndroidManifest.xml

1
2
3
4
5
6
7
8
<activity android:name=".NotificationActivity"
          android:label="@string/app_name">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<service android:name="NotificationChangeService" />

service要素を追加します。サンプルコードではActivityはNotificationActivity、ServiceがNotificationChangeServiceです。

ActivityからServiceを起動する

Activityではスタートボタン、ストップボタンでServiceの開始・終了を制御します。
コードはボタンのOnClickListenerにstartService,stopServiceメソッドを記入するだけのシンプルな構成です。
NotificationActivity.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
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
 
    Button startButton = (Button) findViewById(R.id.StartButton);
    Button stopButton  = (Button) findViewById(R.id.StopButton);
 
    startButton.setOnClickListener(startListener);
    stopButton.setOnClickListener(stopListener);
}
 
private OnClickListener startListener = new OnClickListener() {
    public void onClick(View v) {
        startService(new Intent(NotificationActivity.this,
                NotificationChangeService.class));
    }
};
 
private OnClickListener stopListener = new OnClickListener() {
    public void onClick(View v) {
        stopService(new Intent(NotificationActivity.this,
                NotificationChangeService.class));
    }
};

ステータス通知を変化させる – スレッドの生成

実際にステータス通知を変える処理にはServiceを使います。
具体的にはサービスを起動したときのonCreateメソッドでスレッドを生成します。
通常、Serviceはメインスレッドで実行されるため、ほかの処理を妨げるような負荷をかけることができません。

しかしステータス通知をアニメーションさせたい場合は、どうしてもWait処理が必要になります。
そこでスレッドを生成して、Notificationを使う処理は別スレッド(mTask)で行います。
NotificationChangeService.java

1
2
3
4
5
6
7
8
public void onCreate() {
    mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
 
    //サービスはメインスレッドで実行されるため、処理を止めないように更新処理を別スレッドに。
    Thread thread = new Thread(null, mTask, "NotifyingService");
    mCondition = new ConditionVariable(false);
    thread.start();
}

ステータス通知を変化させる – アニメーション

スレッド内部の処理は以下の通りです。丸→三角→音符の順で4回通知内容を差し替えています。
NotificationChangeService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private int WAIT_TIME = 5000;//5秒単位
private Runnable mTask = new Runnable() {
    public void run() {
        for (int i = 0; i < 4; ++i) {
            showNotification(R.drawable.maru,"丸を表示しています");
            if (mCondition.block(WAIT_TIME))
                break;
            showNotification(R.drawable.sankaku,"三角を表示しています");
            if (mCondition.block(WAIT_TIME))
                break;
            showNotification(R.drawable.onpu,"音符を表示しています");
            if (mCondition.block(WAIT_TIME))
                break;
        }
        //アニメーションの終了、サービスを終了する
        NotificationChangeService.this.stopSelf();
    }
};

アニメーションの終了時、 NotificationChangeService.this.stopSelf();でサービスを終了(スレッドも廃棄)します。
for文中の「mCondition.block(WAIT_TIME)」は、決められた時間(WAIT_TIME、ここでは5秒間)スレッドをブロック(停止状態)にする処理です。ステータス通知を変化させる処理はshowNotificationメソッド(次項参照)で実装されています。

Notificationを使ってステータス表示を更新する

NotificationChangeService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// ユニークなIDを取得するために、R.layout.mainのリソースIDを使います
private static int NOTIFICATION_ID = R.layout.main;
 
private void showNotification(int drawableId,   CharSequence text) {
 
    //通知内容を決定
    Notification notification = new Notification(drawableId, null, System.currentTimeMillis());
 
    //PendingIntentはタイミングを指定したインテント
    //今回はユーザーがnotificationを選択した時にActivityを起動
    PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
            new Intent(this, NotificationActivity.class), 0);
 
    //notificationを設定
    notification.setLatestEventInfo(this, "NotificationService",
                   text, contentIntent);
 
    mNotificationManager.notify(NOTIFICATION_ID, notification);
}

NotificationManagerにユニークなID(NOTIFICATION_ID)を指定することで、特定のノーティフィケーションに対して操作が可能です(18行目)。Notification自体は通常通り
・7行目:表示時刻、表示アイコンの指定
・15行目:表示文字列(”NotificationService”)とPendingIntentの設定
を行います。

サービスの終了処理

NotificationChangeService.java

1
2
3
4
5
6
7
@Override
public void onDestroy() {
    //サービスの停止時、通知内容を破棄する
    mNotificationManager.cancel(NOTIFICATION_ID);
    //スレッドを停止するため、ブロックを解除
    mCondition.open();
}

終了時はステータス通知を消す必要があります。NotificationManager#cancel(int id)メソッドでステータス通知をキャンセルし、スレッドをブロックしていたmConditionをopen(解放)します。

One Comment