minimize

事業拡大のため、新しい仲間を募集しています。
→詳しくはこちら

Intent について詳しく説明します。

Activity, Service, Broadcast Receiver の3つのコンポーネントは
Intent と呼ばれるメッセージによってアクティブ化されます。

Intent によって同一、または異なるアプリケーションのコンポーネント同士を
動的に結びつけることが容易になります。
Intent はフィルタを持ち、これによって応答するコンポーネントを
動的に決定することが可能になります。

各コンポーネントへの Intent 配信メカニズムは、それぞれ独立しています。

Activity

Context.startActivity() または Activity.startActivityForResult() によって
Activity を起動、または既に存在する Activity を得ることができます。
※ 後者の方法の場合、Activity.setResult() によって結果を渡すことができます

Service

Context.startService() によってサービスを初期化、または
既に起動しているサービスに対して新たな指示を送ることができます。

Context.bindService() によって、呼び出し側とサービス間の接続を確保することができます。
この場合、もしサービスが起動していない場合は自動的に起動します。

Broadcast Receiver

Context.sendBroadcast() などの呼び出しによって、レシーバにメッセージを送信できます。

まとめ

どのケースにおいても、Android システムは送信した Intent に対応する Activity, Service または
Broadcast Receiver のセットを探し、Intent に応答させます。
必要ならばこのとき、各コンポーネントが初期化されます。

これらは重複することがありません。
つまり、Broadcast に向けた Intent は Broadcast Receiver にのみ届き、Activity や Service には決して届きません。
簡単に言えば、呼び出すメソッドによって、その Intent が到達するコンポーネントの種類が
決定するということです。
startActivity() によって送信された Intent は、Service や Receiver に到達することはあり得ません。

Intent はその対象となるコンポーネントの名前を(ほとんどの場合)明示しません。
Intent Filter というフィルタを用いて、Intent の対象となるコンポーネントが決定する仕組みになっています。

Intent オブジェクト

Intent オブジェクトは、様々な情報をまとめて持っています。
以下、これらの情報を「属性」と呼びます。※ 公式な呼び名ではありません

コンポーネント名

ComponentName フィールドに格納されます。
これを指定することによって、応答させるコンポーネントを明示的に指定することができます。

ここには、コンポーネントのクラスを完全限定名(fully qualified name)で指定します。
例えば、"com.example.project.app.FreneticActivity" のように指定します。
また、Manifest File の Application に指定した基準パッケージからの相対で指定することもできます。
例えば Application の基準パッケージが "com.example.project" だった場合、".app.FreneticActivity" と書けます。

この属性を指定した場合、応答コンポーネントは一意に決まります。
よって、それ以外の属性で指定された値は無視されることになります。

この属性を指定しない場合は、後述する属性で指定された各種のフィルタによって
応答コンポーネントが決まることになります。

Action

実行するアクション名を指定します。

Intent クラスは、予めいくつかのアクション名を定数で持っています。

定数名 対象コンポーネント アクションの意味
ACTION_CALL Activity 電話をコールします。
ACTION_EDIT Activity データ編集画面を表示します。
ACTION_VIEW Activity 指定したデータ(URL)をブラウジングします。
ACTION_MAIN Activity 初期 Activity を起動します。このときデータの入出力は行えません。
ACTION_SYNC Activity 携帯端末のデータとサーバのデータを同期化します。
ACTION_BATTERY_LOW Broadcast Receiver バッテリーが少なくなったときに警告します。
ACTION_HEADSET_PLUG Broadcast Receiver ヘッドセットの取り付け・取り外し時に知らせます。
ACTION_SCREEN_ON Broadcast Receiver 画面表示がOFF->ONになったときに知らせます。
ACTION_TIMEZONE_CHANGED Broadcast Receiver タイムゾーンの設定を変更したときに知らせます。

他にも様々な(50を超える)アクションが定義されています。詳しくは、Intent クラスの Javadoc を読んで下さい。
もちろん、自分自身でアクションを定義することもできます。
その場合、"com.example.project.SHOW_COLOR" のようにパッケージ名をPrefixに使って下さい。

Action は、応答コンポーネントを大まかに絞るために利用されます。

Data

処理したいデータのURIを指定します。

例えば Action = ACTION_EDIT だったら、編集したいデータのURIを指定します。
Action = ACTION_CALL だったら、tel: で始まるURIによって電話番号を指定します。
Action = ACTION_VIEW だったら、http: で始まるURIによってブラウズしたいURLを指定します。

また、Data Type も指定することができます。
これには setType() によって、データの MIME Type を指定します。

Category

応答するコンポーネントの種類を指定します。
多くの場合、Action と Category の組み合わせによって応答コンポーネントが大体決まります。

定数名 カテゴリの意味
CATEGORY_BROWSABLE 対象 Activity が安全にデータをブラウジングできることを指示します。例えば、画像データはこのカテゴリに当てはまりますが、バイナリデータでは当てはまりません。
CATEGORY_GADGET 他のホストで作成された Activity の中に組み込める Activity であることを指示します。
CATEGORY_HOME ホーム画面に表示される Activity であることを指示します。
CATEGORY_LAUNCHER この Activity が Task の初期 Activity であり、トップレベルのアプリケーションランチャに表示されることを指示します。
CATEGORY_PREFERENCE この Activity が Preference Panel であることを指示します。

