View on GitHub
mixi-inc/AndroidTraining
メッセージングと通知
この章では、アプリ内や、アプリ外との遣り取りをする仕組みであるメッセージングについて解説します。

参考:Context | Android Developers
参考:Intent | Android Developers
参考:Intents and Intent Filters | Android Developers
参考:BroadcastReceiver | Android Developers
参考:LocalBroadcastManager | Android Developers
参考:Notifications | Android Developers

目次

Intent

Android のメッセージングで、最も頻繁に使われるオブジェクトに Intent があります。
Intent は、メッセージングでやり取りするメッセージそのものを取り扱う Entity の役割を持っています。

実際に Intent をメッセージとして送る仕組みは、Context が持っており、
Intent を受け取ることが出来るのは、Activity、Service、BroadcastReceiver の 3 つのコンポーネントです。

Intent オブジェクト

Intent オブジェクトは、メッセージを送信する相手に実行してもらいたい処理を記述したデータです。
Intent オブジェクトには、以下に挙げる情報が含まれています。

Action

どのようなアクション(処理)を実行してほしいか、を示します。
Activity に向けた Action と、Broadcast 用の Action の 2 種類があります。

Activity に向けた Action の代表的なものを以下に示します。

  • ACTION_VIEW
  • ACTION_MAIN
  • ACTION_SEND
  • ACITON_SENDTO
  • ACTION_EDIT
  • ACTION_PICK
  • ACTION_DELETE
  • ACTION_INSERT
  • ACTION_SEARCH
  • ACTION_CALL

Broadcast 用の Action の代表的なものを以下に示します。

  • ACTION_BOOT_COMPLETED
  • ACTION_SHUTDOWN
  • ACTION_PACKAGE_ADDED
  • ACTION_PACKAGE_REPLACE
  • ACTION_PACKAGE_REMOVED

Category
Intent を処理するべき対象が、どのような属性を持っていることを期待しているかを示すものです。
  • CATEGORY_DEFAULT
  • CATEGORY_LAUNCHER
  • CATEGORY_HOME
  • CATEGORY_PREFERENCE
  • CATEGORY_BROWSABLE
Data
Action の対象となるデータを指し示す URI です。
例えば、ACTION_VIEW と対にして Data を渡すということは、対象のデータを表示するよう指示することを意味します。
Type
Data の種類を表す MIME タイプです。
Component

Action を実行することを期待するコンポーネントです。
Intent を送りつける対象のコンポーネントとも読み替えることができます。

この、Component を明示している(Intent を送る対象が明らかな)Intent のことを、明示的 Intent と呼んでいます。
一方、Component を明示していない(Action をハンドリング出来るもの全てを対象とする)Intent のことを、 暗黙的 Intent と呼びます。

Extras
Intent を送りつける対象に渡す追加情報です。
Key と Value のペアを Bundle オブジェクトに詰めて渡します。
Flag
Activity の起動方法をシステムに通知するための情報です。

Intent Filter

暗黙的 Intent を受け取るコンポーネントが、その Intent をハンドリング可能かどうかを宣言するための仕組みです。
Android フレームワークは、この Intent Filter の宣言を元にして、暗黙的 Intent の対象となるコンポーネントをリストアップします。

ActionDataCategoryの 3 つの情報を基準に暗黙的 Intent がハンドリング可能なものを選択するように設計されているので、Intent Filter にもこの 3 つの情報について宣言をしておきます。

暗黙的 Intent がハンドリング可能かどうかの判定に、Flag や Extras は使われません。

