Intent
https://developer.android.com/guide/components/intents-common?hl=ja
https://developer.android.com/guide/components/intents-filters.html?hl=ja#Receiving
Intentは、別のアプリコンポーネントから、アクションをリクエストする時に使用する、メッセージングオブジェクト。
Intentには、開始するコンポーネントを明示する方法と、どのコンポーネントを開始するかをAndroidシステムに委ねる方法がある。前者を明示的Intent、後者を暗黙的Intentと呼ぶ。開始するコンポーネントをAndroidシステムに委ねる方法では、Androidシステムがコンポーネントを検索できるように、検索されるコンポーネントを持つアプリのマニフェストに、検索されるように情報(<intent-filter>)を記述する。
暗黙的Intentオブジェクトに、簡単なアクションと必要なデータを設定することで、別のアプリでアクションを実行するアビリティを開始できる。実行するコンポーネントは指定する必要がない。
startActivity()やstartActivityResult()を呼び出して、暗黙的Intentを渡すと、システムは、Intentフィルターを通じて、そのIntentを使うに適したアプリを判定して起動する。Intentを使うアプリが複数あったときには、ユーザーがアプリを選択できるようにダイアログを表示する。
以下では、Intentを扱えるアプリの種類別に、一般的なアクションを実行する暗黙的Intentについて説明。
COUTION 端末に、暗黙的Intentを使えるアプリがない場合、startActivity()を使うとアプリがクラッシュする。クラッシュを回避するため、Intentを受け取れるアプリの存在を確認するresolveActibity()メソッド(Intentオブジェクトのメソッド)を呼び出して確認する。結果がnull以外ならIntentを受け取れるアプリが存在し、startActivity()を安全に呼び出せます。結果がnullの時には、そのIntentはクラッシュの原因となるので、そのIntentは使わない。 |
IntentとIntentFilter
https://developer.android.com/guide/components/intents-filters.html?hl=ja
Intentはコンポーネント間のコミュニケーションを円滑化します。基本的な使用例は以下の3つ。
Intentの使用例
-
アクティビティの開始
Activityの新しいインスタンスを開始(新しい画面を生成)するには、IntentをstartActivity()に渡す。Intentには開始するアクティビティが記述され、必要なデータをセットする。
アクティビティの完了時に結果を受け取る場合には、startActivityForResult()を使う。アクティビティは、onActivityResult()callbackを使って、結果をIntentオブジェクトとして受け取る。 -
サービスの開始
ServiceはUIのないバックグラウンド操作のためのコンポーネント。Android5.0(API21)以降では、JobSchedulerでサービスを開始できる。Android5.0以前では、Serviceクラスのメソッドでサービスを開始する。ファイルダウンロードのような1回限りの操作なら、IntentをstartService()に渡せばOK。Intentには開始するサービスとデータをセットする。
サービスに、クライアントサーバーのインターフェイスを設定してる場合、IntentをbindService()に渡して、他のコンポーネントのサービスにバインドできる。 -
ブロードキャスト配信
ブロードキャストは、どんなアプリでも受信できるメッセージ。システムは端末の起動、充電開始など、さまざまなシステムイベントに関するブロードキャストを配信する。他のアプリにブロードキャスト配信するには、IntentをsendBroadcast()、もしくはsendOrderedBroadcast()に渡す。
Intentのタイプ | 明示的Intent 暗黙的Intent
-
明示的Intent
ターゲットアプリのパッケージ名またはコンポーネントの完全装飾クラス名を指定して、Intentを実行するアプリを指定する。多くのケースでは、開発者が開始したいアクティビティやサービスのクラス名を知っているので、明示的Intentを利用している。 -
暗黙的Intent
特定のコンポーネントは指名しない。Intentに処理をと必要データをセットすることで、別のアプリのコンポーネントで実行できるようにする。
例えば、ユーザーに対して、地図上のある場所を示したい場合、別のアプリによって指定された場所を地図上に表示させるように、Intentを使ってリクエストする。
アクティビティを処理するコンポーネントを、Androidシステムに委ねる場合には、暗黙的Intentを使い、コンポーネントが特定してる場合(システムに委ねない)には明示的Intentを使う。
<Intentの働き:イメージ>
1. Activity(A)が、アクションを記述したIntentを作成し、startActivity()に渡す(startActivity(intent)) 2. Androidシステムが全アプリを検索し、Intentに一致するIntentフィルタを検索 3. 一致するIntentフィルタが見つかると、システムはそのアプリのonCreate()メソッドを呼び出して、Intentを渡す 4. 検索されたアプリはIntentに一致するActivity(B)を開始する |
暗黙的Intentを使うと、AndroidシステムはIntentの内容を、他のアプリのマニフェストファイルで定義されたIntentフィルタと比較する。IntentがIntentフィルタに一致すると、Androidシステムはそのコンポーネントを開始してIntentオブジェクトを配信する。一致するアプリが複数あった場合には、ダイアログでユーザーに選択させる。Intentフィルタでは、アプリのマニフェストファイルで、コンポーネントが受け取りたいインテントのタイプを指定する。
例えば、アクティビティのインテントフィルタを宣言すると、特定の種類のIntentを使って、他のアプリから直接アクティビティを開始できる。アクティビティのIntentフィルタを宣言しなければ、明示的Intentでなければアクティビティを開始できない。
COUTION Serviceを使って開始するときは、明示的Intentを使う。サービスのIntentフィルタは使わない。Serviceで暗黙的Intentを使うと、そのサービスがIntentに応答するか把握できなくなり、ユーザーが開始サービスを認識できず、セキュリティに危険が生じます。Android5.0以降では暗黙的IntentでbindService()を使うと、システムが例外を投げます。 |
Intentをビルド
Intentオブジェクトには、Androidシステムが開始するコンポーネントを検索するのに必要な情報と、コンポーネントがアクションを実行するに必要な情報(以下)を設定する。
- コンポーネント名
- アクション
- データ
- カテゴリ
- エクストラ
- フラグ
Intent intent = new Intent(this,MainActivity.class);
intent.setComponent() // setClass(),setClassName(),Intent Constructor
intent.setAction() // Intent Constructor
intent.setData() // setType setDataAndType
intent.CATEFORY_BROWSABLE // CATEGORY_LAUNCHER
intent.putExtar()
intent.setFlags()
// Android Developer intent : public constructors の (Context packageContext, Class<?> cls)参照
// 指定されたコンポーネント(Class<?>)にIntentを生成する
// Contextは、AndroidSystem <-> app :Enviroment Infomationを受け渡す
■ コンポーネント名(ComponentNameオブジェクト)
-
開始するコンポーネント名
明示的インテントでは必須。またServiceを開始する時にも明示的Intentを使ってセキュリティの安全性を確保する。- ComponentNameオブジェクトは、ターゲットコンポーネントの完全装飾クラス名を使って指定できる(例:com.example.ExampleActivity)。指定は以下のメソッド等で。
- setComponent()
- setClass()
- setClassName()
- Intentコンストラクタ
- ComponentNameオブジェクトは、ターゲットコンポーネントの完全装飾クラス名を使って指定できる(例:com.example.ExampleActivity)。指定は以下のメソッド等で。
■ アクション
実行した一般的なアクション(表示や選択)を指定する文字列。
-
ブロードキャストIntentの場合、この文字列は発生済みで報告済みのアクションとなる。アクションの種類(表示や選択)によって、データやエクストラに含まれる情報など、他のIntentを構成する情報は決まっている。
-
自分のアプリ内で、開始するアクションをIntentで指定したり、他のアプリから自分のアプリのコンポーネントを呼び出すためにIntentで指定されたりするが、通常はIntentクラスや他のフレームワーククラスで定義されたアクション定数を指定する。
-
<アクティビティを開始する一般的なアクション定数>
-
ACTION_VIEW
アプリで表示する写真や、マップアプリで表示する住所など、アクティビティがユーザーに表示する情報がある場合に、インテントにACTION_VIEW定数を使い、startActivity()に渡す。
-
ACTION_SEND
ACTION_SENDは共有Intent。メールアプリやソーシャルシェアリングアプリなどの別のアプリと共有できるデータがある場合に、IntentにACTION_SEND定数を使い、startActivity()に渡す。
-
ACTION_VIEW
-
<アクティビティを開始する一般的なアクション定数>
その他のアクションを定義する定数は>https://developer.android.com/reference/android/content/Intent.html?hl=ja(Contents参照)
他のアクションはAndroidフレームワークの別の場所で定義している。例えば、システムの設定アプリの特定の画面を開くアクションは、Settingsで定義する。
Intentのアクションは、setAction()かIntentコンストラクタを使って指定する。
下記は独自のアクション(TIMETRAVEL)を定義したら接頭辞としてアプリのパッケージ名を指定(ACTION_TIMETRAVEL="com.example.action.TIMETRAVEL"
)している。
static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
■ データ
アクションの実行に必要なデータや、データのMINEタイプを参照するURI(Uriオブジェクト)。指定されるデータのタイプはIntentのアクションによって決まる。アクションがACTION_EDITの場合なら、データには編集するドキュメントURIが設定される。
Intent生成時、URIだけでなく、データタイプ(MIME)を指定することも重要なことがある。画像表示のアクティビティでは音楽再生はできない。データのMIMEタイプを指定して、AndroidシステムがIntentに適したコンポーネントを検索できるようにする。
ただし、URIからMIMEを推定できることがある。データがcontentの時は、URIは端末上にあり、ContentProviderによって制御されているので、AndroidシステムはURIからMIMEタイプを判定できる。
<データ・MINEタイプの設定>
- データURIのみを設定 :setData()
- MIMEタイプのみを設定:setType()
- 両方を設定 :setDataAndType()を使う。
COUTION URIとMIMEタイプの両方を設定する場合には、setData()とsetType()は使わない(互いの値を無効にする恐れがある)。両方を設定する場合は、必ず setDataAndType()を使う |
■ カテゴリ
Intentを処理するコンポーネントの種類に関する追加情報を設定する文字列。ほとんどのIntentでカテゴリは不要。カテゴリの記述はIntentに好きなだけ設定できる。良く使われるカテゴリの例は以下。
-
CATEFORY_BROWSABLE
ターゲットアクティビティによって、ブラウザが画像やメールメッセージなどのデータを表示する。 -
CATEGORY_LAUNCHER
タスクの初期アクティビティで、システムのアプリケーションランチャーの一覧に、当該アクティビティーを表示させる。
■ エクストラ
コンポーネント名、アクション、データ、カテゴリによって、Androidシステムは適切なアプリコンポーネントを検索します。この検索に影響を与えない追加情報は、Intentのエクストラに記述します。
リクエストアクションの実行に必要な情報を、キー/値のペアで設定する。アクションは、特定の種類のデータURIを使ったり、特定のエクストラを使ったりする。
エクストラデータはputExtra()メソッドで、キーと値のパラメータを追加する。Bundleは全てのエクストラデータを設定でき、putExtras()を使って、BundleをIntentに設定できる。
例えば、ACTION_SENDを使ってメール送信するIntentを作成するとき、EXTRA_EMAILキーを使って宛先の受信者を指定したり、EXTRA_SUBJECTキーを使って件名を指定できる。
Intentクラスは、標準化されたデータタイプのEXTRA_*定数を複数指定できる。あなたのアプリが受け取るIntent用に、独自のエクストラキーを宣言する場合は、アプリのパッケージ名を接頭辞として指定する(下記)。
static final String EXTRA_GIGAWATTS = "com.example.EXTRA_FIFAWATTS";
COUTION: 他のアプリが受信するIntentを送信する場合、ParcelableやSerializableは使用しない。アプリがBundleオブジェクトデータにアクセスしようとして、パーセル化クラスやシリアル化クラスにアクセスできないと、システムはRuntimeExceptionを投げる。 |
■ フラグ
フラグなIntentクラスで定義する。フラグはIntentのメタデータ(ファイルやフォルダなど、データそのものを示す情報(名前、日付、拡張子etc))として機能する。フラグはAndroidシステムにアクティビティの起動方法(アクティビティがどのタスクに属するか等)や、起動後の取り扱い方法(最近のアクティビティ一覧にふくめるか等)を指定する。
□ setFlags
-
フラグでIntentの取り扱いを設定する。設定値はIntentによって実行されるコンポーネントのタイプに従います。FLAG_ACTIVITY_*フラグは、ConText#startActivity、FLAG_RECEIVER_*フラグは**Context#sendBroadcast(Intent)**で使う。(例えば、FLAG_ACTIVITY_NO_HISTORYをセットすると、新しいアクティビティはスタック履歴に残らなくなる)
-
setFlags()詳細は>https://developer.android.com/reference/android/content/Intent.html?hl=ja#setFlags(int)
明示的Intent、暗黙的Intentの例
明示的Intentの例
特手のアプリコンポーネントを起動する際は、明示的Intentを使う。明示的Intentの作成は、Intentオブジェクトでコンポーネント名を定義する。他のIntentプロパティは省略可能。
<例:ウェブからファイルをダウンロードする`DownloadService`を開始する>
// あるアクティビティで実行すると仮定。'this'はコンテキストとする。
// fileUrlは文字列のURL。("http:://www.example.com/image.png")
Intent downloadIntent = new Intent(this,DownloadService.class);
downloadIntent.setData(Uri.parse(fileUrl));
startService(downloadIntent);
Intent(Context,Class)コンストラクタが、アプリにContextを、コンポーネントにClassオブジェクトを提供する。このようにして、このIntentはアプリにDownloadServiceクラスを明示的に開始する。
暗黙的Intentの例
暗黙的Intentは、アクションを指定し、それを実行できる端末上のアプリを起動する。自分のアプリではそのアクションを実行しないが、他のアプリで実行可能であり、そのアプリを使うかをユーザーに選ばせたい場合に、暗黙的Intentは適している。
たとえば、ユーザーに他の人と共有してほしいコンテンツがある場合は、ACTION_SENDアクションを使ってIntentを作成し、共有するコンテンツを指定するエクストラを追加する。そのIntentを使ってstartActivity()を呼び出すと、ユーザーはどのアプリでコンテンツを共有するかを選択できる。
COUTION: startActivity()に送る暗黙的Intentを処理できるアプリがない場合や、ファイル上の制限や設定でアクセス不可になっている場合がある。この場合、アプリはクラッシュする。クラッシュを回避するため、IntentオブジェクトでresolveActivity()を使い、結果がnull以外であればIntentを使うアクティビティが存在する。nullの場合にはIntentを発行する処理を無効化しクラッシュを避ける。以下のコードは例。この例ではURIを使わず、Intentのデータタイプを宣言することで、エクストラの内容を指定している。 |
// 文字列でテキストメッセージを生成する
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT,textMessage);
sendIntent.setType("text/plain");
// Intentを使うアクティビティがあるか確認する
if(sendIntent.resolbeActivity(getPackageManager()) !=null){
startActivity(sendIntent);
}
startActivity()が呼び出されると、システムはすべてのインストール済みアプリを調べ、どのアプリがこの種類のIntentが処理できるか判定する。Intentはに、ACTION_SENDアクションと"text/plain"データが設定されてる必要がある。このようなアクティビティが複数の場合には、ダイアログにて起動するアクティビティをユーザーに選択させる(チューザーダイアログ)。
アプリチューザーの表示
暗黙的Intentに応答するアプリが複数のときに、ユーザーはアプリを選択し、そのアプリをアクションのデフォルト選択肢にする。デフォルト選択肢を設定は、ユーザーが毎回同じアプリを選択する場合に便利です。
ただし、Intentに応答するアプリが複数で、ユーザーが毎回別のアプリを使用する可能性がある場合、チューザーダイアログを明示的に表示させる(アクションのデフォルトのアプリは選択できない)。
アプリがACTION_SENDアクションで「共有」を実行すると、ユーザーは、その時の状況によっては別のアプリをつかって共有したいと思うかもしれない。以下のようなチューザーダイアログを常に使用する。
チューザーの表示コード
createChooser()を使いIntentを作成し、startActivity()に渡す。以下のコードではcreateChooser()メソッドに渡されたIntentに応答するアプリのリストをダイアログに表示する。ダイアログのタイトルには、指定されたテキストを使う。
Intent sendIntent = new Intent(Intent.ACTION_SEND);
...
// "この●●アプリを使う"という感じで
// UIテキストには文字列リソースを使う
String title = getResources().getString(R.string.chooser_title);
// チューザーダイアログを表示するIntentを生成する
Intent chooser = Intent.createChooser(sendIntent,title);
// 暗黙的Intentは応答するアクションの存在が必須
// 応答するアクションが存在するか確認する
if(sendIntent.sesolveActivity(getPackageManager())!=null){
startActivity(chooser);
}
暗黙的Intentを受け取る
アプリが受け取れる暗黙的Intentを告知するには、マニフェストファイルで要素を使って、それぞれのアプリコンポーネントに対して1以上のIntentフィルターを宣言する。各Intentフィルターは、Intentのアクション、データ、カテゴリによって、受け入れるIntentのタイプを指定する。Intentが何れかのIntentフィルタを通過した場合のみ、システムが暗黙的Intentを、そのアプリコンポーネントに配信する。
明示的Intentは、コンポーネントが宣言するIntentフィルタに関係なく、常にターゲットコンポーネントに配信される
|
アプリコンポーネントは、実行する固有のジョブに対して、それぞれ個別にフィルタ宣言する。例えば、画像ギャラリーのアプリの1つのアクティビティには、画像を表示するフィルタと編集するフィルタの2つがある場合、このアクティビティを開始すると、Intentにある情報に戻づいて、画像表示か、編集か、どちらのアクションを選択するかを決定する。
各Intentフィルタは、アプリのマニフェストファイルの要素で定義されていて、対応するアプリコンポーネント(要素など)にネストする。内で、次の3要素の中から1つ以上を使い、受け入れるIntentタイプを指定する。
-
<action>
name属性で、受け入れるIntentのアクションを宣言。値はアクションのリテラル文字列とする("この●●アクションを使う")。 -
<data>
データURI(scheme / host / port / path)と色々なMIMEタイプの1つ以上の属性を使って、受け入れるデータタイプを宣言する。 -
<category>
name属性で、受け入れるIntentカテゴリを宣言する。値は、アクションのリテラル文字列とする。暗黙的Intentを受け取るには、IntentフィルタにCATEGORY_DEFAULTカテゴリを含める。
startActivity()メソッドと、startActivityForResult()メソッドは、CATEGORY_DEFAULTカテゴリを宣言してるものとして、すべてのIntentを処理する。IntentフィルタでCATEGORY_DEFAULTカテゴリを宣言していない場合は、暗黙的Intentに応答するアクティビティがないと判定します
データタイプがテキストの場合に、ACTION_SEND Intentを受け取るIntentフィルタの、アクティビティ宣言を、下記に例示する。
<activity ancroid:name="ShareActivity">
<intent-filter>
<action ancroid:name = "android.intent.action.SEND"/>
<category android:name = "android.intent.category.DEFAULT"/>
<data android:mimeType = "text/plain"/>
</intent-filter>
</activity>
<action> <data> <category>のうち、2つ以上を含むフィルタを作成できる。その時は、コンポーネントがそれらのフィルタ要素のいかなる組み合わせも処理できることを確認しておく必要がある。
複数の種類のIntentに対応し、かつaction data catetoryのタイプの特定の組み合わせのみを処理したい場合、複数のIntentフィルタを作成する必要がある。
暗黙的Intentは、これらの3つの各要素とIntentを、フィルタに照らして適合判定される。Intentが3要素の全ての適合判定をパスすると、Intentをコンポーネントに配信する。1つでも一致しないと、AndroidシステムはIntentを配信しない。ただし、1つのコンポーネントに複数のIntentフィルタを設定してる場合、どれかのフィルタをパスすることがある。
COUTION:Intentフィルタによって、他のアプリが自分のアプリのコンポーネントを使えないようにするのは危険が生じる。Intentフィルタは特定の種類の暗黙的Intentにのみ応答するようコンポーネントを制限するが、別のアプリが自分のアプリのコンポーネントを指定して明示的Intentを使う場合には、コンポーネントが開始できてしまう可能性がある。別のアプリから使えないようにするには、マニフェストのIntentフィルタを使うのではなく、コンポーネントのexported属性を"false"に設定する。 他のアプリのServiceを誤って実行しないように、自分のサービスは常に明示的Intentを使って開始する。 |
全てのアクティビティで、マニフェストファイルでIntentフィルタを宣言する。ただし、ブロードキャストレシーバのフィルタは、registerReceiver()を呼び出すことで、動的に登録できる。その後、レシーバーの登録を解除するには、unregisterReceiver()を使う。これによって、アプリが実行中の特定の期間だけ、アプリが特定のブロードキャストをリッスンできる。 |
フィルタの例
ソーシャル・シェアリング・アプリのマニフェストファイルを例に、Intentフィルタの動作を説明する。
<activity android:name="MainActivity">
<!-- ランチャーからアプリを開始するメインアクティビティ-->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="ShareActivity">
<!-- テキストデータを送信する処理を扱うアクティビティ-->
<intent-filter>
<action android:name ="android.intent.action.SEND"/>
<category android:name ="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
<!-- メディアデータを送信するアクティビティ-->
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<action android:name="android.intent.action.SEND_MULTIPLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/vnd.google.panorama360+jpg"/>
<data android:mimeType="image/*"/>
<data android:mimeType="video/*"/>
</intent-filter>
</activity>
一つめのIntentフィルタはメインアクティビティで、ユーザーがランチャーアイコンから初めてアプリを起動したときに開くアクティビティ。
-
ACTION_MAINアクション
メインのエントリポイントで、Intentデータはないことを示してる。 -
CATEGORY_LAUNCHERカテゴリ
このアクティビティのアイコンをシステムのアプリランチャーに配置するべきことを示している。- <activity>要素がiconでアイコンを指定してない場合、システムは<application>要素のアイコンを使う。
このアクティビティをアプリランチャーに表示するには、この2つをペア設定する。
2つ目のアクティビティのShareActivity
は、テキストやメディアコンテンツの共有を円滑化する。ユーザーはMainActivity
から移動することで、このアクティビティに入ることもあるが、2つのIntentフィルタ(テキストデータのIntentフィルタか、メディアデータのIntentフィルタ)のいずれかに一致する暗黙的Intentを発行する別のアプリから、直接ShareActivity
に入ることも可能。
application/vnd.google.panorama360+jpgのMIMEタイプは、パノラマ写真を指定する特別なデータタイプで、GoogleパノラマAPIで処理する。 |
PendingIntentを使う
PendingIntentオブジェクトはIntentオブジェクトのラッパー。主な目的は、開発するアプリのプロセスから実行されたかのように、包含しているIntentを使う許可を、別のアプリに付与すること。
PendingIntentの主な使用例
Pendingは保留という意味。すぐさま使うのではなく、ある時にIntentを使うという感じ。
-
通知を使って、ユーザーがアクションを実行するときに使うIntentを宣言する(AndroidシステムのNotificationManagerがIntentを実行する)。
-
アプリのウィジェットを使い、ユーザーがアクションを実行するときに使うIntentを宣言する(ホーム画面のアプリがIntentを実行する)。
-
将来の指定した時間に実行するアクションのIntentを宣言する(AndroidシステムのAlarmManagerがIntentを実行する)。
各Intentオブジェクトは、アプリの特定のタイプのコンポーネントで処理されることを前提とするため、PendingIntentも同様の前提で作成する。PendingIntentを使うとstartActivity()などの呼び出しで、開発するアプリがIntentを実行することはない。代わりに、以下の生成メソッドを呼び出して、PendingIntentの作成時に目的のコンポーネントタイプを宣言する。
-
Activityを開始するIntent
PendingInten.getActivity() -
Serviceを開始するIntent
PendingIntent.getService() -
BroadcastReceiverを開始するIntent
PendingIntent.getBroadcast()
開発するアプリが他のアプリからPendingIntentを受け取る場合を除き、PendingIntentの作成時に必要となるPendingIntentメソッドは、ほぼ上記の3つとなる(getActivities(Context,int,Intent[],int)もある)。
各メソッドが現在のアプリのContext、ラップしたいIntent、Intentの使用方法を指定する1つ以上のflag(Intentを複数回使えるかどうか)を受け取る。
PendingIntent developers
PendingIntentによって実行されるIntentとアクションの説明。
PendingIntentクラスのインスタンスは、以下のメソッドで生成する。
引数の説明
getActivity(PendingIntenで開始するActivity,PendingIntent送信元のプライベートコード,実行するインテント,Flag)
生成したPendingIntentインスタンスは、他のアプリケーションを、事後に実行させるように機能する。
PendingIntentを他のアプリに渡すと、渡されたアプリは、配布元のアプリ自身と同様の実行権限が付与される(同じ許可やIDを持っていると判定される)。そのため、PendingIntentの生成に方法には注意が必要。例えば、基本となるIntentを発行する場合、Intentを間違えなく発行先のコンポーネントに配信できるよう、明示的にコンポーネント名を付与する。(誤った配信先に重要な権限を付与することがないようにする)
PendingIntentの使用に関する詳細は、以下に記載の使用例で
https://developer.android.com/guide/topics/ui/notifiers/notifications.html?hl=ja
https://developer.android.com/guide/topics/appwidgets/index.html?hl=ja
暗黙的Intenの応答判定
システムは、アクティビティを開始する暗黙的Intentを受け取ると、IntentをIntentフィルタと比較して、Intentに最適なアクティビティを検索する。
- Action
- data(URIとデータタイプの両方)
- category
暗黙的IntentのActionテスト
受け入れるIntentのアクションを指定するには、Intentフィルタで0個以上の<action>要素を宣言する。
<intent-filter>
<action android:name="android.intent.action.EDIT"/>
<action android:name="android.intent.action.VIEW"/>
...
</intent-filter>
このフィルタをパスするには、Intentで指定したアクションが、<intent-filter>で指定した何れかのアクションに一致する必要がある。
フィルタのリスト(<intent-filter> ~ )にアクションが1つもない場合、Intentに一致するものがないので、すべてのIntentはテストにパスできない。ただし、Intentがアクションを指定してない時、フィルタに1つ以上のアクションがあれば、テストにパスする。
暗黙的IntentのCategoryテスト
カテゴリを指定する場合、Intentフィルタで0個以上の<category>要素を宣言する。
<intent-filter>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
...
</intent-filter>
Intentがカテゴリのテストにパスするには、Intentの全てのカテゴリが、フィルタ内のカテゴリに一致する必要がある。Intentで指定するカテゴリより、Intentフィルタで指定するカテゴリが多い場合、Intentがパスする可能性がある。例えば、カテゴリの指定のないIntentは、フィルタで宣言されてるカテゴリに関係なく、常にテストのパスする。
startActivity()とstartActivityForResult()に渡される全ての暗黙的Intentに、CATEGORY_DEFAULLTカテゴリを自動的に適応する。自分のアクティビティが暗黙的Intentを受け取るようにしたいのなら、\に"android.intent.category.DEFAULT"のカテゴリを含める必要がある。 |
暗黙的IntentのDataテスト
受け入れるIntentのデータを指定するなら、Intentフィルタで0個以上の<data>要素を宣言する。
<intent-filter>
<data android:mimeType="video/mpeg" android:scheme="http" .../>
<data android:mimeType="audio/mpeg" android:scheme="http" .../>
///
</intent-filter>
各要素で、URI構造とデータタイプ(MIMEメディアタイプ)を指定できる。URIは、次のように、scheme host port pathという4属性で構成する。
<scheme>://<host>:<port>/<path>
次の例では、これらの属性で可能な値を記述する。
content://com.example.project:200/folder/subfolder/etc
このURIでは、スキームがcontent
、ホストがcom.example.project
、ポートが200
、パスがfolder/subfolder/etc
となる。
これらの各属性は<data>要素では省略可能。ただし一次従属性がある。
- schemeが未指定なら、hostは無視
- hostが未指定なら、portは無視
- schemeとhostの両方が未指定なら、pathは無視
IntentのURIを、フィルタのURI指定と比較するとき、フィルタに含まれるURIの一部のみと比較する。
- フィルタでschemeのみが指定されている場合、そのschemeを持つ全てのフィルタがい一致
- フィルタのschemeとhostが指定されていて、pathが指定されてない場合、同じschemeとhostを持つ、すべてのURIがフィルタをパスする
- フィルタでscheme、host、pathが指定されてる場合、同じscheme、host、pathを持つURIのみがフィルタをパスする。
pathの仕様により、ワイルドカードのアスタリスク(*)を含めて、パス名の部分一致のみを要求することもできる。 |
Dataテストでは、IntentのURIとMIMEタイプの両方を、フィルタで指定した値と比較する。そのルールか以下の通り。
- URIもMIMEタイプも未指定のIntentは、フィルタでURIやMIMEタイプが未指定のときのみ、テストをパスできる
- URIは指定、MIMEタイプは未指定のIntent(タイプが明示されてなく、URIからも推測できない)の場合、URIがフィルタのURI形式に一致し、フィルタがMIMEタイプ未指定の場合のみ、テストをパス
- URIが未指定、MIMEタイプが指定のとき、フィルタリストに同じMIMEタイプがあり、URI形式が未指定の場合のみ、テストをパス
- URIとMIMEタイプが指定(明示、URIから推測可能)されたIntentの場合、MIMEタイプがフィルタリストにあるタイプと一致した場合のみ、MIMEタイプのテストをパス。
URIテストは、フィルタURIに一致するか、Intentではcontent:URIかfile:URIがあり、フィルタではURIが未指定の場合にテストをパス。
つまり、フィルタがMIMEタイプのみをリストしてる場合、コンポーネントはcontent:データと、file:データをサポートすると推定する。
IntentでURIまたはMIMEタイプが指定されている場合、\に要素がなければ、データテストは失敗する |
最後のルールは、コンポーネントがファイルやコンテンツプロバイダからのローカルデータを取得できると想定したルール。フィルタにはデータタイプのみをリストして、content:スキームやfile:スキームを明示的に指定する必要はない。次の例は、要素がAndroidoに、コンポーネントがコンテンツプロバイダからの画像データを取得し、それを表示できることを示す典型的なコード。
<intent-filter>
<data android:mimeType="image/*"/>
...
</intent-filter>
利用可能なデータはほとんどコンテンツプロバイダ(情報を共有する。1つのプロセス内のデータを別のプロセスで実行されてるコードに繋げるためのインターフェイス)によって用意されているので、データタイプを指定し、かつURIを指定しない方法が使われることが多い(データタイプを指定すれば、コンテンツプロバイダが必要なデータを特定できることが多い)。
別のよくある構成は、schemeとデータタイプが記述されているフィルタ。例えば、次の要素はAndroidに、コンポーネントネットワーク(scheme="http")から動画データ(video/_*"を取得し、アクションを実行することを定義してる。
<intent-filter>
<data android:scheme="http" android:mimeType="video/*"/>
...
</intent-filter>
Intentとのマッチング
IntentとIntentフィルタのマッチングには、開始するターゲットコンポーネントの検索、端末上の一部コンポーネントに関する情報を検索する働きがあります。たとえば、ホームアプリは、ACTION_MAINアクションとVATEGORY_LUNCHERカテゴリを指定するIntentフィルタを持つ全てのアクティビティを見つけることで、アプリランチャーにデータを入力する(開始できるコンポーネントを持つアプリを、ランチャーに登録する)。Intentのアクションとカテゴリが、フィルタのテストをパスしたものだけ、マッチングが成立する。
開発しているアプリも、ホームアプリと同じ方法で、Intentをマッチングできる。PackageManagerには、query...()メソッドと、resolve...()メソッドがある。query...()メソッドは、Intentを受けられる全てのコンポーネントを提供し、resolve...()メソッドはIntentに応答する最適なコンポーネントを判断する。例えば、queryIntentActivities()は引数Intentを実行できる全アクティビティを提供するし、queryIntentService()は同様のサービスの一覧を提供する。いずれのメソッドもコンポーネントの開始はせず、リストを提供するだけ。ブロードキャストレシーバーも同様のメソッドとしてqueryBroadcastReceivers()がある。
一般的なIntent
アラームロック
カレンダー
カメラ
連絡先/連絡帳アプリ
メール
ファイルストレージ
ローカルアクション
地図
音楽・動画
新しいノート
電話
検索
設定
テキストメッセージ
ウェブブラウザ
Android Debug bridge でIntent検証
Sample Code(以下からは脱リファレンス)
構成
Project | Faile | 設定 |
---|---|---|
Project01 | Manifest.java | activity SubActivityを登録し <Intent-filter>を設定 |
MainActivity.java | ボタンリスナー | |
activity_main.xml | ボタンを2つ配置 | |
SubActivity.java | ||
activity_sub.xml | TextView "Project01 SubActivity" | |
Project02 | Manifest.java | activity MainActivityに <Intent-filter>を設定 |
MainActivity.java | ||
activity_main.xml | TextView "Project02 MainActivity" |
Project01
Manifest.java
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
// ■■■ ↓を追記する ■■■
<activity android:name=".SubActivity">
<intent-filter>
<action android:name="sub_activity"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
// ■■■ ここまで ■■■
MainActivityレイアウト(activity_main.xml)
<Button
android:id="@+id/button01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button01"
/>
<Button
android:id="@+id/button02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button02"
/>
MainActivity.java
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button01 = findViewById(R.id.button01);
Button button02 = findViewById(R.id.button02);
button01.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Intent intent_sub = new Intent("sub_activity");
startActivity(intent_sub);
}
});
button02.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Intent intent_pro02_main = new Intent("pro02_main_activity");
startActivity(intent_pro02_main);
}
});
}
SubActivityレイアウト
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SubActivity in Project01"/>
SubActivity.javaは何もしない
Project02
Manifest.java
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
// ■■■ ↓を追記する ■■■
<intent-filter>
<action android:name="pro02_main_activity"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
// ■■■ ここまで ■■■
</activity>
MainActivityのレイアウト
<TextView
android:text="MainActivity in Project02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
MainActivity.javaは何もしない