他にもたくさんのカテゴリが定義されています。詳しくは、Intent クラスの Javadoc を読んで下さい。

Extras

Key - Value 形式の追加情報を指定します。

これはフィルタではなく、コンポーネントを起動するときの情報を指定したものです。
例えば、ACTION_TIMEZONE_CHANGED を処理する Intent だったら、"time-zone" という名前の Extra を持っているはずです。

Flags

様々なフラグを指定します。

これもフィルタではなく、コンポーネントを起動するときの挙動を指定したものです。
例えば、あるコンポーネントを別の Task で動かしたい場合などに、それ用の Flag を立てたりします。

Intent によるコンポーネントの決定方法

Intent は大きく二種類に分けられます。

Explicit intents

明示的にコンポーネント名を指定した Intent です。
ほとんどの場合、これはアプリケーションの内部メッセージとして使われます。

Implicit intents

コンポーネント名を指定しない Intent です。
これは、他のアプリケーションのコンポーネントをアクティブ化するときに使われます。

以下の属性によって、Intent に応答するコンポーネントが決定されます。

Extras と Flags は、コンポーネント決定のロジックには利用されません。

Intent Filter

コンポーネントには、Intent Filter を付けることができます。
これによって、そのコンポーネントが応答すべき Intent を特定させることができます。

例えば、NotePad 用の NoteEditor という Activity は、二つのフィルタを持っています。
NoteEditor の定義は、以下のようになっています。

<activity android:name="NoteEditor"
          android:theme="@android:style/Theme.Light"
          android:label="@string/title_note" >
    <intent-filter android:label="@string/resolve_edit">
        <action android:name="android.intent.action.VIEW" />
        <action android:name="android.intent.action.EDIT" />
        <action android:name="com.android.notepad.action.EDIT_NOTE" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.INSERT" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />
    </intent-filter>
</activity>

一つ目は、既存のファイルを編集するために自身を起動させるためのフィルタです。
もう一つは、新しくファイルを編集するために自身を起動させるためのフィルタです。

Intent Filter は通常このように Manifest File 上で設定します。
例外として、Context.registerReceiver() の呼び出しによって動的に登録する Broadcast Receiver については
IntentFilter クラスを使ってJavaコード内で Intent Filter を設定することもあります。

以下、<intent-filter> の各要素について説明をします。

Action

Intent Filter は、必ず一つ以上の Action を指定する必要があります。
※ もし指定しない場合、このコンポーネントはいかなる Intent にも応答できません

ここで指定した Action を持つ Intent にのみ、このコンポーネントは応答できます。

Category

ここで指定した Category を持つ Intent にのみ、このコンポーネントは応答できます。

ただし、Action と異なり、この要素は省略可能です。
この場合、このコンポーネントはいかなる Category にも応答できることを意味します。

しかしこれにも一つ例外があります。
startActivity() によって Activity を起動するときには
その Activity には必ず "android.intent.category.DEFAULT" の Category を定義しておく必要があります。
言い換えれば、"android.intent.category.DEFAULT" が定義されていない Activity は起動することができません。

そして最後に、もう一つの例外があります。
それは、"android.intent.category.MAIN" と "android.intent.category.LAUNCHER" の両方の
Category を持つ Activity についてです。

<intent-filter . . . >
    <action android:name="code android.intent.action.MAIN" />
    <category android:name="code android.intent.category.LAUNCHER" />
</intent-filter>

この Activity は startActivity() による起動はできませんが、アプリケーションランチャからは起動させることが可能になります。

Data

Data フィルタには、scheme / host / port / path / mimeType の5属性を指定することができます。

scheme://host:port/path という URI を考えます。

<data android:mimeType="video/mpeg" android:scheme="http" . . . />
<data android:scheme="http" android:host="www.limy.org" . . . />
<data android:port="80" . . . />
<data android:pathPattern="android/*" . . . />

上から順に説明します。
一つ目のフィルタは、"http://" で始まるデータで、かつ MimeType が "video/mpeg" のデータのみに応答します。
次は、"http://www.limy.org/" で始まるデータのみに応答します。
次は、80番ポート(:80)のデータのみに応答します。
最後は、path (ホスト名以降)が "android/" で始まるデータのみに応答します。

path の指定には、android:path / android:pathPrefix / android:pathPattern が使えます。
最後の方式だけ、ワイルドカードを使うことができます。
他に、android:mimeType にもワイルドカードが使用できます。

まとめ

以上の方法によって、Android は Intent に対応するコンポーネントを決定します。
もし複数のコンポーネントが応答可能な場合、どちらを応答させるか Android がユーザに問い合わせます。
一つのコンポーネントも応答不可能な場合は、例外を発生させて発生してユーザに知らせます。

具体的な Intent 作成方法

Intent のコンストラクタにはいくつか種類があるので、紹介します。

Explicit intents

明示的にコンポーネント名を指定する Intent です。

new Intent(context, ComponentClass.class);

context は、どのコンポーネントも持つ基本インスタンスです。
Context.getApplicationContext() によって取得可能です。

Implicit intents

明示的にコンポーネントを指定しないパターンです。
いくつか方法があります。

他の属性については、Intent クラスのメソッドを呼び出して設定します。