AndroidManifest での IntentFilter の宣言の例を以下に示します。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="jp.mixi.sample"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="7"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <activity
            android:name="jp.mixi.sample.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <!-- アプリのメイン(入り口)となる Activity を起動するときの Action を受け取る -->
                <!-- Intent クラスに定義されている ACTION_MAIN 定数の実態は "android.intent.action.MAIN" という文字列 -->
                <action android:name="android.intent.action.MAIN" />

                <!-- ランチャーからの起動のものを受け取る -->
                <!-- Intent クラスに定義されている CATEGORY_LAUNCHER 定数の実態は "android.intent.category.LAUNCHER" という文字列 -->
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity
            android:name="jp.mixi.sample.AnotherActivity"
            android:label="@string/app_name" >
            <!-- 画像を共有する Action のための Intent Filter 宣言 -->
            <intent-filter>
                <!-- ACTION_SEND または ACTION_SEND_MULTIPLE のいずれかを受け取る -->
                <!-- Intent に設定可能な Action は 1 つだけなので、<intent-filter> に Action を複数宣言すると -->
                <!-- その中からいずれかに該当するものを受け取る、という意味になる -->
                <action android:name="android.intent.action.SEND" />
                <action android:name="android.intent.action.SEND_MULTIPLE" />

                <!-- 暗黙的 Intent を扱う際に必須のカテゴリ -->
                <!-- システムは、Activity の起動に暗黙的 Intent を発行すると、 -->
                <!-- このカテゴリが付与されているものとして扱うため、Activity で暗黙的 Intent を受け取りたい場合は -->
                <!-- 必ずこのカテゴリを <intent-filter> に宣言しておく -->
                <!-- 複数のカテゴリを <intent-filter> に宣言した場合は、 -->
                <!-- 全てのカテゴリにマッチするもののみを受け取る、という意味になる -->
                <category android:name="android.intent.category.DEFAULT" />

                <!-- Data の種類の制限 -->
                <!-- MIME タイプのほか、URI のスキームを制限することもできる -->
                <data android:mimeType="image/jpeg" />
            </intent-filter>
        </activity>

    </application>

</manifest>

Intent を用いた、1 対 1 のメッセージング

Activity を起動する Intent

新しい Activity を呼び出すときに使用します。

public class MyActivity extends Activity {
    @Overrride
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // メッセージのオブジェクトとして Intent を作る
        // どの Context から、どのクラスに対してメッセージを送るかを指定する
        Intent intent = new Intent(this, NextActivity.class);
        // Intent を Context に渡して、メッセージを送る
        // この場合、NextActivity クラスにメッセージが送られ、NextActivity が立ち上がる
        startActivity(intent);
    }
}

Activity を起動し、処理結果を期待するメッセージング

新しい Activity を呼び出し、その Activity から元の Activity へと Intent を戻すことで、何らかの処理の結果を呼び出し元に通知することができるものです。

// 呼び出し元の Activity
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 新しい Activit を呼び出す
        // 戻りの Intent を期待する場合は、Activity#startActivityForResult(Intent, int) を使用する
        startActivityForResult(new Intent(this, SubActivity.class), SubActivity.REQUEST_CODE_HOGE);
    }

    // 新しい Activity から戻ってくる Intent を受け取るコールバック
    // 新しい Activity が全面に出る場合は、onRestart()の前、ダイアログのように一部を覆って表示される場合は、onResume()の前で呼ばれる
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        // super.onActivityResult(int, int, Intent) の呼び出しは、条件に関係なくすること
        // Fragment から startActivityForResult(Intent, int) した場合の戻りの判定ができなくなってしまう
        super.onActivityResult(requestCode, resultCode, data);

        // requestCode には、startActivityForResult(Intent, int) の第 2 引数で指定したものが来る
        // resultCode には、呼び出し先で setResult(int, Intent) をコールした時の第 1 引数が来る
        // data には、呼び出し先で setResult(int, Intent) をコールした時の第 2 引数が来る 
        switch (requestCode) {
            case SubActivity.REQEUST_CODE_HOGE:
                 // REQUEST_CODE_HOGE の戻りが来た時の処理
                 return;
            default:
                 // 知らない requestCode の戻りが来た時の処理
                 return;
        }
    }
}
// 呼び出し先の Activity
public class SubActivity extends Activity {
    public static final int REQUEST_CODE_HOGE = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 何かする

        // 呼び出し元に返す Intent オブジェクトをセットする
        // 第 1 引数には、RESULT_OK または RESULT_CANCELLED、あるいは、RESULT_FIRST_USER を起点にした独自の int 型定数を使う
        setResult(RESULT_OK, new Intent());
        finish();
    }
}

Service を起動する Intent

Service を呼び出します。Service そのものについては、別の章で解説します。

public class MyActivity extends Activity {
    private ServiceConnection mServiceConnection;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // サービスのバインド要求
        bindService(new Intent(this, MyService.class), mServiceConnection, Context.BIND_AUTO_CREATE);

        // サービスの開始要求
        startService(new Intent(this, MyIntentService.class));
    }
}

Intent を用いた、1 対 多 のメッセージング

アプリ内、アプリ外問わず、Intent を全体へ投げかける仕組みのことを、ブロードキャストと言います。
Android のシステムでは、端末の状態を全アプリに通知するための仕組みとして利用しています。

BroadcastReceiver

ブロードキャストされる Intent を受信するためのコンポーネントです。

その宣言の仕方に依って、使われ方が異なることに注意します。

BroadcastReceiver のライフサイクル

BroadcastReceiver には、ブロードキャストされた Intent を受け取るためのコールバックメソッドが用意されています。

public class MyBroadcastReceiver extends BroadcastReceiver {
    // Broadcast された Intent を受け取るコールバック
    @Override
    public void onReceive(Context context, Intent intent) {

    }
}

BroadcastReceiver のライフサイクルは、このonReceive(Context, Intent)メソッドが実行されている間となります。
つまり、onReceive(Context, Intent)メソッドの処理が終わると、BroadcastReceiver のライフサイクルが終わることになります。

また、BroadcastReceiver が動作しているプロセスは、最も優先順位の高いフォアグラウンドプロセスとして扱われます。
つまり、BroadcastReceiver のライフサイクルが終了したプロセスは、そのプロセスで動作している他のコンポーネントが持つ優先順位になります。
もし、BroadcastReceiver のみがプロセス上で動作していた場合、BroadcastReceiver のライフサイクルが終了すると、そのプロセスは空プロセスとして扱われ、システムが優先してプロセスを kill するようになります。

よって、この 2 つの特徴から、BroadcastReceiver の中で非同期処理(Service を除く)を実行することは良くない実装となります。
なぜなら、非同期処理が終了する以前に、プロセスが終了してしまう可能性があるからです。
代わりに、別の章で解説するServiceの仕組みを利用します。

また、BroadcastReceiver の中で、ダイアログを表示することも推奨されません。
なぜなら、ダイアログのイベント処理を実行する前に、BroadcastReceiver のライフサイクルが終了してしまうからです。
代わりに、後述するNotificationの仕組みを利用します。

Static BroadcastReceiver

AndroidManifest に宣言される BroadcastReceiver です。

アプリがインストールされている間はずっと、BroadcastReceiver が動作し、ブロードキャストされる Intent の監視を続けます。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="jp.mixi.sample;"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="7"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <!-- ... -->

        <receiver
            android:name="jp.mixi.sample.MyBroadcastReceiver">
            <intent-filter>
                
            </intent-filter>
        </receiver>
    </application>

</manifest>
public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {

    }
}

ただし、Honeycomb 以後の Android では、アプリのインストール直後は、アプリの状態が待機状態として扱われるようになったため、アプリを一度でも起動しないと、ブロードキャストされる Intent が受信できなくなります。

Dynamic BroadcastReceiver

Activity などの Context で動的に登録/解除が行われる BroadcastReceiver です。

Context のライフサイクルの中で動的に登録をするので、解除もライフサイクルの中で実施する必要があります。
また、どのライフサイクルの Context で登録を行うかも重要です。

Activity の Context で動的に登録した場合、解除も Activity の Context の中で行うようにします(下記のサンプルコード参照)。
もし解除を行わなかった場合、システムが自動で登録を解除し、適切に解除を行う指示をエラーログに吐き出します。

Application の Context で動的に登録した場合、アプリケーションの中でグローバルなスコープで BroadcastReceiver が動作します。
つまり、解除を忘れても、システムは自動で登録を解除しません。ですので、解除を適切に行わないと、深刻なリークの原因となります。

public class MyActivity extends Activity {
    private BroadcastReceiver mMyReceiver = new MyBroadcastReceiver();

    @Override
    protected void onStart() {
        super.onStart();

        // ACTION_PACKAGE_ADDED の Action を通す IntentFilter オブジェクトを作成
        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);

        // MyBroadcastReceiver オブジェクトを、指定した IntentFilter オブジェクトで、Activity の Context に登録
        registerReceiver(mMyReceiver, filter);
    }

    @Override
    protected void onStop() {
        // MyBroadcastReceiver オブジェクトの登録を、Activity の Context 上から解除する
        // Activity のライフサイクルが終わりに向かうコールバックの中で実装する
        unregisterReceiver(mMyReceiver);

        super.onStop();
    }
}

Intent を Broadcast する

Context#sendBroadcast(Intent)を利用して、ブロードキャストを送信します。

これによって、端末内で Intent に設定した Action が実行可能で、Category や Data を受け付けてくれる BroadcastReceiver すべてがこの Intent を受信するようになります。

public class MyActivity extends Activity {
    // 自分で独自の Action を定義することも可能
    public static final String ACTION_HOGEHOGE = "jp.mixi.sample.android.intent.action.HOGEHOGE";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // do something...

        // Intent のブロードキャスト
        Intent intent = new Intent();
        intent.setAction(ACTION_HOGEHOGE);
        sendBroadcast(intent);
    }
}

LocalBroadcastManager

特に、アプリ内全体へのブロードキャストを行う仕組みとして、LocalBroadcastManagerがあります。
これによって、他のアプリには知られたくない Broadcast が実現出来ます。

これとは別に、ブロードキャスト時にパーミッションを設定し、そのパーミッションを得ているアプリのみがブロードキャストを受信できるようにする方法もあります。この場合、パーミッションを持っていれば、他のアプリでもブロードキャストの受信が可能となります。

今回は、より軽量に利用可能な LocalBroadcastManager を使って解説します。

注:LocalBroadcastManager では、マルチプロセスをサポートしていないため、プロセスの異なるコンポーネントへのブロードキャストは上手く動作しない。

// LocalBroadcastManager は Support Package に含まれている
import android.support.v4.content.LocalBroadcastManager;

public class MainActivity extends Activity {
    public static final String TAG = MainActivity.class.getSimpleName();
    public static final String ACTION_HOGEHOGE = "jp.mixi.sample.android.intent.action.HOGEHOGE";
    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.v(TAG, "local broadcast received.");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void onStart() {
        super.onStart();

        // この Activity の Context の中での、Local な Broadcast を管理する為の LocalBroadcastManager オブジェクト
        LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this);
        manager.registerReceiver(mReceiver, new IntentFilter(ACTION_HOGEHOGE));
    }

    @Override
    protected void onStop() {
        LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this);
        manager.unregisterReceiver(mReceiver);

        super.onStop();
    }

    // ボタンなどのクリックハンドラ
    public void onHogeClick(View v) {
        // Local な Broadcast として Intent を投げる
        // 通常の sendBroadcast(Intent) メソッドと違い、この仕組で投げた Intent は他のアプリ(プロセス)では拾うことが出来ない
        LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this);
        manager.sendBroadcast(new Intent(ACTION_HOGEHOGE));
    }
}

Intent に付加情報を追加する

Intentオブジェクトには、受け取り側への付加情報を付与するための仕組みも持っています。

Intent Extras

いくつかのプリミティブ型と、文字列、コレクション、Parcelable オブジェクトを付加情報として付与することができます。
Parcelable オブジェクトについての詳細は別の章で解説しますが、オブジェクトの簡易的なシリアライズの仕組みとして利用します。

// Intent を送信する側の Activity
public class MyActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // do something...

        List<String> list = new ArrayList<String>();
        list.add("fuga");
        list.add("piyo");

        Intent intent = new Intent(this, NewActivity.class);
        intent.putExtra("StringExtraKey", "hogehoge");  // 文字列の場合
        intent.putExtra("BooleanExtraKey", true); // boolean の場合
        intent.putExtra("IntegerExtraKey", 10); // int の場合
        intent.putStringArrayListExtra("StringArrayListExtraKey", list); // ArrayList<String> の場合
        startActivity(intent);
    }
}
// Intent を受け取る側の Activity
public class NewActivity extends Activity {
    @Override
    protected void onCreate(savedInstanceState) {
        super.onCreate(savedInstanceState);
        // do something...

        // この Activity への Intent オブジェクトを取得する
        Intent received = getIntent();
        String stringExtra = received.getStringExtra("StringExtraKey"); // 文字列の Extra を取り出す
        boolean booleanExtra = received.getBooleanExtra("BooleanExtraKey"); // boolean の Extra を取り出す
        int integerExtra = received.getIntExtra("IntegerExtraKey"); // int の Extra を取り出す
        List<String> listExtra = received.getStringArrayListExtra("StringArrayListExtraKey"); // ArrayList<String> の Extra を取り出す
    }
}

Notification

Android のステータスバー(画面上部の、時間や電波状況を表示している領域)に、アプリからのお知らせを表示する仕組みを Notification と言います。

Notification の役割

Notification の表示には、以下に挙げる 2 種類のものがあります。

Normal View

Normal View

Android で最も一般的な Notification の表示です。
左端から順に、6 つの要素から構成されています。

  1. 通知のタイトル
  2. アプリのアイコン
  3. 通知の詳細メッセージ
  4. 通知の情報量
  5. 通知の小さいアイコン
  6. 通知を表示した時間

Big View

Big View

JellyBean 以降の Android で登場した、新しいスタイルの Notification です。
通知ドロワーの 1 番上にくる Notification のための表示スタイルです。

以下に挙げる 7 つの要素から構成されています。

  1. 通知のタイトル
  2. アプリのアイコン
  3. 通知の詳細メッセージ
  4. 通知の情報量
  5. 通知の小さいアイコン
  6. 通知を表示した時間
  7. 詳細表示 View

詳細表示 View には、標準で幾つかのスタイルが決められています。

  • Big Picture Style
  • Big Text Style
  • Inbox Style

Notification の仕組み

通知を表示するための窓口は、NotificationManagerが持っています。
このNotificationManagerに対して、通知そのもののデータを受け持つNotificationオブジェクトを渡すことによって、通知を表示しています。

Notificatonオブジェクトそのものについては、NotificationCompat.Builderクラスがその生成の役割を持っています。
Notificationクラスそのものを用いてNotificationオブジェクトを生成することも可能ですが、一部端末で不具合があることから、非推奨となっています。
通知を表すNotificationオブジェクトは、少なくとも、アプリのアイコン、通知のタイトル、通知の詳細メッセージの 3 つの情報を持っていなくてはなりません。

通知をタップすると、通知を発信したアプリが起動します。
このため、通知でもIntentの仕組みを利用しています。
通知でのIntentの利用方法は、通常の Activity の起動方法とは異なり、すこし特殊な側面を持っています。

PendingIntent

通常、Intentオブジェクトは、Activity の呼び出しや、Service の呼び出し、Broadcast の為に利用されます。
先の項で挙げた方法では、それぞれの呼び出しのタイミングで即座に各コンポーネントが呼び出されます。

一方、通知では、自分たちのアプリケーションではなく、他のアプリケーション(通知の場合は Android のシステム)にIntentの送信を 行わせる ことになります。

このような要求を満たすための仕組みとして、PendingIntentがあります。
この仕組を用いることで、Intentの送信のタイミングを遅延させたり、他のアプリに自分の作ったIntentオブジェクトのハンドリングを任せたりすることができます。
この仕組は、AppWidget でも利用されています。

参考:PendingIntent | Android Developers

public class MyActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // do something...

        // Intent の準備。明示的 Intent でも、暗黙的 Intent でもどちらでも構わない
        Intent intent = new Intent(this, SubActivity.class);

        // PendingIntent オブジェクトの生成。このオブジェクトを他のアプリに渡すことで、引数に渡した Intent の送信を委ねることができる
        // PendingIntent は、Intent の送信先のコンポーネントの種類によって使い分けること
        PendingIntent activityIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    }
}

PendingIntentオブジェクトの作成は、遅延させるIntentオブジェクトのターゲットとしているコンポーネントによって、利用するメソッドが変わります。

PendingIntent#getActivity(Context, int, Intent, int)
Activity がターゲットの`PendingIntent`オブジェクトを作成します。
PendingIntent#getActivities(Context, int, Intent[], int)
Activity がターゲットの`PendingIntent`オブジェクトを作成します。
こちらは、複数の Activity を扱うことが出来るよう、`Intent`オブジェクトを配列で渡すようになっています。
Honeycomb 以降で利用可能です。
PendingIntent#getBroadcast(Context, int, Intent, int)
Broadcast 用の`Intent`を持つ`PendingIntent`オブジェクトを作成します。
PendingIntent#getService(Context, int, Intent, int)
Service がターゲットの`PendingIntent`オブジェクトを作成します。

それぞれどのメソッドも、第 2 引数に、int 型整数を要求しています。
この整数は、PendingIntentを一意に認識するためのものです。どの Context から発せられたPendingIntentか、だけでなく、その中でもどのような種類のPendingIntentか、を示すことができます。
公式の API リファレンスには、Currently not usedと記載されていますが、実際には利用されている点に注意してください。

第 4 引数の int 型整数は、PendingIntentオブジェクトを受け取る側が、それをどのように扱うかを指示するためのものです。
以下の 4 つの定数が定義されており、ビット演算(OR)で複数指定することが可能です。

PendingIntent.FLAG_CANCEL_CURRENT
既にPendingIntentオブジェクトを作成している場合、新しいPendingIntentオブジェクトを生成する前に、古い方をキャンセルします。
PendingIntent.FLAG_NO_CREATE
未だPendingIntentオブジェクトが作成されていない場合、null を返します。つまり、既にPendingIntentオブジェクトが作成されている場合には、そのオブジェクトが返されます。
PendingIntent.FLAG_ONE_SHOT
PendingIntentオブジェクトを利用できるのは、ただ一度だけに制限するものです。
PendingIntent.FLAG_UPDATE_CURRENT
既にPendingIntentオブジェクトを作成している場合、そのオブジェクトが持つ`Intent`オブジェクト自体は置き換えず、`Intent`オブジェクトが持つ`Extras`のみを置き換えます。

NotificationCompat.Builder

通知そのものを表すNotificationオブジェクトを作成するものです。

名前が示す通り、Builder パターンにしたがってNotificationオブジェクトを作成していきます。

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent(this, SubActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

        NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
        Notification notification = builder
                // 通知の日時
                .setWhen(System.currentTimeMillis())
                // 通知のタイトル
                .setContentTitle("通知だヨ!")
                // 通知の詳細メッセージ
                .setContentText("通知の詳しい内容をここに書きます。")
                // 通知のアイコン
                .setSmallIcon(R.drawable.ic_launcher)
                // 通知を表示した瞬間、通知バーに表示するショートメッセージ
                .setTicker("通知だヨ!")
                // 通知をタップした時に使う PendingIntent
                .setContentIntent(pendingIntent)
                // この通知が未だ表示されていない時だけ、音やバイブレーション、ショートメッセージの表示を行う
                .setOnlyAlertOnce(true)
                // タップしたら消えるようにする
                .setAutoCancel(true)
                .build();
    }
}

Notificationオブジェクトの作成ができたら、NotificationManagerを利用して、通知を表示します。

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Notification notification = /* 通知オブジェクトの作成(省略) */

        // 直接インスタンス化せず、Context を経由してインスタンスを取得する
        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        // 通知の種類に応じて id を割当てることが出来る。
        // id の異なる通知は違うものとして扱われる。
        manager.notify(0, notification);
    }
}

実習

この実習では 1-4-MessagingAndNotificationPracticeを使用します。
プロジェクトの開き方は課題プロジェクトの開き方を参照してください。

Intent

  1. 画面に複数のボタンが配置されています。各ボタンのクリックイベントを拾う処理の中で、コメントに記述された Activity を呼び出すコードを書いてください。(使用するActivity:jp.mixi.practice.messagingandnotification.IntentActivity1.java)
  2. 画面に複数のボタンが配置されています。各ボタンのクリックイベントを拾う処理の中で、コメントに記述された Action を実行させるコードを書き、そのIntentオブジェクトを受け取るためのBroadcastReceiverを作成し、AndroidManifest に記述してください。(使用するActivity:jp.mixi.practice.messagingandnotification.IntentActivity2.java)

Notification

  1. アイコン、タイトル、詳細メッセージを含む通知を表示してください。(使用するActivity: jp.mixi.practice.messagingandnotification.NotificationActivity.java
  2. アイコン、タイトル、詳細メッセージを含む通知を表示し、通知をタップしたら MainActivity ではない新しい Activity を立ち上げるようにしてください

課題

この課題では 1-4-MessagingAndNotificationAssignmentsを使用します。

Intent

  1. 画面にボタンが 1 つ配置されています。このボタンのクリックイベントを拾う処理の中で、ブラウザを立ち上げ、指定した URL を読み込むためのIntentオブジェクトを作成し、ブラウザを立ち上げるところまでを実装してください。(使用するActivity: jp.mixi.assignment.messagingandnotification.IntentActivity1.java
  2. 画面にボタンが 1 つ配置されています。このボタンのクリックイベントを拾う処理の中で、EditText を 1 つと、ボタンを 1 つ配置した新しい Activity を立ち上げ、EditText の入力内容を結果として返し、返された結果を Toast で表示するようにしてください。(使用するActivity: jp.mixi.assignment.messagingandnotification.IntentActivity2.java

Notification

  1. アイコン、タイトル、詳細メッセージを含む通知を表示してください。通知を表示するときに、バイブレーションを作動させるようにしてください。(使用するActivity: jp.mixi.assignment.messagingandnotification.NotificationActivity1.java
  2. アイコン、タイトル、詳細メッセージと、通知を表示した時に展開するティッカーテキストを含む通知を表示してください( Activity は課題 1 と同じもので良い)。
  3. アイコン、タイトル、詳細メッセージを含む通知を表示してください。通知をタップしたら、指定した ACTION を受け取ることが出来る Activity を実行するようにしてください。(使用するActivity: jp.mixi.assignment.messagingandnotification.NotificationActivity2.java
    • 通知をタップすると、このような画面が表示されます。
    • この画面では、どちらがどの画面に対応しているのかが分からないので、AndroidManifest を編集して分かりやすい表示にしてください