diff options
Diffstat (limited to 'docs/html-intl/intl/ja/guide/components')
-rw-r--r-- | docs/html-intl/intl/ja/guide/components/activities.jd | 756 | ||||
-rw-r--r-- | docs/html-intl/intl/ja/guide/components/bound-services.jd | 658 | ||||
-rw-r--r-- | docs/html-intl/intl/ja/guide/components/fragments.jd | 812 | ||||
-rw-r--r-- | docs/html-intl/intl/ja/guide/components/fundamentals.jd | 480 | ||||
-rw-r--r-- | docs/html-intl/intl/ja/guide/components/index.jd | 57 | ||||
-rw-r--r-- | docs/html-intl/intl/ja/guide/components/intents-filters.jd | 901 | ||||
-rw-r--r-- | docs/html-intl/intl/ja/guide/components/loaders.jd | 494 | ||||
-rw-r--r-- | docs/html-intl/intl/ja/guide/components/processes-and-threads.jd | 411 | ||||
-rw-r--r-- | docs/html-intl/intl/ja/guide/components/recents.jd | 256 | ||||
-rw-r--r-- | docs/html-intl/intl/ja/guide/components/services.jd | 813 | ||||
-rw-r--r-- | docs/html-intl/intl/ja/guide/components/tasks-and-back-stack.jd | 578 |
11 files changed, 6216 insertions, 0 deletions
diff --git a/docs/html-intl/intl/ja/guide/components/activities.jd b/docs/html-intl/intl/ja/guide/components/activities.jd new file mode 100644 index 000000000000..9b06d2c838bb --- /dev/null +++ b/docs/html-intl/intl/ja/guide/components/activities.jd @@ -0,0 +1,756 @@ +page.title=アクティビティ +page.tags=activity,intent +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> +<h2>本書の内容</h2> +<ol> + <li><a href="#Creating">アクティビティを作成する</a> + <ol> + <li><a href="#UI">ユーザー インターフェースを実装する</a></li> + <li><a href="#Declaring">マニフェストでアクティビティを宣言する</a></li> + </ol> + </li> + <li><a href="#StartingAnActivity">アクティビティを開始する</a> + <ol> + <li><a href="#StartingAnActivityForResult">結果待ちのアクティビティを開始する</a></li> + </ol> + </li> + <li><a href="#ShuttingDown">アクティビティをシャットダウンする</a></li> + <li><a href="#Lifecycle">アクティビティのライフサイクルを管理する</a> + <ol> + <li><a href="#ImplementingLifecycleCallbacks">ライフサイクル コールバックを実装する</a></li> + <li><a href="#SavingActivityState">アクティビティの状態を保存する</a></li> + <li><a href="#ConfigurationChanges">構成の変更を処理する</a></li> + <li><a href="#CoordinatingActivities">アクティビティを連携する</a></li> + </ol> + </li> +</ol> + +<h2>キークラス</h2> +<ol> + <li>{@link android.app.Activity}</li> +</ol> + +<h2>関連ドキュメント</h2> +<ol> + <li><a href="{@docRoot}guide/components/tasks-and-back-stack.html">タスクとバックスタック +</a></li> +</ol> + +</div> +</div> + + + +<p>{@link android.app.Activity} は、電話をかける、写真を撮影する、メールを送る、マップを閲覧するといった操作をユーザーができる画面を提供するアプリケーション コンポーネントです。 + +各アクティビティには、ユーザー インターフェースを描画できるウィンドウがあります。一般的にはウィンドウは画面と同じ大きさになりますが、画面より小さくしたり、他のウィンドウ上にフローティングさせたりすることもできます。 + +</p> + +<p> 通常、アプリケーションは複数のアクティビティで構成されており、各アプリケーションはそれぞれ緩やかにつながっています。 +一般的には、アプリケーションの 1 つのアクティビティが「メイン」アクティビティとして指定され、ユーザーが初めてアプリケーションを起動したときに表示されるのがこのアクティビティになります。 +その後、各アクティビティで別のアクティビティを開始して別の操作を実行できます。 +新しいアクティビティの開始時には、前のアクティビティは停止しますが、そのアクティビティはシステムによってスタック(「バックスタック」)に維持されます + +新しいアクティビティが開始すると、それがバックスタックに入ってユーザーに表示されます。 +バックスタックは「後入れ先出し」の基本的なスタック メカニズムを順守するため、ユーザーが現在のアクティビティを完了して [<em>戻る</em>] ボタンを押すと、そのアクティビティはスタックから消え(破棄され)、前のアクティビティが再開します。 + +(バックスタックの詳細については、<a href="{@docRoot}guide/components/tasks-and-back-stack.html">タスクとバックスタック</a>ドキュメントで説明します)。 + +</p> + +<p>新しいアクティビティが開始したことで、別のアクティビティが停止した場合、その状態の変化がアクティビティのライフサイクル コールバック メソッド経由で通知されます。システムがアクティビティを作成しているのか、停止しているのか、再開しているのか、破棄しているのかという状態の変化によって、アクティビティが受け取るコールバック メソッドにはいくつかの種類があり、各コールバックではユーザーがその状態の変化に応じた特定の操作を実行できます。 + + +—— + +たとえば、アクティビティが停止した場合は、ネットワーク接続やデータベース接続などの大きなオブジェクトを解放することになります。 +アクティビティが再開した場合は、必要なリソースを再度取得し、中断したところから操作を再開できます。 +このような状態の推移はすべて、アクティビティのライフサイクルの一部です。 +</p> + +<p>このドキュメントでは、さまざまなアクティビティの状態間の切り替えを正しく管理できるよう、アクティビティのライフサイクルの仕組みについてさらに詳しく説明する他、アクティビティのビルド方法と使用方法の基本について解説します。 + +</p> + + + +<h2 id="Creating">アクティビティを作成する</h2> + +<p>アクティビティを作成するには、{@link android.app.Activity} のサブクラス(またはその既存のサブクラス)を作成する必要があります。 +サブクラスでは、アクティビティのライフサイクルの状態の切り替え時(アクティビティの作成、停止、再開、破棄など)にシステムが呼び出すコールバック メソッドを実装する必要があります。 + +最も重要なコールバック メソッドは次の 2 つです。 +</p> + +<dl> + <dt>{@link android.app.Activity#onCreate onCreate()}</dt> + <dd>このメソッドは必ず実装してください。システムはアクティビティ作成の際にこのメソッドを呼び出します。 +実装の際には、アクティビティの必須コンポーネントを初期化する必要があります。 + + さらに重要な点は、ここで {@link android.app.Activity#setContentView + setContentView()} を呼び出してアクティビティのユーザー インターフェースのレイアウトを定義する必要があるということです。</dd> + <dt>{@link android.app.Activity#onPause onPause()}</dt> + <dd>システムは、ユーザーがアクティビティを終了したことを始めて示すときに、このメソッドを呼び出します(アクティビティが破棄されていない場合も含む)。 +通常はここで、現在のユーザー セッション後も維持する必要のある変更点を保存しておきます(ユーザーが戻ってこない可能性があるため)。 + +</dd> +</dl> + +<p>アクティビティ間の滑らかな操作感を実現し、アクティビティが停止したり破棄されたりする可能性のある予想外の中断に対応するために使用できるライフサイクル コールバック メソッドは他にもいくつかあります。 + +すべてのライフサイクル コールバック メソッドについては、<a href="#Lifecycle">アクティビティのライフサイクルを管理する</a>のセクションで説明します。 +</p> + + + +<h3 id="UI">ユーザー インターフェースを実装する</h3> + +<p> アクティビティのユーザー インターフェースは、ビューの階層、 {@link android.view.View} から派生したオブジェクトから提供されます。— +各ビューはアクティビティ ウィンドウ内の特定の長方形のエリアを制御し、ユーザーの操作に応答します。 +たとえば、1 つのビューが、ユーザーがタップしたときに操作を開始するボタンである場合があります。 +</p> + +<p>Android には、レイアウトのデザインや整理に使用できる既成のビューが多数用意されています。 +「ウィジェット」は、ボタン、テキスト フィールド、チェックボックス、画像といった画像の視覚的(操作可能な)要素を提供するビューです。 +「レイアウト」は、{@link +android.view.ViewGroup} から派生したビューで、線形レイアウト、グリッド レイアウト、相対レイアウトなど、子ビューの特有のレイアウト モデルを提供するものです。 +また、{@link android.view.View} クラスと {@link android.view.ViewGroup} クラス(または既存のサブクラス)のサブクラスを作成し、独自のウィジェットやレイアウトを作ってアクティビティのレイアウトに適用することもできます。 + +</p> + +<p>ビューを使用したレイアウトの定義で最も一般的なのは、XML レイアウト ファイルをアプリケーション リソースに保存する方法です。 +この方法では、ユーザー インターフェースのデザインを、アクティビティの挙動を定義するソース コードとは別に維持できます。 +{@link android.app.Activity#setContentView(int) setContentView()} を使用して、レイアウトのリソース ID を渡すと、アクティビティの UI としてレイアウトを設定できます。 + +ただし、アクティビティ コードに新しい {@link android.view.View} を作成して、{@link android.view.ViewGroup} に新しい {@link +android.view.View} を挿入してビュー階層をビルドし、ルートの {@link android.view.ViewGroup} を {@link android.app.Activity#setContentView(View) +setContentView()} に渡して、そのレイアウトを使うこともできます。 + +</p> + +<p>ユーザー インターフェースの作成の詳細については、「<a href="{@docRoot}guide/topics/ui/index.html">ユーザー インターフェース</a>」のドキュメントをご覧ください。</p> + + + +<h3 id="Declaring">マニフェストでアクティビティを宣言する</h3> + +<p>アクティビティがシステムにアクセスできるようにするには、マニフェストでアクティビティを宣言する必要があります。 +アクティビティを宣言するには、マニフェスト ファイルを開いて、<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> 要素を <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a> の子要素として追加します。 + +次に例を示します。</p> + +<pre> +<manifest ... > + <application ... > + <activity android:name=".ExampleActivity" /> + ... + </application ... > + ... +</manifest > +</pre> + +<p>この要素には他にも、アクティビティのラベル、アクティビティのアイコン、アクティビティの UI を決めるテーマなどのプロパティを定義する属性を含めることができます。<a href="{@docRoot}guide/topics/manifest/activity-element.html#nm">{@code android:name}</a> 属性は、アクティビティのクラス名を指定するもので、唯一の必須属性です。 + + +—アプリケーションを発行したら、この名前は変更できません。変更すると、アプリケーションのショートカットなどの一部の機能が破損する可能性があります(ブログの投稿「<a href="http://android-developers.blogspot.com/2011/06/things-that-cannot-change.html">Things That Cannot Change</a>」をご覧ください)。 + + +</p> + +<p>マニフェストでのアクティビティの宣言に関する詳細については、<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> 要素のリファレンスをご覧ください。 +</p> + + +<h4>インテント フィルタを使用する</h4> + +<p><a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code +<activity>}</a> 要素でも — <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code +<intent-filter>}</a> 要素を使用してさまざまなインテント フィルタを指定して — 他のアプリケーション コンポーネントでのアクティベート方法を宣言できます。 +</p> + +<p>Android SDK ツールを使用して新しいアプリケーションを作成する際、自動的に作成されるスタブ アクティビティには、「メイン」アクションに応答するアクティビティで、「ランチャー」カテゴリに置かれるべきものを宣言するインテント フィルタが含まれます。 + +インテント フィルタは次のように表示されます。 +</p> + +<pre> +<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> +</activity> +</pre> + +<p><a href="{@docRoot}guide/topics/manifest/action-element.html">{@code +<action>}</a> 要素は、これがアプリケーションへの「メイン」エントリ ポイントであることを指定します。<a href="{@docRoot}guide/topics/manifest/category-element.html">{@code +<category>}</a> 要素は、アクティビティをシステムのアプリケーション ランチャーに入れるべきであると指定します(ユーザーがこのアクティビティを起動できるようにします)。 +</p> + +<p>アプリケーションを自己完結型にして、他のアプリケーションでアクティビティをアクティベートできないようにする場合は、他のインテント フィルタは必要ありません。 +前の例のように、「メイン」アクションを持ち、「ランチャー」カテゴリにできるのは 1 つのアクティビティのみです。 +アクティビティを他のアプリケーションで利用できないようにする場合は、そのアクティビティにはインテント フィルタを使用せず、明示的なインテントを使用して自身でアクティビティを開始するようにできます(次のセクションで説明します)。 + +</p> + +<p>ただし、他のアプリケーション(と自身のアプリケーション)から派生した暗黙的なインテントにアクティビティが応答するようにする場合は、アクティビティで追加のインテント フィルタを定義する必要があります。 + +応答するインテントのタイプごとに、<a href="{@docRoot}guide/topics/manifest/action-element.html">{@code +<action>}</a> 要素を含む <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code +<intent-filter>}</a> と、任意で <a href="{@docRoot}guide/topics/manifest/category-element.html">{@code +<category>}</a> 要素や <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code +<data>}</a> 要素を含める必要があります。 +これらの要素は、アクティビティが応答できるインテントのタイプを指定します。 +</p> + +<p>アクティビティがインテントに応答する方法の詳細については、「<a href="{@docRoot}guide/components/intents-filters.html">インテントとインテント フィルタ</a>」のドキュメントをご覧ください。 +</p> + + + +<h2 id="StartingAnActivity">アクティビティを開始する</h2> + +<p>@link android.app.Activity#startActivity + startActivity()} を呼び出して、開始するアクティビティを記述する {@link android.content.Intent} を渡すと、新しいアクティビティを開始できます。 +インテントは開始するアクティビティを正確に指定するか、実行する操作のタイプを記述します(システムが適切なアクティビティを選択しますが、それが他のアプリケーションのアクティビティである場合もあります)。 + + +また、インテントには開始したアクティビティで使用する少量のデータを含めることもできます。 +</p> + +<p>自身のアプリケーションを操作するとき、既知のアクティビティを起動することが頻繁にあります。 + そのような場合、クラス名を使用して開始するアクティビティを明示的に定義するインテントを作成できます。 +例として、1 つのアクティビティで {@code +SignInActivity} という名前の他のアクティビティを開始する方法を次に示します。</p> + +<pre> +Intent intent = new Intent(this, SignInActivity.class); +startActivity(intent); +</pre> + +<p>ただし、アクティビティからのデータを使用して、アプリケーションでメールやテキスト メッセージの送信、ステータスのアップデートといった操作を実行する場合もあります。 +アプリケーションにそのような操作を実行できるアクティビティがない場合、代わりに、端末上の他のアプリケーションによるアクティビティを活用できます。 + +ここが、インテントがその存在意義を発揮する場面です。実行する操作を記述するインテントを作成し、システムが適切なアクティビティを他のアプリケーションから起動します。 +— + +インテントを処理できるアクティビティが複数ある場合は、使用するアクティビティを 1 つユーザーが選択できます。 +たとえば、メールを送信できるようにする場合は、次のようなインテントを作成します。 + +</p> + +<pre> +Intent intent = new Intent(Intent.ACTION_SEND); +intent.putExtra(Intent.EXTRA_EMAIL, recipientArray); +startActivity(intent); +</pre> + +<p>インテントに追加された {@link android.content.Intent#EXTRA_EMAIL} のエクストラは、メールの送信先となるメールアドレスの文字列配列です。 +メール アプリケーションがこのインテントに応答するとき、エクストラにある文字列配列を読み取り、それをメール作成フォームの「宛先」フィールドに置きます。 + +この場合、メール アプリケーションのアクティビティが開始してユーザーが操作を完了したときにアクティビティが再開します。 +</p> + + + + +<h3 id="StartingAnActivityForResult">結果待ちのアクティビティを開始する</h3> + +<p>開始するアクティビティから結果を受け取りたい場合は、{@link android.app.Activity#startActivityForResult + startActivityForResult()}({@link android.app.Activity#startActivity + startActivity()} の代わりに)を呼び出してアクティビティを開始します。 +その後のアクティビティから結果を受け取るには、 +{@link android.app.Activity#onActivityResult onActivityResult()} コールバック メソッドを実装します。 +後続のアクティビティが完了すると、{@link +android.content.Intent} の結果を {@link android.app.Activity#onActivityResult onActivityResult()} メソッドに返します。 +</p> + +<p>たとえば、連絡先を 1 つ受け取って、アクティビティでその連絡先情報を使用する場合は、 +次のようにインテントを作成して結果を処理できます。 +</p> + +<pre> +private void pickContact() { + // Create an intent to "pick" a contact, as defined by the content provider URI + Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI); + startActivityForResult(intent, PICK_CONTACT_REQUEST); +} + +@Override +protected void onActivityResult(int requestCode, int resultCode, Intent data) { + // If the request went well (OK) and the request was PICK_CONTACT_REQUEST + if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) { + // Perform a query to the contact's content provider for the contact's name + Cursor cursor = getContentResolver().query(data.getData(), + new String[] {Contacts.DISPLAY_NAME}, null, null, null); + if (cursor.moveToFirst()) { // True if the cursor is not empty + int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME); + String name = cursor.getString(columnIndex); + // Do something with the selected contact's name... + } + } +} +</pre> + +<p>この例では、アクティビティの結果を処理するために {@link +android.app.Activity#onActivityResult onActivityResult()} メソッドで使用すべき基本ロジックを示しています。 +1 つ目の条件では、要求が成功したかどうかを確認し、成功した場合は {@code resultCode} が{@link android.app.Activity#RESULT_OK} になり、この結果への要求が応答しているかどうかが判明します。この場合、{@code requestCode} が {@link android.app.Activity#startActivityForResult +startActivityForResult()} で送信された 2 つ目のパラメータに一致しています。— +—— + +そこから、コードが {@link android.content.Intent}({@code data} パラメータ)に返されたデータを照会することでアクティビティの結果を処理します。 +</p> + +<p>ここで、{@link +android.content.ContentResolver} がコンテンツ プロバイダに対してクエリを実行し、照会されたデータを読み取れるようにする {@link android.database.Cursor} が返されます。 +詳細については、「<a href="{@docRoot}guide/topics/providers/content-providers.html">コンテンツ プロバイダ</a>」のドキュメントをご覧ください。 +</p> + +<p>インテントの使用に関する詳細については、「<a href="{@docRoot}guide/components/intents-filters.html">インテントとインテント フィルタ</a>」のドキュメントをご覧ください。 +</p> + + +<h2 id="ShuttingDown">アクティビティをシャットダウンする</h2> + +<p>アクティビティは、{@link android.app.Activity#finish +finish()} メソッドを呼び出すことでシャットダウンできます。また、{@link android.app.Activity#finishActivity finishActivity()} を呼び出すと以前に開始した別のアクティビティをシャットダウンすることもできます。 +</p> + +<p class="note"><strong>注:</strong> ほとんどの場合、これらのメソッドを用いてアクティビティを明示的に終了しないでください。 +後述のアクティビティのライフサイクルでも説明していますが、Android システム自体がアクティビティのライフサイクルを管理するため、アクティビティを自身で終了させる必要はありません。 + +これらのメソッドを呼び出すと、期待された操作性に影響を与えることがあるため、ユーザーが絶対にアクティビティのこのインスタンスに戻らないようにする場合にのみ使用するようにしてください。 + +</p> + + +<h2 id="Lifecycle">アクティビティのライフサイクルを管理する</h2> + +<p>コールバック メソッドを実装したアクティビティのライフサイクルの管理は、強固で柔軟なアプリケーションの開発にとって重要です。 + +アクティビティのライフサイクルは、他のアクティビティ、タスク、バックスタックとの関連による影響を直接受けます。 +</p> + +<p>基本的に、アクティビティには次の 3 つの状態があります。</p> + +<dl> + <dt><i>再開状態</i></dt> + <dd>アクティビティが画面のフォアグラウンドにあり、ユーザー フォーカスのある状態。(この状態は「実行中」とも呼ばれます)。 +</dd> + + <dt><i>一時停止状態</i></dt> + <dd>他のアクティビティがフォアグラウンドにあり、メインに表示されているが、このアクティビティも表示されている。つまり、このアクティビティの上に他のアクティビティが表示されており、他方のアクティビティは一部が透明であるか、画面全体を覆ってはいない状態です。 + +一時停止状態のアクティビティは完全に生きている状態ですが({@link android.app.Activity} オブジェクトがメモリに保持されており、すべての状態やメンバー情報が維持され、ウィンドウ マネージャーにもアタッチされたまま)、メモリ量が極端に低下した場合にはシステムによって強制停止される場合もあります。 + +</dd> + + <dt><i>停止状態</i></dt> + <dd>アクティビティは、他のアクティビティによって完全に見えない状態です(アクティビティが「バックグラウンド」にある)。 +停止状態のアクティビティもまだ生きていますが({@link android.app.Activity} オブジェクトがメモリに保持されており、すべての状態やメンバー情報が維持されているが、ウィンドウ マネージャーにはアタッチ<em>されていない</em>状態です)。 + +ただし、ユーザーには表示されておらず、別の場所でメモリが必要になればシステムによって強制終了される場合もあります。 +</dd> +</dl> + +<p>アクティビティが一時停止か停止状態の場合、システムはアクティビティに終了するかどうかを尋ねる({@link android.app.Activity#finish finish()} メソッドを呼び出す)か、単純にプロセスを強制終了してメモリから解放できます。 + +アクティビティを再度開くとき(終了や強制終了後)は、もう一度最初から作成する必要があります。 +</p> + + + +<h3 id="ImplementingLifecycleCallbacks">ライフサイクル コールバックを実装する</h3> + +<p>アクティビティが上記の異なる状態の間を遷移するとき、さまざまなコールバック メソッドを介して通知されます。 +すべてのコールバック メソッドは、アクティビティの状態が変化したときに必要な操作を実行するようオーバーライドできるフックになります。 +次のスケルトン アクティビティには、基本的なライフサイクル メソッドがそれぞれ含まれています。 +</p> + + +<pre> +public class ExampleActivity extends Activity { + @Override + public void {@link android.app.Activity#onCreate onCreate}(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // The activity is being created. + } + @Override + protected void {@link android.app.Activity#onStart onStart()} { + super.onStart(); + // The activity is about to become visible. + } + @Override + protected void {@link android.app.Activity#onResume onResume()} { + super.onResume(); + // The activity has become visible (it is now "resumed"). + } + @Override + protected void {@link android.app.Activity#onPause onPause()} { + super.onPause(); + // Another activity is taking focus (this activity is about to be "paused"). + } + @Override + protected void {@link android.app.Activity#onStop onStop()} { + super.onStop(); + // The activity is no longer visible (it is now "stopped") + } + @Override + protected void {@link android.app.Activity#onDestroy onDestroy()} { + super.onDestroy(); + // The activity is about to be destroyed. + } +} +</pre> + +<p class="note"><strong>注:</strong> これらのライフサイクル メソッドを実装する際は、上記の例のように、すべての操作の前にスーパークラスの実装を呼び出す必要があります。 +</p> + +<p>これらのメソッドすべてで、アクティビティのライフサイクル全体を定義します。これらのメソッドを実装すると、アクティビティのライフサイクル内の次の 3 つのネストされたループを監視できます。 + </p> + +<ul> +<li>アクティビティの<b> entire lifetime</b> は、{@link +android.app.Activity#onCreate onCreate()} の呼び出しから、{@link +android.app.Activity#onDestroy} の呼び出しまでの間です。アクティビティは、{@link android.app.Activity#onCreate onCreate()} で「グローバル」状態のセットアップ(レイアウトの定義など)を実行し、{@link android.app.Activity#onDestroy} に残っているすべてのリソースを解放する必要があります。 + +たとえば、アクティビティにネットワークからデータをダウンロードするためバックグラウンドで実行しているスレッドがある場合、そのスレッドが {@link android.app.Activity#onCreate onCreate()} に作成され、{@link +android.app.Activity#onDestroy} のスレッドが停止される場合があります。 + +</li> + +<li><p>アクティビティの<b>visible lifetime</b> は、{@link +android.app.Activity#onStart onStart()} の呼び出しから、{@link +android.app.Activity#onStop onStop()} の呼び出しまでの間です。この間、アクティビティは画面上に表示され、ユーザーが操作できる状態です。 +たとえば {@link android.app.Activity#onStop onStop()} は、新たなアクティビティが開始してこのアクティビティが表示されなくなったときに呼び出されます。 +これらの 2 つのメソッド間で、アクティビティをユーザーに表示するのに必要なリソースは保持できます +たとえば、{@link android.content.BroadcastReceiver} を {@link +android.app.Activity#onStart onStart()} に登録して UI に影響のある変更を監視し、ユーザーが表示内容の閲覧をやめたときに {@link android.app.Activity#onStop onStop()} で登録解除できます + + +アクティビティがユーザーに表示されたり、非表示になったりとアクティビティの状態が変化する場合、アクティビティの entire lifetime 中にシステムが {@link android.app.Activity#onStart onStart()} と {@link +android.app.Activity#onStop onStop()} を複数回呼び出すこともあります。 +</p></li> + +<li><p>アクティビティの <b>foreground lifetime</b> は {@link +android.app.Activity#onResume onResume()} の呼び出しから、{@link android.app.Activity#onPause +onPause()} の呼び出しまでの間です。この間、アクティビティは画面上の他のすべてのアクティビティの前面にあり、ユーザーの入力フォーカスがある状態です。 +アクティビティは フォアグラウンドにある状態からそうでない状態に頻繁に遷移する可能性があります。たとえば、端末がスリープ状態になったり、ダイアログが表示されたりしたときには{@link android.app.Activity#onPause onPause()} が呼び出されます。 +— +この状態遷移は頻繁に起こるため、この 2 つのメソッドのコードはユーザーを待たせてしまうような遅い遷移にならないよう、適正な軽い処理にしておく必要があります。 +</p></li> +</ul> + +<p>図 1 では、状態間でアクティビティがたどる可能性のあるループと経路を表しています。長方形はアクティビティが状態間で遷移したときの処理用に実装できるコールバック メソッドを表しています。 + + <p> + +<img src="{@docRoot}images/activity_lifecycle.png" alt="" /> +<p class="img-caption"><strong>図 1.</strong> アクティビティのライフサイクル</p> + +<p>表 1 には同じライフサイクル コールバック メソッドがリストされており、各コールバック メソッドの詳細と、アクティビティのライフサイクル全体でのそれぞれの位置関係、コールバック メソッドの完了後にシステムによってアクティビティが強制終了されるかどうかを示しています。 + + +</p> + +<p class="table-caption"><strong>表 1.</strong> ライフサイクル コールバック メソッドの概要 +</p> + +<table border="2" width="85%" frame="hsides" rules="rows"> +<colgroup align="left" span="3"></colgroup> +<colgroup align="left"></colgroup> +<colgroup align="center"></colgroup> +<colgroup align="center"></colgroup> + +<thead> +<tr><th colspan="3">メソッド</th> <th>説明</th> <th>完了後の強制終了</th> <th>次のメソッド</th></tr> +</thead> + +<tbody> +<tr> + <td colspan="3" align="left"><code>{@link android.app.Activity#onCreate onCreate()}</code></td> + <td>アクティビティが最初に作成されるときに呼び出されます。 + ここで、ビューの作成、リストとのデータバインドといった、通常の静的なセットアップを行います。— +アクティビティの前の状態を含む Bundle オブジェクトを取り出せた場合、それをメソッドに渡します(後半の<a href="#actstate">アクティビティの状態を保存する</a>をご覧ください)。 + + + + <p>常に {@code onStart()} が後に続きます。</p></td> + <td align="center">いいえ</td> + <td align="center">{@code onStart()}</td> +</tr> + +<tr> + <td rowspan="5" style="border-left: none; border-right: none;"> </td> + <td colspan="2" align="left"><code>{@link android.app.Activity#onRestart +onRestart()}</code></td> + <td>アクティビティが停止した後、再開する直前に呼び出されます。 + + <p>常に {@code onStart()} が後に続きます。</p></td> + <td align="center">いいえ</td> + <td align="center">{@code onStart()}</td> +</tr> + +<tr> + <td colspan="2" align="left"><code>{@link android.app.Activity#onStart onStart()}</code></td> + <td>アクティビティがユーザーに見える状態になる直前に呼び出されます。 + <p>アクティビティがフォアグラウンドになったときは {@code onResume()} が後に続き、アクティビティが非表示になったときは {@code onStop()} が後に続きます。 +</p></td> + <td align="center">いいえ</td> + <td align="center">{@code onResume()} <br/>または<br/> {@code onStop()}</td> +</tr> + +<tr> + <td rowspan="2" style="border-left: none;"> </td> + <td align="left"><code>{@link android.app.Activity#onResume onResume()}</code></td> + <td>アクティビティとユーザーとの操作が開始する直前に呼び出されます。 +この時点で、アクティビティはアクティビティ スタックの先頭にあり、ユーザー入力の準備ができています。 + + <p>常に {@code onPause()} が後に続きます。</p></td> + <td align="center">いいえ</td> + <td align="center">{@code onPause()}</td> +</tr> + +<tr> + <td align="left"><code>{@link android.app.Activity#onPause onPause()}</code></td> + <td>システムが別のアクティビティを再開する直前に呼び出されます。 +通常、このメソッドは永続化データへの未保存の変更をコミットしたり、アニメーションや CPU を消費する可能性のあるその他の動作を停止したりする際に使用されます。 + +それが完了するまで次のアクティビティが再開できないため、それらの操作は迅速に行う必要があります。 + + <p>アクティビティが前面に戻るときは {@code onResume()} が後に続き、アクティビティが非表示になるときは {@code onStop()} が後に続きます。 + +</td> + <td align="center"><strong style="color:#800000">はい</strong></td> + <td align="center">{@code onResume()} <br/>または<br/> {@code onStop()}</td> +</tr> + +<tr> + <td colspan="2" align="left"><code>{@link android.app.Activity#onStop onStop()}</code></td> + <td>アクティビティがユーザーに見えなくなると呼び出されます。これは、アクティビティが破棄されたか、別のアクティビティ(既存のアクティビティや新しいアクティビティ)が再開されてこのアクティビティを覆っている場合に起こります。 + + + <p>アクティビティのユーザー操作が可能に戻るときは {@code onRestart()} が後に続き、アクティビティがなくなるときは {@code onDestroy()} が後に続きます。 + +</p></td> + <td align="center"><strong style="color:#800000">はい</strong></td> + <td align="center">{@code onRestart()} <br/>または<br/> {@code onDestroy()}</td> +</tr> + +<tr> + <td colspan="3" align="left"><code>{@link android.app.Activity#onDestroy +onDestroy()}</code></td> + <td>アクティビティが破棄される前に呼び出されます。これはアクティビティが受け取る最後の呼び出しです。 +アクティビティが終了した(<code>{@link android.app.Activity#finish + finish()}</code> が呼び出された)か、アクティビティ領域を節約するためにシステムが一時的にこのアクティビティを破棄した場合に呼び出されます。 + +この 2 つのシナリオは、<code>{@link + android.app.Activity#isFinishing isFinishing()}</code> メソッドで区別できます。 +</td> + <td align="center"><strong style="color:#800000">はい</strong></td> + <td align="center"><em>なし</em></td> +</tr> +</tbody> +</table> + +<p>「完了後の強制終了」の列は、<em>メソッドが戻った後</em>に、アクティビティのコードの後続行を実行することなく、アクティビティをホストするプロセスをシステムが強制終了できるかどうかを示しています。 + +3 つのメソッド({@link +android.app.Activity#onPause +onPause()}、{@link android.app.Activity#onStop onStop()}、{@link android.app.Activity#onDestroy +onDestroy()})が「はい」になっています。{@link android.app.Activity#onPause onPause()} は 3 つのなかで最初であるため、アクティビティが作成された後は{@link android.app.Activity#onPause onPause()} がプロセスが強制終了される<em>可能性がある</em>前に呼び出されることが保証される最後のメソッドです。システムが緊急でメモリを空ける必要がある場合は、{@link +android.app.Activity#onStop onStop()} と {@link android.app.Activity#onDestroy onDestroy()} は呼び出されない場合があります。 + +— + +そのため、重要な永続的データ(ユーザーの編集内容など)をストレージに書き込む際は、{@link android.app.Activity#onPause onPause()} を使用する必要があります。 +ただし、このメソッドで後続のアクティビティへの遷移をブロックしてしまい、ユーザー操作の速度を送らせてしまうことから、{@link android.app.Activity#onPause onPause()} 中にどんな情報を保持するかについては吟味する必要があります。 + + +</p> + +<p> <b>「強制終了」</b>列で「いいえ」となっているメソッドでは、アクティビティが呼び出された時点から、アクティビティをホストするプロセスが強制終了されないよう保護します。 +つまり、アクティビティが強制終了される可能性があるのは、{@link android.app.Activity#onPause onPause()} が戻ってから、{@link android.app.Activity#onResume onResume()} が呼び出されるまでの間です。 + +{@link android.app.Activity#onPause onPause()} が再度呼び出されて戻るまでは、再度強制終了されることはありません。 + </p> + +<p class="note"><strong>注:</strong> 表 1 の定義では技術的に「強制終了」できないアクティビティでも、システムによって強制終了されることがありますが、そうなるのはリソース不足などの緊急時のみです。 +— +アクティビティが強制終了されるケースについては、<a href="{@docRoot}guide/components/processes-and-threads.html">Processes and Threading</a> のドキュメントで説明しています。 + +</p> + + +<h3 id="SavingActivityState">アクティビティの状態を保存する</h3> + +<p><a href="#Lifecycle">アクティビティのライフサイクルを管理する</a>でも簡単に説明したように、アクティビティが一時停止や停止したとき、アクティビティの状態は保持されます。 + +これは、一時停止や停止されたときも {@link android.app.Activity} オブジェクトがメモリに保持されるためです — メンバーや現在の状態といったすべての情報は残っています。 + +つまり、アクティビティ内でユーザーが加えた変更点は保持されるため、アクティビティがフォアグラウンドに戻ったとき(「再開」したとき)、それらの変更点はそのまま表示されます。 + +</p> + +<p>ただし、メモリを確保するためにシステムがアクティビティを破棄すると、 {@link +android.app.Activity} オブジェクトが破棄されるため、システムはそれをそのままの状態で再開できなくなります。 +代わりに、ユーザーがそれに戻る操作を行った場合、システムは {@link android.app.Activity} オブジェクトを再作成します。 +ユーザーにはシステムがアクティビティを破棄して再作成したことはわからないため、アクティビティが以前の状態のままであることを期待します。 + +この場合、アクティビティの状態情報を保存できる追加のコールバック メソッド({@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()})を実装することで、アクティビティの状態に関する重要な情報を維持できます。 + +</p> + +<p>アクティビティが破棄されるような状態になる前に、システムが {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()} を呼び出します。 +システムはこのメソッドを {@link android.os.Bundle} に渡し、そこでアクティビティの状態情報を名前と値のペアとして {@link +android.os.Bundle#putString putString()} や {@link +android.os.Bundle#putInt putInt()} などのメソッドを使用して保存できます。 + +その後、システムがアプリケーション プロセスを強制終了して、ユーザーがアクティビティに戻った場合、システムはアクティビティを再作成して {@link android.os.Bundle} を {@link android.app.Activity#onCreate onCreate()} と {@link +android.app.Activity#onRestoreInstanceState onRestoreInstanceState()} の両方に渡します。 + +いずれのメソッドを使った場合でも、保存した状態を {@link android.os.Bundle} から抽出してアクティビティの状態を復元できます。 + +復元する状態情報がない場合は、{@link +android.os.Bundle} は null で渡されます(アクティビティを最初に作成した場合がこれにあたります)。 +</p> + +<img src="{@docRoot}images/fundamentals/restore_instance.png" alt="" /> +<p class="img-caption"><strong>図 2.</strong> アクティビティが前の状態のままでユーザー フォーカスに戻るには、アクティビティが破棄され、再作成された後にアクティビティが保存された以前の状態を復元する必要があるか、アクティビティが停止し、再開した後にアクティビティの状態が以前のままになるか、の 2 つの方法があります。 + + +</p> + +<p class="note"><strong>注:</strong> アクティビティが破棄される前に {@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()} が呼び出される保証はありません。これは、状態を保存する必要がないケースがあるためです(ユーザーが [<em>戻る</em>] ボタンを使用してアクティビティを離れることで明示的にアクティビティを閉じた場合など)。 + + + +システムが {@link android.app.Activity#onSaveInstanceState +onSaveInstanceState()} を呼び出す場合、呼び出しは常に {@link +android.app.Activity#onStop onStop()} の前、場合によっては {@link android.app.Activity#onPause +onPause()} の前に行われます。</p> + +<p>ただし、何もせず {@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()} も実装しない場合でも、{@link android.app.Activity} クラスの {@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()} のデフォルトの実装によって、アクティビティの状態が復元されるものもあります。 +具体的には、デフォルトの実装がレイアウト内のすべての {@link +android.view.View} の {@link +android.view.View#onSaveInstanceState onSaveInstanceState()} を呼び出すことで、各ビューが保存すべき情報を提供できるようになります。 + +Android フレームワークの大半のウィジェットが必要に応じてこのメソッドを実装しており、UI への視覚的な変更は自動的に保存され、アクティビティが再作成されると復元されるようになっています。 + +たとえば、{@link android.widget.EditText} ウィジェットではユーザーが入力したすべてのテキストを保存し、{@link android.widget.CheckBox} ウィジェットはオンにされたかどうかを保存するようになっています。 + +ここで必要な作業は、状態を保存する各ウィジェット用の一意の ID(<a href="{@docRoot}guide/topics/resources/layout-resource.html#idvalue">{@code android:id}</a>)を提供するだけです。 +ウィジェットに ID がないと、システムは状態を保存できません。 +</p> + +<div class="sidebox-wrapper"> +<div class="sidebox"> +<p>また、レイアウトのビューでの状態の保存を明示的に停止するには、{@link android.R.attr#saveEnabled android:saveEnabled} 属性を {@code "false"} に設定するか、{@link android.view.View#setSaveEnabled setSaveEnabled()} メソッドを呼び出します。 + +通常はこの機能を無効にしませんが、アクティビティ UI の状態を別の方法で復元する場合には無効にできます。 +</p> +</div> +</div> + +<p>{@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()} のデフォルトの実装によってアクティビティの UI に関する有用な情報は保存されますが、追加の情報を保存するようそれをオーバーライドすることもできます。例としては、アクティビティの期間に変更されたメンバー値を保存する必要があるケースなどがあります。(UI で復元された値に関連している場合でも、それらの UI 値を持つメンバーはデフォルトでは復元されません)。 + + + +</p> + +<p>{@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()} のデフォルトの実装で UI の状態を保存できるため、状態の追加情報を保存するようメソッドをオーバーライドする場合は、常に作業前に {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()} のスーパークラス実装を呼び出す必要があります。 + + +同様に、オーバーライドする場合はデフォルトの実装でビューの状態を復元できるよう、{@link +android.app.Activity#onRestoreInstanceState onRestoreInstanceState()} のスーパークラスの実装も呼び出す必要があります。 +</p> + +<p class="note"><strong>注:</strong> {@link android.app.Activity#onSaveInstanceState +onSaveInstanceState()} は呼び出される保証がないため、これはアクティビティの一時的な状態の記録用にのみ使用し、永続的データの保存には使用しないようにします。 + +—代わりに {@link +android.app.Activity#onPause onPause()} を使用して、ユーザーがアクティビティを離れたときの永続的データ(データベースに保存するインストール必要のあるデータなど)を保存します。 +</p> + +<p>アプリケーションが状態を復元できるかどうかテストするには、端末を回転してみて、方向が変化するかを確認します +画面の方向が変わるとき、システムがアクティビティを破棄して再作成し、新しい画面構成に利用可能な別のリソースを適用します。 + +アプリケーションの使用中にユーザーが端末を回転させるという場面は日常的にあるため、アクティビティが再作成されたときに状態を完全に復元することは非常に重要です。 + +</p> + + +<h3 id="ConfigurationChanges">構成の変更を処理する</h3> + +<p>端末の構成の中には、実行の際に変化するものがあります(画面の向き、キーボードの可用性、言語など)。 +そのような変化が生じたとき、Android は実行中のアクティビティを再作成します(システムが {@link android.app.Activity#onDestroy} を呼び出し、その後すぐに {@link +android.app.Activity#onCreate onCreate()})を呼び出します。 +この動作は、提供した別のリソース(異なる画面の向きやサイズに応じたレイアウトなど)を使用してアプリケーションを自動的にリロードすることで、アプリケーションを新しい構成に適応させることを目的としています。 + + +</p> + +<p>前述のように画面の向きの変化による再起動を処理して、アクティビティの状態を復元するようアプリケーションを適切にデザインしていれば、アプリケーションはアクティビティのライフサイクルでの予期しない他のイベントに対しても回復力を持つことができます。 + +</p> + +<p>このような再起動を処理するのに最適な方法は、前のセクションで説明したように、{@link + android.app.Activity#onSaveInstanceState onSaveInstanceState()} と {@link +android.app.Activity#onRestoreInstanceState onRestoreInstanceState()}(または {@link +android.app.Activity#onCreate onCreate()})を使用してアクティビティの状態を保存、復元する方法です。 +</p> + +<p>実行の際に起こる構成の変更と、その処理方法の詳細については、「<a href="{@docRoot}guide/topics/resources/runtime-changes.html">実行時の変更の処理</a>」のガイドをご覧ください。 + +</p> + + + +<h3 id="CoordinatingActivities">アクティビティを連携する</h3> + + <p>1 つのアクティビティで別のアクティビティを開始すると、双方でライフサイクルの遷移が生じます。1 つ目のアクティビティが一時停止したり停止したりすると(バックグラウンドにある場合は停止しません)、もう一方のアクティビティが作成されます。 + +これらのアクティビティでディスクなどに保存されているデータを共有している場合は、2 つ目のアクティビティが作成される前に 1 つ目のアクティビティが完全に停止することはないということを理解しておくことが重要です。むしろ、2 つ目の開始プロセスは、1 つ目の停止プロセスにオーバーラップします。 + + +</p> + +<p>特に 2 つのアクティビティが同じプロセスにあって 1 つが別のアクティビティを開始する場合、ライフサイクル コールバックの順序は厳密に定義されています。 +アクティビティ A がアクティビティ B を開始する場合の動作の順序を次に示します。 + </p> + +<ol> +<li>アクティビティ A の {@link android.app.Activity#onPause onPause()} メソッドが実行されます。</li> + +<li>アクティビティ B の {@link android.app.Activity#onCreate onCreate()}、{@link +android.app.Activity#onStart onStart()}、{@link android.app.Activity#onResume onResume()} メソッドが順次実行されます +(このとき、ユーザー フォーカスはアクティビティ B にあります)。</li> + +<li>次に、アクティビティ A が画面から消えた場合、{@link +android.app.Activity#onStop onStop()} メソッドが実行されます。</li> +</ol> + + <p>このライフサイクル コールバックの順序を予測しておくことで、1 つのアクティビティから他のアクティビティへの情報の遷移を管理できるようになります。 +たとえば、1 つ目のアクティビティが停止したときに、後続のアクティビティが読み取れるようにデータベースに書き込む必要がある場合、データベースに書き込むタイミングは {@link +android.app.Activity#onStop onStop()} ではなく {@link android.app.Activity#onPause onPause()} の間になります。 + +</p> + +<!-- +<h2>Beginner's Path</h2> + +<p>For more information about how Android maintains a history of activities and +enables user multitasking, continue with the <b><a +href="{@docRoot}guide/components/tasks-and-back-stack.html">Tasks and Back +Stack</a></b> document.</p> +--> diff --git a/docs/html-intl/intl/ja/guide/components/bound-services.jd b/docs/html-intl/intl/ja/guide/components/bound-services.jd new file mode 100644 index 000000000000..d115e76ed04b --- /dev/null +++ b/docs/html-intl/intl/ja/guide/components/bound-services.jd @@ -0,0 +1,658 @@ +page.title=バインドされたサービス +parent.title=サービス +parent.link=services.html +@jd:body + + +<div id="qv-wrapper"> +<ol id="qv"> +<h2>本書の内容</h2> +<ol> + <li><a href="#Basics">基本</a></li> + <li><a href="#Creating">バインドされたサービスを作成する</a> + <ol> + <li><a href="#Binder">Binder クラスを拡張する</a></li> + <li><a href="#Messenger">メッセンジャーを使用する</a></li> + </ol> + </li> + <li><a href="#Binding">サービスにバインドする</a></li> + <li><a href="#Lifecycle">バインドされたサービスのライフサイクルを管理する</a></li> +</ol> + +<h2>キークラス</h2> +<ol> + <li>{@link android.app.Service}</li> + <li>{@link android.content.ServiceConnection}</li> + <li>{@link android.os.IBinder}</li> +</ol> + +<h2>サンプル</h2> +<ol> + <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">{@code + RemoteService}</a></li> + <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code + LocalService}</a></li> +</ol> + +<h2>関連ドキュメント</h2> +<ol> + <li><a href="{@docRoot}guide/components/services.html">サービス</a></li> +</ol> +</div> + + +<p>バインドされたサービスは、クライアントサーバー インターフェースにおけるサーバーになります。バインドされたサービスでは、コンポーネント(アクティビティなど)をサービスにバインドしたり、送信を要求したり、受信を応答したり、さらにはプロセス間通信(IPC)を実行したりできるようにします。 + +通常、バインドされたサービスは他のアプリケーション コンポーネントを提供している間だけ機能し、バックグラウンドで無期限に実行されることはありません。 +</p> + +<p>このドキュメントでは、他のアプリケーション コンポーネントからのサービスにバインドする方法を含む、バインドされたサービスの作成方法について説明します。 +ただし、サービスから通知を配信する方法や、フォアグラウンドでサービスを実行するよう設定する方法など、サービス全般の詳細については、「<a href="{@docRoot}guide/components/services.html">サービス</a>」のドキュメントをご覧ください。 + +</p> + + +<h2 id="Basics">基本</h2> + +<p>バインドされたサービスは、他のアプリケーションのバインドとやり取りを可能にする {@link android.app.Service} クラスの実装です。 +サービスのバインドを提供するには、{@link android.app.Service#onBind onBind()} コールバック メソッドを実装する必要があります。 +このメソッドでは {@link android.os.IBinder} オブジェクトが返されます。このオブジェクトはクライアントがサービスとのやり取りに使用するプログラミング インターフェースを定義します。 + +</p> + +<div class="sidebox-wrapper"> +<div class="sidebox"> + <h3>開始されたサービスにバインドする</h3> + +<p><a href="{@docRoot}guide/components/services.html">サービス</a> ドキュメントで説明されているように、開始されるサービスとバインドされるサービスの両方を作成できます。 +つまり、{@link android.content.Context#startService startService()} を呼び出して開始されるサービスは無期限に実行でき、クライアントが {@link +android.content.Context#bindService bindService()} を呼び出してサービスにバインドできます。 + + + <p>サービスの開始とバインドを許可すると、サービスが開始するとすべてのクライアントがアンバインドしても、システムによってサービスが破棄されることは<em>ありません</em>。 +代わりに、{@link android.app.Service#stopSelf stopSelf()} や {@link +android.content.Context#stopService stopService()} を呼び出して、サービスを明示的に停止する必要があります。 +</p> + +<p>通常実装するのは、{@link android.app.Service#onBind onBind()} +<em> か </em>{@link android.app.Service#onStartCommand onStartCommand()} のどちらかですが、両方の実装が必要な場合もあります。 +たとえば、音楽プレーヤーの場合はサービスを無期限に実行しつつ、バインドも提供できると便利な場合があります。 +この方法であれば、アクティビティがサービスを開始して音楽を再生し、ユーザーがアプリケーションから離れた場合も音楽を再生し続けることができます。 +次にユーザーがアプリケーションに戻ったとき、アクティビティがサービスにバインドして再生のコントロールをもう一度行えるようになります。 +</p> + +<p>開始されたサービスにバインドを追加する際のサービスのライフサイクルの詳細については、<a href="#Lifecycle">バインドされたサービスのライフサイクルを管理する</a>を必ずご覧ください。 + +</p> +</div> +</div> + +<p>クライアントは、{@link android.content.Context#bindService +bindService()} を呼び出せばサービスにバインドできます。バインドするときは、サービスとの接続を監視する {@link +android.content.ServiceConnection} を実装する必要があります。{@link +android.content.Context#bindService bindService()} メソッドは値なしですぐに返されますが、Android システムがクライアントとサービス間の接続を作成すると {@link +android.content.ServiceConnection} の {@link +android.content.ServiceConnection#onServiceConnected onServiceConnected()} が呼び出され、クライアントがサービスとの通信に使用できる {@link android.os.IBinder} が配信されます。 + + +</p> + +<p>複数のクライアントが同時にサービスに接続できます。ただし、1 つ目のクライアントのバインドの際にのみ、システムはサービスの {@link android.app.Service#onBind onBind()} メソッドを呼び出して{@link android.os.IBinder} を取得します。 + +その後システムは {@link android.app.Service#onBind onBind()} を呼び出すことなく、同じ {@link android.os.IBinder} をバインドしたすべてのクライアントに配信します。 +</p> + +<p>最後のクライアントがサービスからアンバインドされると、システムはサービスを破棄します(サービスが {@link android.content.Context#startService startService()} でも開始された場合を除く)。 +</p> + +<p>バインドされたサービスを実装するときに最も重要なのは、{@link android.app.Service#onBind onBind()} コールバック メソッドが返すインターフェースを定義することです。 +サービスの {@link android.os.IBinder} インターフェースの定義には複数の方法があり、次のセクションではそれぞれのテクニックについて説明していきます。 + +</p> + + + +<h2 id="Creating">バインドされたサービスを作成する</h2> + +<p>バインドを提供するサービスを作成するとき、クライアントがサービスとのやり取りに使用するプログラミング インターフェースを提供する {@link android.os.IBinder} を提示する必要があります。 +インターフェースを定義するには、次の 3 つの方法があります。 +</p> + +<dl> + <dt><a href="#Binder">Binder クラスを拡張する</a></dt> + <dd>サービスが独自のアプリケーション専用であり、クライアントと同じプロセスで実行する場合(ほとんどのケースに該当)、{@link android.os.Binder} クラスを拡張して {@link android.app.Service#onBind onBind()} からそのインスタンスを返すことでインターフェースを作成します。 + + +クライアントは {@link android.os.Binder} を受け取り、それを使用して {@link android.os.Binder} の実装や {@link android.app.Service} で利用できる public メソッドに直接アクセスできます。 + + + <p>サービスが単にアプリケーションのバックグラウンド ワーカーである場合は、この方法が適しています。 +この方法が適していない唯一のケースは、サービスが他のアプリケーションや、別のプロセス間で使用されている場合です。 +</dd> + + <dt><a href="#Messenger">メッセンジャーを使用する</a></dt> + <dd>別のプロセス間で動作するインターフェースが必要な場合は、{@link android.os.Messenger} を使用してサービス用のインターフェースを作成できます。 +この方法では、サービスが異なるタイプの {@link +android.os.Message} オブジェクトに応答する {@link android.os.Handler} を定義します。 +この {@link android.os.Handler} を基本として {@link android.os.Messenger} は {@link android.os.IBinder} をクライアントと共有でき、 クライアントは {@link +android.os.Message} オブジェクトを使用してサービスにコマンドを送信できるようになります。 + +さらに、クライアントはサービスがメッセージを返信できるように独自の {@link android.os.Messenger} を定義できます。 + + <p>これは、最も簡単にプロセス間通信(IPC)を実行する方法であり、{@link +android.os.Messenger} がすべてのリクエストを 1 つのスレッドにキューイングするため、サービスをスレッドセーフにデザインする必要がありません。 +</p> + </dd> + + <dt>AIDL を使用する</dt> + <dd>AIDL(Android インターフェース定義言語)は、オブジェクトをオペーレーティングシステムが理解できるプリミティブに分解するためのすべての処理のを実行し、プロセス間でそれを整理して IPC 実行します。{@link android.os.Messenger} を使用する前の方法は、実際には AIDL を基本構造としています。 + + +前述したように、{@link android.os.Messenger} はすべてのクライアントの要求のキューを 1 つのスレッドに作成するため、サービスは要求を一度に受け取ります。 +ただし、サービスで複数の要求を同時に処理する場合は、AIDL を直接使用できます。 + +その場合、サービスがマルチスレッドに対応しており、スレッドセーフで構築されている必要があります。 + <p>AIDL を直接使用するには、プログラミング インターフェースを定義する {@code .aidl} ファイルを作成する必要があります。 +Android SDK ツールはこのファイルを使用して、インターフェースを実装して IPC を処理する抽象クラスを生成し、それをサービス内に拡張できます。 + +</p> + </dd> +</dl> + + <p class="note"><strong>注:</strong> ほとんどのアプリケーションにおいて、マルチスレッド化が必要な点や、結果的により複雑な実装となってしまうことから、AIDL を使ったバインドされたサービスの作成は<strong>お勧めしません</strong>。 + +AIDL はほとんどのアプリケーションに適していないため、このドキュメントではサービスでの AIDL の使用方法については取り上げません。 +どうしても AIDL の直接使用が必要な場合は、「<a href="{@docRoot}guide/components/aidl.html">AIDL</a>」のドキュメントをご覧ください。 + +</p> + + + + +<h3 id="Binder">Binder クラスを拡張する</h3> + +<p>サービスがローカルのアプリケーションでのみ使用されていて、プロセス間での作業が必要ない場合は、クライアントがサービスの public メソッドに直接アクセスできるようにする独自の {@link android.os.Binder} クラスを実装できます。 + +</p> + +<p class="note"><strong>注:</strong> この方法は、クライアントとサービスが同じアプリケーションとプロセスにある場合(最も一般的なケース)のみ使用できます。 +たとえば、バックグラウンドで音楽を再生する独自のサービスに、アクティビティをバインドする必要のある音楽アプリケーションに適しています。 + +</p> + +<p>セットアップ方法は次のとおりです。</p> +<ol> + <li>サービスで次のいずれかに該当する {@link android.os.Binder} のインスタンスを作成します。 + <ul> + <li>クライアントが呼び出せる public メソッドを含んでいる</li> + <li>クライアントが呼び出せる public メソッドのある現在の {@link android.app.Service} インスタンスを返す +</li> + <li>クライアントが呼び出せる public メソッドのあるサービスでホストされた他のクラスのインスタンスを返す +</li> + </ul> + <li>{@link android.os.Binder} のインスタンスを {@link +android.app.Service#onBind onBind()} コールバック メソッドから返します。</li> + <li>クライアントで、{@link android.os.Binder} を {@link +android.content.ServiceConnection#onServiceConnected onServiceConnected()} コールバック メソッドから受け取り、提供されたメソッドを使用してバインドされたサービスを呼び出します。 +</li> +</ol> + +<p class="note"><strong>注:</strong> サービスとクライアントが同じアプリケーションになければならない理由は、クライアントが返されたオブジェクトをキャストでき、その API を適切に呼び出せるようにするためです。 +また、サービスとクライアントが同じプロセスになければならない理由は、この方法ではプロセス間の整理が一切行われないためです。 + +</p> + +<p>以下は、{@link android.os.Binder} の実装を介してサービスのメソッドにクライアントアクセスを提供するサービスの例です。 +</p> + +<pre> +public class LocalService extends Service { + // Binder given to clients + private final IBinder mBinder = new LocalBinder(); + // Random number generator + private final Random mGenerator = new Random(); + + /** + * Class used for the client Binder. Because we know this service always + * runs in the same process as its clients, we don't need to deal with IPC. + */ + public class LocalBinder extends Binder { + LocalService getService() { + // Return this instance of LocalService so clients can call public methods + return LocalService.this; + } + } + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + /** method for clients */ + public int getRandomNumber() { + return mGenerator.nextInt(100); + } +} +</pre> + +<p>{@code LocalBinder} が {@code LocalService} の現在のインスタンスを取り出すための {@code getService()}メソッドをクライアントに提供します。 +これにより、クライアントがサービス内の public メソッドを呼び出せるようになります。 +たとえば、クライアントはサービスから {@code getRandomNumber()} を呼び出すことができます。</p> + +<p>以下は、{@code LocalService} にバインドして、ボタンがクリックされたときに {@code getRandomNumber()} を呼び出すアクティビティの例です。 +</p> + +<pre> +public class BindingActivity extends Activity { + LocalService mService; + boolean mBound = false; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + } + + @Override + protected void onStart() { + super.onStart(); + // Bind to LocalService + Intent intent = new Intent(this, LocalService.class); + bindService(intent, mConnection, Context.BIND_AUTO_CREATE); + } + + @Override + protected void onStop() { + super.onStop(); + // Unbind from the service + if (mBound) { + unbindService(mConnection); + mBound = false; + } + } + + /** Called when a button is clicked (the button in the layout file attaches to + * this method with the android:onClick attribute) */ + public void onButtonClick(View v) { + if (mBound) { + // Call a method from the LocalService. + // However, if this call were something that might hang, then this request should + // occur in a separate thread to avoid slowing down the activity performance. + int num = mService.getRandomNumber(); + Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show(); + } + } + + /** Defines callbacks for service binding, passed to bindService() */ + private ServiceConnection mConnection = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName className, + IBinder service) { + // We've bound to LocalService, cast the IBinder and get LocalService instance + LocalBinder binder = (LocalBinder) service; + mService = binder.getService(); + mBound = true; + } + + @Override + public void onServiceDisconnected(ComponentName arg0) { + mBound = false; + } + }; +} +</pre> + +<p>上の例は、{@link android.content.ServiceConnection} の実装と {@link +android.content.ServiceConnection#onServiceConnected onServiceConnected()} コールバックを使用してクライアントがサービスにバインドする方法を示しています。 +次のセクションでは、サービスへのバインドのプロセスについて詳しく説明していきます。 +</p> + +<p class="note"><strong>注:</strong> 上記の例ではサービスから明示的にアンバウンドしていませんが、すべてのクライアントは適切なタイミング(アクティビティが一時停止したときなど)でアンバウンドする必要があります。 +</p> + +<p>他のサンプル コードについては、<a href="{@docRoot}resources/samples/ApiDemos/index.html">ApiDemos</a> の <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code +LocalService.java}</a> クラスと <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalServiceActivities.html">{@code +LocalServiceActivities.java}</a> クラスをご覧ください。</p> + + + + + +<h3 id="Messenger">メッセンジャーを使用する</h3> + +<div class="sidebox-wrapper"> +<div class="sidebox"> + <h4>AIDL との比較</h4> + <p>IPC を実行する必要がある場合、インターフェースで {@link android.os.Messenger} を使う方が AIDL で実装するよりも簡単です。{@link android.os.Messenger} がすべての呼び出しをサービスにキューイングするのに対して、純粋な AIDL インターフェースでは同時に複数の要求をサービスに送るため、マルチスレッドの処理が必要になるためです。 + + +</p> + <p>ほとんどのアプリケーションにおいて、サービスはマルチスレッドを実行する必要がないため、{@link +android.os.Messenger} を使用することでサービスが一度に 1 つの呼び出しを処理できます。サービスのマルチスレッド化が重視されている場合は、<a href="{@docRoot}guide/components/aidl.html">AIDL</a> を使用してインターフェースを定義してください。 +</p> +</div> +</div> + +<p>リモート プロセスと通信するサービスが必要な場合は、{@link android.os.Messenger} を使用してサービスのインターフェースを提供できます。 +この方法では、AIDL を使用する必要なくプロセス間通信(IPC)を実行できます。 +</p> + +<p>{@link android.os.Messenger} の使用方法の概要は以下のとおりです。</p> + +<ul> + <li>クライアントからの呼び出しごとにコールバックを受け取る{@link android.os.Handler} をサービスが実装します。 +</li> + <li>{@link android.os.Handler} を使用して {@link android.os.Messenger} オブジェクトを作成します( +{@link android.os.Handler} への参照になります)。</li> + <li>{@link android.os.Messenger} が、サービスが {@link android.app.Service#onBind onBind()} からクライアントに返す {@link android.os.IBinder} を作成します。 +</li> + <li>クライアントが {@link android.os.IBinder} を使用して、(サービスの {@link android.os.Handler} を参照する){@link android.os.Messenger} をインスタンス化し、これを使用してクライアントが {@link android.os.Message} オブジェクトをサービスに送ります。 + +</li> + <li>サービスが {@link +android.os.Handler}、具体的には、{@link android.os.Handler#handleMessage +handleMessage()} メソッドで、それぞれの {@link android.os.Message} を受け取ります。—</li> +</ul> + + +<p>この方法には、クライアントがサービスで呼び出す「メソッド」はありません。代わりに、クライアントはサービスが {@link android.os.Handler} で受け取る「メッセージ({@link android.os.Message} オブジェクト)」を配信します。 + +</p> + +<p>以下は、{@link android.os.Messenger} インターフェースを使用するサービスの簡単な例です。</p> + +<pre> +public class MessengerService extends Service { + /** Command to the service to display a message */ + static final int MSG_SAY_HELLO = 1; + + /** + * Handler of incoming messages from clients. + */ + class IncomingHandler extends Handler { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_SAY_HELLO: + Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show(); + break; + default: + super.handleMessage(msg); + } + } + } + + /** + * Target we publish for clients to send messages to IncomingHandler. + */ + final Messenger mMessenger = new Messenger(new IncomingHandler()); + + /** + * When binding to the service, we return an interface to our messenger + * for sending messages to the service. + */ + @Override + public IBinder onBind(Intent intent) { + Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show(); + return mMessenger.getBinder(); + } +} +</pre> + +<p>{@link android.os.Handler} の {@link android.os.Handler#handleMessage handleMessage()} メソッドが、サービスが {@link android.os.Message} を受け取る場所であり、{@link android.os.Message#what} メンバーに基づいてその後の操作を決める場面であることに注目してください。 + +</p> + +<p>クライアントで必要な操作は、サービスから返された {@link +android.os.IBinder} に基づいて {@link android.os.Messenger} を作成し、{@link +android.os.Messenger#send send()} を使用してメッセージを送信するだけです。例として、サービスにバインドして {@code MSG_SAY_HELLO} メッセージをサービスに送信する簡単なアクティビティを次に示します。 +</p> + +<pre> +public class ActivityMessenger extends Activity { + /** Messenger for communicating with the service. */ + Messenger mService = null; + + /** Flag indicating whether we have called bind on the service. */ + boolean mBound; + + /** + * Class for interacting with the main interface of the service. + */ + private ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + // This is called when the connection with the service has been + // established, giving us the object we can use to + // interact with the service. We are communicating with the + // service using a Messenger, so here we get a client-side + // representation of that from the raw IBinder object. + mService = new Messenger(service); + mBound = true; + } + + public void onServiceDisconnected(ComponentName className) { + // This is called when the connection with the service has been + // unexpectedly disconnected -- that is, its process crashed. + mService = null; + mBound = false; + } + }; + + public void sayHello(View v) { + if (!mBound) return; + // Create and send a message to the service, using a supported 'what' value + Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0); + try { + mService.send(msg); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + } + + @Override + protected void onStart() { + super.onStart(); + // Bind to the service + bindService(new Intent(this, MessengerService.class), mConnection, + Context.BIND_AUTO_CREATE); + } + + @Override + protected void onStop() { + super.onStop(); + // Unbind from the service + if (mBound) { + unbindService(mConnection); + mBound = false; + } + } +} +</pre> + +<p>この例では、サービスがクライアントにどのように応答できるのかは示されていません。サービスが応答するようにするには、クライアントで {@link android.os.Messenger} も作成する必要があります。 +その後、クライアントが {@link android.content.ServiceConnection#onServiceConnected +onServiceConnected()} コールバックを受け取るとき、{@link android.os.Messenger#send send()} メソッドの {@link android.os.Message#replyTo} パラメータにクライアントの{@link android.os.Messenger} を含めてサービスに {@link android.os.Message} を送信します。 + + +</p> + +<p>双方向メッセージを提供する方法のサンプルについては、<a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerService.html">{@code +MessengerService.java}</a>(サービス)と <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerServiceActivities.html">{@code +MessengerServiceActivities.java}</a>(クライアント)のサンプルをご覧ください。</p> + + + + + +<h2 id="Binding">サービスにバインドする</h2> + +<p>アプリケーションのコンポーネント(クライアント)は、{@link android.content.Context#bindService bindService()} を呼び出してサービスにバインドできます。 +次に Android システムがサービスの {@link android.app.Service#onBind +onBind()} メソッドを呼び出し、そこからサービスとのやり取りに必要な {@link android.os.IBinder} が返されます。 +</p> + +<p>バインドは非同期的に行われます。{@link android.content.Context#bindService +bindService()} は瞬時に返され、{@link android.os.IBinder} はクライアントには<em>返されません</em>。 +{@link android.os.IBinder} を受け取るには、クライアントが {@link +android.content.ServiceConnection} のインスタンスを作成し、それを {@link android.content.Context#bindService +bindService()} に渡す必要があります。{@link android.content.ServiceConnection} にはシステムが {@link android.os.IBinder} の配信用に呼び出すコールバック メソッドが含まれています。 +</p> + +<p class="note"><strong>注:</strong> サービスにバインドできるのは、アクティビティ、サービス、コンテンツ プロバイダのみです。ブロードキャスト レシーバーからサードパーティビスにはバインド<strong>できません</strong>。 +—</p> + +<p>そのため、クライアントからサービスにバインドするには次の操作が必要です。 </p> +<ol> + <li>{@link android.content.ServiceConnection} を実装する。 + <p>実装では次の 2 つのコールバック メソッドをオーバーライドする必要があります。</p> + <dl> + <dt>{@link android.content.ServiceConnection#onServiceConnected onServiceConnected()}</dt> + <dd>システムがこれを呼び出して、サービスの {@link android.app.Service#onBind onBind()} メソッドから返された {@link android.os.IBinder} を配信します。 +</dd> + <dt>{@link android.content.ServiceConnection#onServiceDisconnected +onServiceDisconnected()}</dt> + <dd>サービスがクラッシュしたり強制終了されたりした場合など、サービスへの接続が予期せず失われたときに、Android システムがこれを呼び出します。 +これは、クライアントのアンバウンドの際には<em>呼び出されません</em>。 +</dd> + </dl> + </li> + <li>{@link +android.content.Context#bindService bindService()} を呼び出して、{@link +android.content.ServiceConnection} の実装を渡します。 </li> + <li>システムが {@link android.content.ServiceConnection#onServiceConnected +onServiceConnected()} コールバック メソッドを呼び出すと、インターフェースで定義されたメソッドを使用してサービスへの呼び出しを開始できます。 +</li> + <li>サービスとの接続を切断するには、{@link +android.content.Context#unbindService unbindService()} を呼び出します。 + <p>クライアントが破棄されたときにはサービスからアンバウンドしますが、サービスが使用されていないときはシャットダウンできるよう、サービスとのやり取りが終了したときや、アクティビティが停止したときは常にアンバウンドする必要があります + +(バインドとアンバインドの適切なタイミングについては後半でさらに詳しく説明します)。 +</p> + </li> +</ol> + +<p>たとえば、次のスニペットは <a href="#Binder"> Binder クラスを拡張</a>して先ほど作成したサービスにクライアントを接続しており、返された {@link android.os.IBinder} を {@code LocalService} クラスにキャストして、{@code +LocalService} インスタンスを要求することだけが必要になります。 + +</p> + +<pre> +LocalService mService; +private ServiceConnection mConnection = new ServiceConnection() { + // Called when the connection with the service is established + public void onServiceConnected(ComponentName className, IBinder service) { + // Because we have bound to an explicit + // service that is running in our own process, we can + // cast its IBinder to a concrete class and directly access it. + LocalBinder binder = (LocalBinder) service; + mService = binder.getService(); + mBound = true; + } + + // Called when the connection with the service disconnects unexpectedly + public void onServiceDisconnected(ComponentName className) { + Log.e(TAG, "onServiceDisconnected"); + mBound = false; + } +}; +</pre> + +<p>この {@link android.content.ServiceConnection} を使用して、クライアントは {@link android.content.Context#bindService bindService()} に渡すことでサービスにバインドできます。 +次に例を示します。</p> + +<pre> +Intent intent = new Intent(this, LocalService.class); +bindService(intent, mConnection, Context.BIND_AUTO_CREATE); +</pre> + +<ul> + <li>{@link android.content.Context#bindService bindService()} の最初のパラメータは、バインドするサービス名を明示的に指定する {@link android.content.Intent} です(インテントは暗黙的である場合があります)。 + +</li> +<li>2 つ目のパラメータは {@link android.content.ServiceConnection} オブジェクトです。</li> +<li>3 つ目のパラメータはバインドのオプションを示すフラグです。通常は {@link +android.content.Context#BIND_AUTO_CREATE} でサービスがまだ存在していない場合にサービスを作成します。他の有効な値は、{@link android.content.Context#BIND_DEBUG_UNBIND} と {@link android.content.Context#BIND_NOT_FOREGROUND} か、未指定の {@code 0} です。 + +</li> +</ul> + + +<h3>その他の注意点</h3> + +<p>サービスへのバインドに関する重要な注意点は次のとおりです。</p> +<ul> + <li>接続が切れたときに投げられる {@link android.os.DeadObjectException} 例外は、常に処理する必要があります。 +リモート メソッドから投げられる例外はこれのみです。</li> + <li>オブジェクトはプロセス間で有効な参照です。 </li> + <li>通常は、クライアントのライフサイクルの立ち上がりと終了のタイミングに合わせて、その間でバインドとアンバインドをペア設定します。 +次に例を示します。 + <ul> + <li>アクティビティが見えている間のみサービスとやり取りする必要がある場合は、 +{@link android.app.Activity#onStart onStart()} の間にバインドし、{@link +android.app.Activity#onStop onStop()} の間にアンバインドします。</li> + <li>アクティビティがバックグラウンドで停止している間も応答を受け取りたい場合は、{@link android.app.Activity#onCreate onCreate()} の間にバインドし、{@link android.app.Activity#onDestroy onDestroy()} の間にアンバインドします。 + +つまり、アクティビティの実行中は(バックグラウンドも含む)常にサービスを使用する必要があるため、サービスが別のプロセスにある場合は、プロセスの重みを上げて、システムに強制終了させやすいようにします。 + + +</li> + </ul> + <p class="note"><strong>注:</strong> 通常、アクティビティの {@link android.app.Activity#onResume onResume()} と {@link +android.app.Activity#onPause onPause()} の間にはバインドとアンバインドは<strong>行いません</strong>。これは、これらのコールバックがライフサイクルの遷移すべてで発生するため、その遷移で発生するプロセスを最小限に抑える必要があるためです。 + +また、アプリケーションの複数のアクティビティが同一サービスにバインドしていて、そのなかの 2 つのアクティビティ間の遷移が生じる場合、現在のアクティビティは次のアクティビティがバインドする(再開中)前にアンバインドされる(停止中)ため、サービスが破棄されて再作成される場合があります + + +(ライフサイクルと連携したアクティビティの遷移の詳細については、「<a href="{@docRoot}guide/components/activities.html#CoordinatingActivities">Activities</a>」のドキュメントをご覧ください)。 + +</p> +</ul> + +<p>他のサンプル コードについては、 <a href="{@docRoot}resources/samples/ApiDemos/index.html">ApiDemos</a> の <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">{@code +RemoteService.java}</a> クラスをご覧ください。</p> + + + + + +<h2 id="Lifecycle">バインドされたサービスのライフサイクルを管理する</h2> + +<p>サービスがすべてのクライアントからアンバインドされると、Android システムがそれを破棄します({@link android.app.Service#onStartCommand onStartCommand()} でも開始された場合を除く)。 +純粋にバインドされたサービスであれば、サービスのライフサイクルを管理する必要はありません。サービスがクライアントにバインドされているかどうかに基づいて Android システムがそれを管理します。 + +—</p> + +<p>ただし、{@link android.app.Service#onStartCommand +onStartCommand()} コールバック メソッドを実装する場合は、サービスは <em>開始された</em>とみなされるため、明示的に停止する必要があります。 +この場合、クライアントにバインドされているかどうかにかかわらず、サービスが {@link android.app.Service#stopSelf()} で自ら停止するまで、または他のコンポーネントが {@link +android.content.Context#stopService stopService()} を呼び出すまで実行し続けます。 + +</p> + +<p>さらに、サービスが開始されてバインドを許可する場合、システムが {@link android.app.Service#onUnbind onUnbind()} メソッドを呼び出すとき、次回クライアントがサービスにバインドするときに {@link android.app.Service#onRebind +onRebind()} への呼び出しを受け取りたい場合は、{@code true} を返すようにすることもできます({@link +android.app.Service#onBind onBind()} への呼び出しを受け取る代わりに)。{@link android.app.Service#onRebind +onRebind()} からは void が返されますが、クライアントは {@link android.content.ServiceConnection#onServiceConnected onServiceConnected()} コールバックで {@link android.os.IBinder} を受け取ります。下の図 1 は、ライフサイクルのこの種の論理を表しています。 + + + +</p> + + +<img src="{@docRoot}images/fundamentals/service_binding_tree_lifecycle.png" alt="" /> +<p class="img-caption"><strong>図 1.</strong> 開始されたサービスでバインドを許可するサービスのライフサイクル +</p> + + +<p>開始されたサービスのライフサイクルの詳細については、「<a href="{@docRoot}guide/components/services.html#Lifecycle">サービス</a>」のドキュメントをご覧ください。</p> + + + + diff --git a/docs/html-intl/intl/ja/guide/components/fragments.jd b/docs/html-intl/intl/ja/guide/components/fragments.jd new file mode 100644 index 000000000000..31fb7f5020b2 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/components/fragments.jd @@ -0,0 +1,812 @@ +page.title=フラグメント +parent.title=アクティビティ +parent.link=activities.html +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + <h2>本書の内容</h2> + <ol> + <li><a href="#Design">デザインの指針</a></li> + <li><a href="#Creating">フラグメントを作成する</a> + <ol> + <li><a href="#UI">ユーザー インターフェースを追加する</a></li> + <li><a href="#Adding">フラグメントをアクティビティに追加する</a></li> + </ol> + </li> + <li><a href="#Managing">フラグメントを管理する</a></li> + <li><a href="#Transactions">フラグメントのトランザクションを実行する</a></li> + <li><a href="#CommunicatingWithActivity">アクティビティと通信する</a> + <ol> + <li><a href="#EventCallbacks">アクティビティへのイベント コールバックを作成する</a></li> + <li><a href="#ActionBar">アクションバーにアイテムを追加する</a></li> + </ol> + </li> + <li><a href="#Lifecycle">フラグメントのライフサイクルを処理する</a> + <ol> + <li><a href="#CoordinatingWithActivity">アクティビティのライフサイクルと連携する</a></li> + </ol> + </li> + <li><a href="#Example">例</a></li> + </ol> + + <h2>キークラス</h2> + <ol> + <li>{@link android.app.Fragment}</li> + <li>{@link android.app.FragmentManager}</li> + <li>{@link android.app.FragmentTransaction}</li> + </ol> + + <h2>関連ドキュメント</h2> + <ol> + <li><a href="{@docRoot}training/basics/fragments/index.html">Building a Dynamic UI with Fragments</a></li> + <li><a href="{@docRoot}guide/practices/tablets-and-handsets.html">Supporting Tablets +and Handsets</a></li> + </ol> +</div> +</div> + +<p>{@link android.app.Fragment} は、{@link android.app.Activity} でのユーザー インターフェースの挙動や部位を表すものです。 +1 つのアクティビティに複数のフラグメントを組み合わせてマルチペインの UI をビルドしたり、複数のアクティビティでフラグメントを再利用したりできます。 +フラグメントとは、アクティビティのモジュール型セクションのようなもので、独自のライフサイクルを持ち、独自の入力イベントを受信します。フラグメントはアクティビティの実行中に追加したり削除したりできます(別のアクティビティで再利用できる「サブ アクティビティ」のようなものです)。 + + +</p> + +<p>フラグメントは常にアクティビティに埋め込まれている必要があり、フラグメントのライフサイクルはホストのアクティビティのライフサイクルの影響を直接受けます。 +たとえば、アクティビティが一時停止しているとき、その中のすべてのフラグメントも一時停止し、アクティビティが破棄されると、すべてのフラグメントも破棄されます。 +ただし、アクティビティの実行中(<a href="{@docRoot}guide/components/activities.html#Lifecycle">ライフサイクル</a>で<em>再開</em>された状態)は、追加や削除といった操作は各フラグメントだけで行うことができます。 + +このようなフラグメントのトランザクションを実行するとき、アクティビティで管理されているバックスタックにそれを追加することもできます。アクティビティの各バックスタック エントリは、発生したフラグメントのトランザクションの記録になります。 + +— +バックスタックでは、[<em>戻る</em>] ボタンを押すとフラグメントのトランザクションを戻す(前に戻る)ことができます。 +</p> + +<p>アクティビティのレイアウトの一部としてフラグメントを追加すると、フラグメントはアクティビティのビュー階層の {@link +android.view.ViewGroup} に置かれ、フラグメントが自身のビュー レイアウトを定義します。フラグメントをアクティビティのレイアウトに挿入するには、アクティビティのレイアウト ファイルでフラグメントを {@code <fragment>} として定義するか、アプリケーション コードで既存の {@link android.view.ViewGroup} に追加します。 + + + +ただし、フラグメントは必ずしもアクティビティの一部になる必要はなく、アクティビティの目に見えないワーカーとして、フラグメント独自の UI なしで使用することもできます。 + +</p> + +<p>このドキュメントでは、アクティビティのバックスタックに追加した時のフラグメントの状態を維持する方法、アクティビティ内でアクティビティと他のフラグメントとイベントを共有する方法、アクティビティのアクションバーへの影響など、フラグメントを使用してアプリケーションをビルドする方法について説明します。 + + +</p> + + +<h2 id="Design">デザインの指針</h2> + +<p>Android では、タブレットなどの大画面でのよりダイナミックで柔軟な UI デザインに対応するため、Android 3.0(API レベル 11)でフラグメントが採用されました。 +タブレットの画面はハンドセットよりもかなり大きいため、UI コンポーネントを組み合わせたり入れ替えたりできる領域が広くなります。 + +フラグメントでは、ビュー階層に複雑な変更を加えることなく、そのようなデザインを実現できます。 +アクティビティのレイアウトをフラグメントに分割することで、アクティビティの外観を実行時に変更でき、それらの変更をアクティビティが管理するバックスタックに保持できます。 + +</p> + +<p>たとえば新しいアプリケーションでは、1 つのフラグメントを使って左側に記事の一覧を表示したり、別のフラグメントを使って右側に記事の内容を表示したりできます。両方のフラグメントが 1 つのアクティビティに横並びに表示され、それぞれのフラグメントには自身のライフサイクル メソッドがあり、それぞれのユーザー入力イベントを処理します。 +— + +つまり、1 つのアクティビティで記事を選択して、別のアクティビティで記事を閲覧するのではなく、図 1 のタブレットのレイアウトのように 1 つのアクティビティ内で記事を選択して閲覧できるようになります。 + +</p> + +<p>各フラグメントはモジュール型の、再利用可能なアクティビティ コンポーネントとしてデザインする必要があります。各フラグメントは独自のライフサイクル コールバックを使用して自身のレイアウトと挙動とを定義するため、1 つのフラグメントを複数のアクティビティに含めることができます。このことから、再利用可能なデザインを用いることに加えて、1 つのフラグメントを他のフラグメントから直接操作しないようにする必要があります。 + + +これは、モジュール型のフラグメントでは画面のサイズごとにフラグメントの組み合わせを変更できる点からも、特に重要です。 +タブレットとハンドセットの両方に対応したアプリケーションをデザインする場合、異なるレイアウト構成でフラグメントを再利用することで、利用可能な画面の領域に応じて最適な使い心地を実現できます。 + +たとえばハンドセットの場合、同一のアクティビティ内に 2 つ以上のフラグメントが収まりきらないときは、フラグメントを分割してシングルペインの UI を提示する必要があることもあります。 + +</p> + +<img src="{@docRoot}images/fundamentals/fragments.png" alt="" /> +<p class="img-caption"><strong>図 1.</strong> 1 つのアクティビティ内で、フラグメントで定義された 2 つの UI モジュールを組み合わせたタブレット用デザインと、それぞれを分けたハンドセット用デザインの例。 + +</p> + +<p>引き続きニュース アプリケーションの例を使うと、アプリケーションがタブレット サイズの端末で実行中は、 2 つのフラグメントを<em>アクティビティ A</em> に埋め込むことができます。—— +しかし、ハンドセット サイズの画面では両方のフラグメントを表示する領域が足りないため、<em>アクティビティ A</em> には記事の一覧のフラグメントだけが含まれます。記事を選択すると、記事を閲覧するための 2 つ目のフラグメントが含まれる<em>アクティビティ B</em> が開始されます。 + + +そのため、図 1 のようにアプリケーションはフラグメントを異なる組み合わせで再利用することで、タブレットとハンドセットの両方に対応できるようになります。 + +</p> + +<p>異なる画面構成ごとに異なるフラグメントの組み合わせを用いたアプリケーションのデザインの詳細については、「<a href="{@docRoot}guide/practices/tablets-and-handsets.html">Supporting Tablets and Handsets</a>」のガイドをご覧ください。 +</p> + + + +<h2 id="Creating">フラグメントを作成する</h2> + +<div class="figure" style="width:327px"> +<img src="{@docRoot}images/fragment_lifecycle.png" alt="" /> +<p class="img-caption"><strong>図 2.</strong> フラグメントのライフサイクル(アクティビティの実行中) +</p> +</div> + +<p>フラグメントを作成するには、{@link android.app.Fragment} のサブクラス(またはその既存のサブクラス)を作成する必要があります。 +{@link android.app.Fragment} クラスには、{@link android.app.Activity} に非常に似ているコードがあります。 +これには、{@link android.app.Fragment#onCreate onCreate()}、{@link android.app.Fragment#onStart onStart()}、{@link android.app.Fragment#onPause onPause()}、{@link android.app.Fragment#onStop onStop()} のようなアクティビティと同様のコールバック メソッドが含まれています。 + +実際に、既存の Android アプリケーションを変換してフラグメントを使用するには、アクティビティのコールバック メソッドから、フラグメントの各コールバック メソッドにコードを移動させるだけで。 + + +</p> + +<p>通常は、少なくとも次のライフサイクル メソッドを実装する必要があります。</p> + +<dl> + <dt>{@link android.app.Fragment#onCreate onCreate()}</dt> + <dd>フラグメントの作成時にシステムが呼び出します。実装内で、フラグメントが一時停止、停止、再開されたときに保持するフラグメントの必須コンポーネントを初期化する必要があります。 + +</dd> + <dt>{@link android.app.Fragment#onCreateView onCreateView()}</dt> + <dd>フラグメントが初めてユーザー インターフェースを描画するタイミングでシステムがこれを呼び出します。 +フラグメントの UI を描画するには、このメソッドからフラグメントのレイアウトのルートとなっている {@link android.view.View} を返す必要があります。 +フラグメントが UI を提示しない場合は、null を返すことができます。 +</dd> + <dt>{@link android.app.Activity#onPause onPause()}</dt> + <dd>ユーザーがフラグメントから離れたことを初めて示すときに、このメソッドを呼び出します(フラグメントが破棄されていない場合も含む)。 +通常はここで、現在のユーザー セッション後も維持する必要のある変更点を保存しておきます(ユーザーが戻ってこない可能性があるため)。 + +</dd> +</dl> + +<p>ほとんどのアプリケーションでは、各フラグメントで少なくともこれら 3 つのメソッドを実装する必要がありますが、フラグメントのライフサイクルのさまざまなステージを処理する際に使用する他のコールバック メソッドもいくつかあります。 + +すべてのライフサイクル コールバック メソッドについては、<a href="#Lifecycle">フラグメントのライフサイクルの処理</a>のセクションで説明します。 +</p> + + +<p>基本の {@link +android.app.Fragment} クラスの代わりに拡張できるサブクラスもいくつかあります。</p> + +<dl> + <dt>{@link android.app.DialogFragment}</dt> + <dd>フローティング ダイアログを表示します。{@link android.app.Activity} のダイアログ ヘルパー メソッド代わりにこのクラスを使用してダイアログを作成すると、アクティビティで管理されるフラグメントのバックスタックにフラグメント ダイアログを組み込むことができるため、ユーザーは終了したフラグメントに戻ることが可能になります。 + + +</dd> + + <dt>{@link android.app.ListFragment}</dt> + <dd>{@link android.app.ListActivity} と同様に、アダプタで管理されるアイテムのリストを表示します({@link +android.widget.SimpleCursorAdapter} など)。クリック イベントを処理するための {@link +android.app.ListFragment#onListItemClick(ListView,View,int,long) onListItemClick()} コールバックなど、リスト ビューを管理するメソッドがいくつか提供されます。 + +</dd> + + <dt>{@link android.preference.PreferenceFragment}</dt> + <dd>{@link android.preference.PreferenceActivity} と同様に、{@link android.preference.Preference} オブジェクトの階層をリストとして表示します。 +アプリケーションの「設定」アクティビティの作成時に便利です。 +</dd> +</dl> + + +<h3 id="UI">ユーザー インターフェースを追加する</h3> + +<p>通常、フラグメントはアクティビティのユーザー インターフェースの一部であり、独自のレイアウトをアクティビティに提示します。 +</p> + +<p>フラグメントのレイアウトを提供するには、{@link +android.app.Fragment#onCreateView onCreateView()} コールバック メソッドを実装する必要があります。これは、フラグメントがレイアウトを描画するタイミングで Android システムが呼び出します。 +このメソッドの実装では、フラグメントのレイアウトのルートである {@link android.view.View} を返す必要があります。 +</p> + +<p class="note"><strong>注:</strong> フラグメントは {@link +android.app.ListFragment} のサブクラスの場合、デフォルトの実装で {@link android.widget.ListView} が{@link android.app.Fragment#onCreateView onCreateView()} から返されるため、これを実装する必要はありません。 +</p> + +<p>{@link +android.app.Fragment#onCreateView onCreateView()} からレイアウトを返すには、XML で定義した<a href="{@docRoot}guide/topics/resources/layout-resource.html">レイアウト リソース</a>からインフレートできます。これを行うため、{@link android.app.Fragment#onCreateView onCreateView()} から {@link android.view.LayoutInflater} オブジェクトが提供されます。 + +</p> + +<p>たとえば、次の例では {@link android.app.Fragment} のサブクラスが {@code example_fragment.xml} ファイルからレイアウトをロードします。 +</p> + +<pre> +public static class ExampleFragment extends Fragment { + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.example_fragment, container, false); + } +} +</pre> + +<div class="sidebox-wrapper"> +<div class="sidebox"> + <h3>レイアウトを作成する</h3> + <p>上の例では、{@code R.layout.example_fragment} はアプリケーション リソースに保存されている {@code example_fragment.xml} という名前のレイアウト リソースへの参照です。 +XML でレイアウトを作成する方法の詳細いついては、「<a href="{@docRoot}guide/topics/ui/index.html">ユーザー インターフェース</a>」のドキュメントをご覧ください。 + +</p> +</div> +</div> + +<p>{@link android.app.Fragment#onCreateView +onCreateView()} に渡される {@code container} パラメータは、フラグメントのレイアウトが挿入される {@link android.view.ViewGroup} の親になります(アクティビティのレイアウトから)。 + +{@code savedInstanceState} パラメータは、フラグメントが再開された場合にフラグメントの前のインスタンスに関する情報を提供する {@link android.os.Bundle} です(状態の復元の詳細については、<a href="#Lifecycle">フラグメントのライフサイクルの処理</a>で説明します)。 + + +</p> + +<p>{@link android.view.LayoutInflater#inflate(int,ViewGroup,boolean) inflate()} メソッドは、次の 3 つの引数を受け取ります。 +</p> +<ul> + <li>拡張するレイアウトのリソース ID。</li> + <li>インフレートされたレイアウトの親となる {@link android.view.ViewGroup}。システムがインフレートされたレイアウトのルートビュー(親ビューが指定)にレイアウト パラメータ適用するには、{@code +container} を渡すことが重要です。 +</li> + <li>インフレート中に、インフレートされたレイアウトを {@link +android.view.ViewGroup}(2 つ目のパラメータ)にアタッチすべきかどうかを示すブール値(この場合、システムが既にインフレートされたレイアウトを {@code +container} に挿入しているため、false になります。true を渡すと、最終レイアウトに余分なビューグループが作成されます。 +—</li> +</ul> + +<p>ここまで、レイアウトを提供するフラグメントの作成方法について説明しました。次は、フラグメントをアクティビティに追加する必要があります。 +</p> + + + +<h3 id="Adding">フラグメントをアクティビティに追加する</h3> + +<p>通常、フラグメントはホスト アクティビティに UI の一部を提供し、アクティビティの全体的なビュー階層の一部として埋め込まれます。 +アクティビティのレイアウトにフラグメントを追加する方法は 2 つあります。 +</p> + +<ul> + <li><b>アクティビティのレイアウト ファイル内でフラグメントを宣言する</b> +<p>この場合、フラグメントがビューであるかのようにレイアウト プロパティを指定できます。 +以下は、2 つのフラグメントを持つアクティビティのレイアウト ファイルです。 +</p> +<pre> +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <fragment android:name="com.example.news.ArticleListFragment" + android:id="@+id/list" + android:layout_weight="1" + android:layout_width="0dp" + android:layout_height="match_parent" /> + <fragment android:name="com.example.news.ArticleReaderFragment" + android:id="@+id/viewer" + android:layout_weight="2" + android:layout_width="0dp" + android:layout_height="match_parent" /> +</LinearLayout> +</pre> + <p>{@code <fragment>} の {@code android:name} 属性は、{@link +android.app.Fragment} クラスを指定してレイアウトにインスタンスを作成します。</p> + +<p>システムがこのアクティビティ レイアウトを作成するとき、レイアウトで指定された各フラグメントのインスタンスを作成し、それぞれの {@link android.app.Fragment#onCreateView onCreateView()} メソッドを呼び出して、各フラグメントのレイアウトを取得します。 + +システムがフラグメントから返された{@link android.view.View} を {@code <fragment>} 要素の代わりに挿入します。 +</p> + +<div class="note"> + <p><strong>注:</strong> 各フラグメントには、アクティビティの再開時にフラグメントを復元するためにシステムが使用できる(そしてフラグメントをキャプチャして削除などのトランザクションを実行する際に使用できる)一意の識別子が必要です + +フラグメントの ID を提供するには、次の 3 つの方法があります。 +</p> + <ul> + <li>{@code android:id} 属性に一意の ID を提供する。</li> + <li>{@code android:tag} 属性に一意の文字列を提供する。</li> + <li>上記のいずれも提供しない場合、システムはコンテナビューの ID を使用します。 +</li> + </ul> +</div> + </li> + + <li><b>または、既存の {@link android.view.ViewGroup} にプログラムを使用してフラグメントを追加します</b>。 +<p>アクティビティの実行中は、いつでもフラグメントをアクティビティ レイアウトに追加できます。必要なのは、フラグメントを配置する場所に {@link +android.view.ViewGroup} を指定するだけです。 +</p> + <p>アクティビティ内にフラグメントのトランザクション(フラグメントの追加、削除、置換など)を作るには、{@link android.app.FragmentTransaction} からの API を使用する必要があります。 +{@link android.app.FragmentTransaction} のインスタンスは、{@link android.app.Activity} から次のようにして取得できます。 +</p> + +<pre> +FragmentManager fragmentManager = {@link android.app.Activity#getFragmentManager()} +FragmentTransaction fragmentTransaction = fragmentManager.{@link android.app.FragmentManager#beginTransaction()}; +</pre> + +<p>次に、{@link +android.app.FragmentTransaction#add(int,Fragment) add()} メソッドを使用して、追加するフラグメントと挿入するビューを指定してフラグメントを追加できます。 +次に例を示します。</p> + +<pre> +ExampleFragment fragment = new ExampleFragment(); +fragmentTransaction.add(R.id.fragment_container, fragment); +fragmentTransaction.commit(); +</pre> + + <p>{@link android.app.FragmentTransaction#add(int,Fragment) add()} に渡される最初の引数はフラグメントを配置する {@link android.view.ViewGroup} でリソース ID で指定されており、2 つ目のパラメータは追加するフラグメントです。 + +</p> + <p>{@link android.app.FragmentTransaction} で変更を加えたら、{@link android.app.FragmentTransaction#commit} を呼び出して変更を適用する必要があります。 + +</p> + </li> +</ul> + + +<h4 id="AddingWithoutUI">UI のないフラグメントを追加する</h4> + +<p>上の例では、UI を提供するためにフラグメントをアクティビティに追加する方法を紹介しましたが、UI を提示せずにアクティビティのバックグラウンド動作を提供するためにフラグメントを使うこともできます。 + +</p> + +<p>UI のないフラグメントを追加するには、{@link +android.app.FragmentTransaction#add(Fragment,String)} を使用してアクティビティからフラグメントを追加します(ビュー ID ではなくフラグメントの一意の文字列である「タグ」を提供します)。 +これでフラグメントが追加されますが、アクティビティ レイアウトのビューには関連付けられていないため、{@link +android.app.Fragment#onCreateView onCreateView()} への呼び出しは受け取りません。 +そのため、このメソッドを実装する必要はありません。</p> + +<p>フラグメントに文字列のタグを提供するのは UI のないフラグメントの場合だけではありません。UI のあるフラグメントにも文字列のタグを提供することはできますが、UI のないフラグメントにとっては、文字列のタグがフラグメントを識別する唯一の手段になります。— +— +後でアクティビティからフラグメントを取得する場合は、 {@link android.app.FragmentManager#findFragmentByTag +findFragmentByTag()} を使用する必要があります。 +</p> + +<p>たとえば、フラグメントを UI を持たないバックグラウンド ワーカーとして使用するアクティビティの場合は、SDK サンプルに含まれている(Android SDK マネージャーで利用可能){@code +FragmentRetainInstance.java} のサンプルでシステムに <code><sdk_root>/APIDemos/app/src/main/java/com/example/android/apis/app/FragmentRetainInstance.java</code> として置かれているものをご覧ください。 + +</p> + + + +<h2 id="Managing">フラグメントを管理する</h2> + +<p>アクティビティのフラグメントを管理するには、{@link android.app.FragmentManager} を使用する必要があります。フラグメントを取得するには、アクティビティから {@link android.app.Activity#getFragmentManager()} を呼び出します。 +</p> + +<p>{@link android.app.FragmentManager} では、次の操作が可能です。</p> + +<ul> + <li>{@link +android.app.FragmentManager#findFragmentById findFragmentById()}(アクティビティ レイアウトで UI を提供するフラグメントの場合)や {@link android.app.FragmentManager#findFragmentByTag +findFragmentByTag()}(UI を提供しないフラグメントの場合)を使用して、アクティビティにあるフラグメントを取得する。 +</li> + <li>{@link +android.app.FragmentManager#popBackStack()} を使用してフラグメントをバックスタックから取り出す(ユーザーによる [<em>戻る</em>] コマンドをシミュレートする)。</li> + <li>{@link +android.app.FragmentManager#addOnBackStackChangedListener addOnBackStackChangedListener()} を使用して、バックスタックの変更に対するリスナを登録する。</li> +</ul> + +<p>これらのメソッドや他のメソッドの詳細については、{@link +android.app.FragmentManager} クラスのドキュメントをご覧ください。</p> + +<p>前のセクションで説明したように、{@link android.app.FragmentManager} を使用して {@link android.app.FragmentTransaction} を開くことで、フラグメントの追加や削除といったトランザクションを実行することもできます。 + +</p> + + +<h2 id="Transactions">フラグメントのトランザクションを実行する</h2> + +<p>アクティビティでのフラグメントの使用における優れた機能として、フラグメントを追加、削除、置換したり、ユーザー操作への応答にフラグメントを使用して他のアクションを実行したりできる点が挙げられます。 +アクティビティに加える変更はそれぞれ 1 つのトランザクションとして、{@link +android.app.FragmentTransaction} の API を使用して実行できます。 +各トランザクションはアクティビティが管理するバックスタックに保存でき、ユーザーはフラグメントの変更を元に戻すことができます(アクティビティ間で元に戻す動作と似ています)。 + +</p> + +<p>{@link android.app.FragmentTransaction} のインスタンスは、次のように {@link +android.app.FragmentManager} から作成できます。</p> + +<pre> +FragmentManager fragmentManager = {@link android.app.Activity#getFragmentManager()}; +FragmentTransaction fragmentTransaction = fragmentManager.{@link android.app.FragmentManager#beginTransaction()}; +</pre> + +<p>各トランザクションは、同時に実行する一連の変更点です。{@link +android.app.FragmentTransaction#add add()}、{@link android.app.FragmentTransaction#remove remove()}、{@link android.app.FragmentTransaction#replace replace()} などのメソッドを使って、トランザクションで実行するすべての変更点をセットアップできます。 + +次に、トランザクションをアクティビティに適用するには、{@link android.app.FragmentTransaction#commit()} を呼び出す必要があります。 +</p> +</dl> + +<p>ただし、{@link +android.app.FragmentTransaction#commit()} を呼び出す前に、{@link +android.app.FragmentTransaction#addToBackStack addToBackStack()} を呼び出して、フラグメントのトランザクションのバックスタックにトランザクションを追加することもできます。 +このバックスタックはアクティビティによって管理され、ユーザーが [<em>戻る</em>] ボタンを押して前のフラグメントの状態に戻れるようにします。 +</p> + +<p>例として、フラグメントを別のフラグメントに置き換えて、バックスタックで前の状態を保持する方法を次に示します。 +</p> + +<pre> +// Create new fragment and transaction +Fragment newFragment = new ExampleFragment(); +FragmentTransaction transaction = getFragmentManager().beginTransaction(); + +// Replace whatever is in the fragment_container view with this fragment, +// and add the transaction to the back stack +transaction.replace(R.id.fragment_container, newFragment); +transaction.addToBackStack(null); + +// Commit the transaction +transaction.commit(); +</pre> + +<p>この例では、{@code R.id.fragment_container} ID で識別されるレイアウト コンテナに現在あるフラグメント(存在する場合)を {@code newFragment} が置き換えます。{@link +android.app.FragmentTransaction#addToBackStack addToBackStack()} を呼び出すと、置き換えのトランザクションがバックスタックに保存されるため、ユーザーはトランザクションを元に戻して、[<em>戻る</em>] ボタンを押すことで前のフラグメントに戻れるようになります。 + + +</p> + +<p>トランザクションに複数の変更を加えて({@link +android.app.FragmentTransaction#add add()} や {@link android.app.FragmentTransaction#remove +remove()} など)、{@link +android.app.FragmentTransaction#addToBackStack addToBackStack()} を呼び出した場合、{@link android.app.FragmentTransaction#commit commit()} を呼び出す前に適用されたすべての変更点が 1 つのトランザクションとしてバックスタックに追加され、[<em>戻る</em>] ボタンを押すとすべてが同時に元に戻るようになります。 + +</p> + +<p>次の場合を除き、{@link android.app.FragmentTransaction} に加える変更の順序は影響しません。 +</p> +<ul> + <li>{@link android.app.FragmentTransaction#commit()} は最後に呼び出す必要があります。</li> + <li>複数のフラグメントを同じコンテナに追加する場合、追加する順序がビュー階層に表示される順序になります。 +</li> +</ul> + +<p>フラグメントを削除するトランザクションの実行時に {@link android.app.FragmentTransaction#addToBackStack(String) +addToBackStack()} を呼び出さない場合、トランザクションの実行時にそのフラグメントは破棄され、ユーザーは操作を元に戻すことができなくなります。 +一方で、フラグメントの削除時に {@link android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} を呼び出した場合、フラグメントは<em>停止</em>状態になり、ユーザーが元に戻した時に再開します。 + + +</p> + +<p class="note"><strong>ヒント:</strong> それぞれのフラグメントのトランザクションでは、コミットする前に {@link android.app.FragmentTransaction#setTransition setTransition()} と呼ばれる遷移のアニメーションを適用できます。 + +</p> + +<p>{@link android.app.FragmentTransaction#commit()} を呼び出してもトランザクションはすぐには実行されません。 +具体的には、アクティビティの UI スレッド(「メイン」スレッド)で実行可能になったときにすぐに実行されるようスケジュールされます。 +ただし、必要であれば UI スレッドから {@link +android.app.FragmentManager#executePendingTransactions()} を呼び出して、{@link android.app.FragmentTransaction#commit()} から送信されたトランザクションをすぐに実行することもできます。 +通常、トランザクションが他のスレッドのジョブに依存していない限り、この操作は必要ありません。 +</p> + +<p class="caution"><strong>警告:</strong> {@link +android.app.FragmentTransaction#commit commit()} を使用したトランザクションをコミットできるのは、アクティビティが<a href="{@docRoot}guide/components/activities.html#SavingActivityState">状態を保存</a>する前(ユーザーがアクティビティを離れるとき)にのみに限定されます。 +それ以降にコミットしようとすると、例外がスローされます。 +これは、アクティビティの復元が必要な場合に、コミット後のステータスが失われてしまう可能性があるためです。 +コミットが失われてもよい場合は、{@link +android.app.FragmentTransaction#commitAllowingStateLoss()} を使用します。</p> + + + + +<h2 id="CommunicatingWithActivity">アクティビティと通信する</h2> + +<p>{@link android.app.Fragment} が {@link android.app.Activity} から独立したフラグメントとして実行されていて、複数のアクティビティ内で使用可能であっても、フラグメントの特定のインスタンスは、それが含まれるアクティビティに直接結び付いています。 + +</p> + +<p>具体的には、フラグメントは {@link +android.app.Fragment#getActivity()} を使用して {@link android.app.Activity} インスタンスにアクセスでき、アクティビティのレイアウトでビューを見つけるなどのタスクを簡単に実行できます。 +</p> + +<pre> +View listView = {@link android.app.Fragment#getActivity()}.{@link android.app.Activity#findViewById findViewById}(R.id.list); +</pre> + +<p>同様に、アクティビティが {@link +android.app.FragmentManager#findFragmentById findFragmentById()} や {@link +android.app.FragmentManager#findFragmentByTag findFragmentByTag()} を使って {@link android.app.FragmentManager} から {@link android.app.Fragment} への参照を取得することで、フラグメント内のメソッドを呼び出すこともできます。 +次に例を示します。</p> + +<pre> +ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment); +</pre> + + +<h3 id="EventCallbacks">アクティビティへのイベント コールバックを作成する</h3> + +<p>アクティビティとイベントを共有するフラグメントが必要になる場面もあります。これを実現するには、フラグメント内でコールバック インターフェースを定義して、ホスト アクティビティがそれを実装するよう要求します。 + +アクティビティがインターフェースを介してコールバックを受け取ると、必要に応じてレイアウト内の他のフラグメントと情報を共有します。 +</p> + +<p>たとえば、新しいアプリケーションでアクティビティ内に、記事のリストを表示するフラグメント(フラグメント A)と、記事を表示するフラグメント(フラグメント B)の 2 つのフラグメントがある場合、リストのアイテムが選択されたときに、フラグメント B に記事を表示するよう伝えるため、フラグメント A から選択されたことをアクティビティに伝える必要があります。— +— +ここでは、{@code OnArticleSelectedListener} インターフェースがフラグメント A で宣言されています。 +</p> + +<pre> +public static class FragmentA extends ListFragment { + ... + // Container Activity must implement this interface + public interface OnArticleSelectedListener { + public void onArticleSelected(Uri articleUri); + } + ... +} +</pre> + +<p>次に、フラグメントのホストであるアクティビティが {@code OnArticleSelectedListener} インターフェースを実装して {@code onArticleSelected()} をオーバーライドし、フラグメント B にフラグメント A からのイベントを通知します。ホスト アクティビティがこのインターフェースを確実に実装するようにするため、フラグメント A の {@link +android.app.Fragment#onAttach onAttach()} コールバック メソッド(フラグメントをアクティビティに追加するときにシステムが呼び出すメソッド)が、{@link android.app.Fragment#onAttach +onAttach()} に渡される {@link android.app.Activity} をキャストして {@code OnArticleSelectedListener} のインスタンスを登録します。 + + + + +</p> + +<pre> +public static class FragmentA extends ListFragment { + OnArticleSelectedListener mListener; + ... + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + mListener = (OnArticleSelectedListener) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener"); + } + } + ... +} +</pre> + +<p>アクティビティがインターフェースを実装していない場合は、フラグメントは {@link java.lang.ClassCastException} をスローします。成功すると、{@code mListener} メンバーがアクティビティの {@code OnArticleSelectedListener} の実装への参照を保持でき、フラグメント A が {@code OnArticleSelectedListener} インターフェースで定義されたコールバック メソッドを呼び出すことでアクティビティとイベントを共有できるようになります。 + + + +たとえば、フラグメント A は {@link android.app.ListFragment} の拡張で、ユーザーがリストアイテムをクリックするたびに、システムがフラグメントの {@link android.app.ListFragment#onListItemClick +onListItemClick()} を呼び出し、それが{@code onArticleSelected()} を呼び出してアクティビティとイベントを共有します。 + + +</p> + +<pre> +public static class FragmentA extends ListFragment { + OnArticleSelectedListener mListener; + ... + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + // Append the clicked item's row ID with the content provider Uri + Uri noteUri = ContentUris.{@link android.content.ContentUris#withAppendedId withAppendedId}(ArticleColumns.CONTENT_URI, id); + // Send the event and Uri to the host activity + mListener.onArticleSelected(noteUri); + } + ... +} +</pre> + +<p>{@link +android.app.ListFragment#onListItemClick onListItemClick()} に渡される {@code id} パラメータはクリックされたアイテムの行 ID で、アクティビティ(または他のフラグメント)がアプリケーションの {@link +android.content.ContentProvider} から記事を取得する際に使用します。 +</p> + +<p><!--To see a complete implementation of this kind of callback interface, see the <a +href="{@docRoot}resources/samples/NotePad/index.html">NotePad sample</a>. -->コンテンツ プロバイダの使用に関する詳細については、「<a href="{@docRoot}guide/topics/providers/content-providers.html">コンテンツ プロバイダ</a>」のドキュメントをご覧ください。 +</p> + + + +<h3 id="ActionBar">アクションバーにアイテムを追加する</h3> + +<p>フラグメントは、{@link android.app.Fragment#onCreateOptionsMenu(Menu,MenuInflater) onCreateOptionsMenu()} を実装することでアクティビティの<a href="{@docRoot}guide/topics/ui/menus.html#options-menu">オプション メニュー</a>(とその<a href="{@docRoot}guide/topics/ui/actionbar.html">アクション バー</a>)にメニュー アイテムを提供することができます。 +ただし、このメソッドが呼び出しを受け取るには、{@link +android.app.Fragment#onCreate(Bundle) onCreate()} の間に {@link +android.app.Fragment#setHasOptionsMenu(boolean) setHasOptionsMenu()} を呼び出して、フラグメントがオプション メニューにアイテムを追加することを示す必要があります(これを行わない場合、フラグメントは {@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()} への呼び出しを受け取りません)。 + + +</p> + +<p>フラグメントから追加するアイテムはすべて、既存のメニュー アイテムに追加されます。 +また、メニュー アイテムが選択されたとき、フラグメントは {@link +android.app.Fragment#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} へのコールバックも受け取ります。 +</p> + +<p>また、{@link +android.app.Fragment#registerForContextMenu(View) registerForContextMenu()} を呼び出して、フラグメントのレイアウトにビューを登録してコンテキスト メニューを提供することもできます。ユーザーがコンテキスト メニューを開くと、フラグメントは {@link +android.app.Fragment#onCreateContextMenu(ContextMenu,View,ContextMenu.ContextMenuInfo) +onCreateContextMenu()} への呼び出しを受け取ります。 +ユーザーがアイテムを選択すると、フラグメントは {@link +android.app.Fragment#onContextItemSelected(MenuItem) onContextItemSelected()} への呼び出しを受け取ります。</p> + +<p class="note"><strong>注:</strong> 追加するメニュー アイテムごとにフラグメントは on-item-selected コールバックを受け取りますが、ユーザーがメニュー アイテムを選択したときに最初にそれぞれのコールバックを受け取るのはアクティビティになります。 + +アクティビティの on-item-selected コールバックの実装で、選択されたアイテムが処理されなかった場合、イベントはフラグメントのコールバックに渡されます。 +この挙動は、オプション メニューとコンテキスト メニューの両方に適用されます。 +</p> + +<p>メニューの詳細については、デベロッパー ガイドの「<a href="{@docRoot}guide/topics/ui/menus.html">メニュー</a>」と「<a href="{@docRoot}guide/topics/ui/actionbar.html">アクションバー</a>」をご覧ください。</p> + + + + +<h2 id="Lifecycle">フラグメントのライフサイクルを処理する</h2> + +<div class="figure" style="width:350px"> +<img src="{@docRoot}images/activity_fragment_lifecycle.png" alt="" /> +<p class="img-caption"><strong>図 3.</strong> フラグメントのライフサイクルに対するアクティビティのライフサイクルの影響。 +</p> +</div> + +<p>フラグメントのライフサイクルの管理は、アクティビティのライフサイクルの管理によく似ています。アクティビティと同様に、フラグメントには次の 3 つの状態があります。 +</p> + +<dl> + <dt><i>再開状態</i></dt> + <dd>フラグメントが実行中のアクティビティで表示されている。</dd> + + <dt><i>一時停止状態</i></dt> + <dd>他のアクティビティがフォアグラウンドにあり、フォーカスがあるが、このアクティビティも表示されている(フォアグラウンドにある別のアクティビティは半透明になっているか、全画面をカバーしていない)。 + +</dd> + + <dt><i>停止状態</i></dt> + <dd>フラグメントは表示されていない。ホスト アクティビティが停止状態か、フラグメントがアクティビティから削除されたが、バックスタックに追加されている。 +停止状態のフラグメントはまだ存続しています(すべての状態とメンバー情報がシステムで保持されています)。 +ただし、アクティビティが破棄されるとユーザーには表示されなくなり、フラグメントも破棄されます。 +</dd> +</dl> + +<p>さらに、アクティビティと同様に、アクティビティのプロセスが破棄されて、アクティビティが再作成されたときにフラグメントの状態を復元する必要がある場合は、 {@link +android.os.Bundle} を使用してフラグメントの状態を保持できます。 +フラグメントの {@link +android.app.Fragment#onSaveInstanceState onSaveInstanceState()} コールバックの間に状態を保存して、{@link android.app.Fragment#onCreate onCreate()}、{@link +android.app.Fragment#onCreateView onCreateView()}、{@link +android.app.Fragment#onActivityCreated onActivityCreated()} の間にそれを復元できます。 +状態の保存の詳細については、「<a href="{@docRoot}guide/components/activities.html#SavingActivityState">Activities</a>」のドキュメントをご覧ください。 + +</p> + +<p>アクティビティとフラグメントのライフサイクルの最も重要な違いは、バックスタックでのそれぞれの保存方法です。 +アクティビティは、デフォルトで停止状態の時にシステムが管理するアクティビティのバックスタックに置かれますが(<a href="{@docRoot}guide/components/tasks-and-back-stack.html">タスクとバックスタック</a> で説明したようにユーザーが [<em>戻る</em>] ボタンで前に戻ることができるように)、フラグメントの場合は、フラグメントを削除するトランザクションの間に {@link +android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} を呼び出してインスタンスを保存するよう明示的に要求した場合のみ、ホスト アクティビティが管理するバックスタックに置かれます。 + + + + +</p> + +<p>これ以外については、フラグメントのライフサイクルの管理は、アクティビティのライフサイクルの管理とほとんど同じです。 +そのため、<a href="{@docRoot}guide/components/activities.html#Lifecycle">アクティビティのライフサイクルの管理</a>におけるベスト プラクティスがフラグメントにも適用されます。 +もう 1 つ理解しておくべき事項は、アクティビティの寿命がどのようにフラグメントの寿命に影響を与えるかという点です。 +</p> + +<p class="caution"><strong>警告:</strong> {@link android.app.Fragment} 内に {@link android.content.Context} オブジェクトが必要な場合は、{@link android.app.Fragment#getActivity()} を呼び出すことができます。ただし、{@link android.app.Fragment#getActivity()} はフラグメントがアクティビティにアタッチされている場合にのみ呼び出すようにしてください。 + + +フラグメントがまだアタッチされていない場合や、ライフサイクルの終了時にデタッチされた場合は、{@link android.app.Fragment#getActivity()} は null を返します。 +</p> + + +<h3 id="CoordinatingWithActivity">アクティビティのライフサイクルと連携する</h3> + +<p>フラグメントが含まれるアクティビティのライフサイクルは、フラグメントのライフサイクルに直接影響し、アクティビティに対する各ライフサイクル コールバックは、各フラグメントに対して同様のコールバックをもたらします。 + +たとえば、アクティビティが {@link android.app.Activity#onPause} を受け取ると、アクティビティ内の各フラグメントが {@link android.app.Fragment#onPause} を受け取ります。 +</p> + +<p>ただし、フラグメントにはフラグメントの UI をビルドしたり破棄したりするアクションを実行する際のアクティビティとの独自のやり取りを処理する追加のライフサイクル コールバックがいくつかあります。これらの追加のコールバック メソッドは次のとおりです。 + +</p> + +<dl> + <dt>{@link android.app.Fragment#onAttach onAttach()}</dt> + <dd>フラグメントがアクティビティと関連付けられたときに呼び出されます(ここで {@link +android.app.Activity} が渡されます)。</dd> + <dt>{@link android.app.Fragment#onCreateView onCreateView()}</dt> + <dd>フラグメントに関連付けられたビュー階層を作成する際に呼び出されます。</dd> + <dt>{@link android.app.Fragment#onActivityCreated onActivityCreated()}</dt> + <dd>アクティビティの {@link android.app.Activity#onCreate +onCreate()} メソッドが戻ったときに呼び出されます。</dd> + <dt>{@link android.app.Fragment#onDestroyView onDestroyView()}</dt> + <dd>フラグメントに関連付けられたビュー階層が削除されたときに呼び出されます。</dd> + <dt>{@link android.app.Fragment#onDetach onDetach()}</dt> + <dd>フラグメントとアクティビティとの関連付けが解除されたときに呼び出されます。</dd> +</dl> + +<p>図 3 は、ホスト アクティビティの影響を受けたフラグメントのライフサイクルのフローを表しています。 +この図から、アクティビティの一連の状態によって、フラグメントが受け取るコールバック メソッドがどのように決められているかがわかります。 +たとえば、アクティビティが {@link +android.app.Activity#onCreate onCreate()} コールバックを受け取ると、アクティビティ内のフラグメントは {@link android.app.Fragment#onActivityCreated onActivityCreated()} コールバックまでを受け取ります。 +</p> + +<p>アクティビティが再開状態になると、アクティビティでのフラグメントの追加や削除を自由に行えます。 +つまり、アクティビティが再開された状態が、フラグメントのライフサイクルを独立して変更できる唯一の期間になります。 +</p> + +<p>ただし、アクティビティが再開状態でなくなると、フラグメントはアクティビティによって再度ライフサイクル間を通過することになります。 +</p> + + + + +<h2 id="Example">例</h2> + +<p>このドキュメントで解説した内容をすべて網羅するため、2 つのフラグメントを使用して 2 つのペインのレイアウトを作成するアクティビティの例を紹介します。 +次のアクティビティには、シェイクスピア劇のタイトル リストを表示するフラグメントと、リストから劇が選択されたときに劇のあらすじを表示するフラグメントがあります。 + +また、ここでは画面構成によって異なるフラグメント構成を提供する方法も示しています。 +</p> + +<p class="note"><strong>注:</strong> このアクティビティのすべてのソース コードは、<a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.html">{@code +FragmentLayout.java}</a> で入手できます。 +</p> + +<p>メイン アクティビティでは、通常の方法で {@link +android.app.Activity#onCreate onCreate()} の間にレイアウトを適用します。</p> + +{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java main} + +<p>適用されるレイアウトは {@code fragment_layout.xml} です。</p> + +{@sample development/samples/ApiDemos/res/layout-land/fragment_layout.xml layout} + +<p>このレイアウトを使って、アクティビティがレイアウトをロードするとすぐにシステムが {@code TitlesFragment}(これが劇のタイトルをリストします)のインスタンスを作成します。このとき、{@link android.widget.FrameLayout} (劇のあらすじを表示するフラグメントの目的地)が画面右側を使用し、残りは空白の状態です。 + + +ご覧のように、フラグメントが {@link android.widget.FrameLayout} に置かれるのはユーザーがアイテムを選択してからになります。 +</p> + +<p>ただし、画面構成によっては、劇の一覧とあらすじを横並びに表示するほどの幅がない場合もあります。 +そのため、上記のレイアウトは横方向の画面構成の場合のみ使用され、{@code res/layout-land/fragment_layout.xml} に保存されます。 +</p> + +<p>画面が縦方向の場合、システムは次のレイアウトを適用して {@code res/layout/fragment_layout.xml} に保存します。 +</p> + +{@sample development/samples/ApiDemos/res/layout/fragment_layout.xml layout} + +<p>このレイアウトには、{@code TitlesFragment} のみが含まれます。つまり、端末が縦方向の場合、劇のタイトルのみが表示されます。 +そのため、この構成時にユーザーがリストのアイテムをクリックしたとき、アプリケーションは 2 つ目のフラグメントをロードする代わりに新しいアクティビティを開始してあらすじを表示します。 + +</p> + +<p>次に、フラグメントのクラスでこれをどう実現するのかを見ていきます。まず、{@code +TitlesFragment} はシェイクスピア劇のタイトル リストを表示します。このフラグメントは {@link +android.app.ListFragment} を拡張し、リスト ビューの動作の処理のほとんどを委ねます。</p> + +<p>このコードをよく見ると、ユーザーがリストのアイテムをクリックしたときの挙動が 2 つ考えられます。2 つのレイアウトのどちらがアクティブになっているかによって、新しいフラグメントを作成して表示することで同じアクティビティで詳細を表示するか({@link +android.widget.FrameLayout} にフラグメントを追加する)、新しいアクティビティを(フラグメントを表示できる場所に)開始するかのいずれかになります。 + +</p> + +{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java titles} + +<p>2 つ目のフラグメントである {@code DetailsFragment} は、{@code TitlesFragment} のリストで選択された劇のあらすじを表示します。 +</p> + +{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java details} + +<p>{@code TitlesFragment} クラスで説明したように、ユーザーがリストアイテムをクリックしたときに、現在のレイアウトに{@code R.id.details} ビュー({@code DetailsFragment} が属する場所)が<em>含まれていない</em>場合、アプリケーションは {@code DetailsActivity} のアクティビティを開始してアイテムのコンテンツを表示します。 + + +</p> + +<p>次の {@code DetailsActivity} では、画面が縦方向のときに単純に {@code DetailsFragment} を埋め込んで選択された劇のあらすじを表示します。 +</p> + +{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java +details_activity} + +<p>構成が横方向の場合はアクティビティは自ら終了するため、メイン アクティビティが引き継いで {@code DetailsFragment} を {@code TitlesFragment} の横に表示できます。これは、ユーザーが縦方向のときに {@code DetailsActivity} を開始し、その後横方向に回転した(ここで現在のアクティビティが再開される)ときに起こることがあります。 + + +</p> + + +<p>フラグメントを使用したその他のサンプルとこの例の完全なソース ファイルについては、<a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/index.html#Fragment">ApiDemos</a>(<a href="{@docRoot}resources/samples/get.html">SDK コンポーネントのサンプル</a>から入手可能)にある API デモサンプルをご覧ください。 + +</p> + + diff --git a/docs/html-intl/intl/ja/guide/components/fundamentals.jd b/docs/html-intl/intl/ja/guide/components/fundamentals.jd new file mode 100644 index 000000000000..46e98689a3ec --- /dev/null +++ b/docs/html-intl/intl/ja/guide/components/fundamentals.jd @@ -0,0 +1,480 @@ +page.title=アプリケーションの基礎 +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + +<h2>本書の内容</h2> +<ol> +<li><a href="#Components">アプリのコンポーネント</a> + <ol> + <li><a href="#ActivatingComponents">コンポーネントをアクティベートする</a></li> + </ol> +</li> +<li><a href="#Manifest">マニフェスト ファイル</a> + <ol> + <li><a href="#DeclaringComponents">コンポーネントを宣言する</a></li> + <li><a href="#DeclaringRequirements">アプリの要件を宣言する</a></li> + </ol> +</li> +<li><a href="#Resources">アプリのリソース</a></li> +</ol> +</div> +</div> + +<p>Android アプリは Java プログラミング言語で記述されています。APKAndroid SDK ツールがコードを—データとリソース ファイルと共に、 +—APK <i>(Android パッケージ)にコンパイルします。</i>これは、 +{@code .apk} という接尾語の付いたアーカイブ ファイルです。1 つの APK ファイルにはAndroid アプリのすべてのコンテンツが含まれており、Android 端末はアプリをインストールする際にこのファイルを使用します。 +</p> + +<p>端末にインストールすると、各 Android アプリはそれぞれのセキュリティ サンドボックス内で動作します。 </p> + +<ul> + <li>Android オペレーティング システムはマルチユーザーの Linux システムであり、各アプリが異なるユーザーになります。 +</li> + +<li>デフォルトで、システムは各アプリに一意の Linux ユーザー ID を割り当てます(ID はシステムのみが使用し、アプリは ID を関知しません)。 +アプリが割り当てられたユーザー ID のみがアプリ内のすべてのファイルにアクセスできるよう、システムがパーミッションを設定します。 + </li> + +<li>各プロセスにはそれぞれ独自の仮想マシン(VM)があるため、アプリのコードは他のアプリとは分離して実行します。 +</li> + +<li>デフォルトで、すべてのアプリは独自の Linux プロセス上で実行します。Android はアプリのコンポーネントのいずれかを実行する必要があるときにプロセスを開始し、それが必要なくなったときや、システムが他のアプリ用にメモリを回復させる必要があるときにプロセスをシャットダウンします。 + +</li> +</ul> + +<p>このようにして、Android システムは<em>最小権限の原則</em>を実装しています。つまり、デフォルトでは各アプリにはコンポーネントの動作に必要な分だけのアクセス権が与えられます。 + +これにより、パーミッションの与えられていないシステムの一部にアプリはアクセスできないという非常に安全性の高い環境が作り出されます。 +</p> + +<p>ただし、アプリが他のアプリとデータを共有したり、システムのサービスにアクセスしたりする方法もあります。 +</p> + +<ul> + <li>2 つのアプリで同一の Linux ユーザー ID を共有して、お互いのファイルにアクセスできるようにすることも可能です。 +システム リソースを節約するため、同じユーザー ID を持つアプリを同じ Linux プロセス上で実行し、同じ VM を共有するよう設定することもできます(アプリを同じ証明書で署名する必要があります)。 + +</li> + <li>アプリから、ユーザーの連絡先、SMS メッセージ、マウント可能なストレージ(SD カード)、カメラ、Bluetooth といった端末データにアクセスするためのパーミッションを要求できます。 +アプリのすべてのパーミッションは、インストール時にユーザーから付与される必要があります。 +</li> +</ul> + +<p>以上が、システム内の Android アプリの基本的な仕組みです。続いて、このドキュメントでは次の内容について説明します。 +</p> +<ul> + <li>アプリを定義するコア フレームワーク コンポーネント。</li> + <li>コンポーネントを宣言し、アプリの端末機能に必要なマニフェスト ファイル。 +</li> + <li>アプリでさまざまな端末構成の動作を最適化できるようにする、アプリコードから分離されたリソース。 +</li> +</ul> + + + +<h2 id="Components">アプリのコンポーネント</h2> + +<p>アプリのコンポーネントは、Android アプリに不可欠な構成要素です。各コンポーネントは、システムがアプリにアクセスするためのさまざまなエントリ ポイントになります。すべてのコンポーネントがユーザーの実際のエントリ ポイントになるわけではなく、中にはお互いに依存関係にあるものもありますが、それぞれが独自のエンティティとして存在し、特定の役割を担っています。各コンポーネントはアプリの全体的な動作を定義する固有の構成要素となっています。 + + +— +</p> + +<p>アプリのコンポーネントには、4 つのタイプがあります。それぞれのタイプは、まったく異なる目的を果たし、コンポーネントの作成や破棄方法を定義するライフサイクルもそれぞれ異なります。 +</p> + +<p>アプリのコンポーネントのタイプは次の 4 つです。</p> + +<dl> + +<dt><b>アクティビティ</b></dt> + +<dd>アクティビティ <i>は</i> 1 つのユーザー インターフェースで 1 つの画面を表すものです。たとえば、メール アプリには新着メールの一覧を表示する 1 つのアクティビティと、メールを作成するアクティビティ、メールを閲覧するアクティビティがそれぞれ別にあります。 + +メールアプリでは、複数のアクティビティが一体となって結合したユーザー操作を実現しますが、それぞれは他のものから独立しています。 + +それにより、別のアプリで複数のアクティビティの中から、1 つのアクティビティを開始できるようになります(メールアプリが許可している場合)。 +たとえば、カメラアプリでは写真を他のユーザーと共有するために、メール アプリの新規メールを作成するアクティビティを開始できます。 + + +<p>アクティビティは {@link android.app.Activity} のサブクラスとして実装されます。詳細については、デベロッパー ガイドの「<a href="{@docRoot}guide/components/activities.html">Activities</a>」をご覧ください。 + +</p> +</dd> + + +<dt><b>サービス</b></dt> + +<dd>サービス <i>は、</i> 長期間の操作やリモート プロセスを処理するためにバックグラウンドで実行するコンポーネントです。 +サービスは、ユーザー インターフェースを提供しません。 +たとえば、サービスはユーザーが別のアプリを使用している間にバックグラウンドで音楽を再生したり、ユーザーが別のアクティビティを操作している間にそれを妨げることなくネットワークからデータを取得したりします。 + +アクティビティなどの別のコンポーネントは、サービスを開始して実行したり、それをバインドしたりして操作することもできます。 + + +<p>サービスは {@link android.app.Service} のサブクラスとして実装されます。詳細については、デベロッパー ガイドの「<a href="{@docRoot}guide/components/services.html">サービス</a>」をご覧ください。 + +</p> +</dd> + + +<dt><b>コンテンツ プロバイダ</b></dt> + +<dd>コンテンツ プロバイダ <i>は</i> 共有されているアプリデータを管理します。データは、ファイル システム、SQLite データベース、ウェブ、アプリがアクセスできる、あらゆる永続性のストレージに保存できます。 + +コンテンツ プロバイダを介して、他のアプリがデータをクエリしたり、修正したりすることもできます(コンテンツ プロバイダが許可している場合)。 +たとえば、Android システムではユーザーの連絡先情報を管理するコンテンツ プロバイダを提供しています。 +このように、適切なパーミッションさえあれば、アプリからコンテンツ プロバイダの一部({@link +android.provider.ContactsContract.Data}など)に問い合わせて、特定の人物に関する情報を読み取ったり書き込んだりできます。 + + +<p>コンテンツ プロバイダは、アプリで非公開扱いの共有されていないデータを閲覧したり書き込んだりする場合にも役立ちます。 +たとえば、<a href="{@docRoot}resources/samples/NotePad/index.html">Note Pad</a> のサンプル アプリでは、コンテンツ プロバイダを使用してメモを保存します。 +</p> + +<p>コンテンツ プロバイダは {@link android.content.ContentProvider} のサブクラスとして実装され、他のアプリがトランザクションを実行できるようにする API の標準セットを実装する必要があります。 + +詳細については、デベロッパー ガイドの「<a href="{@docRoot}guide/topics/providers/content-providers.html">Contetns Providers</a>」をご覧ください。 +</p> +</dd> + + +<dt><b>ブロードキャスト レシーバー</b></dt> + +<dd>ブロードキャスト レシーバー <i>は</i> システム全体のブロードキャスト アナウンスに応答するコンポーネントです。 +たとえば、画面がオフになった、バッテリ残量が低い、写真が撮影されたなど、システムに起因するブロードキャストはたくさんあります。アプリでもブロードキャストを開始でき、たとえば他のアプリに、一部のデータが端末にダウンロードされ、利用可能になったことを伝えることもできます。— + +— +ブロードキャスト レシーバーがユーザー インターフェースを表示することはありませんが、<a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">ステータスバー通知を作成</a>して、ブロードキャスト イベントの発生時にユーザーに警告できます。 + +一般的には、ブロードキャスト レシーバーは他のコンポーネントへの単なる「入り口」であり、最小限の操作を行うことが前提となっています。 +たとえば、イベントに基づいた何らかの作業を実行するサービスを開始する場合などに適しています。 + + +<p>ブロードキャスト レシーバーは、{@link android.content.BroadcastReceiver} のサブクラスとして実装され、各ブロードキャストは {@link android.content.Intent} オブジェクトとして配信されます。 +詳細については、{@link android.content.BroadcastReceiver} クラスをご覧ください。 +</p> +</dd> + +</dl> + + + +<p>Android ならではのシステムデザインによって、どのアプリケーションからでも別のアプリケーションを開始できます。 +たとえば、ユーザーが端末のカメラで写真を撮影できるようにする場合、既にその機能を備えた別のアプリがあることを想定して、写真を撮影するアクティビティを自身で開発する代わりに、アプリがそれを使用できます。 + +カメラアプリを組み込んだり、コードにリンクしたりする必要もなく、単純に写真を撮影するカメラアプリのアクティビティを開始するだけです。 + + +完了後、写真はアプリに戻り、それを使用することもできます。ユーザー側には、カメラがアプリの一部であるかのように見えます。 +</p> + +<p>システムがコンポーネントを開始すると、そのアプリのプロセスを開始し(まだ実行していない場合)、コンポーネントが必要とするクラスをインスタンス化します。 +たとえば、アプリで写真を撮影するカメラアプリのアクティビティを開始すると、そのアクティビティはアプリのプロセスではなく、カメラアプリのプロセスで実行します。そのため、他のシステムのアプリとは異なり、Android アプリのエントリ ポイントは 1 つではありません(たとえば、{@code main()} 関数はありません)。 + + + +</p> + +<p>システムは、他のアプリへのアクセスを制限するファイル許可を使用して各アプリを別々のプロセスで実行するため、アプリから直接他のアプリのコンポーネントはアクティベートできませんが、Android システムはそれが可能です。 + +そのため、他のアプリのコンポーネントをアクティベートするには、特定のコンポーネントを開始する<em>インテント</em>を指定するメッセージをシステムに配信する必要があります。 + +その後、システムが代わりにコンポーネントをアクティベートします。</p> + + +<h3 id="ActivatingComponents">コンポーネントをアクティベートする</h3> + +<p>4 つのコンポーネント タイプのなかで、アクティビティ、サービス、ブロードキャスト レシーバーの 3 つは、<em>インテント</em>と呼ばれる非同期メッセージによってアクティベートされます。コンポーネントがアプリに属していても他のものに属していても、インテントにより実行時に個別のコンポーネントがお互いに結び付けられます(他のコンポーネントからのアクションを要求するメッセンジャーのようなものです)。—— + + + +</p> + +<p>インテントは {@link android.content.Intent} オブジェクトを使用して作成されます。このオブジェクトは特定のコンポーネントや特定の<em>タイプ</em>のコンポーネントをアクティベートするようにメッセージを定義します。インテントはそれぞれ明示的、暗黙的のいずれかになります。— + +</p> + +<p>アクティビティとサービスでは、インテントが実行するアクション(「閲覧」したり「送信」したりする)を定義し、操作に使うデータ(特に、開始されるコンポーネントが知っておく必要があるデータ)の URI を指定することもできます。 + +たとえば、インテントはアクティビティに画像を表示したり、ウェブページを開いたりするアクティビティに対して要求を伝達します。 +場合によっては、結果を受け取るアクティビティを開始でき、この場合にアクティビティが返す結果も {@link android.content.Intent} になります(たとえば、ユーザーが個人の連絡先を取り出し、それを返してくれるインテントを発行できます。返されたインテントには選択された連絡先を指す URI が含まれています)。 +— + + +</p> + +<p>ブロードキャスト レシーバーの場合、インテントは単純にブロードキャストするアナウンスを定義します(たとえば、端末のバッテリ残量が少ないことを示すブロードキャストには、「バッテリが少ない」ことを示す既知のアクション文字列が含まれます)。 + +</p> + +<p>他のコンポーネント タイプであるコンテンツ プロバイダは、インテントではアクティベートされず、{@link android.content.ContentResolver} からの要求の対象となったときにアクティベートされます。 +コンテンツリゾルバが、コンテンツプロバイダを使ってすべてのトランザクションを直接処理することで、プロバイダを使ってトランザクションを実行しているコンポーネントは処理する必要がなくなり、代わりに {@link +android.content.ContentResolver} オブジェクトのメソッドを呼び出します。 + +これによりコンテンツ プロバイダと情報を要求しているコンポーネントとの間に(セキュリティ目的で)抽象的な層ができます。 +</p> + +<p>各コンポーネント タイプのアクティベート用に、個別のメソッドが用意されています。</p> +<ul> + <li>アクティビティを開始する(または新しい作業を与える)場合は、{@link android.content.Intent} を {@link android.content.Context#startActivity +startActivity()} や {@link android.app.Activity#startActivityForResult startActivityForResult()} (アクティビティに結果を求める場合)に渡します。 + +</li> + <li>サービスを開始する(または継続中のサービスに新しい指示を与える)には、{@link android.content.Intent} を {@link android.content.Context#startService +startService()} に渡します。 +または、{@link android.content.Intent} を {@link android.content.Context#bindService bindService()} に渡してサービスにバインドできます。 +</li> + <li>ブロードキャストを開始するには、{@link android.content.Intent} を {@link android.content.Context#sendBroadcast(Intent) sendBroadcast()}、{@link +android.content.Context#sendOrderedBroadcast(Intent, String) sendOrderedBroadcast()}、{@link +android.content.Context#sendStickyBroadcast sendStickyBroadcast()} などのメソッドに渡します。 +</li> + <li>コンテンツ プロバイダへのクエリを実行するには、{@link android.content.ContentResolver} の {@link +android.content.ContentProvider#query query()} を呼び出します。</li> +</ul> + +<p>インテントの使用に関する詳細については、「<a href="{@docRoot}guide/components/intents-filters.html">インテントとインテント フィルタ</a>」のドキュメントをご覧ください。 +特定のコンポーネントのアクティベートの詳細については、 +<a href="{@docRoot}guide/components/activities.html">アクティビティ</a>、<a href="{@docRoot}guide/components/services.html">サービス</a>、{@link +android.content.BroadcastReceiver}、<a href="{@docRoot}guide/topics/providers/content-providers.html">コンテンツ プロバイダ</a> のドキュメントでも説明しています。</p> + + +<h2 id="Manifest">マニフェスト ファイル</h2> + +<p>Android システムがコンポーネントを開始する前に、システムはアプリの {@code AndroidManifest.xml} ファイル(「マニフェスト」ファイル)を読み取って、コンポーネントの存在を認識する必要があります。 + +アプリはこのファイルですべてのコンポーネントを宣言し、このファイルはアプリ プロジェクトのディレクトリのルートに置く必要があります。 +</p> + +<p>マニフェストはアプリのコンポーネントを宣言する他にも、次のようにさまざまな役割があります。 +</p> +<ul> + <li>インターネット アクセスや、ユーザーの連絡先への読み取りアクセスなど、アプリに必要なユーザー パーミッションを識別する。 +</li> + <li>アプリが使用する API に基づいた、アプリが必要とする最小 <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API レベル</a>を宣言する。 +</li> + <li>カメラ、Bluetooth サービス、マルチタッチ スクリーンなど、アプリで使用されるか必要とされるハードウェア機能やソフトウェア機能を宣言する。 +</li> + <li><a href="http://code.google.com/android/add-ons/google-apis/maps-overview.html">Google マップ ライブラリ</a>など、アプリにリンクする必要のある API ライブラリ(Android フレームワーク API は除く)。 + +</li> + <li>その他の役割</li> +</ul> + + +<h3 id="DeclaringComponents">コンポーネントを宣言する</h3> + +<p>マニフェストの主なタスクは、システムにアプリ コンポーネントに関する情報を与えることです。たとえば、マニフェスト ファイルではアクティビティを次のように宣言できます。 + </p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<manifest ... > + <application android:icon="@drawable/app_icon.png" ... > + <activity android:name="com.example.project.ExampleActivity" + android:label="@string/example_label" ... > + </activity> + ... + </application> +</manifest></pre> + +<p><code><a +href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code> 要素では、{@code android:icon} 属性でアプリを特定するアイコンのリソースを指します。 + +</p> + +<p><code><a +href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> 要素では、{@code android:name} 属性で{@link +android.app.Activity} サブクラスの完全修飾k裏スパイウェア名を指定し、{@code android:label} 属性でアクティビティのユーザーに表示するラベルとして使用する文字列を指定しています。 + +</p> + +<p>すべてのアプリ コンポーネントは、次の方法で宣言する必要があります。</p> +<ul> + <li><code><a +href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> アクティビティ用の要素 +</li> + <li><code><a +href="{@docRoot}guide/topics/manifest/service-element.html"><service></a></code> サービス用の要素 +</li> + <li><code><a +href="{@docRoot}guide/topics/manifest/receiver-element.html"><receiver></a></code> ブロードキャスト レシーバー用の要素 +</li> + <li><code><a +href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a></code> コンテンツ プロバイダ用の要素 +</li> +</ul> + +<p>ソースに含まれていながら、マニフェスト ファイルでは定義されていないアクティビティ、サービス、コンテンツ プロバイダはシステムには見えないため、実行されることはありません。 +ただし、ブロードキャスト レシーバーはマニフェストで宣言するか、コードで動的に作成({@link android.content.BroadcastReceiver} オブジェクトとして)して {@link android.content.Context#registerReceiver registerReceiver()} を呼び出すことでシステムに登録できます。 + + + +</p> + +<p>アプリのマニフェスト ファイルの構築方法の詳細については、「<a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml File</a>」のドキュメントをご覧ください。 + </p> + + + +<h3 id="DeclaringComponentCapabilities">コンポーネントの機能を宣言する</h3> + +<p><a href="#ActivatingComponents">コンポーネントをアクティベートする</a>で説明したように、{@link android.content.Intent} を使用してアクティビティ、サービス、ブロードキャスト レシーバーを開始できます。 +開始するには、インテントでターゲットのコンポーネントの名前を(コンポーネントのクラス名を使って)明示的に指定する必要があります。 +ただし、インテントの本来の能力は、<em>暗黙的インテント</em>の概念にあります。 +暗黙的インテントは、単に実行するアクションのタイプを記述し(どのデータ上でアクションを実行するかも任意で記述できます)、それによりシステムがそのアクションを実行できる端末上のコンポーネントを見つけて開始できます。 + + +インテントで記述されたアクションを実行できるコンポーネントが複数ある場合は、使用するコンポーネントを 1 つ選択できます。 +</p> + +<p>システムは、端末の他のアプリのマニフェスト ファイルに提供されたインテント フィルタが受け取った + <i>インテントを比較して、</i> インテントに応答できるコンポーネントを識別します。 +</p> + +<p>アプリのマニフェストでアクティビティを宣言するとき、任意でアクティビティの機能を宣言するインテント フィルタを含めて、他のアプリからのインテントに応答できるようにできます。 + +<a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code +<intent-filter>}</a> 要素を、コンポーネントを宣言している要素の子として追加することで、コンポーネントのインテント フィルタを宣言できます。 +</p> + +<p>たとえば、新規メールを作成するアクティビティを持つメールアプリをビルドした場合、次のように「送信」インテント(新規メールを送信するための)に応答するインテント フィルタを宣言できます。 +</p> +<pre> +<manifest ... > + ... + <application ... > + <activity android:name="com.example.project.ComposeEmailActivity"> + <intent-filter> + <action android:name="android.intent.action.SEND" /> + <data android:type="*/*" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + </application> +</manifest> +</pre> + +<p>次に、別のアプリが {@link +android.content.Intent#ACTION_SEND} アクションを持つインテントを作成し、{@link android.app.Activity#startActivity +startActivity()} に渡す場合、ユーザーがメールを下書きして送信できるよう、システムがアクティビティを開始する場合があります。 +</p> + +<p>インテント フィルタの作成の詳細については、「<a href="{@docRoot}guide/components/intents-filters.html">インテントとインテント フィルタ</a>」のドキュメントをご覧ください。 +</p> + + + +<h3 id="DeclaringRequirements">アプリの要件を宣言する</h3> + +<p>Android が搭載された端末は数多くありますが、すべての端末が同じ機能や性能を備えているわけではありません。 +アプリに必要な機能を搭載していない端末にアプリをインストールしてしまわないよう、アプリがサポートする端末のタイプについてプロファイルで明確に定義し、マニフェスト ファイルで端末の要件やソフトウェア要件を宣言しておくことが重要です。 + + +これらの宣言のほとんどはただの情報で、システムがそれを読み取ることはありませんが、Google Play などの外部サービスはそれを読み取って、ユーザーが端末からアプリを検索したときにフィルタを提供します。 + +</p> + +<p>たとえば、アプリでカメラを使用する必要があり、Android 2.1 で採用された API(<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API レベル</a> 7)を使用する場合、次のようにマニフェスト ファイルでそれを要件として宣言する必要があります。 +</p> + +<pre> +<manifest ... > + <uses-feature android:name="android.hardware.camera.any" + android:required="true" /> + <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" /> + ... +</manifest> +</pre> + +<p>カメラの<em>ない</em>端末で、Android バージョンが 2.1 <em>以下</em>の場合は、Google Play からアプリをインストールできません。 +</p> + +<p>ただし、アプリでカメラを使用するが、それが<em>必須</em>ではないということを宣言することもできます。 +この場合、アプリで <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#required">{@code required}</a> 属性を {@code "false"} に設定し、端末にカメラがあるかどうかを実行時に確認して、必要に応じてすべてのカメラ機能を無効にする必要があります。 + +</p> + +<p>異なる端末でのアプリの互換性を管理する方法については、「<a href="{@docRoot}guide/practices/compatibility.html">Device Compatibility</a>」をご覧ください。 + +</p> + + + +<h2 id="Resources">アプリのリソース</h2> + +<p>Android アプリは、コードだけで構成されているわけではありません。ソース コードから分離された画像、オーディオ ファイル、その他アプリの外観に関連するあらゆるリソースが必要です。たとえば、アクティビティのアニメーション、メニュー、スタイル、色、レイアウトなどを XML ファイルで定義する必要があります。— + + +アプリのリソースを使用すると、コードを修正することなく別のリソースセットを提供することで、アプリのあらゆる特性を簡単にアップデートできるようになります。これにより、さまざまな端末の設定用(別の言語や画面サイズなど)にアプリを最適化できます。 +— +— +</p> + +<p>Android プロジェクトに含めるすべてのリソースに対し、SDK ビルド ツールが一意の整数 ID を定義し、アプリコードや XML で定義された他のリソースからリソースにそれを使って参照できます。 + +たとえば、アプリに {@code +logo.png} という名前の画像ファイルがある場合({@code res/drawable/} ディレクトリ内に保存)、SDK ツールが {@code R.drawable.logo} という名前のリソース ID を生成し、これを使って画像を参照してユーザー インターフェースに挿入できます。 + +</p> + +<p>リソースとソース コードを分離して提供する方法の最も重要な側面は、さまざまな端末設定に合わせて別のリソースを提供できるという点です。 + +たとえば、XML で UI 文字列を定義することで、その文字列を他の言語に翻訳して、それらの文字列を別のファイルに保存しておくことができます。 +それを、リソースのディレクトリ名に付けた言語の<em>修飾子</em>(フランス語の文字列値なら {@code res/values-fr/} のように)とユーザーの言語設定に基づいて、Android システムによって UI に適切な言語の文字列が適用されます。 + + +</p> + +<p>Android では代替リソース用に多様な<em>修飾子</em>をサポートしています。修飾子は、リソースのディレクトリ名に含める短い文字列で、そのリソースを使用する端末構成を定義するものです。 + +例をもう 1 つ挙げると、端末の画面の向きやサイズによって、アクティビティのレイアウトを複数作成する必要があります。 + +たとえば、端末が縦方向(縦長)の場合、ボタンの付いたレイアウトを縦に並べ、端末が横方向(横長)の場合はボタンを横並びにする、といった場合です。 + +画面の方向によってレイアウトを変更するには、2 つの異なるレイアウトを定義して、それぞれのレイアウトのディレクトリ名に適切な修飾子を適用します。 + +そうすることで、現在の端末の向きによってシステムが自動的に適切なレイアウトを適用できます。 +</p> + +<p>アプリケーションに含めることのできるリソースの種類や、異なる端末設定用の代替リソースの作成方法については、「<a href="{@docRoot}guide/topics/resources/providing-resources.html">リソースの提供</a>」をご覧ください。 +</p> + + + +<div class="next-docs"> +<div class="col-6"> + <h2 class="norule">こちらもご覧ください。</h2> + <dl> + <dt><a href="{@docRoot}guide/components/intents-filters.html">インテントとインテント フィルタ</a> + </dt> + <dd>{@link android.content.Intent} API を使用して、アクティビティやサービスなどのアプリのコンポーネントをアクティベートする方法や、アプリのコンポーネントを他のアプリで利用できるようにする方法について説明しています。 + +</dd> + <dt><a href="{@docRoot}guide/components/activities.html">Activities</a></dt> + <dd>ユーザー インターフェースを使って独特のアプリケーション画面を提供する {@link android.app.Activity} + クラスのインスタンスの作成方法について説明しています。</dd> + <dt><a href="{@docRoot}guide/topics/resources/providing-resources.html">リソースの提供</a></dt> + <dd>特定の端末構成に対して代替リソースを提供する方法など、Android アプリでアプリのリソースをアプリコードから分離する仕組みについて説明しています。 + + + </dd> + </dl> +</div> +<div class="col-6"> + <h2 class="norule">関連ドキュメント</h2> + <dl> + <dt><a href="{@docRoot}guide/practices/compatibility.html">Device Compatibility</a></dt> + <dd>あらゆるタイプの端末での Android の動作と、端末ごとにアプリを最適化したり、別の端末でのアプリの利用を制限したりする方法について説明しています。 + +</dd> + <dt><a href="{@docRoot}guide/topics/security/permissions.html">System Permissions</a></dt> + <dd>アプリが特定の API を使用するのにユーザーの同意を必要とするパーミッション システムを使用して、アプリから特定の API へのアクセスを Android が制限する仕組みについて説明しています。 +</dd> + </dl> +</div> +</div> + diff --git a/docs/html-intl/intl/ja/guide/components/index.jd b/docs/html-intl/intl/ja/guide/components/index.jd new file mode 100644 index 000000000000..803f99b2ebd2 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/components/index.jd @@ -0,0 +1,57 @@ +page.title=アプリ<br>コンポーネント +page.landing=true +page.landing.intro=Android のアプリケーション フレームワークでは、再利用可能なコンポーネント セットを使用して豊富な内容を備えた斬新なアプリを作成できます。このセクションでは、アプリの構成要素を定義するコンポーネントのビルド方法と、インテントを使用してそれらをつなぎ合わせる方法について説明します。 +page.metaDescription=Android のアプリケーション フレームワークでは、再利用可能なコンポーネント セットを使用して豊富な内容を備えた斬新なアプリを作成できます。このセクションでは、アプリの構成要素を定義するコンポーネントのビルド方法と、インテントを使用してそれらをつなぎ合わせる方法について説明します。 +page.landing.image=images/develop/app_components.png +page.image=images/develop/app_components.png + +@jd:body + +<div class="landing-docs"> + + <div class="col-6"> + <h3>ブログの記事</h3> + + <a href="http://android-developers.blogspot.com/2012/05/using-dialogfragments.html"> + <h4>DialogFragments の使用</h4> + <p>この投稿では、DialogFragments を v4 サポート ライブラリで使用して(Honeycomb 以前の端末での下方互換性のため)ダイアログを編集したり、インターフェースを使用して呼び出し元の Activity に結果を返したりする方法について説明します。</p> + </a> + + <a href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html"> + <h4>すべてに Fragments を</h4> + <p>本日、同じ Fragments API を利用できる静的なライブラリが公開され、Android 1.6 以降でもフラグメントを使用してタブレット対応のユーザー インターフェースを作成できるようになりました。 </p> + </a> + + <a href="http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html"> + <h4>マルチスレッドでパフォーマンス向上</h4> + <p>応答の速いアプリケーションを作成する上で重要なのは、メイン UI スレッドが最小限の作業を行うようにすることです。 +アプリケーションのハングにつながる可能性のある長期的なタスクは、別のスレッドで処理するようにします。 +</p> + </a> + </div> + + <div class="col-6"> + <h3>トレーニング</h3> + + <a href="http://developer.android.com/training/basics/activity-lifecycle/index.html"> + <h4>アクティビティのライフサイクルの管理</h4> + <p>このレッスンでは、各 Activity インスタンスが受け取る重要なライフサイクル コールバック メソッドについて、それらを使用してユーザーの予期する内容でアクティビティを動作させる方法と、アクティビティがそれらを必要としないときに、システムのリソースを消費しないようにする方法について学習します。 + +</p> + </a> + + <a href="http://developer.android.com/training/basics/fragments/index.html"> + <h4>フラグメントで動的 UI を構築</h4> + <p>このレッスンでは、Android 1.6 以降の旧バージョンを実行する端末に対応しながら、フラグメントを使用して動きのある使用感を実現し、異なる画面サイズでのアプリの操作感を最適化する方法について説明します。 + +</p> + </a> + + <a href="http://developer.android.com/training/sharing/index.html"> + <h4>コンテンツの共有</h4> + <p>このレッスンでは、Intent API と ActionProvider オブジェクトを使用して、アプリケーション間でコンテンツを送受信する際の一般的な方法について説明します。 +</p> + </a> + </div> + +</div> diff --git a/docs/html-intl/intl/ja/guide/components/intents-filters.jd b/docs/html-intl/intl/ja/guide/components/intents-filters.jd new file mode 100644 index 000000000000..b5d49f1b7cae --- /dev/null +++ b/docs/html-intl/intl/ja/guide/components/intents-filters.jd @@ -0,0 +1,901 @@ +page.title=インテントとインテント フィルタ +page.tags="IntentFilter" +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + +<h2>本書の内容</h2> +<ol> + <li><a href="#Types">インテントのタイプ</a></li> + <li><a href="#Building">インテントを作成する</a> + <ol> + <li><a href="#ExampleExplicit">明示的インテントの例</a></li> + <li><a href="#ExampleSend">暗黙的インテントの例</a></li> + <li><a href="#ForceChooser">アプリチューザを表示する</a></li> + </ol> + </li> + <li><a href="#Receiving">暗黙的インテントを受け取る</a> + <ol> + <li><a href="#ExampleFilters">フィルタの例</a></li> + </ol> + </li> + <li><a href="#PendingIntent">ペンディング インテントを使用する</a></li> + <li><a href="#Resolution">インテント解決</a> + <ol> + <li><a href="#ActionTest">アクションのテスト</a></li> + <li><a href="#CategoryTest">カテゴリのテスト</a></li> + <li><a href="#DataTest">データのテスト</a></li> + <li><a href="#imatch">インテントのマッチング</a></li> + </ol> + </li> +</ol> + +<h2>関連ドキュメント</h2> +<ol> +<li><a href="{@docRoot}training/basics/intents/index.html">Interacting with Other Apps</a></li> +<li><a href="{@docRoot}training/sharing/index.html">Sharing Content</a></li> +</ol> + +</div> +</div> + + + + +<p>{@link android.content.Intent} は、他の<a href="{@docRoot}guide/components/fundamentals.html#Components">アプリ コンポーネント</a>からのアクションを要求するときに使用するメッセージング オブジェクトです。インテントを使用することでコンポーネント間の通信を促進する方法はいくつかありますが、基本的な使用例は次の 3 つです。 + + +</p> + +<ul> +<li><b>アクティビティを開始するには:</b> +<p>{@link android.app.Activity} はアプリ内の 1 つの画面を表します。{@link android.app.Activity} の新しいインスタンスを開始するには、{@link android.content.Intent} を {@link android.content.Context#startActivity startActivity()} に渡します。 + +{@link android.content.Intent} は、開始するアクティビティを記述し、必要なデータすべてを含んでいます。 +</p> + +<p>アクティビティの完了時に結果を受け取る場合は、{@link android.app.Activity#startActivityForResult +startActivityForResult()} を呼び出します。 +アクティビティは、結果を別の {@link android.content.Intent} オブジェクトとして、アクティビティの {@link +android.app.Activity#onActivityResult onActivityResult()} コールバック内に受け取ります。詳細については、「<a href="{@docRoot}guide/components/activities.html">Activities</a>」のガイドをご覧ください。 + +</p></li> + +<li><b>サービスを開始するには:</b> +<p>{@link android.app.Service} は、ユーザー インターフェースを持たず、バックグラウンドで操作を実行するコンポーネントです。 +サービスを開始して 1 回限りの操作を実行する(ファイルのダウンロードなど)には、{@link android.content.Intent} を {@link android.content.Context#startService startService()} に渡します。 + +{@link android.content.Intent} は、開始するサービスを記述し、必要なデータすべてを含んでいます。 +</p> + +<p>クライアントサーバーのインターフェースでサービスがデザインされている場合、{@link android.content.Intent} を {@link +android.content.Context#bindService bindService()}</code> に渡して、他のコンポーネントからのサービスにバインドできます。 +詳細については、「<a href="{@docRoot}guide/components/services.html">サービス</a>」のガイドをご覧ください。</p></li> + +<li><b>ブロードキャストを配信するには:</b> +<p>ブロードキャストは、アプリが受け取ることのできるメッセージです。システムは、システムの起動や端末の充電開始など、さまざまなシステム イベントを配信します。他のアプリにブロードキャストを配信するには、{@link android.content.Intent} を {@link android.content.Context#sendBroadcast(Intent) sendBroadcast()}、{@link android.content.Context#sendOrderedBroadcast(Intent, String) +sendOrderedBroadcast()}、{@link +android.content.Context#sendStickyBroadcast sendStickyBroadcast()} のいずれかに渡します。 + + + +</p> +</li> +</ul> + + + + +<h2 id="Types">インテントのタイプ</h2> + +<p>インテントには 2 つのタイプがあります。</p> + +<ul> +<li><b>明示的インテント</b>は、開始するコンポーネントを名前(完全修飾クラス名)で指定します。 +通常は開始するアクティビティやサービスのクラス名がわかっているため、明示的インテントを使用してアプリ内のコンポーネントを開始します。 +たとえば、ユーザー操作に応答して新しいアクティビティを開始したり、バックグラウンドでファイルをダウンロードするサービスを開始したりします。 + +</li> + +<li><b>暗黙的インテント</b>では、特定のコンポーネントを指定せず、代わりに実行する全般的な動作を宣言することで、他のアプリからコンポーネントを処理できるようにします。 +たとえば、マップ上にユーザーの位置を表示する場合、暗黙的インテントを使って、特定の場所をマップ上に表示できる別のアプリにその操作を要求します。 + +</li> +</ul> + +<p>暗黙的インテントを使用してアクティビティやサービスを開始する際、システムによってただちに {@link android.content.Intent} オブジェクトで指定されたアプリ コンポーネントが開始されます。 +</p> + +<div class="figure" style="width:446px"> +<img src="{@docRoot}images/components/intent-filters@2x.png" width="446" alt="" /> +<p class="img-caption"><strong>図 1.</strong> 暗黙的インテントが他のアクティビティを開始するようシステム内に配信される仕組みを表しています。<b>[1]</b> <em>Activity A</em> がアクションの記述を使って {@link android.content.Intent} を作成し、それを {@link +android.content.Context#startActivity startActivity()} に渡します。<b>[2]</b> Android システムがすべてのアプリに対してインテントに一致するインテント フィルタを検索します。 + + +一致するものが見つかったら、<b>[3]</b> システムが {@link +android.app.Activity#onCreate onCreate()} メソッドを呼び出して、{@link android.content.Intent} に渡すことで、そのアクティビティ(<em>Activity B</em>)を開始します。 + +</p> +</div> + +<p>暗黙的インテントを作成するとき、Android システムはインテントの内容を、端末上の他のアプリの <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">マニフェスト ファイル</a>で定義された <em>インテント フィルタ</em> と比較して、開始すべきコンポーネントを見つけます。 + +インテントがインテント フィルタに一致した場合、システムがそのコンポーネントを開始して、{@link android.content.Intent} を配信します。 +複数のインテント フィルタが競合する場合、ユーザーが仕様するアプリを選択できるようシステムによってダイアログが表示されます。 +</p> + +<p>インテント フィルタは、コンポーネントが受け取りたいインテントのタイプを指定する式で、アプリのマニフェスト ファイルに含まれています。 + +たとえば、アクティビティのインテント フィルタを宣言すると、特定のインテント タイプを持つアクティビティを他のアプリから直接開始できるようになります。同様に、アクティビティでインテント フィルタを宣言<em>しない</em>場合は、明示的インテントでのみアクティビティを開始できます。 + + +</p> + +<p class="caution"><strong>警告:</strong> アプリの安全性を保つため、{@link android.app.Service} を開始するときは常に明示的インテントを使用し、サービスでインテント フィルタを宣言しないようにしてください。 + +暗黙的インテントを使ってサービスを開始すると、どのサービスがインテントに応答するかを把握できず、ユーザーにはどのサービスが開始するのかがわからないため、セキュリティ上の危険が伴います。 + +Android 5.0(API レベル 21)以降では、暗黙的インテントで {@link android.content.Context#bindService bindService()} を呼び出すと、システムから例外がスローされます。 + +</p> + + + + + +<h2 id="Building">インテントを作成する</h2> + +<p>{@link android.content.Intent} オブジェクトには Android システムが開始するコンポーネントを決定する際に使用する情報(インテントを受け取るべき正確なコンポーネント名やコンポーネントのカテゴリなど)に加えて、受け取る側のコンポーネントがアクションを適切に実行するために使用する情報(実行するアクションと、実行対象のデータなど)が含まれています。 + + +</p> + + +<p>{@link android.content.Intent} に含まれる主な情報は次のとおりです。</p> + +<dl> + +<dt><b>コンポーネント名</b></dt> +<dd>開始するコンポーネントの名前です。 + +<p>これは省略可能ですが、インテントを<b>明示的</b>にするためには不可欠な情報です。つまり、コンポーネント名で定義されたアプリ コンポーネントにのみ、インテントが配信されます + +コンポーネント名がない場合、インテントは<b>暗黙的</b>になり、他のインテント情報(下記で説明するアクション、データ、カテゴリなど)に基づいてインテントを受け取るべきコンポーネントをシステムが決定します + +—そのため、アプリ内の特定のコンポーネントを開始する必要がある場合は、コンポーネント名を指定する必要があります。 +</p> + +<p class="note"><strong>注:</strong> {@link android.app.Service} を開始するときは、<strong>常にコンポーネント名を指定</strong>する必要があります。 +指定しない場合、どのサービスがインテントに応答するかを把握できず、ユーザーにはどのサービスが開始するのかがわからなくなります。 +</p> + +<p>{@link android.content.Intent} のフィールドは {@link android.content.ComponentName} オブジェクトで、アプリのパッケージ名など、ターゲットのコンポーネントの完全修飾クラス名を使用して指定できます(例: {@code com.example.ExampleActivity})。 + + +コンポーネント名は、{@link +android.content.Intent#setComponent setComponent()}、{@link android.content.Intent#setClass +setClass()}、{@link android.content.Intent#setClassName(String, String) setClassName()}、{@link android.content.Intent} コンストラクタなどを使用して設定できます。 +</p> + +</dd> + +<p><dt><b>アクション</b></dt> +<dd>実行する全体的なアクションを指定する文字列です(<em>閲覧</em>や<em>選択</em>など)。 + +<p>ブロードキャスト インテントの場合、これが発生済みで報告済みのアクションになります。ほとんどのアクションは、残りのインテントがどのように構成されているか、特にデータやエクストラに含まれている内容によって決まります。 +— + + +<p>インテントによって自身のアプリで使用する(または他のアプリで使用して自身のアプリのコンポーネントを呼び出す)独自のアクションを指定できますが、通常は {@link android.content.Intent} クラスや他のフレームワーク クラスで定義されたアクション定数を使用します。 + +アクティビティを開始する際の一般的なアクションをいくつか次に示します。 +</p> + +<dl> +<dt>{@link android.content.Intent#ACTION_VIEW}</dt> + <dd>ギャラリー アプリで表示する写真や、マップアプリで表示する住所など、アクティビティ内にユーザーに表示する情報がある場合は、{@link + android.content.Context#startActivity startActivity()} を使ってインテントにこのアクションを使用します。 + +</dd> + +<dt>{@link android.content.Intent#ACTION_SEND}</dt> + <dd>これは「共有」インテントとしても知られており、メールアプリやソーシャル シェアリング アプリなどの他のアプリ経由でユーザーが共有できるデータがある場合に、{@link + android.content.Context#startActivity startActivity()} でインテントに使用します。 +</dd> +</dl> + +<p>全体的なアクションを定義するその他の定数については、{@link android.content.Intent} クラスのリファレンスをご覧ください。 +システムの設定アプリで特定の画面を開くアクションの {@link android.provider.Settings} など、他のアクションは Android フレームワークの別の場所で定義されます。 + +</p> + +<p>インテントのアクションは、{@link android.content.Intent#setAction +setAction()} や {@link android.content.Intent} コンストラクタを使って指定できます。</p> + +<p>独自のアクションを定義したら、接頭辞としてアプリのパッケージ名を必ず含めます。 +次に例を示します。</p> +<pre>static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";</pre> +</dd> + +<dt><b>データ</b></dt> +<dd>アクションの実行対象であるデータや、データの MIME タイプを参照する URI({@link android.net.Uri} オブジェクト)です。 +提供されるデータタイプは、インテントのアクションによって決まります。たとえば、アクションが {@link android.content.Intent#ACTION_EDIT} の場合、データには編集するドキュメントの URI が含まれます。 + + + +<p>インテントの作成時、URI だけでなくデータタイプ(MINE タイプ)を指定することが重要な場面が多くあります。たとえば、画像を表示できるアクティビティの場合、URI 形式は似ていてもオーディオ ファイルは再生できません。そのため、データの MIME タイプを指定することで、Android システムがインテントを受け取るのに最適なコンポーネントを見つけることができます。ただし、MIME タイプは URI から推測できることもあります。特にデータが {@code content:} URI の場合は、データが端末上にあり、{@link android.content.ContentProvider} に制御されるデータであることを示し、データの MIME タイプがシステムから見えるようになります。 + + + + + +— + +</p> + +<p>データ URI のみを設定するには、{@link android.content.Intent#setData setData()} を呼び出します。MIME タイプのみを設定するには、{@link android.content.Intent#setType setType()} を呼び出します。 +必要であれば、{@link +android.content.Intent#setDataAndType setDataAndType()} を使って両方を明示的に設定することもできます。 +</p> + +<p class="caution"><strong>警告:</strong> URI と MIME タイプの両方を設定する場合は、お互いの値を無効にしてしまわないよう、{@link android.content.Intent#setData setData()} と {@link android.content.Intent#setType setType()} を<strong>呼び出さないで</strong>ください。URI と MIME タイプの両方を設定する場合は、常に {@link android.content.Intent#setDataAndType setDataAndType()} を使用してください。 + + + +</p> +</dd> + +<p><dt><b>カテゴリ</b></dt> +<dd>インテントを処理するコンポーネントの種類に関する追加情報が含まれた文字列です。 +カテゴリの記述は、インテントにいくつでも含めることができますが、ほとんどのインテントではカテゴリは必須ではありません。一般的なカテゴリの例を次に示します。 + + + +<dl> +<dt>{@link android.content.Intent#CATEGORY_BROWSABLE}</dt> + <dd>ターゲットのアクティビティは、ウェブブラウザから開始して画像やメール メッセージなど、リンクで参照されたデータを表示できます。 +— + </dd> +<dt>{@link android.content.Intent#CATEGORY_LAUNCHER}</dt> + <dd>このアクティビティはタスクの初期のアクティビティで、システムのアプリケーション ランチャーの一覧に表示されます。 + + </dd> +</dl> + +<p>カテゴリの全一覧は、{@link android.content.Intent} クラスの説明をご覧ください。 +</p> + +<p>カテゴリは、{@link android.content.Intent#addCategory addCategory()} を使って指定できます。</p> +</dd> +</dl> + + +<p>上記のプロパティ(コンポーネント名、アクション、データ、カテゴリ)は、インテントの特性の定義を表しています。 +これらのプロパティを読み取ることで、Android システムはどのアプリ コンポーネントを開始すべきかを解決できます。 +</p> + +<p>ただし、インテントにはアプリ コンポーネントの解決に影響を与えない追加情報を含めることもできます。 +インテントに含めることのできる情報は次のとおりです。</p> + +<dl> +<dt><b>エクストラ</b></dt> +<dd>要求されたアクションの実行に必要な追加情報のキーと値のペアです。データの URI の特定の種類を使用するアクションがあるのと同様に、特定のエクストラを使用するアクションもあります。 + + +<p>エクストラはさまざまな {@link android.content.Intent#putExtra putExtra()} を使って追加でき、それぞれがキー名と値の 2 つのパラメータを受け入れます。また、すべてのエクストラ データを使って {@link android.os.Bundle} オブジェクトを作成し、{@link +android.content.Intent#putExtras putExtras()} を使って {@link android.os.Bundle} を {@link android.content.Intent} に挿入することもできます。 + + +</p> + +<p>たとえば、{@link android.content.Intent#ACTION_SEND} を使ってメールを送信するインテントを作成するとき、{@link android.content.Intent#EXTRA_EMAIL} キーを使って「宛先」の受信者を指定したり、{@link android.content.Intent#EXTRA_SUBJECT} を使って「件名」を指定したりできます。 + + +</p> + +<p>{@link android.content.Intent} クラスは多くの標準データタイプの {@code EXTRA_*} 定数を指定できます。 +独自のエクストラ キーを宣言する必要がある場合は(アプリが受け取るインテント用に)、アプリのパッケージ名を接頭辞として必ず含めます。 + +次に例を示します。</p> +<pre>static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";</pre> +</dd> + +<dt><b>フラグ</b></dt> +<dd>{@link android.content.Intent} クラスで定義されるフラグは、インテントのメタデータとして機能します。 +フラグは、Android システムにアクティビティの起動方法(アクティビティがどの<a href="{@docRoot}guide/components/tasks-and-back-stack.html">タスク</a>に属するかなど)や、起動後の取り扱い方法(最近のアクティビティの一覧に含めるかどうかなど)を指示します。 + + + + +<p>詳細については、{@link android.content.Intent#setFlags setFlags()} メソッドをご覧ください。</p> +</dd> + +</dl> + + + + +<h3 id="ExampleExplicit">明示的インテントの例</h3> + +<p>明示的インテントは、アプリ内の特定のアクティビティやサービスなど、特定のアプリ コンポーネントを起動する際に使用するものです。明示的インテントを作成するには、{@link android.content.Intent} オブジェクトでコンポーネント名を定義します。他のインテント プロパティはすべて省略可能です。 + + +—</p> + +<p>たとえば、アプリでウェブからファイルをダウンロードするサービスを {@code DownloadService} という名前でビルドした場合、次のコードでそれを開始できます。 +</p> + +<pre> +// Executed in an Activity, so 'this' is the {@link android.content.Context} +// The fileUrl is a string URL, such as "http://www.example.com/image.png" +Intent downloadIntent = new Intent(this, DownloadService.class); +downloadIntent.setData({@link android.net.Uri#parse Uri.parse}(fileUrl)); +startService(downloadIntent); +</pre> + +<p>{@link android.content.Intent#Intent(Context,Class)} コンストラクタがアプリに {@link android.content.Context} を、コンポーネントに {@link java.lang.Class} オブジェクトを提供します。 + +このようにして、このインテントはアプリの {@code DownloadService} クラスを明示的に開始します。 +</p> + +<p>サービスのビルドと開始の詳細については、「<a href="{@docRoot}guide/components/services.html">サービス</a>」のガイドをご覧ください。 +</p> + + + + +<h3 id="ExampleSend">暗黙的インテントの例</h3> + +<p>暗黙的インテントは、端末上のどんなアプリでも実行できるアクションを指定します。 +暗黙的インテントは、自身のアプリではそのアクションを実行できないが、他のアプリでは実行可能であり、どのアプリを使うかをユーザーに選ばせたい場合に便利です。 +</p> + +<p>たとえば、他のユーザーと共有できるようにするコンテンツがある場合は、{@link android.content.Intent#ACTION_SEND} アクションを使ってインテントを作成し、共有するコンテンツを指定するエクストラを追加します。 + +そのインテントで {@link android.content.Context#startActivity startActivity()} を呼び出すと、ユーザーはどのアプリでコンテンツを共有するかを選択できます。 + +</p> + +<p class="caution"><strong>警告:</strong> {@link android.content.Context#startActivity +startActivity()} に送る暗黙的インテントを処理できるアプリがユーザーが<em>持っていない</em>場合もあります。 +その場合、呼び出しは失敗し、アプリはクラッシュします。アクティビティが必ずインテントを受け取るようにするには、{@link android.content.Intent} オブジェクトで {@link android.content.Intent#resolveActivity +resolveActivity()} を呼び出します。 +結果が null 以外の場合は、インテントを処理できるアプリが少なくとも 1 つはあることを意味し、{@link android.content.Context#startActivity startActivity()} を安全に呼び出すことができます。 + +結果が null の場合は、そのインテントは使用せず、可能であればそのインテントを発行する機能を無効にする必要があります。 + +</p> + + +<pre> +// Create the text message with a string +Intent sendIntent = new Intent(); +sendIntent.setAction(Intent.ACTION_SEND); +sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage); +sendIntent.setType({@link + org.apache.http.protocol.HTTP#PLAIN_TEXT_TYPE + HTTP.PLAIN_TEXT_TYPE}); // "text/plain" MIME type + +// Verify that the intent will resolve to an activity +if (sendIntent.resolveActivity(getPackageManager()) != null) { + startActivity(sendIntent); +} +</pre> + +<p class="note"><strong>注:</strong> この場合、URI は使用されませんが、エクストラに含まれるコンテンツを指定するためインテントのデータタイプは宣言されます。 +</p> + + +<p>{@link android.content.Context#startActivity startActivity()} が呼び出されたとき、システムによってすべてのインストール済みアプリの中にこのタイプのインテント({@link android.content.Intent#ACTION_SEND} アクションとテキスト/プレーン データが含まれるインテント)を処理できるものがあるかどうかが確認されます + + +インテントを処理できるアプリが 1 つしかない場合は、そのアプリがすぐに開いてインテントを受け取ります。 +インテントを処理できるアクティビティが複数ある場合、ユーザーが使用するアプリを選択できるダイアログが表示されます。 +</p> + + +<div class="figure" style="width:200px"> + <img src="{@docRoot}images/training/basics/intent-chooser.png" alt=""> + <p class="img-caption"><strong>図 2.</strong> チューザのダイアログ</p> +</div> + +<h3 id="ForceChooser">アプリチューザを表示する</h3> + +<p>暗黙的インテントに応答するアプリが 2 つ以上ある場合、ユーザーは使用するアプリを選択でき、そのアプリをアクションに対するデフォルトの選択肢にすることができます。 + +これは、ウェブ ページを開いたり、(1 つのカメラを選ぶ傾向にあるユーザーが) +写真を撮影したりといったアクションの実行時に、ユーザーが今後同じアプリの使用を希望するような場合に便利です(ユーザーは常に同じウェブブラウザを使用する傾向があります)。 +</p> + +<p>ただし、インテントに応答するアプリが複数あって、ユーザーが毎回別のアプリを使用する可能性がある場合は、チューザのダイアログを明示的に表示する必要があります。 +チューザのダイアログでは、 +アクションのたびに使用するアプリをユーザーに選択させます(ユーザーはアクションのデフォルトのアプリを選択できません)。 +たとえば、アプリが {@link +android.content.Intent#ACTION_SEND} アクションを使って「共有」を実行するとき、 ユーザーが現在の状況によって別のアプリを使用して共有する場合もあるため、図 2 のようにチューザのダイアログは常に表示する必要があります。 +</p> + + + + +<p>チューザを表示するには、{@link +android.content.Intent#createChooser createChooser()} を使用して {@link android.content.Intent} を作成し、{@link +android.app.Activity#startActivity startActivity()} に渡します。次に例を示します。</p> + +<pre> +Intent sendIntent = new Intent(Intent.ACTION_SEND); +... + +// Always use string resources for UI text. +// This says something like "Share this photo with" +String title = getResources().getString(R.string.chooser_title); +// Create intent to show the chooser dialog +Intent chooser = Intent.createChooser(sendIntent, title); + +// Verify the original intent will resolve to at least one activity +if (sendIntent.resolveActivity(getPackageManager()) != null) { + startActivity(chooser); +} +</pre> + +<p>これにより、{@link +android.content.Intent#createChooser createChooser()} メソッドに渡されたインテントに応答するアプリのリストを示すダイアログが表示され、 +指定されたテキストがダイアログのタイトルになります。</p> + + + + + + + + + +<h2 id="Receiving">暗黙的インテントを受け取る</h2> + +<p>アプリが受け取ることのできる暗黙的インテントを通知するには、<a href="{@docRoot}guide/topics/manifest/manifest-intro.html">マニフェスト ファイル</a>で <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code <intent-filter>}</a> 要素を使ってアプリのコンポーネントごとに 1 つ以上のインテント フィルタを宣言します。各インテント フィルタは、インテントのアクション、データ、カテゴリに基づいて受け入れるインテントのタイプを指定します。 + + + +インテントがいずれかのインテント フィルタを通過した場合のみ、システムが暗黙的インテントをアプリのコンポーネントに配信します。 +</p> + +<p class="note"><strong>注:</strong> 明示的インテントは、コンポーネントが宣言しているインテント フィルタに関係なく、常にターゲットに配信されます。 +</p> + +<p>アプリのコンポーネントは固有のジョブそれぞれに対して個別のフィルタを宣言する必要があります。たとえば、画像キャラリーのアプリの 1 つのアクティビティには、画像を表示するフィルタと、画像を編集するフィルタの 2 つがあります。 + +アクティビティが開始すると、{@link android.content.Intent} を調べて {@link android.content.Intent} にある情報に基づいてどのように動作するかを決定します(編集コントロールを表示するかどうかなど)。 + +</p> + +<p>各インテント フィルタは、アプリのマニフェスト ファイルの <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code <intent-filter>}</a> 要素で定義され、これは対応するアプリのコンポーネント(<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> 要素など)にネストされます。 + + +<a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code <intent-filter>}</a> 内で、次の 3 つの要素のなかで 1 つ以上を使用して、受け入れるインテントのタイプを指定できます。 + +</p> + +<dl> +<dt><a href="{@docRoot}guide/topics/manifest/action-element.html">{@code <action>}</a></dt> + <dd>{@code name} 属性で、受け入れるインテントのアクションを宣言します。値は、クラス定数ではなく、アクションのリテラル文字列値である必要があります。 +</dd> +<dt><a href="{@docRoot}guide/topics/manifest/data-element.html">{@code <data>}</a></dt> + <dd>データ URI (<code>scheme</code>、<code>host</code>、<code>port</code>、<code>path</code> など) や MIME タイプのさまざまな側面を指定する 1 つ以上の属性を使用して、受け入れるデータのタイプを宣言します。 + +</dd> +<dt><a href="{@docRoot}guide/topics/manifest/category-element.html">{@code <category>}</a></dt> + <dd>{@code name} 属性で、受け入れるインテントのカテゴリを宣言します。値は、クラス定数ではなく、アクションのリテラル文字列値である必要があります。 + + + <p class="note"><strong>注:</strong> 暗黙的インテントを受け取るには、インテント フィルタに {@link android.content.Intent#CATEGORY_DEFAULT} カテゴリを<strong>含める</strong>必要があります。 + +{@link android.app.Activity#startActivity startActivity()} メソッドと {@link android.app.Activity#startActivityForResult startActivityForResult()}メソッドはすべてのインテントを、{@link android.content.Intent#CATEGORY_DEFAULT} カテゴリを宣言しているものとして処理します。 + + + + インテント フィルタでカテゴリを宣言していない場合、暗黙的インテントはアクティビティに紐付けされません。 +</p> + </dd> +</dl> + +<p>次に、データ タイプがテキストの場合に、{@link android.content.Intent#ACTION_SEND} インテントを受け取るインテント フィルタを使用したアクティビティ宣言の例を示します。 +</p> + +<pre> +<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> +</activity> +</pre> + +<p><a href="{@docRoot}guide/topics/manifest/action-element.html">{@code <action>}</a>、<a href="{@docRoot}guide/topics/manifest/data-element.html">{@code <data>}</a>、<a href="{@docRoot}guide/topics/manifest/category-element.html">{@code <category>}</a> のなかで 2 つ以上のインスタンスを含むフィルタを作成することもできます。その場合、コンポーネントがそれらのフィルタ要素のすべての組み合わせを処理できることを確認しておきます。 + + + + +</p> + +<p>複数のタイプのインテントに対応しながら、アクション、データ、カテゴリタイプの特定の組み合わせのみを処理する場合は、複数のインテント フィルタを作成する必要があります。 +</p> + + +<div class="sidebox-wrapper"> +<div class="sidebox"> +<h2>コンポーネントへのアクセスを制限する</h2> +<p>インテント フィルタを使用して他のアプリでコンポーネントを開始できないようにする方法は安全ではありません。 +インテント フィルタでは暗黙的インテントの特定の種類にのみ応答するようコンポーネントを制限しますが、開発者がコンポーネントを決定する場合は、明示的インテントを使用して別のアプリからアプリのコンポーネントを開始できるようになります。アプリのコンポーネントを<em>自身のアプリでのみ</em>開始できるようにする必要がある場合は、そのコンポーネントの <a href="{@docRoot}guide/topics/manifest/activity-element.html#exported">{@code +exported}</a> 属性を{@code "false"} に設定します。 + + + + +</p> +</div> +</div> + +<p>暗黙的インテントは、3 つの要素それぞれへのインテントを比較して、フィルタでテストされます。 +コンポーネントに配信されるには、インテントが 3 つのテストすべてを通過する必要があります。一致しないものが 1 つでも場合、Android システムはインテントをコンポーネントに配信しません。 + +ただし、コンポーネントは複数のインテント フィルタを保持していることもあるため、1 つのインテント フィルタを通過できなかったインテントでも、別のフィルタを通過できる場合があります。システムによるインテント解決の詳細は、次のセクションの<a href="#Resolution">インテントの解決</a>で説明します。 + + +</p> + +<p class="caution"><strong>警告:</strong> 他のアプリの {@link android.app.Service} で誤って実行されないように、自身のサービスは常に明示的インテントを使用して開始し、サービスではインテント フィルタは宣言しないでください。 + +</p> + +<p class="note"><strong>注:</strong> すべてのアクティビティにおいて、インテント フィルタはマニフェスト ファイルで宣言する必要があります。ただし、ブロードキャスト レシーバーのフィルタは、{@link android.content.Context#registerReceiver(BroadcastReceiver, IntentFilter, String, +Handler) registerReceiver()} を呼び出すことで動的に登録できます。 + + +その後、レシーバーの登録を解除するには、{@link +android.content.Context#unregisterReceiver unregisterReceiver()} を使用します。これにより、アプリが実行中の特定の期間だけ、アプリが特定のブロードキャストをリッスンできるようになります。 + +</p> + + + + + + + +<h3 id="ExampleFilters">フィルタの例</h3> + +<p>インテント フィルタの動作をより深く理解するため、ソーシャル シェアリング アプリのマニフェスト ファイルからの次のスニペットをご覧ください。 +</p> + +<pre> +<activity android:name="MainActivity"> + <!-- This activity is the main entry, should appear in app launcher --> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> +</activity> + +<activity android:name="ShareActivity"> + <!-- This activity handles "SEND" actions with text data --> + <intent-filter> + <action android:name="android.intent.action.SEND"/> + <category android:name="android.intent.category.DEFAULT"/> + <data android:mimeType="text/plain"/> + </intent-filter> + <!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data --> + <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> +</pre> + +<p>1 つ目のアクティビティである {@code MainActivity} は、アプリのメイン エントリ ポイントで、ユーザーがランチャー アイコンから初めてアプリを起動したときに開くアクティビティです。— +</p> +<ul> + <li>{@link android.content.Intent#ACTION_MAIN} アクションが、これがメインのエントリ ポイントで、インテント データはないことを示しています。 +</li> + <li>{@link android.content.Intent#CATEGORY_LAUNCHER} カテゴリが、このアクティビティのアイコンをシステムのアプリ ランチャーに配置する必要があることを示しています。 +<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> 要素が {@code icon} を使ってアイコンを指定しない場合、システムは <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a> 要素からのアイコンを使用します。 + +</li> +</ul> +<p>アクティビティをアプリ ランチャーに表示するには、この 2 つをペアリングする必要があります。</p> + +<p>2 つ目のアクティビティである {@code ShareActivity} が、テキストやメディア コンテンツの共有を促します。 +ユーザーは {@code MainActivity} に移動することでこのアクティビティに入ることもありますが、2 つのインテント フィルタのいずれかに一致する暗黙的インテントを発行する別のアプリから直接 {@code ShareActivity} に入ることもできます。 + +</p> + +<p class="note"><strong>注:</strong> MIME タイプ(<a href="https://developers.google.com/panorama/android/">{@code +application/vnd.google.panorama360+jpg}</a>)は、パノラマ写真を指定する特別なデータタイプで、<a href="{@docRoot}reference/com/google/android/gms/panorama/package-summary.html">Google +panorama</a> API を使って処理できます。 + +</p> + + + + + + + + + + + + + +<h2 id="PendingIntent">ペンディング インテントを使用する</h2> + +<p>{@link android.app.PendingIntent} オブジェクトは、{@link +android.content.Intent} オブジェクトのラッパーです。{@link android.app.PendingIntent} の主な目的は、別のアプリケーションに {@link android.content.Intent} をアプリ自身のプロセスから実行したように使用できるパーミッションを付与することです。 + + +</p> + +<p>ペンディング インテントの主な使用例には、次のようなものがあります。</p> +<ul> + <li><a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">通知</a> を使ってユーザーがアクションを実行するときに実施するインテントを宣言する(Android システムの {@link android.app.NotificationManager} が {@link android.content.Intent} を実行します)。 + + + <li> +<a href="{@docRoot}guide/topics/appwidgets/index.html">アプリのウィジェット</a> を使ってユーザーがアクションを実行するときに実施するインテントを宣言する(ホーム画面のアプリが {@link android.content.Intent} を実行します)。 + + <li>今後の指定された時間に実施するインテントを宣言する(Android システムの {@link android.app.AlarmManager} が {@link android.content.Intent} を実行します)。 + +</ul> + +<p>各 {@link android.content.Intent} オブジェクトはアプリの特定のタイプのコンポーネント({@link android.app.Activity}、{@link android.app.Service}、{@link android.content.BroadcastReceiver} のいずれか)で処理されることを前提としているため、{@link android.app.PendingIntent} も同様の前提で作成する必要があります。 + + +ペンディング インテントを使用する場合、アプリはインテントの実行時に {@link android.content.Context#startActivity +startActivity()} などの呼び出しを行いません。 +代わりに、{@link android.app.PendingIntent} の作成時にそれぞれのクリエーター メソッドを呼び出して目的のコンポーネント タイプを宣言する必要があります。 +</p> + +<ul> + <li>{@link android.app.Activity} を開始する {@link android.content.Intent} の場合は、{@link android.app.PendingIntent#getActivity PendingIntent.getActivity()}。 +</li> + <li>{@link android.app.Service} を開始する {@link android.content.Intent} の場合は、{@link android.app.PendingIntent#getService PendingIntent.getService()}。 +</li> + <li>{@link android.content.BroadcastReceiver} を開始する {@link android.content.Intent} の場合は、{@link android.app.PendingIntent#getBroadcast PendingIntent.getBroadcast()}。 +</li> +</ul> + +<p>アプリが他のアプリからペンディング インテントを<em>受け取る</em>場合を除いて、{@link android.app.PendingIntent} の作成時に必要となる {@link android.app.PendingIntent} メソッドはほぼ上記の 3 つのみです。 + +</p> + +<p>各メソッドが現在のアプリの {@link android.content.Context}、ラップする {@link android.content.Intent}、インテントの使用方法を指定する 1 つ以上のフラグ(インテントを 2 回以上できるかどうかなど)を受け取ります。 + +</p> + +<p>ペンディング インテントの使用に関する詳細については、 +「<a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">通知</a>」や「<a href="{@docRoot}guide/topics/appwidgets/index.html">App Widgets</a>」など、それぞれの使用例の API ガイドをご覧ください。 +</p> + + + + + + + +<h2 id="Resolution">インテント解決</h2> + + +<p>システムがアクティビティを開始する暗黙的インテントを受け取ると、次の 3 つの側面に基づいてインテントをインテント フィルタと比較し、そのインテントに最適なアクティビティを検索します。 +</p> + +<ul> + <li>インテントのアクション + <li>インテントのデータ(URI とデータタイプの両方) + <li>インテントのカテゴリ +</ul> + +<p>次のセクションでは、インテント フィルタがアプリのマニフェスト ファイルでどのように宣言されているかという観点から、インテントが適切なコンポーネントに紐付けられる方法について説明します。 +</p> + + +<h3 id="ActionTest">アクションのテスト</h3> + +<p>受け入れるインテントのアクションを指定するには、インテント フィルタでゼロ個以上の <a href="{@docRoot}guide/topics/manifest/action-element.html">{@code +<action>}</a> 要素を宣言します。 +次に例を示します。</p> + +<pre> +<intent-filter> + <action android:name="android.intent.action.EDIT" /> + <action android:name="android.intent.action.VIEW" /> + ... +</intent-filter> +</pre> + +<p>このフィルタを通過するには、{@link android.content.Intent} で指定されたアクションが、フィルタにリストされたアクションのいずれかに一致する必要があります。 +</p> + +<p>フィルタのリストにアクションが 1 つもない場合は、インテントに一致するものがないため、すべてのインテントがテストに失敗します。 +ただし、{@link android.content.Intent} がアクションを指定していない場合は、テストに合格します(フィルタに少なくとも 1 つのアクションが含まれている必要があります)。 + +</p> + + + +<h3 id="CategoryTest">カテゴリのテスト</h3> + +<p>受け入れるインテントのカテゴリを指定するには、インテント フィルタでゼロ個以上の <a href="{@docRoot}guide/topics/manifest/category-element.html">{@code +<category>}</a> 要素を宣言します。 +次に例を示します。</p> + +<pre> +<intent-filter> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.BROWSABLE" /> + ... +</intent-filter> +</pre> + +<p>インテントがカテゴリのテストに合格するには、{@link android.content.Intent} 内のすべてのカテゴリが、フィルタ内のカテゴリに一致する必要があります。 +インテント フィルタでは、{@link android.content.Intent} で指定されたカテゴリよりも多くのカテゴリが宣言されている場合もあるため、すべてが {@link android.content.Intent} に一致しなくてもテストには合格します。— + +そのため、カテゴリのないインテントは、フィルタで宣言されているカテゴリに関係なく、常にこのテストに合格することになります。 +</p> + +<p class="note"><strong>注:</strong> Androidは自動的に、{@link +android.content.Context#startActivity startActivity()} と {@link +android.app.Activity#startActivityForResult startActivityForResult()} に渡されるすべての暗黙的インテントに {@link android.content.Intent#CATEGORY_DEFAULT} カテゴリを自動的に適用します。そのため、アクティビティで暗黙的インテントを受け取りたい場合は、前出の {@code <intent-filter>} の例のように、アクティビティのインテント フィルタに {@code "android.intent.category.DEFAULT"} のカテゴリを含める必要があります。 + + + + +</p> + + + +<h3 id="DataTest">データのテスト</h3> + +<p>受け入れるインテント データを指定するには、インテント フィルタでゼロ個以上の <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code +<data>}</a> 要素を宣言します。 +次に例を示します。</p> + +<pre> +<intent-filter> + <data android:mimeType="video/mpeg" android:scheme="http" ... /> + <data android:mimeType="audio/mpeg" android:scheme="http" ... /> + ... +</intent-filter> +</pre> + +<p>各 <code><a href="{@docRoot}guide/topics/manifest/data-element.html"><data></a></code> 要素では、URI 構造とデータタイプ(MIME メディア タイプ)を指定できます。 +URI の各パートには、{@code scheme}、{@code host}、{@code port}、{@code path} の個別の属性があります。— +— + +</p> + +<p style="margin-left: 2em">{@code <scheme>://<host>:<port>/<path>}</p> + +<p> +次に例を示します。 +</p> + +<p style="margin-left: 2em">{@code content://com.example.project:200/folder/subfolder/etc}</p> + +<p>この URI では、スキームが {@code content}、ホストが {@code com.example.project}、ポートが {@code 200}、パスが {@code folder/subfolder/etc} です。 + +</p> + +<p>これらの各属性は <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code <data>}</a> 要素では省略可能ですが、一次従属があります。 +</p> +<ul> + <li>スキームが指定されていない場合、ホストは無視されます。</li> + <li>ホストが指定されていない場合、ポートは無視されます。</li> + <li>スキームとホストの両方が指定されていない場合、パスは無視されます。</li> +</ul> + +<p>インテントの URI をフィルタの URI 仕様に比較するときは、フィルタに含まれる URI の一部でのみ比較されます。 +次に例を示します。</p> +<ul> + <li>フィルタでスキームのみが指定されている場合、そのスキームを持つすべての URI がフィルタに一致します。 +</li> + <li>フィルタでスキームと認証局が指定されていて、パスが指定されていない場合、パスにかかわらず同じスキームと認証局を持つすべての URI がフィルタを通過します。 +</li> + <li>フィルタでスキーム、認証局、パスが指定されている場合、同じスキーム、認証局、パスを持つ URI のみがフィルタを通過します。 +</li> +</ul> + +<p class="note"><strong>注:</strong> パスの指定では、ワイルドカードのアスタリスク(*)を使ってパス名の部分一致のみを要求することもできます。 +</p> + +<p>データのテストでは、インテントの URI と MIME タイプの両方を、フィルタで指定された URI と MIME タイプと比較します。 +規則は次のとおりです。 +</p> + +<ol type="a"> +<li>URI も MIME タイプも含まないインテントは、フィルタで URI や MIME タイプが指定されていない場合のみテストをパスします。 +</li> + +<li>URI を含んでいて MIME タイプを含んでいないインテント(明示的にも含まれておらず、URI からも推測できない)場合は、URI がフィルタの URI 形式に一致し、フィルタが MIME タイプを指定していない場合のみテストをパスします。 + +</li> + +<li>MIME タイプを含んでいて、URI を含んでいないインテントは、フィルタのリストに同じ MIME タイプがあり、URI 形式が指定されていない場合のみテストをパスします。 +</li> + +<li>URI と MINE タイプの両方を含む(明示的か、URI からの推測)インテントは、MIME タイプがフィルタのリストにあるタイプに一致した場合のみ、テストの MIME タイプのパートをパスします。 + +テストの URI のパートは、URI がフィルタの URI に一致するか、{@code content:} URI か {@code file:} URI があって URI が指定されていない場合にパスできます。つまり、フィルタにリストに MIME タイプ<em>のみ</em>がある場合、コンポーネントは {@code content:} データと {@code file:} データをサポートすると推定されます。 + + + +</p></li> +</ol> + +<p> +この最後の規則(d)は、コンポーネントがファイルやコンテンツ プロバイダからのローカル データを取得できるという予測を反映しています。そのため、フィルタにはデータタイプのみをリストして、{@code content:} スキームや {@code file:} スキームを明示的に指定する必要はありません。これは一般的なケースです。 + + + +たとえば、次の <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code <data>}</a> 要素は、コンポーネントがコンテンツ プロバイダからの画像データを取得し、それを表示できることを Android に伝えています。 + + +</p> + +<pre> +<intent-filter> + <data android:mimeType="image/*" /> + ... +</intent-filter></pre> + +<p> +利用可能なデータはほとんどコンテンツプロバイダによって投入されることから、データタイプが指定されていて URI 指定されていないデータが最も一般的です + +</p> + +<p> +もうひとつ一般的な設定として、スキームと データタイプを使ったフィルタがあります。たとえば、次の <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code <data>}</a> 要素は、アクションを実行するためにコンポーネントがネットワークから動画データを取得できることを Android に伝えています。 + + + +</p> + +<pre> +<intent-filter> + <data android:scheme="http" android:type="video/*" /> + ... +</intent-filter></pre> + + + +<h3 id="imatch">インテントのマッチング</h3> + +<p>インテントをインテント フィルタにマッチングする目的には、アクティベートするターゲットを発見するということだけでなく、端末上のコンポーネントのセットに関連する何かを発見するという目的があります。 + +たとえば、ホーム アプリは {@link android.content.Intent#ACTION_MAIN} アクションと {@link android.content.Intent#CATEGORY_LAUNCHER} カテゴリを指定するインテント フィルタを持つすべてのアクティビティを見つけることで、アプリ ランチャーを設定します。 + + +</p> + +<p>アプリケーションでも、同様の方法でインテントのマッチングを使用できます。{@link android.content.pm.PackageManager} には特定のインテントを受け入れることのできるすべてのコンポーネントを返す一連の {@code query...()} メソッドと、インテントに応答できる最適なコンポーネントを返す同様のシリーズの {@code resolve...()} メソッドがあります。 + + + +たとえば、{@link android.content.pm.PackageManager#queryIntentActivities +queryIntentActivities()} は引数として渡されたインテントを実行できるすべてのアクティビティの一覧を返し、{@link +android.content.pm.PackageManager#queryIntentServices +queryIntentServices()} は同様のサービスの一覧を返します。いずれのメソッドでもコンポーネントのアクティベートは行われず、応答できるものを列挙するだけです。 + + + +ブロードキャスト レシーバー用にも、同様のメソッド {@link android.content.pm.PackageManager#queryBroadcastReceivers +queryBroadcastReceivers()} があります。 + +</p> + + + + diff --git a/docs/html-intl/intl/ja/guide/components/loaders.jd b/docs/html-intl/intl/ja/guide/components/loaders.jd new file mode 100644 index 000000000000..bc936774f721 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/components/loaders.jd @@ -0,0 +1,494 @@ +page.title=ローダ +parent.title=アクティビティ +parent.link=activities.html +@jd:body +<div id="qv-wrapper"> +<div id="qv"> + <h2>本書の内容</h2> + <ol> + <li><a href="#summary">Loader API の概要</a></li> + <li><a href="#app">アプリケーションでローダを使用する</a> + <ol> + <li><a href="#requirements"></a></li> + <li><a href="#starting">ローダを開始する</a></li> + <li><a href="#restarting">ローダを再開する</a></li> + <li><a href="#callback">LoaderManager コールバックを使用する</a></li> + </ol> + </li> + <li><a href="#example">例</a> + <ol> + <li><a href="#more_examples">その他の例</a></li> + </ol> + </li> + </ol> + + <h2>キークラス</h2> + <ol> + <li>{@link android.app.LoaderManager}</li> + <li>{@link android.content.Loader}</li> + + </ol> + + <h2>関連サンプル</h2> + <ol> + <li> <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderCursor.html"> +LoaderCursor</a></li> + <li> <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> +LoaderThrottle</a></li> + </ol> + </div> +</div> + +<p>Android 3.0 で導入されたローダによって、アクティビティやフラグメントでのデータの非同期ロードが簡単になりました。 +ローダには、次の 3 つの特徴があります。</p> + <ul> + <li>すべての {@link android.app.Activity} と {@link +android.app.Fragment} で使用できる。</li> + <li>非同期のデータロードを提供する。</li> + <li>データのソースを監視し、コンテンツが変更されたときに新しい結果を配信する。 +</li> + <li>設定の変更後に再作成されると、自動的に最後のローダのカーソルに再接続するため、 +再度データを問い合わせる必要がない。 +</li> + </ul> + +<h2 id="summary">Loader API の概要</h2> + +<p>アプリケーションでローダを使用するのに必要になりそうなクラスやインターフェースは複数あります。 +次の表で、それらの概要をまとめました。</p> + +<table> + <tr> + <th>クラス/インターフェース</th> + <th>説明</th> + </tr> + <tr> + <td>{@link android.app.LoaderManager}</td> + <td>1 つ以上の {@link +android.content.Loader} インスタンスを管理するための、{@link android.app.Activity} や {@link android.app.Fragment} に関連した抽象クラスです。 +これにより、アプリケーションは {@link android.app.Activity} や {@link android.app.Fragment} のライフサイクルと連動して長時間の操作を管理できるようになります。最も一般的なのは、{@link android.content.CursorLoader} で使用する方法ですが、アプリケーションでは他のタイプのデータのロード用に、独自のローダを自由に作成することもできます。 + + + + + <br /> + <br /> + 1 つのアクティビティやフラグメントごとに、{@link android.app.LoaderManager} は 1 つだけ存在しますが、{@link android.app.LoaderManager} は複数のローダを持つことができます。 +</td> + </tr> + <tr> + <td>{@link android.app.LoaderManager.LoaderCallbacks}</td> + <td>クライアントが {@link +android.app.LoaderManager} とやり取りするためのコールバック インターフェースです。たとえば、{@link +android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} コールバック メソッドを使用してと新しいローダを作成します。 +</td> + </tr> + <tr> + <td>{@link android.content.Loader}</td> + <td>非同期のデータロードを実行する抽象クラスです。これは、ローダの基本クラスです。 +通常は {@link +android.content.CursorLoader} を使用しますが、独自のサブクラスを実装することもできます。ローダがアクティブな間は、データのソースを管理し、コンテンツが変更されたときに新しい結果を配信します。 + + </td> + </tr> + <tr> + <td>{@link android.content.AsyncTaskLoader}</td> + <td>処理を行うための {@link android.os.AsyncTask} を提供する抽象的なローダです。</td> + </tr> + <tr> + <td>{@link android.content.CursorLoader}</td> + <td>{@link android.content.ContentResolver} に問い合わせて {@link +android.database.Cursor} を返す{@link android.content.AsyncTaskLoader} のサブクラスです。 +これは、カーソルのクエリ用に標準的な方法で {@link +android.content.Loader} プロトコルを実装するクラスで、アプリケーションの UI をブロックせずにバックグラウンドでカーソルのクエリを実行するように、{@link android.content.AsyncTaskLoader} を基に構築されています。{@link +android.content.ContentProvider} からデータを非同期的にロードする際は、フラグメントの API やアクティビティの API 経由でマネージド クエリを実行するのではなく、このローダを使用するのが最適です。 + + + +</td> + </tr> +</table> + +<p>上の表のクラスとインターフェースは、アプリケーションでローダを実装する際に使用する必須コンポーネントです。 +作成するローダごとにこれらすべてが必要になるわけではありませんが、{@link +android.app.LoaderManager} への参照は、ローダを初期化したり {@link +android.content.CursorLoader} などの {@link android.content.Loader} を実装したりするには {@link +android.app.LoaderManager} への参照が常に必要になります。 +次のセクションでは、アプリケーションでのこれらのクラスとインターフェースの使用方法を説明します。 +</p> + +<h2 id ="app">アプリケーションでローダを使用する</h2> +<p>このセクションでは、Android アプリケーションのローダの使用方法について説明します。通常、ローダを使用するアプリケーションには次の内容が含まれます。 +</p> +<ul> + <li>{@link android.app.Activity} または {@link android.app.Fragment}。</li> + <li>{@link android.app.LoaderManager} のインスタンス。</li> + <li>{@link +android.content.ContentProvider} でサポートされているデータをロードする {@link android.content.CursorLoader}。あるいは、{@link android.content.Loader} や{@link android.content.AsyncTaskLoader} の独自のサブクラスを実装して他のソースからデータをロードすることもできます。 + +</li> + <li>{@link android.app.LoaderManager.LoaderCallbacks} の実装。ここで、新しいローダを作成して既存のローダへの参照を管理します。 + +</li> +<li>{@link +android.widget.SimpleCursorAdapter} などのローダのデータを表示する方法。</li> + <li>{@link android.content.CursorLoader} を使用するときの、{@link android.content.ContentProvider} などのデータ ソース。 +</li> +</ul> +<h3 id="starting">ローダを開始する</h3> + +<p>{@link android.app.LoaderManager} は 1 つ以上の {@link +android.content.Loader} インスタンスを {@link android.app.Activity} や {@link android.app.Fragment} 内で管理します。 +1 つのアクティビティやフラグメントごとに、{@link +android.app.LoaderManager} は 1 つだけ存在します。</p> + +<p>通常は、アクティビティの {@link +android.app.Activity#onCreate onCreate()} メソッドか、フラグメントの {@link android.app.Fragment#onActivityCreated onActivityCreated()} メソッド内で {@link android.content.Loader} を初期化します。 + +その方法は次のとおりです。 +</p> + +<pre>// Prepare the loader. Either re-connect with an existing one, +// or start a new one. +getLoaderManager().initLoader(0, null, this);</pre> + +<p>{@link android.app.LoaderManager#initLoader initLoader()} メソッドが次のパラメータを受け取ります。 +</p> +<ul> + <li>ローダを識別する一意の ID。この例では、ID は 0 です。</li> +<li>ローダの構築時に提供する任意の引数(この例では <code>null</code>)。 +</li> + +<li>{@link android.app.LoaderManager} がローダのイベントを報告する際に呼び出す {@link android.app.LoaderManager.LoaderCallbacks} の実装。 +この例では、ローカルクラスが {@link +android.app.LoaderManager.LoaderCallbacks} インターフェースを実装するため、自身の {@code this} に参照を渡します。 + +</li> +</ul> +<p>{@link android.app.LoaderManager#initLoader initLoader()} の呼び出しによって、ローダが初期化され、アクティブになります。 +結果には次の 2 つの可能性があります。</p> +<ul> + <li>ID で指定されたローダが既に存在する場合は、最後に作成されたローダが再利用されます。 +</li> + <li>ID で指定したローダが存在<em>しない</em>場合、{@link android.app.LoaderManager#initLoader initLoader()} が {@link android.app.LoaderManager.LoaderCallbacks} メソッドの {@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} をトリガーします。ここで、インスタンスを作成して新しいローダを返すコードを実装します。詳細については、<a href="#onCreateLoader">onCreateLoader</a> のセクションをご覧ください。 + + + +</li> +</ul> +<p>いずれの場合でも、その {@link android.app.LoaderManager.LoaderCallbacks} の実装はローダに関連付けられ、ローダの状態が変化したときに呼び出されます。 + +この呼び出しの時点で、呼び出し側が開始された状態にあり、要求されたローダが既に存在し、データを生成済みの場合は、システムはただちに {@link +android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()} を呼び出す({@link android.app.LoaderManager#initLoader initLoader()} の間に)ため、それに備えておく必要があります。 + + + +このコールバックの詳細については、<a href="#onLoadFinished"> +onLoadFinished</a> をご覧ください。</p> + +<p>{@link android.app.LoaderManager#initLoader initLoader()} メソッドは作成された {@link android.content.Loader} を返しますが、そこへの参照はキャプチャしないことに注意してください。 + +{@link android.app.LoaderManager} は自動的にローダの生存状態を管理します。 +{@link android.app.LoaderManager} は必要に応じて開始と停止を行いし、ローダとそれに関連付けられたコンテンツの状態を管理します。 + +このことからもわかるように、ローダと直接やり取りすることはほとんどありません(ローダの動作を微調整するローダ メソッドの使用例については、<a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> LoaderThrottle</a> のサンプルをご覧ください)。 + +特定のイベントが発生したときにローディングの処理に干渉することを目的に、{@link +android.app.LoaderManager.LoaderCallbacks} を使用することがよくあります。 + +このトピックの詳細については、<a href="#callback">LoadManager コールバックを使用する</a>をご覧ください。</p> + +<h3 id="restarting">ローダを再開する</h3> + +<p>上記のように {@link android.app.LoaderManager#initLoader initLoader()} を使用する場合、指定した ID があれば既存のローダを使用し、なければ新たに作成します。 + +ただし、古いデータを破棄して最初からやり直したいこともあります。 +</p> + +<p>古いデータを破棄するには、{@link +android.app.LoaderManager#restartLoader restartLoader()} を使用します。たとえば、この {@link android.widget.SearchView.OnQueryTextListener} を実装すると、ユーザーのクエリが変化したときにローダが再開されます。 + +新しい検索フィルタを使用して新しいクエリを実行できるように、ローダは再開される必要があります。 +</p> + +<pre> +public boolean onQueryTextChanged(String newText) { + // Called when the action bar search text has changed. Update + // the search filter, and restart the loader to do a new query + // with this filter. + mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; + getLoaderManager().restartLoader(0, null, this); + return true; +}</pre> + +<h3 id="callback">LoaderManager コールバックを使用する</h3> + +<p>{@link android.app.LoaderManager.LoaderCallbacks} はクライアントが {@link android.app.LoaderManager} とやり取りできるようにするコールバック インターフェースです。 + </p> +<p>特に、{@link android.content.CursorLoader} のローダでは、停止後もデータを保持しておくことが望まれます。 +これにより、アプリケーションがアクティビティやフラグメントの {@link android.app.Activity#onStop +onStop()} メソッドや {@link android.app.Activity#onStart onStart()} メソッド全体でデータを維持することができるので、ユーザーがアプリケーションに戻ったときにデータの再ロードを待つ必要がありません。 + + +新しいローダを作成するタイミングを知りたいときや、ローダのデータの使用を停止するタイミングをアプリケーションに伝えるときは、{@link android.app.LoaderManager.LoaderCallbacks} メソッドを使用します。 + +</p> + +<p>{@link android.app.LoaderManager.LoaderCallbacks} には次のメソッドが含まれています。 +</p> +<ul> + <li>{@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} — 指定された ID の新しい {@link android.content.Loader} をインスタンス化して返します。 + +</li></ul> +<ul> + <li> {@link android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}— 前に作成されたローダがロードを完了した時に呼び出されます。 + +</li></ul> +<ul> + <li>{@link android.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()} — 前に作成されたローダがリセットされ、データが利用不可になったときに呼び出されます。 + + +</li> +</ul> +<p>これらのメソッドについては、次のセクションで詳しく説明します。</p> + +<h4 id ="onCreateLoader">onCreateLoader</h4> + +<p>ローダにアクセスしようとしたとき(たとえば、{@link +android.app.LoaderManager#initLoader initLoader()} 経由など)、ID で指定したローダが存在するかどうかを確認されます。 +存在しない場合は、{@link +android.app.LoaderManager.LoaderCallbacks} メソッドの {@link +android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} をトリガーします。ここで、新しいローダを作成します。 +通常は、{@link +android.content.CursorLoader} になりますが、独自の {@link +android.content.Loader} サブクラスを実装することもできます。 </p> + +<p>この例では、{@link +android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} +コールバック メソッドが {@link android.content.CursorLoader} を作成します。{@link android.content.CursorLoader}は、そのコンストラクタ メソッドを使用して構築する必要があり、{@link +android.content.ContentProvider} へのクエリを実行するのに必要なすべての情報が必要になります。 + +具体的に必要な情報は次のとおりです。</p> +<ul> + <li><em>uri</em> — 取得するコンテンツの URI。 </li> + <li><em>projection</em> — 返す列のリスト。<code>null</code> を渡すとすべての列が返されるため、効率的ではありません。 + </li> + <li><em>selection</em> — SQL WHERE 句の書式で返す行を宣言するフィルタ(WHERE 自体は除く)。 +<code>null</code> を渡すと指定した URI のすべての行が返されます。 + </li> + <li><em>selectionArgs</em> — selection に ? を含めると、selection に表示される順序で <em>selectionArgs</em> の値に置き換えられます。 + +この値は、Strings 配列でバインドされます。 </li> + <li><em>sortOrder</em> — SQL +ORDER BY 句(ORDER 自体は除く)の形式で行を順序付けします。<code>null</code> を渡すとデフォルトのソート順序が使用されるため、順序が付けられない場合があります。 +</li> +</ul> +<p>次に例を示します。</p> +<pre> + // If non-null, this is the current filter the user has provided. +String mCurFilter; +... +public Loader<Cursor> onCreateLoader(int id, Bundle args) { + // This is called when a new Loader needs to be created. This + // sample only has one Loader, so we don't care about the ID. + // First, pick the base URI to use depending on whether we are + // currently filtering. + Uri baseUri; + if (mCurFilter != null) { + baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, + Uri.encode(mCurFilter)); + } else { + baseUri = Contacts.CONTENT_URI; + } + + // Now create and return a CursorLoader that will take care of + // creating a Cursor for the data being displayed. + String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" + + Contacts.HAS_PHONE_NUMBER + "=1) AND (" + + Contacts.DISPLAY_NAME + " != '' ))"; + return new CursorLoader(getActivity(), baseUri, + CONTACTS_SUMMARY_PROJECTION, select, null, + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); +}</pre> +<h4 id="onLoadFinished">onLoadFinished</h4> + +<p>このメソッドは、前に作成したローダがロードを完了したときに呼び出されます。このメソッドは、このローダが提供した最後のデータが解放される前に呼び出されることが保証されています。 + +この時点で、すべての古いデータを削除する必要がありますが(まもなく解放されるため)、データの所有者はローダでありローダが処理するため、自身でデータを解放しないようにしてください。 + +</p> + + +<p>アプリケーションがもうデータを使用していないことを検知すると、ローダがデータを解放します。 +たとえば、データが {@link +android.content.CursorLoader} からのカーソルの場合は、自身で {@link +android.database.Cursor#close close()} を呼び出さないようにしてください。カーソルが {@link android.widget.CursorAdapter} に置かれている場合は、古い {@link android.database.Cursor} がクローズされないように {@link +android.widget.SimpleCursorAdapter#swapCursor swapCursor()} メソッドを使用する必要があります。 + +次に例を示します。</p> + +<pre> +// This is the Adapter being used to display the list's data.<br +/>SimpleCursorAdapter mAdapter; +... + +public void onLoadFinished(Loader<Cursor> loader, Cursor data) { + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + mAdapter.swapCursor(data); +}</pre> + +<h4 id="onLoaderReset">onLoaderReset</h4> + +<p>このメソッドは、前に作成されたローダがリセットされ、データが利用できなくなったときに呼び出されます。 +このコールバックにより、データが解放されるタイミングがわかり、そのデータへの参照を削除できます。 + </p> +<p>この実装では、<code>null</code> の値を使用して {@link android.widget.SimpleCursorAdapter#swapCursor swapCursor()} を呼び出します。 + +</p> + +<pre> +// This is the Adapter being used to display the list's data. +SimpleCursorAdapter mAdapter; +... + +public void onLoaderReset(Loader<Cursor> loader) { + // This is called when the last Cursor provided to onLoadFinished() + // above is about to be closed. We need to make sure we are no + // longer using it. + mAdapter.swapCursor(null); +}</pre> + + +<h2 id="example">例</h2> + +<p>以下は、連絡先のコンテンツ プロバイダに対するクエリの結果が含まれた {@link android.widget.ListView} を表示する {@link +android.app.Fragment} の完全な実装の例です。 +{@link +android.content.CursorLoader} を使用してプロバイダへのクエリを管理しています。</p> + +<p>この例にあるように、アプリケーションがユーザーの連絡先にアクセスするには、マニフェストに {@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS} の許可を含める必要があります。 + +</p> + +<pre> +public static class CursorLoaderListFragment extends ListFragment + implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> { + + // This is the Adapter being used to display the list's data. + SimpleCursorAdapter mAdapter; + + // If non-null, this is the current filter the user has provided. + String mCurFilter; + + @Override public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + // Give some text to display if there is no data. In a real + // application this would come from a resource. + setEmptyText("No phone numbers"); + + // We have a menu item to show in action bar. + setHasOptionsMenu(true); + + // Create an empty adapter we will use to display the loaded data. + mAdapter = new SimpleCursorAdapter(getActivity(), + android.R.layout.simple_list_item_2, null, + new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS }, + new int[] { android.R.id.text1, android.R.id.text2 }, 0); + setListAdapter(mAdapter); + + // Prepare the loader. Either re-connect with an existing one, + // or start a new one. + getLoaderManager().initLoader(0, null, this); + } + + @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + // Place an action bar item for searching. + MenuItem item = menu.add("Search"); + item.setIcon(android.R.drawable.ic_menu_search); + item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); + SearchView sv = new SearchView(getActivity()); + sv.setOnQueryTextListener(this); + item.setActionView(sv); + } + + public boolean onQueryTextChange(String newText) { + // Called when the action bar search text has changed. Update + // the search filter, and restart the loader to do a new query + // with this filter. + mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; + getLoaderManager().restartLoader(0, null, this); + return true; + } + + @Override public boolean onQueryTextSubmit(String query) { + // Don't care about this. + return true; + } + + @Override public void onListItemClick(ListView l, View v, int position, long id) { + // Insert desired behavior here. + Log.i("FragmentComplexList", "Item clicked: " + id); + } + + // These are the Contacts rows that we will retrieve. + static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] { + Contacts._ID, + Contacts.DISPLAY_NAME, + Contacts.CONTACT_STATUS, + Contacts.CONTACT_PRESENCE, + Contacts.PHOTO_ID, + Contacts.LOOKUP_KEY, + }; + public Loader<Cursor> onCreateLoader(int id, Bundle args) { + // This is called when a new Loader needs to be created. This + // sample only has one Loader, so we don't care about the ID. + // First, pick the base URI to use depending on whether we are + // currently filtering. + Uri baseUri; + if (mCurFilter != null) { + baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, + Uri.encode(mCurFilter)); + } else { + baseUri = Contacts.CONTENT_URI; + } + + // Now create and return a CursorLoader that will take care of + // creating a Cursor for the data being displayed. + String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" + + Contacts.HAS_PHONE_NUMBER + "=1) AND (" + + Contacts.DISPLAY_NAME + " != '' ))"; + return new CursorLoader(getActivity(), baseUri, + CONTACTS_SUMMARY_PROJECTION, select, null, + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); + } + + public void onLoadFinished(Loader<Cursor> loader, Cursor data) { + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + mAdapter.swapCursor(data); + } + + public void onLoaderReset(Loader<Cursor> loader) { + // This is called when the last Cursor provided to onLoadFinished() + // above is about to be closed. We need to make sure we are no + // longer using it. + mAdapter.swapCursor(null); + } +}</pre> +<h3 id="more_examples">その他の例</h3> + +<p><strong>ApiDemos</strong> には、ローダの使用方法を示す他のサンプルがいくつか用意されています。 +</p> +<ul> + <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderCursor.html"> +LoaderCursor</a> — 上記のスニペットの完全バージョン。 +</li> + <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> LoaderThrottle</a> — スロットリングを使用して、データの変更時にコンテンツ プロバイダのクエリ数を軽減する方法の例です。 +</li> +</ul> + +<p>SDK サンプルのダウンロードとインストールの詳細については、<a href="http://developer.android.com/resources/samples/get.html">Getting the Samples</a> をご覧ください。 + </p> + diff --git a/docs/html-intl/intl/ja/guide/components/processes-and-threads.jd b/docs/html-intl/intl/ja/guide/components/processes-and-threads.jd new file mode 100644 index 000000000000..691a5f471880 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/components/processes-and-threads.jd @@ -0,0 +1,411 @@ +page.title=プロセスとスレッド +page.tags=lifecycle,background + +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + +<h2>本書の内容</h2> +<ol> +<li><a href="#Processes">プロセス</a> + <ol> + <li><a href="#Lifecycle">プロセスのライフサイクル</a></li> + </ol> +</li> +<li><a href="#Threads">スレッド</a> + <ol> + <li><a href="#WorkerThreads">ワーカー スレッド</a></li> + <li><a href="#ThreadSafe">スレッド セーフのメソッド</a></li> + </ol> +</li> +<li><a href="#IPC">プロセス間通信(IPC)</a></li> +</ol> + +</div> +</div> + +<p>アプリケーション コンポーネントが開始し、アプリケーションに他に実行中のコンポーネントがない場合、Android システムは実行用のシングル スレッドを持つアプリケーション用の新しい Linux プロセスを開始します。 + +デフォルトでは、同じアプリケーションのすべてのコンポーネントは同じプロセスとスレッド(「メイン」 スレッドと呼ばれます)で実行します。 +アプリケーション コンポーネントが開始したときに、既にそのアプリケーションのプロセスが存在する場合(アプリケーションからの他のコンポーネントが存在するため)、コンポーネントはそのプロセス内で開始し、同じ実行用のスレッドを使用します。 + +ただし、アプリケーション内の別のコンポーネントを別のプロセスで実行するよう調整でき、あらゆるプロセスに対して追加のスレッドを作成できます。 + +</p> + +<p>このドキュメントでは、Android アプリケーションでプロセスとスレッドがどのように動作するかについて説明します。</p> + + +<h2 id="Processes">プロセス</h2> + +<p>デフォルトでは、同じアプリケーションのすべてのコンポーネントは同じプロセスで実行し、ほとんどのアプリケーションでこの動作を変更する必要はありません。 +ただし、特定のコンポーネントが属するプロセスを管理する必要がある場合は、マニフェスト ファイルでそれを行うことができます。 +</p> + +<p>コンポーネント要素の各タイプのマニフェスト エントリ(<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code +<activity>}</a>、<a href="{@docRoot}guide/topics/manifest/service-element.html">{@code +<service>}</a>、<a href="{@docRoot}guide/topics/manifest/receiver-element.html">{@code +<receiver>}</a>、<a href="{@docRoot}guide/topics/manifest/provider-element.html">{@code +<provider>}</a>)は、コンポーネントを実行するプロセスを指定できる {@code android:process} 属性をサポートしています。— +—この属性を設定して、各コンポーネントが独自のプロセスで実行するようにしたり、一部のコンポーネントで同じプロセスを共有し、残りのコンポーネントでは別のプロセスを使用するようにしたりできます。 +また、{@code android:process} を設定すると、異なるアプリケーションのコンポーネントを同じプロセスで実行させることもできます。この場合、アプリケーションが同じ Linux ユーザー ID を共有していて、同じ証明書で署名されている必要があります。 +— + +</p> + +<p><a href="{@docRoot}guide/topics/manifest/application-element.html">{@code +<application>}</a> 要素も {@code android:process} 属性をサポートしており、すべてのコンポーネントに適用されるデフォルトの値を設定します。 +</p> + +<p>メモリの空きが少なくなり、早急にユーザーに提供する必要のあるプロセスが必要とする場合は、Android がプロセスをどこかの時点でシャットダウンするよう決定する場合があります。 +破棄されたプロセスで実行しているアプリケーション コンポーネントは、結果的に破棄されます。 +プロセスは、それらのコンポーネントの処理が再度発生したときに再開されます。 +</p> + +<p>破棄するプロセスを決定する際、Android システムはユーザーへの相対的な重要度を測ります。 +たとえば、画面に見えているアクティビティをホストするプロセスよりも、もう画面に見えていないアクティビティをホストするプロセスの方が先にシャットダウンされることになります。 +そのため、プロセスを停止するかどうかは、そのプロセスで実行しているコンポーネントの状態によって決まります。 +ここから、停止するプロセスを決定する規則について詳しく説明していきます。 + </p> + + +<h3 id="Lifecycle">プロセスのライフサイクル</h3> + +<p>Android システムは、可能な限り長期間アプリケーション プロセスを維持しようとしますが、新たに重要なプロセスが発生した際には、メモリを回収するために古いプロセスをいずれは削除する必要が生じます。 +どのプロセスを維持して、どのプロセスを強制終了するかを決定するため、システムはプロセスで実行しているコンポーネントとコンポーネントの状態に基づいて、各プロセスを「重要度の階層」に位置付けします。 + + +まず、重要度の最も低いプロセスが除去され、その後システム リソースを回復できるまで重要度の低い順に除去していきます。 + +</p> + +<p>重要度の階層には 5 つのレベルがあります。次の一覧では、さまざまなプロセスのタイプを重要度の高い順に表しています(1 つ目のプロセスが<em>最も重要度が高く</em>、<em>最後に強制終了</em>されます)。 + +</p> + +<ol> + <li><b>フォアグラウンド プロセス</b> + <p>ユーザーが現在行っている操作に必要なプロセスです。次の条件のいずれかにあてはまる場合、そのプロセスはフォアグラウンドにあるとみなされます。 +</p> + + <ul> + <li>ユーザーが操作している {@link android.app.Activity} のホストになっている({@link +android.app.Activity} の{@link android.app.Activity#onResume onResume()} メソッドが呼び出された)。 +</li> + + <li>ユーザーが操作しているアクティビティにバインドされている {@link android.app.Service} のホストになっている。 +</li> + + <li>「フォアグラウンド」 で実行中の {@link android.app.Service} のホストになっている(サービスが {@link android.app.Service#startForeground startForeground()} を呼び出した)。— + + + <li>{@link android.app.Service#onCreate onCreate()}、{@link android.app.Service#onStart +onStart()}、{@link android.app.Service#onDestroy onDestroy()} のいずれかのライフサイクル コールバックを実行している {@link android.app.Service} のホストになっている。 +</li> + + <li>{@link + android.content.BroadcastReceiver#onReceive onReceive()} メソッドを実行している {@link android.content.BroadcastReceiver} のホストになっている。</li> + </ul> + + <p>通常は、2~3 個のフォアグラウンド プロセスが存在します。フォアグラウンド プロセスは、それらすべてを実行できなくなるほどメモリが少なくなると、最終手段として強制終了されます。 +—通常はその時点で、端末がメモリのページング状態に達しているため、ユーザー インターフェースのレスポンシブを維持するには一部のフォアグラウンド プロセスを強制終了する必要があります。 + +</p></li> + + <li><b>可視プロセス</b> + <p>フォアグラウンド コンポーネントはないものの、ユーザーに対して画面上に表示される内容に影響を与える可能性のあるプロセスです。 +次の条件のいずれかにあてはまる場合、そのプロセスは可視プロセスであるとみなされます。 +</p> + + <ul> + <li>フォアグラウンドにないが、ユーザーに表示されている {@link android.app.Activity} のホストになっている({@link android.app.Activity#onPause onPause()} メソッドが呼び出された)。 +たとえば、フォアグラウンドのアクティビティがダイアログを開始したときに、前のアクティビティがその背後に見えている場合などがあります。 + +</li> + + <li>可視(またはフォアグラウンドの)アクティビティにバインドされている {@link android.app.Service} のホストになっている。 +</li> + </ul> + + <p>可視プロセスは非常に重要度が高いため、フォアグラウンド プロセスの実行を維持するのに必要な場合のみ、強制終了されます。 + </p> + </li> + + <li><b>サービス プロセス</b> + <p>{@link +android.content.Context#startService startService()} メソッドで開始されたサービスを実行するプロセスで、上の 2 つのカテゴリに分類されないものです。 +サービス プロセスは、ユーザーに表示される内容には直接関係ありませんが、ユーザーにとって必要な操作を実行している場合が多いため(バックグラウンドで音楽を再生したり、ネットワーク経由でデータをダウンロードしたりなど)、フォアグラウンド プロセスと可視プロセスのすべてと合わせて、それらを継続するのにメモリが不足した場合のみ強制終了されます。 + + + </p> + </li> + + <li><b>バックグラウンド プロセス</b> + <p>現在ユーザーに表示されていないアクティビティを有するプロセスです(アクティビティの {@link android.app.Activity#onStop onStop()} メソッドが呼び出された)。 +ユーザーの操作性に直接影響を与えるものではなく、フォアグラウンド プロセス、可視プロセス、サービス プロセス用にメモリを回収する必要があればいつでも強制終了されます。 + + +通常はバックグラウンドで実行するプロセスは多数あるため、最近ユーザーに表示されたアクティビティのあるプロセスを最後に強制終了するよう、LRU(最小使用頻度)リストに入れられます。 + +アクティビティがライフサイクル メソッドを正確に実装し、現在の状態を保存する場合は、そのプロセスを強制終了しても、ユーザーがそのアクティビティに戻ったときに、アクティビティがすべての視覚的状態を復元するため、ユーザーの操作性に視覚的な影響はありません + + +。状態の保存と復元の詳細については、「<a href="{@docRoot}guide/components/activities.html#SavingActivityState">Activities</a>」のドキュメントをご覧ください。 +</p> + </li> + + <li><b>空のプロセス</b> + <p>アクティブなアプリケーション コンポーネントが 1 つも含まれていないプロセスです。このようなプロセスは、プロセスをキャッシュしておくことのみを目的として保持され、次回コンポーネントを実行する際の起動時間を向上させることができます。 + +システムは、プロセスのキャッシュと下層のカーネル キャッシュとの間の全体的なシステム リソースのバランスを整える目的でこれらのシステムを頻繁に強制終了します。 +</p> + </li> +</ol> + + + <p>Android では、プロセスで現在アクティブなコンポーネントの重要度に基づいて、あてはまるランクのなかで最も高いランクにプロセスを位置付けます。 +たとえば、サービス アクティビティと可視アクティビティの両方のホストとなっているプロセスは、サービス プロセスではなく、可視プロセスとして位置付けられます。 +</p> + + <p>さらに、他のプロセスから依存されているプロセスの位置付けが上がる場合があります。他のプロセスのために動作しているプロセスは、その対象プロセスよりも下に位置付けられることはありません。 +— +たとえば、プロセス A のコンテンツ プロバイダが、プロセス B のクライアントのために動作している場合や、プロセス A のサービスがプロセス B のコンポーネントにバインドされている場合、プロセス A の重要度は常にプロセス B 以上であるとみなされます。 + +</p> + + <p>サービスを実行するプロセスは、バックグラウンドのアクティビティを持つプロセスよりも上に位置付けされるため、長時間の操作を開始するアクティビティでは、特に、操作がアクティビティよりも長く続く場合、ワーカー スレッドを作成するよりもその操作の<a href="{@docRoot}guide/components/services.html">サービス</a>を開始する方がよいと考えられます。たとえば、ウェブサイトに写真をアップロードするアクティビティでは、ユーザーがアクティビティから離れた後もアップロードをバックグラウンドで続行できるよう、アップロードを実行するサービスを開始することをお勧めします。サービスを使用することで、アクティビティの状況に変わらず、その操作に「サービス プロセス」以上の優先度が保証されることになります。 + + + + + +同じ理由から、ブロードキャスト レシーバーでもスレッドに長時間の処理を置くのではなく、サービスを採用するようお勧めします。 +</p> + + + + +<h2 id="Threads">スレッド</h2> + +<p>アプリケーション起動の際、システムは アプリケーション実行用のスレッドを作成します。これは、「メイン スレッド」と呼ばれます。 +このスレッドは、イベント(描画イベントを含む)を適切なユーザー インターフェース ウィジェットに送信する役割を担うため非常に重要です。 +また、これはアプリケーションが Android UI ツールキット({@link +android.widget} と {@link android.view} パッケージからのコンポーネント)からのコンポーネントとやり取りをするスレッドでもあります。 +そのため、メイン スレッドは UI スレッドと呼ばれることもあります。 +</p> + +<p>コンポーネントのインスタンスごとに別のスレッドが作成されることは<em>ありません</em>。同じプロセスで実行するすべてのコンポーネントは UI スレッドでインスタンス化され、スレッドから送られた各コンポーネントをシステムが呼び出します。 + +結果的に、システムのコールバック(ユーザー操作を報告する {@link android.view.View#onKeyDown onKeyDown()} やライフサイクル コールバック メソッドなど)に応答するメソッドは常にプロセスの UI スレッドで実行することになります。 + +</p> + +<p>たとえば、ユーザーが画面上のボタンをタッチすると、アプリの UI スレッドがタッチ イベントをウィジェットに送信し、ウィジェットがそのタッチされた状態を設定してイベント キューに無効化の要求を投稿します。 + +UI スレッドが要求をキューから取り出し、ウィジェットに自身を描画するよう通知します。 +</p> + +<p>アプリがユーザー操作に応答して集中的な動作を実行する場合、アプリケーションを正しく実装していない限りこのシングル スレッド モデルではパフォーマンスの低下につながる可能性があります。 +具体的には、すべてが UI スレッドで行われている場合、長ネットワークへのアクセスやデータベースへの問い合わせといった時間のかかる操作を実行すると UI 全体をブロックしてしまいます。スレッドがブロックされると、描画イベントを含むすべてのイベントを送信できなくなります。 + + +ユーザー側には、アプリケーションがハングしたように見えます。 +さらには、UI スレッドが数秒以上(現時点では 5 秒以上)ブロックされると、ユーザーに<a href="http://developer.android.com/guide/practices/responsiveness.html">「アプリケーションが応答していません」</a>のダイアログが表示されます。 + +ユーザーはアプリケーションを停止するか、不快な場合はアンインストールしてしまう可能性があります。 +</p> + +<p>また、Android UI ツールキットはスレッド セーフ<em>ではありません</em>。そのため、ワーカー スレッドから UI を操作できません。すべての操作は、UI スレッドから行う必要があります。 +— +そのため、Android のシングル スレッド モデルには 2 つの明快なルールがあります。</p> + +<ol> +<li>UI スレッドをブロックしない +<li>UI スレッド以外から Android UI ツールキットにアクセスしない +</ol> + +<h3 id="WorkerThreads">ワーカー スレッド</h3> + +<p>上記で説明したシングル スレッド モデルにより、アプリケーションの UI の応答性のためにも UI スレッドをブロックしないことが不可欠です。 +即座に実行する必要のない操作の場合は、別のスレッド(「バックグラウンド」スレッドや「ワーカー」スレッド)で実行するようにする必要があります。 + +</p> + +<p>例として、別のスレッドから画像をダウンロードして {@link android.widget.ImageView} に表示するクリック リスナのコードの一部を次に示します。 +</p> + +<pre> +public void onClick(View v) { + new Thread(new Runnable() { + public void run() { + Bitmap b = loadImageFromNetwork("http://example.com/image.png"); + mImageView.setImageBitmap(b); + } + }).start(); +} +</pre> + +<p>ここでは、ネットワークの操作を処理する新しいスレッドを作成しているため、一見問題ないように見えます。 +ただし、これは<em>UI スレッド以外から Android UI ツールキットにアクセスしない</em>というシングルスレッド モデルの 2 つ目のルールに違反しています。このサンプルは、UI スレッドではなくワーカー スレッドから {@link +android.widget.ImageView} を変更しています。— +結果として、未定義かつ予想外の動作を引き起こし、追跡が難しく時間のかかる作業になってしまいます。 +</p> + +<p>この問題を修正するため、Android には UI スレッド以外からのアクセス方法がいくつか用意されています。 +使用できるメソッドは次のとおりです。</p> + +<ul> +<li>{@link android.app.Activity#runOnUiThread(java.lang.Runnable) +Activity.runOnUiThread(Runnable)}</li> +<li>{@link android.view.View#post(java.lang.Runnable) View.post(Runnable)}</li> +<li>{@link android.view.View#postDelayed(java.lang.Runnable, long) View.postDelayed(Runnable, +long)}</li> +</ul> + +<p>たとえば、上記のコードは {@link +android.view.View#post(java.lang.Runnable) View.post(Runnable)} メソッドを使用して修正できます。</p> + +<pre> +public void onClick(View v) { + new Thread(new Runnable() { + public void run() { + final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png"); + mImageView.post(new Runnable() { + public void run() { + mImageView.setImageBitmap(bitmap); + } + }); + } + }).start(); +} +</pre> + +<p>これで、この実装がスレッドセーフになりました。ネットワーク操作は別のスレッドから実行され、{@link android.widget.ImageView} は UI スレッドから操作されます。 +</p> + +<p>ただし、操作が複雑になるにつれて、この種のコードも複雑化してメンテナンスも難しくなります。 +ワーカー スレッドとのより複雑なやり取りを処理するため、ワーカー スレッドで {@link android.os.Handler} を使うと、UI スレッドから配信されたメッセージを処理できます。 + +ただし、最善なのは{@link android.os.AsyncTask} クラスを拡張することであり、これにより UI を操作する必要のあるワーカー スレッドのタスクの実行を簡素化できます。 +</p> + + +<h4 id="AsyncTask">AsyncTask を使用する</h4> + +<p>{@link android.os.AsyncTask} では、ユーザー インターフェースに非同期の処理を実行できます。 +スレッドやハンドラを自身で処理する必要なく、ワーカー スレッドの操作をブロックし、結果を UI スレッドに発行します。 +</p> + +<p>これを使用するには、{@link android.os.AsyncTask} をサブクラス化し、バックグラウンド スレッドのプール内で実行する {@link +android.os.AsyncTask#doInBackground doInBackground()} コールバック メソッドを実装する必要があります。 +UI を更新するには、{@link +android.os.AsyncTask#onPostExecute onPostExecute()} を実装します。これは {@link +android.os.AsyncTask#doInBackground doInBackground()} からの結果を配信し、UI スレッド内で実行されるため、UI を安全に更新できます。その後、UI スレッドから {@link android.os.AsyncTask#execute execute()} を呼び出してタスクを実行できます。 + +</p> + +<p>たとえば、次のように {@link android.os.AsyncTask} を使って前出の例を実装できます。 +</p> + +<pre> +public void onClick(View v) { + new DownloadImageTask().execute("http://example.com/image.png"); +} + +private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> { + /** The system calls this to perform work in a worker thread and + * delivers it the parameters given to AsyncTask.execute() */ + protected Bitmap doInBackground(String... urls) { + return loadImageFromNetwork(urls[0]); + } + + /** The system calls this to perform work in the UI thread and delivers + * the result from doInBackground() */ + protected void onPostExecute(Bitmap result) { + mImageView.setImageBitmap(result); + } +} +</pre> + +<p>ワーカー スレッドで処理される作業と、UI スレッドで処理される作業が分けられたため、UI は安全に、コードはシンプルになりました。 +</p> + +<p>このクラスの使用方法をより深く理解するには {@link android.os.AsyncTask} に目を通す必要がありますが、ここに、その仕組みについて簡単に挙げておきます。 +</p> + +<ul> +<li>ジェネリックを使ってパラメータのタイプ、進捗の値、タスクの最終値を指定できます +</li> +<li>{@link android.os.AsyncTask#doInBackground doInBackground()} メソッドがワーカー スレッド上で自動的に実行されます +</li> +<li>{@link android.os.AsyncTask#onPreExecute onPreExecute()}、{@link +android.os.AsyncTask#onPostExecute onPostExecute()}、{@link +android.os.AsyncTask#onProgressUpdate onProgressUpdate()}はすべて UI スレッドで呼び出されます</li> +<li>{@link android.os.AsyncTask#doInBackground doInBackground()} から返される値は、{@link android.os.AsyncTask#onPostExecute onPostExecute()} に送られます +</li> +<li>{@link android.os.AsyncTask#publishProgress publishProgress()} は、{@link +android.os.AsyncTask#doInBackground doInBackground()} でいつでも呼び出すことができます。UI スレッドで {@link +android.os.AsyncTask#onProgressUpdate onProgressUpdate()} を実行できます</li> +<li>いつでも、どのスレッドからでもタスクをキャンセルできます</li> +</ul> + +<p class="caution"><strong>警告:</strong> ワーカー スレッドの使用時に発生する可能性のあるもう 1 つの問題として、<a href="{@docRoot}guide/topics/resources/runtime-changes.html">実行時の設定が変更</a>された(ユーザーが画面の向きを変えた場合など)ことによってアクティビティが予期せず再起動され、ワーカー スレッドが破棄されてしまうことがあります。 + +このような再起動の間タスクを維持する方法、アクティビティが破棄されたときの正しいタスクのキャンセル方法については、<a href="http://code.google.com/p/shelves/">Shelves</a> のサンプル アプリケーションのソース コードをご覧ください。 + +</p> + + +<h3 id="ThreadSafe">スレッド セーフのメソッド</h3> + +<p> 状況によっては、実装したメソッドが複数のスレッドから呼び出されることがあり、その場合はメソッドがスレッドセーフになるよう作成する必要があります。 + </p> + +<p>主に、<a href="{@docRoot}guide/components/bound-services.html">バインドされたサービス</a>のメソッドなど、リモートで呼び出されるメソッドなどがこれに該当します。—{@link android.os.IBinder} に実装されたメソッドへの呼び出しが、{@link android.os.IBinder IBinder} を実行しているプロセスと同じプロセスで発生した場合、メソッドは呼び出し側のスレッドで実行されます。ただし、呼び出しが別のプロセスで起こった場合は、メソッドはシステムが {@link android.os.IBinder +IBinder} と同じプロセスに保持するスレッドのプールから選ばれたスレッドで実行されます(プロセスの UI スレッドでは実行されません)。 + + + +たとえば、サービスの {@link android.app.Service#onBind onBind()} メソッドがサービスのプロセスの UI スレッドから呼び出されるのに対して、{@link android.app.Service#onBind +onBind()} が返すオブジェクトで実装されたメソッド(RPC メソッドを実装するサブクラスなど)は、プール内のスレッドから呼び出されます。 + + +サービスは複数のクライアントを持てるため、複数のプール スレッドが同じ {@link android.os.IBinder IBinder} メソッドを同時に動かすことができます。このため、{@link android.os.IBinder +IBinder} メソッドはスレッドセーフになるよう実装する必要があります。 +</p> + +<p> 同様に、コンテンツ プロバイダは他のプロセスから送られたデータ要求を受け取ることができます。{@link android.content.ContentResolver} クラスと {@link android.content.ContentProvider} クラスによってプロセス間通信がどのように管理されているかが見えなくなりますが、それらの要求に応答する {@link +android.content.ContentProvider} メソッド({@link +android.content.ContentProvider#query query()}、 {@link android.content.ContentProvider#insert +insert()}、{@link android.content.ContentProvider#delete delete()}、{@link +android.content.ContentProvider#update update()}、{@link android.content.ContentProvider#getType +getType()})は、プロセスの UI スレッドではなく、コンテンツ プロバイダのプロセスにあるスレッドのプールから呼び出されます。 + + +——これらのメソッドは同時に複数のスレッドから呼び出される可能性があるため、先ほどと同様にスレッドセーフになるよう実装する必要があります。 + </p> + + +<h2 id="IPC">プロセス間通信(IPC)</h2> + +<p>Android では、リモート プロシージャ コール(RPC)を使ったプロセス間通信のメカニズムを備えており、メソッドはアクティビティや他のアプリケーション コンポーネントから呼び出された後に、リモート(別のプロセス)で実行され、結果を呼び出し側に返します。 + + +これにより、メソッドの呼び出しとそのデータをオペレーティング システムが理解できるレベルまで分解し、ローカル プロセスとアドレス空間からリモート プロセスとアドレス空間にそれを送信して、そこで呼び出しが再度組み立てて、再現します。 + +その後、戻り値が逆方向に伝達されます。 +Android ではこれらの IPC トランザクションを実行するためのすべてのコードが用意されているため、開発者は RPC のプログラミング インターフェースの定義と実装に集中できます。 + </p> + +<p>IPC を実行するには、アプリケーションが {@link +android.content.Context#bindService bindService()} を使ってサービスにバインドされている必要があります。詳細については、デベロッパー ガイドの「<a href="{@docRoot}guide/components/services.html">サービス</a>」をご覧ください。</p> + + +<!-- +<h2>Beginner's Path</h2> + +<p>For information about how to perform work in the background for an indefinite period of time +(without a user interface), continue with the <b><a +href="{@docRoot}guide/components/services.html">Services</a></b> document.</p> +--> diff --git a/docs/html-intl/intl/ja/guide/components/recents.jd b/docs/html-intl/intl/ja/guide/components/recents.jd new file mode 100644 index 000000000000..81626e1f2925 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/components/recents.jd @@ -0,0 +1,256 @@ +page.title=オーバービュー画面 +page.tags="recents","overview" + +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + + <h2>本書の内容</h2> + <ol> + <li><a href="#adding">オーバービュー画面にタスクを追加する</a> + <ol> + <li><a href="#flag-new-doc">インテント フラグを使用してタスクを追加する</a></li> + <li><a href="#attr-doclaunch">アクティビティの属性を使用してタスクを追加する</a></li> + </ol> + </li> + <li><a href="#removing">タスクを削除する</a> + <ol> + <li><a href="#apptask-remove">AppTask クラスを使用してタスクを削除する</a></li> + <li><a href="#retain-finished">完了したタスクを保持する</a></li> + </ol> + </li> + </ol> + + <h2>キークラス</h2> + <ol> + <li>{@link android.app.ActivityManager.AppTask}</li> + <li>{@link android.content.Intent}</li> + </ol> + + <h2>サンプル コード</h2> + <ol> + <li><a href="{@docRoot}samples/DocumentCentricApps/index.html">ドキュメント中心のアプリ</a></li> + </ol> + +</div> +</div> + +<p>オーバービュー画面(別名、最近使った画面、最近使ったタスクリスト、最近使ったアプリ)は、最近アクセスした<a href="{@docRoot}guide/components/activities.html">アクティビティ</a>や<a href="{@docRoot}guide/components/tasks-and-back-stack.html">タスク</a>の一覧を示すシステムレベルの UI です。 + +ユーザーはリスト内をナビゲートして再開するタスクを選択したり、スワイプしてタスクをリストから削除したりできます。 + +Android 5.0(API レベル 21)のリリースでは、異なるドキュメントを持つ同一アクティビティ内の複数のインスタンスが、1 つのタスクとしてオーバービュー画面に表示される場合があります。 +たとえば、Google ドライブには複数の Google ドキュメントごとのタスクが表示される場合があります。 +オーバービュー画面には、各ドキュメントが 1 つのタスクとして表示されます。 +</p> + +<img src="{@docRoot}images/components/recents.png" alt="" width="284" /> +<p class="img-caption"><strong>図 1.</strong> オーバービュー画面に表示されている 3 つの Google ドライブ ドキュメントが、それぞれ別のタスクを表しています。 +</p> + +<p>通常、オーバービュー画面にタスクとアクティビティを提示する方法はシステムが定義できるよう許可し、この動作を変更する必要はありません。 +ただし、アクティビティをいつ、どのようにオーバービュー画面に表示するかをアプリで決定することもできます。 +{@link android.app.ActivityManager.AppTask} クラスを使ってタスクを管理でき、{@link android.content.Intent} クラスのアクティビティ フラグを使うとアプリをオーバービュー画面に追加、削除するタイミングを指定できます。 + + +また、<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"> +<activity></a></code> 属性を使ってマニフェストで動作を設定することもできます。</p> + +<h2 id="adding">オーバービュー画面にタスクを追加する</h2> + +<p>{@link android.content.Intent} クラスのフラグを使用してタスクを追加すると、ドキュメントをいつ、どのようにオーバービュー画面で開いたり、再度開いたりできるかを細かく制御できます。 +<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> 属性を使用すると、常に新しいタスクでドキュメントを開くか、ドキュメントの既存のタスクを再利用するかを選択できます。 + + +</p> + +<h3 id="flag-new-doc">インテント フラグを使用してタスクを追加する</h3> + +<p>アクティビティの新しいドキュメントを作成するときは、{@link android.app.ActivityManager.AppTask} クラスの {@link android.app.ActivityManager.AppTask#startActivity(android.content.Context, android.content.Intent, android.os.Bundle) startActivity()} メソッドを呼び出し、アクティビティを起動するインテントを渡します。 + + +論理的な改行を挿入して、システムがアクティビティをオーバービュー画面の新しいタスクとして扱えるようにするには、{@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} フラグを、アクティビティを起動する {@link android.content.Intent} の {@link android.content.Intent#addFlags(int) addFlags()} メソッドに渡します。 + + +</p> + +<p class="note"><strong>注:</strong> {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} フラグは、Android 5.1(API レベル 21)で廃止された {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET} を置き換えるものです。 + +</p> + +<p>新しいドキュメントの作成時に {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK} フラグを設定すると、システムは常にターゲット アクティビティの新しいタスクをルートとして作成するようになります。この設定によって、同じドキュメントを複数のタスクで開くことが可能になります。 + +これをメインのアクティビティが行う方法を、次のコードで示し舞うs。 +</p> + +<p class="code-caption"><a href="{@docRoot}samples/DocumentCentricApps/index.html"> +DocumentCentricActivity.java</a></p> +<pre> +public void createNewDocument(View view) { + final Intent newDocumentIntent = newDocumentIntent(); + if (useMultipleTasks) { + newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + } + startActivity(newDocumentIntent); + } + + private Intent newDocumentIntent() { + boolean useMultipleTasks = mCheckbox.isChecked(); + final Intent newDocumentIntent = new Intent(this, NewDocumentActivity.class); + newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); + newDocumentIntent.putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, incrementAndGet()); + return newDocumentIntent; + } + + private static int incrementAndGet() { + Log.d(TAG, "incrementAndGet(): " + mDocumentCounter); + return mDocumentCounter++; + } +} +</pre> + +<p class="note"><strong>注:</strong> {@code FLAG_ACTIVITY_NEW_DOCUMENT} フラグを使って起動されたアクティビティには、マニフェスト ファイルで {@code android:launchMode="standard"} 属性の値(デフォルト)が設定されている必要があります。 + +</p> + +<p>メイン アクティビティが新しいアクティビティを起動するとき、システムはアクティビティのインテント コンポーネント名とインテント データに一致するインテントを持つ既存のタスクを検索します。 +タスクが見つからない場合や、インテントに {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK} フラグに含まれている場合は、新しいタスクがアクティビティのルートとして作成されます。 + +タスク見つかった場合は、そのタスクをフロントに移動して、新しいインテントを {@link android.app.Activity#onNewIntent onNewIntent()} に渡します。新しいアクティビティがインテントを受け取り、次の例のようにオーバービュー画面に新しいドキュメントを作成します。 + + +</p> + +<p class="code-caption"><a href="{@docRoot}samples/DocumentCentricApps/index.html"> +NewDocumentActivity.java</a></p> +<pre> +@Override +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_new_document); + mDocumentCount = getIntent() + .getIntExtra(DocumentCentricActivity.KEY_EXTRA_NEW_DOCUMENT_COUNTER, 0); + mDocumentCounterTextView = (TextView) findViewById( + R.id.hello_new_document_text_view); + setDocumentCounterText(R.string.hello_new_document_counter); +} + +@Override +protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + /* If FLAG_ACTIVITY_MULTIPLE_TASK has not been used, this activity + is reused to create a new document. + */ + setDocumentCounterText(R.string.reusing_document_counter); +} +</pre> + + +<h3 id="#attr-doclaunch">アクティビティの属性を使用してタスクを追加する</h3> + +<p>アクティビティのマニフェストで、<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> の属性の<a href="{@docRoot}guide/topics/manifest/activity-element.html#dlmode">{@code android:documentLaunchMode}</a> を使ってアクティビティを常に新しいタスクで起動するよう指定することもできます。 + + +この属性には 4 つの値があり、ユーザーがアプリケーションでドキュメントを開くときに次のような効果を生みます。 +</p> + +<dl> + <dt>「{@code intoExisting}」</dt> + <dd>アクティビティがそのドキュメントの既存のタスクを再利用します。これは、<a href="#flag-new-doc">インテント フラグを使用してタスクを追加する</a>で説明したように、{@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK} フラグを<em>設定せずに</em>、{@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} フラグを設定した場合と同じです。 + + +</dd> + + <dt>「{@code always}」</dt> + <dd>ドキュメントが既に開いている場合でも、アクティビティがドキュメントの新しいタスクを作成します。これは、{@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} フラグと {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK} フラグの両方を設定した場合と同じです。 + +</dd> + + <dt>「{@code none”}」</dt> + <dd>アクティビティはドキュメントの新しいタスクを作成しません。オーバービュー画面はデフォルトでアクティビティがタスクを作成したかのように処理し、アプリの 1 つのタスクを表示して、ユーザーが最後に呼び出したアクティビティから再開します。 + +</dd> + + <dt>「{@code never}」</dt> + <dd>アクティビティはドキュメントの新しいタスクを作成しません。この値を設定すると、{@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} フラグと {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK} フラグのいずれかが設定されている場合にその動作をオーバーライドし、オーバービュー画面にはアプリの 1 つのタスクが表示され、ユーザーが最後に呼び出したアクティビティから再開します。 + + + +</dd> +</dl> + +<p class="note"><strong>注:</strong> {@code none} と {@code never} の値以外の場合、アクティビティを {@code launchMode="standard"} を使って定義する必要があります。 +属性が指定されていない場合は、{@code documentLaunchMode="none"} が使用されます。 +</p> + +<h2 id="removing">タスクを削除する</h2> + +<p>デフォルトで、アクティビティの完了時にドキュメントのタスクはオーバービュー画面から自動的に削除されます。 +この動作は、{@link android.app.ActivityManager.AppTask} クラスで {@link android.content.Intent} フラグを使うか、<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"> +<activity></a></code> 属性を使ってオーバーライドできます。 +</p> + +<p><code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> 属性の <a href="{@docRoot}guide/topics/manifest/activity-element.html#exclude">{@code android:excludeFromRecents}</a> を {@code true} に設定すると、タスクを常にオーバービュー画面から完全に除外することができます。 + + +</p> + +<p>アプリがオーバービュー画面に表示できるタスクの最大数を設定するには、<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> 属性の <a href="{@docRoot}guide/topics/manifest/activity-element.html#maxrecents">{@code android:maxRecents}</a> に整数値を設定します。 + + +デフォルトでは 16 に設定されています。タスクの最大数に達すると、最も古いタスクがオーバービュー画面から削除されます。 +{@code android:maxRecents} の最大値は 50(低メモリの端末では 25)で、1 未満の値は無効です。 +</p> + +<h3 id="#apptask-remove">AppTask クラスを使用してタスクを削除する</h3> + +<p>オーバービュー画面に新しいタスクを作成するアクティビティで {@link android.app.ActivityManager.AppTask#finishAndRemoveTask() finishAndRemoveTask()} を呼び出すと、タスクを削除して関連アクティビティのすべてを終了させるタイミングを指定できます。 + +</p> + +<p class="code-caption"><a href="{@docRoot}samples/DocumentCentricApps/index.html"> +NewDocumentActivity.java</a></p> +<pre> +public void onRemoveFromRecents(View view) { + // The document is no longer needed; remove its task. + finishAndRemoveTask(); +} +</pre> + +<p class="note"><strong>注:</strong> {@link android.app.ActivityManager.AppTask#finishAndRemoveTask() finishAndRemoveTask()} メソッドを使用すると、次のセクションで説明する {@link android.content.Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS} タグの使用がオーバーライドされます。 + + +</p> + +<h3 id="#retain-finished">完了したタスクを保持する</h3> + +<p>アクティビティの終了後もオーバービュー画面にタスクを保持する場合は、{@link android.content.Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS} フラグを、アクティビティを起動するインテントの {@link android.content.Intent#addFlags(int) addFlags()} メソッドに渡します。 + +</p> + +<p class="code-caption"><a href="{@docRoot}samples/DocumentCentricApps/index.html"> +DocumentCentricActivity.java</a></p> +<pre> +private Intent newDocumentIntent() { + final Intent newDocumentIntent = new Intent(this, NewDocumentActivity.class); + newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | + android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS); + newDocumentIntent.putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, incrementAndGet()); + return newDocumentIntent; +} +</pre> + +<p><code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> 属性の <a href="{@docRoot}guide/topics/manifest/activity-element.html#autoremrecents">{@code android:autoRemoveFromRecents}</a> を {@code false} に設定することでも同じ効果を得られます。 + + +ドキュメントのアクティビティのデフォルト値は {@code true}、通常のアクティビティでは {@code false} になります。 +この属性を使用すると、前のセクションで説明した {@link android.content.Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS} フラグがオーバーライドされます。 +</p> + + + + + + + diff --git a/docs/html-intl/intl/ja/guide/components/services.jd b/docs/html-intl/intl/ja/guide/components/services.jd new file mode 100644 index 000000000000..fa946dbc94b2 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/components/services.jd @@ -0,0 +1,813 @@ +page.title=サービス +@jd:body + +<div id="qv-wrapper"> +<ol id="qv"> +<h2>本書の内容</h2> +<ol> +<li><a href="#Basics">基本</a></li> +<ol> + <li><a href="#Declaring">マニフェストでサービスを宣言する</a></li> +</ol> +<li><a href="#CreatingAService">開始されたサービスを作成する</a> + <ol> + <li><a href="#ExtendingIntentService">IntentService クラスを拡張する</a></li> + <li><a href="#ExtendingService">Service クラスを拡張する</a></li> + <li><a href="#StartingAService">サービスを開始する</a></li> + <li><a href="#Stopping">サービスを停止する</a></li> + </ol> +</li> +<li><a href="#CreatingBoundService">バインドされたサービスを作成する</a></li> +<li><a href="#Notifications">ユーザーに通知を送信する</a></li> +<li><a href="#Foreground">サービスをフォアグラウンドで実行する</a></li> +<li><a href="#Lifecycle">サービスのライフサイクルを管理する</a> +<ol> + <li><a href="#LifecycleCallbacks">ライフサイクル コールバックを実装する</a></li> +</ol> +</li> +</ol> + +<h2>キークラス</h2> +<ol> + <li>{@link android.app.Service}</li> + <li>{@link android.app.IntentService}</li> +</ol> + +<h2>サンプル</h2> +<ol> + <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/ServiceStartArguments.html">{@code + ServiceStartArguments}</a></li> + <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code + LocalService}</a></li> +</ol> + +<h2>関連ドキュメント</h2> +<ol> +<li><a href="{@docRoot}guide/components/bound-services.html">バインドされたサービス</a></li> +</ol> + +</div> + + +<p>{@link android.app.Service} は、バックグラウンドで長時間動作して作業を行い、ユーザー インターフェースを表示しないアプリケーション コンポーネントです。 +別のアプリケーション コンポーネントがサービスを開始し、ユーザーが他のアプリケーションに切り替えた場合でも、サービスはバックグラウンドで実行し続けることができます。 + +さらに、コンポーネントをサービスにバインドして操作したり、プロセス間通信(IPC)を実行したりすることも可能です。 +たとえば、サービスはネットワーク トランザクションの処理、音楽の再生、ファイルの I/O の実行、コンテンツ プロバイダとのやり取りなどのすべてをバックグラウンドで行うことができます。 + +</p> + +<p>サービスには、基本的に次の 2 つの形式があります。</p> + +<dl> + <dt>開始されたサービス</dt> + <dd>アプリケーション コンポーネント(アクティビティなど)が {@link android.content.Context#startService startService()} を呼び出して開始したときに、サービスが「開始された」状態になります。 +一旦開始されると、たとえ開始したコンポーネントが破棄されても、サービスは無期限に実行できます。 +通常、開始されたサービスは 1 つの操作を実行するだけで、呼び出し元に結果を返すことはありません。たとえば、サービスはネットワーク上でファイルのダウンロードやアップロードを行います。 + +操作が完了すると、サービスは自身で停止する必要があります。 +</dd> + <dt>バインドされたサービス</dt> + <dd>アプリケーション コンポーネントが {@link +android.content.Context#bindService bindService()} を呼び出してサービスにバインドすると、サービスは「バインドされた」状態になります。バインドされたサービスは、コンポーネントがサービスを操作したり、要求を送信したり、結果を取得したり、さらにはプロセス間通信(IPC)でもそれを行えるクライアントサーバー型インターフェースを提供します。 + +バインドされたサービスは、他のアプリケーション コンポーネントがそれにバインドしている限り実行し続けます。 +サービスには同時に複数のコンポーネントがバインドできますが、すべてがアンバインドされると、サービスは破棄されます。 +</dd> +</dl> + +<p>このドキュメントではこの 2 種類のサービスそれぞれの概要について説明しますが、サービスは開始された状態(無期限に実行)、バインドされた状態のどちらの方法でも動作できます。これは、2 つのコールバック メソッドを実装するかどうかの問題で、{@link +android.app.Service#onStartCommand onStartCommand()} ではコンポーネントにサービスの開始を許可し、{@link +android.app.Service#onBind onBind()} ではバインドを許可することになります。 + +</p> + +<p>アプリケーションが開始された、バインドされた、またはその両方かであるかどうかにかかわらず、どんなコンポーネントでもアクティビティを使用できるのと同じように、{@link android.content.Intent} を使って開始することで、どんなアプリケーション コンポーネントでもサービスを使用できます。 + +—ただし、マニフェスト ファイルでサービスを非公開として宣言して、他のアプリケーションからのアクセスをブロックすることもできます。 +詳細については、<a href="#Declaring">マニフェストでサービスを宣言する</a>で説明します。 + +</p> + +<p class="caution"><strong>警告:</strong> サービスは、そのホスト プロセスのメインスレッドで実行します。サービスが自身のスレッドを作成することは<strong>なく</strong>、別のプロセスで実行されることも<strong>ありません</strong>(別の方法を指定しない限り)。 +— +つまり、サービスが CPU を集中的に使ったり、ブロック操作を行ったりするような場合(MP3 の再生やネットワーク作業)は、サービス内に新しいスレッドを作成してその作業を行う必要があります。 + +別のスレッドを使うことで、「アプリケーションが応答していません (ANR)」のエラーが発生するリスクを軽減でき、アプリケーションのメインスレッドをアクティビティのユーザー操作専用にすることができます。 + +</p> + + +<h2 id="Basics">基本</h2> + +<div class="sidebox-wrapper"> +<div class="sidebox"> + <h3>サービスとスレッド、どちらを使用すべきか。</h3> + <p>サービスは、ユーザーがアプリケーションを操作していない間もバックグラウンドで実行できるコンポーネントにすぎません。 +そのような必要性がある場合に限り、サービスを作成します。 +</p> + <p>ユーザーがアプリケーションを操作している間だけ、メインスレッド外で作業を行う必要がある場合は、サービスではなくスレッドを作成することをお勧めします。 +たとえば、アクティビティを実行している間だけ音楽を再生する場合は、{@link android.app.Activity#onCreate onCreate()} にスレッドを作成し、{@link +android.app.Activity#onStart onStart()} で実行を開始して、{@link android.app.Activity#onStop +onStop()} で停止します。 + +また、従来の {@link java.lang.Thread} クラスの代わりに {@link android.os.AsyncTask} や {@link android.os.HandlerThread} を使用する方法もあります。 +スレッドの詳細については、「<a href="{@docRoot}guide/components/processes-and-threads.html#Threads">プロセスとスレッド</a>」のドキュメントをご覧ください。 +</p> + <p>サービスを使用する際は、デフォルトではアプリケーションのメインスレッドで実行されるため、集中的な作業やブロック操作を行う場合はサービス内に新しいスレッドを作成する必要があることに注意してください。 + +</p> +</div> +</div> + +<p>サービスを作成するには、{@link android.app.Service} のサブクラス(またはその既存のサブクラス)を作成する必要があります。 +実装時には、サービスのライフサイクルの重要側面を扱うコールバック メソッドをオーバーライドして、必要に応じてサービスにバインドするためのメカニズムをコンポーネントに提供する必要があります。 + +オーバーライドする必要のある、最も重要なコールバック メソッドは次の 2 つです。</p> + +<dl> + <dt>{@link android.app.Service#onStartCommand onStartCommand()}</dt> + <dd>アクティビティなどの他のコンポーネントが、{@link android.content.Context#startService +startService()} を呼び出してサービスの開始を要求したときに、システムがこのメソッドを呼び出します。 +このメソッドが実行されるとサービスは開始され、バックグラウンドで無期限に実行します。 +これを実装すると、作業完了時に {@link android.app.Service#stopSelf stopSelf()} か {@link +android.content.Context#stopService stopService()} を呼び出して自身でサービスを停止する必要があります +(バインドのみを提供する場合は、このメソッドを実装する必要はありません)。 +</dd> + <dt>{@link android.app.Service#onBind onBind()}</dt> + <dd>{@link android.content.Context#bindService +bindService()} を呼び出して他のコンポーネントをサービスにバインドさせるとき(RPC 実行時など)に、システムがこのメソッドを呼び出します。 +このメソッドの実装時には、{@link android.os.IBinder} を返してクライアントがサービスとの通信に使うインターフェースを提供する必要があります。 +このメソッドの実装は常に必要ですが、バインドを許可しない場合は、null を返す必要があります。 +</dd> + <dt>{@link android.app.Service#onCreate()}</dt> + <dd>サービスが始めて作成されたときに、1 回限りのセットアップ処理を実行するためにシステムがこのメソッドを呼び出します({@link android.app.Service#onStartCommand onStartCommand()} か {@link android.app.Service#onBind onBind()} のいずれかを呼び出す前)。 + +サービスが既に実行中の場合、このメソッドは呼び出されません。 +</dd> + <dt>{@link android.app.Service#onDestroy()}</dt> + <dd>サービスがもう使用されておらず破棄されたときに、システムがこのメソッドを呼び出します。これは、スレッドや登録されたリスナ、レシーバーなどをクリーンアップするためにサービスに実装する必要があります。 + +これが、サービスが受け取る最後の呼び出しになります。</dd> +</dl> + +<p>コンポーネントが {@link +android.content.Context#startService startService()} を呼び出してサービスを開始すると(結果的に {@link +android.app.Service#onStartCommand onStartCommand()} が呼び出される)、{@link android.app.Service#stopSelf()} を使ってサービス自身が停止するか、他のコンポーネントが {@link android.content.Context#stopService stopService()} を呼び出して停止するまで、サービスは実行し続けます。 + +</p> + +<p>コンポーネントが {@link android.content.Context#bindService bindService()} を呼び出してサービスを作成した(そして {@link +android.app.Service#onStartCommand onStartCommand()} が呼び出されて<em>いない</em>)場合、サービスはコンポーネントにバインドされている間のみ実行します。 + +すべてのクライアントからアンバインドされると、サービスはシステムによって破棄されます。 +</p> + +<p>Android システムは メモリが少なくなって、ユーザーが使用しているアクティビティ用のシステムリソースを回復させる必要が生じた場合のみ、サービスを強制的に停止させます。 +サービスがユーザーが使用しているアクティビティにバインドされている場合は、それが強制終了される可能性は低く、<a href="#Foreground">フォアグラウンドで実行</a>(後で説明)するように宣言されている場合は、強制終了されることはほとんどありません。一方で、サービスが開始されてから長時間実行している場合は、システムはバックグラウンド タスクのリストにおけるその位置付けを徐々に低くし、そのサービスが強制終了される確率が高くなります。開始されたサービスを作成する際は、システムによる再起動を円滑に処理するようデザインする必要があります。 + + + +— +システムがサービスを強制終了すると、リソースが回復次第そのサービスが再起動します(後述の {@link +android.app.Service#onStartCommand onStartCommand()} から返される値にもよります)。 +システムがサービスを破棄するタイミングについては、「<a href="{@docRoot}guide/components/processes-and-threads.html">Processes and Threading</a>」のドキュメントをご覧ください。 + +</p> + +<p>次のセクションでは、それぞれのタイプのサービスの作成方法と、他のアプリケーション コンポーネントからの使用方法について説明します。 +</p> + + + +<h3 id="Declaring">マニフェストでサービスを宣言する</h3> + +<p>アクティビティ(や他のコンポーネント)と同様に、すべてのサービスをアプリケーションのマニフェスト ファイルで宣言する必要があります。 +</p> + +<p>サービスを宣言するには、<a href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a> 要素を <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a> の子要素として追加します。 + +次に例を示します。</p> + +<pre> +<manifest ... > + ... + <application ... > + <service android:name=".ExampleService" /> + ... + </application> +</manifest> +</pre> + +<p>マニフェストでのサービスの宣言に関する詳細については、<a href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a> 要素のリファレンスをご覧ください。 +</p> + +<p><a href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a> に含めることで、サービスやサービスを実行するプロセスの開始に必要なパーミッションなどのプロパティを定義できる他の属性がいくつかあります。 + +<a href="{@docRoot}guide/topics/manifest/service-element.html#nm">{@code android:name}</a> 属性は唯一の必須属性で、サービスのクラス名を指定します。 +—アプリケーションを発行したら、この名前は変更できません。変更すると、サービスを開始したりバインドしたりする明示的インテントの依存関係によってコードを破損する可能性があります(ブログの投稿「<a href="http://android-developers.blogspot.com/2011/06/things-that-cannot-change.html">Things That Cannot Change</a>」をご覧ください)。 + + + + +<p>アプリの安全性を保つため、<strong>{@link android.app.Service}を開始したりバインドしたりするときは、常に明示的インテントを使用</strong>し、サービスでインテント フィルタを宣言しないようにしてください。 +どのサービスを開始するかについて、ある程度のあいまい静を残しておく必要がある場合は、サービスにインテント フィルタを定義でき、{@link +android.content.Intent} からコンポーネント名を除外して、その後ターゲットのサービスのあいまい性を十分に解消する {@link +android.content.Intent#setPackage setPackage()} でインテントのパッケージを設定する必要があります。 + + +</p> + +<p>さらに、<a href="{@docRoot}guide/topics/manifest/service-element.html#exported">{@code android:exported}</a> 属性を含めて {@code "false"} に設定すると、サービスを自身のアプリでしか利用できないようにできます。 + +これにより、他のアプリによるサービスの開始を効果的に回避でき、たとえ明示的インテントを使用したとしても開始できなくなります。 +</p> + + + + +<h2 id="CreatingStartedService">開始されたサービスを作成する</h2> + +<p>開始されたサービスは、他のコンポーネントが {@link +android.content.Context#startService startService()} を呼び出すことで結果的にサービスの {@link android.app.Service#onStartCommand onStartCommand()} メソッドを呼び出して開始されたサービスです。 +</p> + +<p>サービスが開始されると、サービスはそれを開始したコンポーネントから独立したライフサイクルを持ち、たとえ開始したコンポーネントが破棄されても、サービスは無期限に実行できます。 + +そのため、サービスはジョブが完了したら {@link android.app.Service#stopSelf stopSelf()} を呼び出して自身で停止する必要があり、他のコンポーネントが {@link android.content.Context#stopService stopService()} を呼び出して停止することもできます。 + +</p> + +<p>アクティビティなどのアプリケーション コンポーネントは、{@link +android.content.Context#startService startService()} を呼び出して、サービスを指定し、サービスが使用するデータを含めた {@link android.content.Intent} を渡してサービスを開始できます。 +サービスはこの {@link android.content.Intent} を、{@link android.app.Service#onStartCommand +onStartCommand()} メソッドで受け取ります。 +</p> + +<p>たとえば、オンライン データベースにデータを保存する必要のあるアクティビティがあるとします。アクティビティでサービスを開始し、{@link +android.content.Context#startService startService()} にインテントを渡して、保存するデータをサービスに配信します。 +サービスはインテントを {@link +android.app.Service#onStartCommand onStartCommand()} で受け取り、インターネットに接続してデータベースのトランザクションを実行します。 +トランザクションが完了したら、サービスは自身で停止し、破棄されます。 +</p> + +<p class="caution"><strong>警告:</strong> デフォルトでは、アプリケーションで宣言されたサービスは、アプリケーションと同じプロセスで、そのアプリケーションのメインスレッドで実行します。 +そのため、ユーザーが同じアプリケーションのアクティビティを操作している間に、サービスが集中的な処理やブロック操作を実行すると、アクティビティのパフォーマンスが低下します。 + +アプリケーションのパフォーマンスへの影響を回避するには、サービス内で新しいスレッドを開始する必要があります。 +</p> + +<p>従来どおり、開始されたサービスを作成するために拡張できるクラスが 2 つあります。</p> +<dl> + <dt>{@link android.app.Service}</dt> + <dd>これは、すべてのサービスの基本クラスです。サービスはデフォルトでアプリケーションのメインスレッドを使用し、アプリケーションが実行しているアクティビティのパフォーマンスを低下させることがあるため、このクラスを拡張するときは、サービスのすべての作業を行うための新しいスレッドを作成することが重要です。 + + +</dd> + <dt>{@link android.app.IntentService}</dt> + <dd>すべての開始要求を一件ずつ処理するワーカー スレッドを使用した {@link android.app.Service} のサブクラスです。 +サービスで同時に複数の要求を処理する必要がない場合は、これが最適です。 +{@link +android.app.IntentService#onHandleIntent onHandleIntent()} を実装するだけで、それぞれの開始要求のインテントを受け取り、バックグラウンドでの処理が可能になります。 +</dd> +</dl> + +<p>次のセクションでは、これらいずれかのクラスを使用してサービスを実装する方法について説明します。 +</p> + + +<h3 id="ExtendingIntentService">IntentService クラスを拡張する</h3> + +<p>開始されたサービスで同時に複数の要求を処理する必要があることはほとんどないため(実際には危険なマルチスレッド シナリオになります)、{@link android.app.IntentService} クラスを使用してサービスを実装するのが最適だと考えられます。 + +</p> + +<p>{@link android.app.IntentService} は、次の操作を行います。</p> + +<ul> + <li>アプリケーションのメインスレッドとは別の {@link +android.app.Service#onStartCommand onStartCommand()} に配信されるすべてのインテントを実行する、デフォルトのワーカー スレッドを作成します。 +</li> + <li>マルチスレッドの懸念を排除するため、一度に 1 つのインテントを {@link +android.app.IntentService#onHandleIntent onHandleIntent()} の実装に渡すワークキューを作成します。 +</li> + <li>{@link android.app.Service#stopSelf} を呼び出す必要がないよう、すべての開始要求の処理後にサービスを停止します。 +</li> + <li>Null を返す {@link android.app.IntentService#onBind onBind()} のデフォルト実装を提供します。 +</li> + <li>インテントをワークキュー、{@link +android.app.IntentService#onHandleIntent onHandleIntent()} の実装の順に送信する {@link android.app.IntentService#onStartCommand +onStartCommand()} のデフォルト実装を提供します。</li> +</ul> + +<p>上記すべての操作が行われることで、開発者が行う必要があるのは、クライアントから指示された内容を処理する {@link +android.app.IntentService#onHandleIntent onHandleIntent()} を実装するだけになります +(ただし、サービスの小さいコンストラクタを提供する必要はあります)。</p> + +<p>{@link android.app.IntentService} の実装例を次に示します。</p> + +<pre> +public class HelloIntentService extends IntentService { + + /** + * A constructor is required, and must call the super {@link android.app.IntentService#IntentService} + * constructor with a name for the worker thread. + */ + public HelloIntentService() { + super("HelloIntentService"); + } + + /** + * The IntentService calls this method from the default worker thread with + * the intent that started the service. When this method returns, IntentService + * stops the service, as appropriate. + */ + @Override + protected void onHandleIntent(Intent intent) { + // Normally we would do some work here, like download a file. + // For our sample, we just sleep for 5 seconds. + long endTime = System.currentTimeMillis() + 5*1000; + while (System.currentTimeMillis() < endTime) { + synchronized (this) { + try { + wait(endTime - System.currentTimeMillis()); + } catch (Exception e) { + } + } + } + } +} +</pre> + +<p>コンストラクタと {@link +android.app.IntentService#onHandleIntent onHandleIntent()} の実装、必要なのはこれだけです。</p> + +<p>{@link +android.app.IntentService#onCreate onCreate()}、{@link +android.app.IntentService#onStartCommand onStartCommand()}、{@link +android.app.IntentService#onDestroy onDestroy()} などの他のコールバック メソッドもオーバーライドする場合は、{@link android.app.IntentService} がワーカー スレッドの生存状態を正しく処理できるよう、必ず super を実装するようにします。 +</p> + +<p>たとえば、{@link android.app.IntentService#onStartCommand onStartCommand()} はデフォルト実装を返す必要があります(これによりインテントが {@link +android.app.IntentService#onHandleIntent onHandleIntent()} に配信されます)。 +</p> + +<pre> +@Override +public int onStartCommand(Intent intent, int flags, int startId) { + Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); + return super.onStartCommand(intent,flags,startId); +} +</pre> + +<p>{@link android.app.IntentService#onHandleIntent onHandleIntent()} 以外で、super クラスを呼び出す必要のないメソッドは、{@link android.app.IntentService#onBind +onBind()} です(ただし、サービスでバインドを許可している場合のみ実装が必要です)。 +</p> + +<p>次のセクションでは、この種のサービスが、基本の {@link android.app.Service} クラスを拡張したときにどのように実装されるかを説明します。 +これにはさらに多くのコードがありますが、開始要求の同時処理が必要な場合には適しています。 +</p> + + +<h3 id="ExtendingService">Service クラスを拡張する</h3> + +<p>前のセクションで説明したように、{@link android.app.IntentService} を使用すると開始されたサービスの実装が非常に簡単になります。 +ただし、サービスでマルチスレッドを実行する必要がある場合(開始要求をワークキュー経由で処理するのではなく)、{@link android.app.Service} クラスを拡張して、それぞれのインテントを処理できます。 + +</p> + +<p>比較のために、{@link +android.app.IntentService} を使用した上記の例とまったく同じ処理を実行する {@link +android.app.Service} クラスの実装の例が次のコードです。つまり、それぞれの開始要求に対し、ワーカー スレッドを使用してジョブとプロセスを実行し、一度に 1 つの要求のみを処理します。 +</p> + +<pre> +public class HelloService extends Service { + private Looper mServiceLooper; + private ServiceHandler mServiceHandler; + + // Handler that receives messages from the thread + private final class ServiceHandler extends Handler { + public ServiceHandler(Looper looper) { + super(looper); + } + @Override + public void handleMessage(Message msg) { + // Normally we would do some work here, like download a file. + // For our sample, we just sleep for 5 seconds. + long endTime = System.currentTimeMillis() + 5*1000; + while (System.currentTimeMillis() < endTime) { + synchronized (this) { + try { + wait(endTime - System.currentTimeMillis()); + } catch (Exception e) { + } + } + } + // Stop the service using the startId, so that we don't stop + // the service in the middle of handling another job + stopSelf(msg.arg1); + } + } + + @Override + public void onCreate() { + // Start up the thread running the service. Note that we create a + // separate thread because the service normally runs in the process's + // main thread, which we don't want to block. We also make it + // background priority so CPU-intensive work will not disrupt our UI. + HandlerThread thread = new HandlerThread("ServiceStartArguments", + Process.THREAD_PRIORITY_BACKGROUND); + thread.start(); + + // Get the HandlerThread's Looper and use it for our Handler + mServiceLooper = thread.getLooper(); + mServiceHandler = new ServiceHandler(mServiceLooper); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); + + // For each start request, send a message to start a job and deliver the + // start ID so we know which request we're stopping when we finish the job + Message msg = mServiceHandler.obtainMessage(); + msg.arg1 = startId; + mServiceHandler.sendMessage(msg); + + // If we get killed, after returning from here, restart + return START_STICKY; + } + + @Override + public IBinder onBind(Intent intent) { + // We don't provide binding, so return null + return null; + } + + @Override + public void onDestroy() { + Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); + } +} +</pre> + +<p>このように、{@link android.app.IntentService} を使う場合よりもかなり面倒です。</p> + +<p>ただし、{@link android.app.Service#onStartCommand +onStartCommand()} への各呼び出しを自身で処理するため、同時に複数の要求を実行することも可能です。この例にはあてはまりませんが、自身の状況に合う場合は、要求ごとに新しいスレッドを作成し、すぐに実行することもできます(前の要求が完了するのを待つ必要がありません)。 + +</p> + +<p>{@link android.app.Service#onStartCommand onStartCommand()} メソッドは整数を返す必要があることに注意してください。 +整数は、システムがサービスを強制終了した場合に、サービスをどのように続行させるかを記述する値です(前述したように、{@link +android.app.IntentService} のデフォルト実装が代わりにこれを処理しますが、自身で修正することもできます)。 +{@link android.app.Service#onStartCommand onStartCommand()} から返される値は、次のいずれかの定数である必要があります。 + +</p> + +<dl> + <dt>{@link android.app.Service#START_NOT_STICKY}</dt> + <dd>{@link android.app.Service#onStartCommand +onStartCommand()} から戻った後でシステムがサービスを強制終了した場合は、配信が保留中のインテントがない限りシステムはサービスを再作成<em>しません</em>。 +これは、サービスが不必要で、アプリケーションが未完了のジョブを再開できる場合にサービスを実行してしまうのを回避できる最も安全な選択肢です。 +</dd> + <dt>{@link android.app.Service#START_STICKY}</dt> + <dd>{@link android.app.Service#onStartCommand +onStartCommand()} から戻った後でシステムがサービスを強制終了した場合は、サービスを再作成し、{@link +android.app.Service#onStartCommand onStartCommand()} を呼び出しますが、最後のインテントは再配信<em>しません</em>。代わりに、サービスを開始するインテントが保留になっている場合を除いて、システムは {@link android.app.Service#onStartCommand onStartCommand()} を null インテントを使って呼び出します。保留中のインテントがある場合、そのインテントは配信されます。 + + +これは、コマンドは実行しないが、無期限に実行し、ジョブを待機するメディア プレーヤー(や同様のサービス)に適しています。 +</dd> + <dt>{@link android.app.Service#START_REDELIVER_INTENT}</dt> + <dd>{@link android.app.Service#onStartCommand +onStartCommand()} から戻った後でシステムがサービスを強制終了した場合は、サービスを再作成し、サービスに最後に配信されたインテントで {@link +android.app.Service#onStartCommand onStartCommand()} を呼び出します。 +すべてのペンディング インテントが順に配信されます。これは、ファイルのダウンロードのような、活発にジョブを実行し、ただちに再開する必要のあるサービスに適しています。 +</dd> +</dl> +<p>これらの戻り値の詳細については、リンクされた各定数のリファレンス ドキュメントをご覧ください。 +</p> + + + +<h3 id="StartingAService">サービスを開始する</h3> + +<p>アクティビティや他のアプリケーション コンポーネントから {@link android.content.Intent}(開始するサービスを指定する)を {@link android.content.Context#startService startService()} に渡すことで、サービスを開始できます。 + +Android システムが、サービスの {@link +android.app.Service#onStartCommand onStartCommand()} メソッドを呼び出して、{@link +android.content.Intent} を渡します(絶対に、{@link android.app.Service#onStartCommand +onStartCommand()} を直接呼び出さないでください)。</p> + +<p>アクティビティが前のセクションで例に挙げたサービス({@code +HelloSevice})を、{@link android.content.Context#startService +startService()} で明示的インテントを使って開始する例を次に示します。</p> + +<pre> +Intent intent = new Intent(this, HelloService.class); +startService(intent); +</pre> + +<p>{@link android.content.Context#startService startService()} メソッドがすぐに戻り、Android システムがサービスの {@link android.app.Service#onStartCommand +onStartCommand()} メソッドを呼び出します。 +サービスがまだ実行されていない場合、システムはまず {@link +android.app.Service#onCreate onCreate()} を呼び出してから、{@link android.app.Service#onStartCommand +onStartCommand()} を呼び出します。</p> + +<p>サービスでバインドが提供されない場合は、{@link +android.content.Context#startService startService()} で配信されたインテントが、アプリケーション コンポーネントとサービス間の唯一の通信モードになります。 +ただし、サービスから結果を送り返す場合は、サービスを開始するクライアントがブロードキャスト用に {@link android.app.PendingIntent} を作成でき({@link android.app.PendingIntent#getBroadcast getBroadcast()} で)、それをサービスを開始する {@link android.content.Intent} のサービスに配信できます。 + + +その後、サービスはブロードキャストを使って結果を配信できます。 +</p> + +<p>サービスを開始する要求が複数ある場合は、それに対応する複数の呼び出しがサービスの {@link android.app.Service#onStartCommand onStartCommand()} に対して発生することになります。 +ただし、サービスを停止するために必要な要求({@link android.app.Service#stopSelf stopSelf()} や {@link +android.content.Context#stopService stopService()} を使用)は、1 つのみです。 +</p> + + +<h3 id="Stopping">サービスを停止する</h3> + +<p>開始されたサービスは、自身でライフサイクルを管理する必要があります。つまり、システムメモリを復元する必要がある場合を除き、システムがサービスを停止したり破棄したりすることはなく、サービスは {@link android.app.Service#onStartCommand onStartCommand()} から戻った後も実行し続けます。 + +そのため、サービスは {@link android.app.Service#stopSelf stopSelf()} を呼び出して自身で停止する必要があり、他のコンポーネントが {@link android.content.Context#stopService stopService()} を呼び出して停止することもできます。 + +</p> + +<p>{@link android.app.Service#stopSelf stopSelf()} や {@link +android.content.Context#stopService stopService()} で停止が要求されたら、システムは可能な限りすぐにサービスを破棄します。 +</p> + +<p>ただし、サービスが {@link +android.app.Service#onStartCommand onStartCommand()} への複数の要求を同時に処理している場合は、その後に新しい開始要求を受け取る可能性があることから、開始要求の処理後もサービスを停止しないでください(1 つ目の要求の最後に停止すると、2 つ目が停止されてしまいます)。 + +この問題を回避するには、{@link android.app.Service#stopSelf(int)} を使って、常に最新の開始要求に基づいてサービスの停止要求を行うようにできます。 + +具体的には、{@link +android.app.Service#stopSelf(int)} を呼び出すとき、停止要求に対応する開始要求の ID({@link android.app.Service#onStartCommand onStartCommand()} に配信された <code>startId</code>)を渡します。 + +その後、{@link +android.app.Service#stopSelf(int)} を呼び出す前にサービスが新しい開始要求を受け取ったとしても、結果的に ID が一致せずサービスが停止されなくなります。</p> + +<p class="caution"><strong>警告:</strong> アプリケーションはサービスの処理が完了したら、システムリソースやバッテリ電力の節約のため、サービスを停止することが重要です。 +必要であれば、他のコンポーネントから {@link +android.content.Context#stopService stopService()} を呼び出してサービスを停止することもできます。 +サービスのバインドを有効にしている場合でも、{@link +android.app.Service#onStartCommand onStartCommand()} を受け取ったときには常に自身でサービスを停止する必要があります。 +</p> + +<p>サービスのライフサイクルの詳細については、後半のセクションの<a href="#Lifecycle">サービスのライフサイクルを管理する</a>をご覧ください。</p> + + + +<h2 id="CreatingBoundService">バインドされたサービスを作成する</h2> + +<p>バインドされたサービスとは、アプリケーション コンポーネントが長時間の接続を作成するために {@link +android.content.Context#bindService bindService()} を呼び出してサービスにバインドできるようにするサービスです(通常はコンポーネントが {@link +android.content.Context#startService startService()} を呼び出すことではサービスは<em>開始</em>できません)。 +</p> + +<p>バインドされたサービスは、アプリケーションのアクティビティや他のコンポーネントからのサービスとやり取りしたり、アプリケーションの一部の機能をプロセス間通信(IPC)を用いて他のアプリケーションが利用できるようにしたりする場合に作成します。 + +</p> + +<p>バインドされたサービスを作成するには、{@link +android.app.Service#onBind onBind()} コールバック メソッドを実装して、サービスとの通信用のインターフェースを定義する {@link android.os.IBinder} を返す必要があります。 +その後、他のアプリケーション コンポーネントが {@link android.content.Context#bindService bindService()} を呼び出してインターフェースを取得し、サービスのメソッドの呼び出しを開始できます。 + +サービスは、バインドされているアプリケーション コンポーネントのためだけに存在するため、バインドされているコンポーネントがなくなると、サービスにシステムによって破棄されます(バインドされたサービスは、{@link android.app.Service#onStartCommand onStartCommand()} でサービスが開始されたときと同じ方法で停止する必要は<em>ありません</em>)。 + + +</p> + +<p>バインドされたサービスを作成するには、まずクライアントからサービスへの通信方法を指定するインターフェースを定義します。 +サービスとクライアント間のこのインターフェースは {@link android.os.IBinder} の実装である必要があり、サービスはこれを {@link android.app.Service#onBind +onBind()} コールバック メソッドから返す必要があります。 + +クライアントが {@link android.os.IBinder} を受け取ると、そのインターフェースを介してサービスとのやり取りを開始できます。 +</p> + +<p>複数のクライアントが同時にサービスにバインドできます。クライアントとサービスのやり取りが終わったら、{@link android.content.Context#unbindService unbindService()} を呼び出してアンバインドします。 +サービスにバインドされているクライアントがなくなったら、システムがサービスを破棄します。 +</p> + +<p>バインドされたサービスの実装方法はいくつかあり、その実装は開始されたサービスよりも複雑であるため、バインドされたサービスの詳細については、<a href="{@docRoot}guide/components/bound-services.html">バインドされたサービス</a> のドキュメントで別途説明しています。 + +</p> + + + +<h2 id="Notifications">ユーザーに通知を送信する</h2> + +<p>一旦サービスが実行されると、<a href="{@docRoot}guide/topics/ui/notifiers/toasts.html">トースト通知</a>や<a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">ステータスバー通知</a>を使ってユーザーにイベントを通知できます。</p> + +<p>トースト通知は、現在のウィンドウに表示されるメッセージで、少しの間表示され、すぐに消えます。一方、ステータスバー通知では、ステータスバーにメッセージの付いたアイコンが表示され、ユーザーはそれを選択して何らかの操作(アクティビティの開始など)を行うことができます。 + +</p> + +<p>通常は、バックグラウンド ワークが完了して、ユーザーが実行できる操作がある場合(ファイルのダウンロードが完了した場合など)は、ステータスバーの通知が最適なテクニックです。 + +展開したビューでユーザーが通知を選択すると、通知がアクティビティ(ダウンロードしたファイルを表示するなど)を開始できるようになります。 +</p> + +<p>詳細については、デベロッパー ガイドの「<a href="{@docRoot}guide/topics/ui/notifiers/toasts.html">トースト通知</a>」や「<a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">ステータスバーの通知</a>」をご覧ください。 +</p> + + + +<h2 id="Foreground">サービスをフォアグラウンドで実行する</h2> + +<p>フォアグラウンド サービスは、ユーザーがその存在を認識しているものであるとみなされるため、メモリ残量が少なくなった場合でも、システムによる強制終了の現候補にはなりません。 +フォアグラウンド サービスではステータスバーに通知を表示する必要があり、通知は「継続中」という見出しの下に表示されるため、サービスが停止するか、フォアグラウンドから除去しない限り通知を消すことはできないということになります。 + + +</p> + +<p>たとえば、サービスから音楽を再生する音楽プレーヤーは、ユーザーがその操作を認識しているのは明らかであるため、フォアグラウンドで実行する必要があります。 + +ステータスバーの通知には現在再生中の曲名を表示でき、ユーザーが音楽プレーヤーを操作するためのアクティビティを起動できるようにできます。 +</p> + +<p>サービスをフォアグラウンドで実行するよう要求するには、{@link +android.app.Service#startForeground startForeground()} を呼び出します。このメソッドは、通知を一意に識別する整数と、ステータスバーの {@link +android.app.Notification} の 2 つのパラメータを受け付けます。 +次に例を示します。</p> + +<pre> +Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text), + System.currentTimeMillis()); +Intent notificationIntent = new Intent(this, ExampleActivity.class); +PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); +notification.setLatestEventInfo(this, getText(R.string.notification_title), + getText(R.string.notification_message), pendingIntent); +startForeground(ONGOING_NOTIFICATION_ID, notification); +</pre> + +<p class="caution"><strong>警告:</strong> {@link +android.app.Service#startForeground startForeground()} に渡す整数 ID には、0 は使用できません。</p> + + +<p>サービスをフォアグラウンドから除去するには、{@link +android.app.Service#stopForeground stopForeground()} を呼び出します。このメソッドでは、同時にステータスバーの通知も除去するかどうかを示すブール値を受け付けます。 +このメソッドでは、サービスは停止<em>されません</em>。 +ただし、サービスがまだフォアグラウンドで実行中に停止した場合は、通知も除去されます。 +</p> + +<p>通知の詳細については、「<a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Creating Status Bar Notifications</a>」をご覧ください。 +</p> + + + +<h2 id="Lifecycle">サービスのライフサイクルを管理する</h2> + +<p>サービスのライフサイクルは、アクティビティのライフサイクルよりもはるかにシンプルです。ただし、サービスはバックグラウンドでサイレントに実行されるため、サービスがどのように作成され、破棄されるかについては、より一層の注意を払っておく必要があります。 + +</p> + +<p>作成されてから破棄されるまでのサービスのライフサイクルには、2 つの経路があります。—— +</p> + +<ul> +<li>開始されたサービスの場合 + <p>他のコンポーネントが {@link +android.content.Context#startService startService()} を呼び出したときにサービスが作成されます。その後サービスは無期限に実行し、{@link +android.app.Service#stopSelf() stopSelf()} を呼び出して自身で停止する必要があります。 +また、他のコンポーネントから {@link android.content.Context#stopService stopService()} を呼び出してサービスを停止することもできます。 + +サービスが停止すると、システムがそれを破棄します。</p></li> + +<li>バインドされたサービス + <p>他のコンポーネント(クライアント)が {@link +android.content.Context#bindService bindService()} を呼び出したときにサービスが作成されます。その後、クライアントが {@link android.os.IBinder} インターフェースを介してサービスとやり取りします。 +クライアントは、{@link android.content.Context#unbindService unbindService()} を呼び出して接続を終了できます。 +サービスには同時に複数のクライアントがバインドでき、すべてがアンバインドされると、サービスはシステムによって破棄されます +(サービスを自身で停止する必要は<em>ありません</em>)。 +</p></li> +</ul> + +<p>この 2 つの経路は、完全に分離しているわけではありません。つまり、{@link android.content.Context#startService startService()} で既に開始されたサービスにバインドすることも可能です。 +たとえば、{@link android.content.Context#startService +startService()} を呼び出してバックグラウンドの音楽サービスを開始し、{@link android.content.Intent} を使って再生する音楽を指定できます。 +その後、ユーザーがプレーヤーを操作したり、現在の曲に関する情報を入手したりする場合は、{@link +android.content.Context#bindService bindService()} を呼び出すことでアクティビティをサービスにバインドできます。 + +このような場合は、すべてのクライアントがアンバインドされるまで、{@link +android.content.Context#stopService stopService()} や {@link android.app.Service#stopSelf +stopSelf()} ではサービスは停止されません。 </p> + + +<h3 id="LifecycleCallbacks">ライフサイクル コールバックを実装する</h3> + +<p>アクティビティと同様に、サービスにもコールバック メソッドがあり、それを実装することでサービスの状態の変化を監視したり、適切なタイミングで処理を実行したりできます。 +次のスケルトン サービスは、それぞれのライフサイクル メソッドを表しています。 +</p> + +<pre> +public class ExampleService extends Service { + int mStartMode; // indicates how to behave if the service is killed + IBinder mBinder; // interface for clients that bind + boolean mAllowRebind; // indicates whether onRebind should be used + + @Override + public void {@link android.app.Service#onCreate onCreate}() { + // The service is being created + } + @Override + public int {@link android.app.Service#onStartCommand onStartCommand}(Intent intent, int flags, int startId) { + // The service is starting, due to a call to {@link android.content.Context#startService startService()} + return <em>mStartMode</em>; + } + @Override + public IBinder {@link android.app.Service#onBind onBind}(Intent intent) { + // A client is binding to the service with {@link android.content.Context#bindService bindService()} + return <em>mBinder</em>; + } + @Override + public boolean {@link android.app.Service#onUnbind onUnbind}(Intent intent) { + // All clients have unbound with {@link android.content.Context#unbindService unbindService()} + return <em>mAllowRebind</em>; + } + @Override + public void {@link android.app.Service#onRebind onRebind}(Intent intent) { + // A client is binding to the service with {@link android.content.Context#bindService bindService()}, + // after onUnbind() has already been called + } + @Override + public void {@link android.app.Service#onDestroy onDestroy}() { + // The service is no longer used and is being destroyed + } +} +</pre> + +<p class="note"><strong>注:</strong> アクティビティのライフサイクル コールバック メソッドの場合とは異なり、これらのコールバック メソッドのスーパークラスの実装を呼び出す必要は<em>ありません</em>。 +</p> + +<img alt="" src="images/hero/how-to-enter1.jpg" /> +<p class="img-caption"><strong>図 2.</strong> サービスのライフサイクル。左側の図は、{@link android.content.Context#startService +startService()} でサービスが作成されたときのライフサイクルを示し、右側の図は、{@link android.content.Context#bindService bindService()} でサービスが作成されたときのライフサイクルを示しています。 + +</p> + +<p>これらのメソッドを実装すると、サービスのライフサイクル内の次の 2 つのネストされたループを監視できます。 </p> + +<ul> +<li>サービスの<strong>全体の生存期間</strong>は、{@link +android.app.Service#onCreate onCreate()} が呼び出されてから、{@link +android.app.Service#onDestroy} から戻るまでの間です。アクティビティと同様に、サービスが {@link android.app.Service#onCreate onCreate()} で初期設定を行い、{@link +android.app.Service#onDestroy onDestroy()} で残りのすべてのリソースを解放します。 +たとえば、音楽再生サービスでは、音楽を再生するスレッドを {@link +android.app.Service#onCreate onCreate()} に作成して、停止するスレッドを {@link +android.app.Service#onDestroy onDestroy()} に作成します。 + + +<p>{@link android.app.Service#onCreate onCreate()} メソッドと {@link android.app.Service#onDestroy +onDestroy()} メソッドは、それが{@link android.content.Context#startService startService()} か {@link +android.content.Context#bindService bindService()} のどちらで作成された場合でも、すべてのサービスに対して呼び出されます。 +</p></li> + +<li>サービスの<strong>アクティブな生存期間</strong> {@link +android.app.Service#onStartCommand onStartCommand()} か {@link android.app.Service#onBind onBind()} のいずれかへの呼び出しから開始します。各メソッドには、{@link android.content.Context#startService +startService()} か {@link android.content.Context#bindService bindService()} のいずれかに渡された {@link +android.content.Intent} が渡されます。 + +<p>サービスが開始された場合、アクティブな生存期間の完了は、全体の生存期間の完了と同じタイミングとなります({@link android.app.Service#onStartCommand +onStartCommand()} から戻った後もサービスはまだアクティブです)。 +サービスがバインドされた場合、アクティブな生存期間は {@link +android.app.Service#onUnbind onUnbind()} から戻った時点で完了します。</p> +</li> +</ul> + +<p class="note"><strong>注:</strong> 開始されたサービスは、{@link android.app.Service#stopSelf stopSelf()} か {@link +android.content.Context#stopService stopService()} への呼び出しで停止されますが、サービスには同様のコールバックはありません({@code onStop()} コールバックがありません)。 + +そのため、サービスがクライアントにバインドされていない限り、サービスが停止するとシステムがそれを破棄します。受け取るコールバックは {@link +android.app.Service#onDestroy onDestroy()} のみです。 +—</p> + +<p>図 2 は、サービスの典型的なコールバック メソッドを表しています。この図では、{@link android.content.Context#startService startService()} で作成されたサービスと {@link android.content.Context#bindService bindService()} で作成されたサービスを分けていますが、開始方法にかかわらず、すべてのサービスがクライアントからバインドされる可能性があることに注意してください。つまり、当初は {@link android.app.Service#onStartCommand +onStartCommand()} で(クライアントが {@link android.content.Context#startService startService()} を呼び出した際)開始されたサービスも、{@link android.app.Service#onBind onBind()} への呼び出し(クライアントが {@link android.content.Context#bindService bindService()} を呼び出した際)を受け取ることができます。 + + + + + +</p> + +<p>バインドを提供するサービスの作成に関する詳細は、「<a href="{@docRoot}guide/components/bound-services.html">バインドされたサービス</a>」のドキュメントをご覧ください。このドキュメントの<a href="{@docRoot}guide/components/bound-services.html#Lifecycle">バインドされたサービスのライフサイクルを管理する</a>では、{@link android.app.Service#onRebind onRebind()} コールバックの詳細についても説明しています。 + + +</p> + + +<!-- +<h2>Beginner's Path</h2> + +<p>To learn how to query data from the system or other applications (such as contacts or media +stored on the device), continue with the <b><a +href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a></b> +document.</p> +--> diff --git a/docs/html-intl/intl/ja/guide/components/tasks-and-back-stack.jd b/docs/html-intl/intl/ja/guide/components/tasks-and-back-stack.jd new file mode 100644 index 000000000000..12f5911da22e --- /dev/null +++ b/docs/html-intl/intl/ja/guide/components/tasks-and-back-stack.jd @@ -0,0 +1,578 @@ +page.title=タスクとバックスタック +parent.title=アクティビティ +parent.link=activities.html +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + +<h2>本書の内容</h2> +<ol> +<li><a href="#ActivityState">アクティビティの状態を保存する</a></li></li> +<li><a href="#ManagingTasks">タスクを管理する</a> + <ol> + <li><a href="#TaskLaunchModes">起動モードを定義する</a></li> + <li><a href="#Affinities">アフィニティを処理する</a></li> + <li><a href="#Clearing">バックスタックをクリアする</a></li> + <li><a href="#Starting">タスクを開始する</a></li> + </ol> +</li> +</ol> + +<h2>記事</h2> +<ol> + <li><a href="http://android-developers.blogspot.com/2010/04/multitasking-android-way.html">Multitasking the Android Way</a> +</li> +</ol> + +<h2>関連ドキュメント</h2> +<ol> + <li><a href="{@docRoot}design/patterns/navigation.html">Android Design: Navigation</a> +</li> + <li><a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>} manifest element</a> +</li> + <li><a href="{@docRoot}guide/components/recents.html">オーバービュー画面</a></li> +</ol> +</div> +</div> + + +<p>通常、アプリケーションには複数の<a href="{@docRoot}guide/components/activities.html">アクティビティ</a>が含まれています。それぞれのアクティビティは、ユーザーが実行して、他のアクティビティを開始するといった特定のアクションを中心に設計されています。 + +たとえば、メール アプリケーションに新規メッセージ一覧を表示する 1 つのアクティビティがあるとします。ユーザーがメッセージを選択すると、そのメッセージを表示するための新しいアクティビティが開きます。 +</p> + +<p>アクティビティでは、端末上の他のアプリケーションに存在するアクティビティを開始することもできます。たとえば、アプリケーションがメールの送信を求める場合は、「送信」アクションを実行し、メールアドレスや本文などのデータを含めるインテントを定義できます。 + +その結果、この種のインテントの処理を宣言している別のアプリケーションのアクティビティが開きます。 +この場合、インテントはメールを送信することであるため、メール アプリケーションの「作成」アクティビティが開始されます(複数のアクティビティが同じインテントに対応している場合、システムはユーザーに選択を求めます)。 + +メールが送信されると、元のアクティビティが再開され、まるでメール アクティビティがそのアプリケーションの一部であるように見えます。 +アクティビティは異なるアプリケーションのものでも、Android は両方のアクティビティを同じ<em>タスク</em>内に保つことによって、このシームレスな操作性を維持しています。 + +</p> + +<p>タスクとは、ユーザーが特定の作業を行う時に情報のやり取りを行うアクティビティの集まりです。 +アクティビティは、各アクティビティが開かれた順にスタック(<em>バックスタック</em>)形式で配置されます。 +</p> + +<!-- SAVE FOR WHEN THE FRAGMENT DOC IS ADDED +<div class="sidebox-wrapper"> +<div class="sidebox"> +<h3>Adding fragments to a task's back stack</h3> + +<p>Your activity can also include {@link android.app.Fragment}s to the back stack. For example, +suppose you have a two-pane layout using fragments, one of which is a list view (fragment A) and the +other being a layout to display an item from the list (fragment B). When the user selects an item +from the list, fragment B is replaced by a new fragment (fragment C). In this case, it might be +desireable for the user to navigate back to reveal fragment B, using the <em>Back</em> button.</p> +<p>In order to add fragment B to the back stack so that this is possible, you must call {@link +android.app.FragmentTransaction#addToBackStack addToBackStack()} before you {@link +android.app.FragmentTransaction#commit()} the transaction that replaces fragment B with fragment +C.</p> +<p>For more information about using fragments and adding them to the back stack, see the {@link +android.app.Fragment} class documentation.</p> + +</div> +</div> +--> + +<p>ほとんどのタスクは、端末のホーム画面から開始されます。ユーザーがアプリケーション ランチャーでアイコン(またはホーム画面のショートカット)にタッチすると、アプリケーションのタスクがフォアグラウンドに移動します。 + +アプリケーションにタスクが存在しない(アプリケーションが最近使われていない)場合は、新しいタスクが作成され、そのアプリケーションの「メイン」アクティビティがスタック内のルート アクティビティとして開きます。 + +</p> + +<p>現在のアクティビティが別のアクティビティを開始すると、新しいアクティビティがスタックの一番上にプッシュされ、アクティブになります。 +前のアクティビティはスタックに残りますが、停止されます。アクティビティが停止すると、システムはそのユーザー インターフェースの状態を維持します。 +ユーザーが [<em>戻る</em>] ボタンを押すと、現在のアクティビティがスタックの一番上から消え(アクティビティは破棄され)、前のアクティビティが再開します(UI は前の状態で復元されます)。 + + +スタック内のアクティビティが並べ替えられることはなく、スタック上にプッシュされるかスタックから消されるかのみです — 現在のアクティビティにより開始されるとスタック上にプッシュされ、ユーザーが [<em>戻る</em>] ボタンを押すと破棄されます。 + +このように、バックスタックは「後入れ先出し」オブジェクト構造となっています。 + +図 1 は、この動作を時系列に視覚化し、アクティビティとそれに伴うその時点でのバックスタックの状態を示したものです。 + +</p> + +<img src="{@docRoot}images/fundamentals/diagram_backstack.png" alt="" /> +<p class="img-caption"><strong>図 1.</strong>タスク内の新しいアクティビティがバックスタックにアイテムを追加するプロセスを示しています。 +ユーザーが [<em>戻る</em>] ボタンを押すと、現在のアクティビティは破棄され、前のアクティビティが再開します。 + +</p> + + +<p>ユーザーが続けて [<em>戻る</em>] ボタンを押すと、スタック内のアクティビティは消えていき、前のアクティビティが表示されます。最終的に、ユーザーはホーム画面(またはタスクの開始時に実行されていたアクティビティ)に戻ります。 + + +すべてのアクティビティがスタックから削除されると、タスクはなくなります。</p> + +<div class="figure" style="width:287px"> +<img src="{@docRoot}images/fundamentals/diagram_multitasking.png" alt="" /> <p +class="img-caption"><strong>図 2.</strong> 2 つのタスク: タスク B がフォアグラウンドでユーザー操作を受け入れます。タスク A は再開されるまでバックグラウンドで待機します。 +</p> +</div> +<div class="figure" style="width:215px"> + <img src="{@docRoot}images/fundamentals/diagram_multiple_instances.png" alt="" /> <p +class="img-caption"><strong>図 3.</strong> 1 つのアクティビティが複数回インスタンス化されます。</p> +</div> + +<p>タスクは結束した構成単位で、ユーザーが新しいタスクを開始したり [<em>ホーム</em>] ボタンを使ってホーム画面に移動したりすると「バックグラウンド」に移動できます。 +バックグラウンドでは、タスク内のすべてのアクティビティが停止されますが、タスクのバックスタックは元の状態を保ちます — 図 2 に示すように、別のタスクが行われている間、タスクはフォーカスを失った状態になります。 + + +タスクはその後「フォアグラウンド」に戻り、ユーザーは操作の続きを行うことができます。 +たとえば、現在のタスク(タスク A)のスタックに 3 つのアクティビティがあるとします。現在のアクティビティの下に 2 つのアクティビティがある状態です。 +ユーザーが [<em>ホーム</em>] ボタンを押し、アプリケーション ランチャーから新しいアプリケーションを起動します。 + +ホーム画面が表示されると、タスク A はバックグラウンドに移動します。 +新しいアプリケーションが起動すると、システムはそのアプリケーションのタスク(タスク B)を開始します。タスク B には独自のアクティビティ スタックがあります。 +アプリケーションの操作が終了すると、ユーザーはホームに戻り、タスク A を開始した元のアプリケーションを選択します。ここでタスク A はフォアグラウンドに移動します — 3 つのアクティビティはすべて元のままで、スタックの一番上にあるアクティビティが再開します。 + + + +この時点で、ユーザーはホームに移動してタスク B を開始したアプリケーションを選択して(または<a href="{@docRoot}guide/components/recents.html">オーバービュー画面</a>でアプリのタスクを選択して)タスク B に切り替えることもできます。これは、Android のマルチタスク操作の一例です。 + + + +</p> + +<p class="note"><strong>注:</strong> バックグラウンドには複数のタスクを一度に置くことができます。しかし、ユーザーが多数のバックグラウンド タスクを同時に実行すると、システムがメモリを回復するためにバックグラウンド アクティビティを破棄する場合があります。その結果、アクティビティの状態は失われます。<a href="#ActivityState">アクティビティの状態</a>セクションをご覧ください。 + + +</p> + +<p>バックスタック内のアクティビティが並べ替えられることはないため、アプリケーションが複数のアクティビティからの特定のアクティビティ開始を許可すると、(アクティビティの前のインスタンスを一番上に移動させるのではなく)そのアクティビティの新しいインスタンスが作成されてスタック上にプッシュされます。 + + +これによって、図 3 に示すように、アプリケーションの 1 つのアクティビティが(別のタスクからも)複数回インスタンス化される場合があります。 +この場合は、ユーザーが [<em>戻る</em>] ボタンを使って移動すると、アクティビティの各インスタンスが(UI の状態はそれぞれそのままで)開いた順に表示されます。 + + +しかし、1 つのアクティビティを何度もインスタンス化したくない場合は、この動作を修正できます。 +その方法については、後述のセクション<a href="#ManagingTasks">タスクを管理する</a>で説明します。</p> + + +<p>以下は、アクティビティとタスクのデフォルトの動作をまとめたものです。</p> + +<ul> + <li>アクティビティ A がアクティビティ B を開始すると、アクティビティ A は停止しますが、システムはその状態(スクロールの位置やフォームに入力されたテキストなど)を保持します。アクティビティ B が開いた状態でユーザーが [<em>戻る</em>] ボタンを押すと、アクティビティ A が再開し、その状態が復元されます。 + + +</li> + <li>ユーザーが [<em>ホーム</em>] ボタンを押してタスクを離れると、現在のアクティビティは停止し、そのタスクはバックグラウンドに移動します。 + +システムはタスク内のすべてのアクティビティの状態を保持します。後にユーザーがタスクを開始したランチャー アイコンを選択してタスクを再開すると、タスクはフォアグラウンドに移動し、スタックの一番上にあるアクティビティを開始します。 + +</li> + <li>ユーザーが [<em>戻る</em>] ボタンを押すと、現在のアクティビティはスタックから消え、破棄されます。 + +スタック内にある前のアクティビティが再開します。アクティビティが破棄された場合、システムはその状態を<em>保持しません</em>。 +</li> + <li>アクティビティは、別のタスクからでも複数回インスタンス化できます。</li> +</ul> + + +<div class="note design"> +<p><strong>ナビゲーション デザイン</strong></p> + <p>Android 上でのアプリ ナビゲーションの仕組みの詳細については、Android Design の「<a href="{@docRoot}design/patterns/navigation.html">Navigation</a>」ガイドをご覧ください。</p> +</div> + + +<h2 id="ActivityState">アクティビティの状態を保存する</h2> + +<p>上述のように、デフォルト動作では、システムはアクティビティが停止するとその状態を保持します。 +この方法では、ユーザーが前のアクティビティに戻ると、ユーザー インターフェースが前の状態のままで表示されます。 +しかし、コールバック メソッドを使って積極的にアクティビティの状態を保持することもできます。破棄されたアクティビティを再作成しなければならないことを考えると、アクティビティの状態は積極的に<strong>保持すべき</strong>です。 + +</p> + +<p>システムが(新しいアクティビティの開始時やバックグラウンドへのタスクの移動時などに)アクティビティの 1 つを停止している時にシステム メモリの回復が必要になると、システムはそのアクティビティを完全に破棄する可能性があります。 + +これにより、アクティビティの状態に関する情報が失われてしまいます。システムは、アクティビティがバックスタックに留まっていることは認識していますが、アクティビティがスタックの一番上に置かれるとアクティビティを(再開ではなく)再作成しなければなりません。 + + +ユーザーの作業内容が失われるのを回避するには、{@link android.app.Activity#onSaveInstanceState onSaveInstanceState()} コールバック メソッドをアクティビティに実装することによって、作業状態を積極的に保持する必要があります。 + + +</p> + +<p>アクティビティの状態の保存方法の詳細については、「<a href="{@docRoot}guide/components/activities.html#SavingActivityState">Activities</a>」ドキュメントをご覧ください。 +</p> + + + +<h2 id="ManagingTasks">タスクを管理する</h2> + +<p>上記のように、Android は、連続して開始されたすべてのアクティビティを同じタスクの「後入れ先出し」式スタックに置くことによって、タスクやバックスタックを管理します。この方法は、ほとんどのアプリケーションでうまく動作し、アクティビティがどのようにタスクに関連付けられ、どのようにバックスタックに置かれているのかを心配する必要はありません。 + + +しかし、通常の動作に割り込みたい場合もあります。 +アプリケーション内のアクティビティが開始された時に(現在のタスク内に置かれる代わりに)新しいタスクを開始させたり、アクティビティの開始時に(新しいインスタンスをバックスタックの一番上に作成する代わりに)アクティビティの既存インスタンスを前に持ってきたり、ユーザーがタスクを離れる時にルート アクティビティ以外のすべてのアクティビティをバックスタックからクリアする場合などが考えられます。 + + + +</p> + +<p><a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> マニフェスト エレメントの属性と {@link android.app.Activity#startActivity startActivity()} に渡すインテント内のフラグを使って、これらの、さらに他の動作を実現できます。 + + +</p> + +<p>この件に関して、使用できる主な <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> 属性には以下のものがあります。 +</p> + +<ul class="nolist"> + <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#aff"> {@code taskAffinity}</a> +</li> + <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode"> {@code launchMode}</a> +</li> + <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#reparent"> {@code allowTaskReparenting}</a> +</li> + <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#clear"> {@code clearTaskOnLaunch}</a> +</li> + <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#always"> {@code alwaysRetainTaskState}</a> +</li> + <li><a href="{@docRoot}guide/topics/manifest/activity-element.html#finish"> {@code finishOnTaskLaunch}</a> +</li> +</ul> + +<p>使用できる主なインテント フラグには以下のものがあります。</p> + +<ul class="nolist"> + <li>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</li> + <li>{@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP}</li> + <li>{@link android.content.Intent#FLAG_ACTIVITY_SINGLE_TOP}</li> +</ul> + +<p>以下のセクションでは、これらのマニフェスト属性とインテント フラグを使ってアクティビティをタスクに関連付ける方法とバックスタック内での動作を定義する方法を説明します。 +</p> + +<p>また、タスクとアクティビティの提示方法やオーバービュー画面での管理方法に関する考慮点について別途記載しています。 +詳細については、「<a href="{@docRoot}guide/components/recents.html">オーバービュー画面</a>」をご覧ください。 +通常、オーバービュー画面にタスクとアクティビティを提示する方法はシステムが定義できるよう許可し、この動作を変更する必要はありません。 +</p> + +<p class="caution"><strong>警告:</strong> ほとんどのアプリケーションはアクティビティとタスクに対するデフォルトの動作に割り込むべきではありません。 +アクティビティがデフォルトの動作を変更する必要があると判断した場合は、起動時と他のアクティビティやタスクからの [<em>戻る</em>] ボタンによる移動時のアクティビティのユーザビリティを慎重にテストする必要があります。ユーザーが想定する動作と競合する恐れのあるナビゲーション時の動作については必ずテストを行ってください。 + + +</p> + + +<h3 id="TaskLaunchModes">起動モードを定義する</h3> + +<p>起動モードでは、アクティビティの新しいインスタンスを現在のタスクに関連付ける方法を定義できます。 +次の 2 つの方法を使ってさまざまな起動モードを定義できます。</p> +<ul class="nolist"> + <li><a href="#ManifestForTasks">マニフェスト ファイルを使用する</a> + <p>マニフェスト ファイルにアクティビティを宣言する際に、開始時にアクティビティをタスクに関連付ける方法を指定できます。 +</li> + <li><a href="#IntentFlagsForTasks">インテント フラグを使用する</a> + <p>{@link android.app.Activity#startActivity startActivity()} を呼び出す際に、新しいアクティビティを現在のタスクに関連付ける方法(または関連付けるかどうか)を宣言する {@link android.content.Intent} にフラグを置くことができます。 + +</p></li> +</ul> + +<p>アクティビティ A がアクティビティ B を開始する場合、アクティビティ B は自身を現在のタスクに関連付ける方法(もしあれば)をマニフェストに定義し、アクティビティ A はアクティビティ B を現在のタスクに関連付ける方法を要求できます。 + +両方のアクティビティがアクティビティ B をタスクに関連付ける方法を定義している場合は、アクティビティ B の要求よりも(インテントに定義される)アクティビティ A の要求が優先されます。 + +</p> + +<p class="note"><strong>注:</strong> マニフェスト ファイルで使用できる起動モードの中にはインテントのフラグとして使用できないものもあります。同様に、インテントのフラグとして使用できる起動モードの中には、マニフェストで定義できないものもあります。 + +</p> + + +<h4 id="ManifestForTasks">マニフェスト ファイルを使用する</h4> + +<p>マニフェスト ファイルでアクティビティを宣言する際に、<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> エレメントの <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a> 属性を使ってアクティビティをタスクに関連付ける方法を定義できます。 + + +</p> + +<p><a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a> 属性は、アクティビティをタスク内で起動する方法についての指示を定めます。 + +<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">launchMode</a></code> 属性には、次の 4 つの起動モードを割り当てることができます。 + +</p> + +<dl> +<dt>{@code "standard"}(デフォルトのモード)</dt> + <dd>デフォルトの設定です。システムは、開始されたタスクからアクティビティの新しいインスタンスをタスク内に作成し、インテントを渡します。 +アクティビティは複数回インスタンス化できます。各インスタンスは異なるタスクに所属でき、1 つのタスクは複数のインスタンスを持つことができます。 +</dd> +<dt>{@code "singleTop"}</dt> + <dd>アクティビティのインスタンスが現在のタスクの一番上に既に存在する場合は、システムはアクティビティの新しいインスタンスを作成せずに、{@link android.app.Activity#onNewIntent onNewIntent()} メソッドを呼び出して、インテントをそのインスタンスに渡します。 + + +アクティビティは複数回インスタンス化できます。各インスタンスは異なるタスクに所属でき、1 つのタスクは複数のインスタンスを持つことができます(バックスタックの一番上にあるアクティビティがそのアクティビティの既存のインスタンスで<em>ない</em>場合のみ)。 + + + <p>たとえば、タスクのバックスタックがアクティビティ B、C、そしてアクティビティ D を一番上に持つルート アクティビティ A で構成されているとします(スタックは A-B-C-D で D が一番上)。 +D タイプのアクティビティにインテントが届きます。もし D の起動モードがデフォルトの {@code "standard"} である場合は、そのクラスの新しいインスタンスが起動し、スタックは A-B-C-D-D となります。しかし、D の起動モードが {@code "singleTop"} である場合は、スタックの一番上にある D の既存のインスタンスが {@link android.app.Activity#onNewIntent onNewIntent()} を介してインテントを受け取ります — この場合、スタックは A-B-C-D のままとなります。ただし、B タイプのアクティビティのインテントが届くと、その起動モードが {@code "singleTop"} であっても、B の新しいインスタンスがスタックに追加されます。 + + + + + +</p> + <p class="note"><strong>注:</strong> アクティビティの新しいインスタンスが作成されると、ユーザーは [<em>戻る</em>] ボタンを押して前のアクティビティに戻ることができます。 +しかし、アクティビティの既存のインスタンスが新しいインテントに対応すると、ユーザーは、新しいインテントが {@link android.app.Activity#onNewIntent onNewIntent()} で届く前の状態に [<em>戻る</em>] ボタンを押して戻ることはできません。 + + + + +</p> +</dd> + +<dt>{@code "singleTask"}</dt> + <dd>システムは新しいタスクを作成し、新しいタスクのルートにアクティビティをインスタンス化します。しかし、そのアクティビティのインスタンスが別のタスクに既に存在する場合は、システムは新しいインスタンスを作成せずに、{@link android.app.Activity#onNewIntent onNewIntent()} メソッドを呼び出して、インテントを既存のインスタンスに渡します。 + + +同時に存在できるアクティビティのインスタンスは 1 つだけです。 + + <p class="note"><strong>注:</strong> アクティビティは新しいタスク内で開始されますが、ユーザーは [<em>戻る</em>] ボタンを押して前のアクティビティに戻ることができます。 +</p></dd> +<dt>{@code "singleInstance"}</dt> + <dd>システムが、他のアクティビティをインスタンスを保持しているタスクで起動しないことを除いて {@code "singleTask"} と同じです。 +アクティビティは、常にタスクの唯一の構成要素となります。このアクティビティによって開始されたアクティビティは別のタスクで開きます。 +</dd> +</dl> + + +<p>たとえば、Android Browser アプリケーションは、<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> エレメントの {@code singleTask} 起動モードを指定することによって、ウェブブラウザ アクティビティを常に自身のタスクで開くことを宣言しています。これは、開発されたアプリケーションが Android Browser を開くインテントを発行すると、そのアクティビティがアプリケーションのタスクには配置<em>されない</em>ことを意味します。 + + + +代わりに、Android Browser の新しいタスクが開始されるか、Android Browser に既に実行中のバックグラウンド タスクがある場合は、そのタスクがフォアグラウンドに移動し、新しいインテントに対応します。 + +</p> + +<p>アクティビティを新しいタスク内で開始するかアクティビティを起動したアクティビティと同じタスクで開始するかにかかわらず、ユーザーは [<em>戻る</em>] ボタンを押して前のアクティビティに戻ることができます。 +ただし、{@code singleTask} 起動モードを設定したアクティビティを開始し、そのアクティビティのインスタンスがバックグラウンド タスクに存在する場合は、そのタスク全体がフォアグラウンドに移動します。 + +この時点で、バックスタックの一番上に、フォアグラウンドに移動したタスクのすべてのアクティビティが含まれてます。 + +図 4 は、このタイプのシナリオを示しています。</p> + +<img src="{@docRoot}images/fundamentals/diagram_backstack_singletask_multiactivity.png" alt="" /> +<p class="img-caption"><strong>図 4.</strong>「singleTask」起動モードを持つアクティビティをバックスタックに追加する方法を示しています。 +アクティビティが自身のバックスタックを持つバックグラウンド タスクの一部である場合は、バックスタック全体がフォアグラウンドに移動し、現在のタスクの上に置かれます。 + +</p> + +<p>マニフェスト ファイルでの起動モードの使用の詳細については、<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> エレメントのドキュメントをご覧ください。{@code launchMode} 属性と利用できる値について詳しく説明しています。 + + +</p> + +<p class="note"><strong>注:</strong> 次のセクションで説明しますが、<a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a> 属性を使ってアクティビティに指定する動作は、アクティビティを開始するインテントに含まれるフラグによって上書きされる場合があります。 + +</p> + + + +<h4 id="#IntentFlagsForTasks">インテント フラグを使用する</h4> + +<p>アクティビティの開始時に、{@link android.app.Activity#startActivity startActivity()} に渡すインテントにフラグを含めることによってアクティビティとタスクのデフォルトの関連付けを変更できます。 + +以下は、デフォルトの動作を変更するために使用できるフラグです。 +</p> + +<p> + <dt>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</dt> + <dd>新しいタスクでアクティビティを開始します。開始しようとしているアクティビティに対してタスクが既に実行されている場合は、そのタスクの最新の状態が復元されてフォアグラウンドに移動し、アクティビティが {@link android.app.Activity#onNewIntent onNewIntent()} で新しいインテントを受け取ります。 + + + <p>この手順は、上述のセクションで説明した {@code "singleTask"} <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a> の値の動作と同じものです。 +</p></dd> + <dt>{@link android.content.Intent#FLAG_ACTIVITY_SINGLE_TOP}</dt> + <dd>開始されるアクティビティが(バックスタックの一番上にある)現在のアクティビティである場合は、アクティビティの新しいインスタンスを作成する代わりに、既存のインスタンスが {@link android.app.Activity#onNewIntent onNewIntent()} の呼び出しを受け取ります。 + + + <p>この手順は、上述のセクションで説明した {@code "singleTop"} <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a> の値の動作と同じものです。 +</p></dd> + <dt>{@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP}</dt> + <dd>開始されるアクティビティが既に現在のタスクを実行している場合は、そのアクティビティの新しいインスタンスを起動する代わりに、上に置かれたその他すべてのアクティビティを破棄し、{@link android.app.Activity#onNewIntent onNewIntent()} を介してこのインテントを(一番上に移動した)アクティビティの再開されたインスタンスに渡します。 + + + + <p>この動作を起こす <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a> 属性には値はありません。 +</p> + <p>ほとんどのケースで {@code FLAG_ACTIVITY_CLEAR_TOP} は {@code FLAG_ACTIVITY_NEW_TASK} と併用されます。同時に使用することで、これらのフラグは、別のタスクにある既存のアクティビティを捜し出し、インテントに対応できる位置に置く手段を提供します。 + + + </p> + <p class="note"><strong>注:</strong> 指定されたアクティビティの起動モードが {@code "standard"} である場合は、やはりスタックから削除されます。その場所に、渡されるインテントに対応する新しいインスタンスが開始されます。 + + +これは、起動モードが {@code "standard"} である場合は、新しいインテントに対して常に新しいインスタンスが作成されるためです。 + </p> +</dd> +</dl> + + + + + +<h3 id="Affinities">アフィニティを処理する</h3> + +<p><em>アフィニティ</em>は、アクティビティの所属が望ましいタスクを示します。 デフォルトでは、同じアプリケーションのすべてアクティビティに相互のアフィニティが設定されています。 +このため、同じアプリケーションのすべてのアクティビティは、デフォルトで同じタスクに属します。 +しかし、アクティビティのデフォルトのアフィニティは変更できます。 +異なるアプリケーションに定義されているアクティビティがアフィニティを共有したり、同じアプリケーションに定義されたアクティビティに別のタスクのアフィニティを割り当てたりすることができます。 + +</p> + +<p><a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> エレメントの <a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">{@code taskAffinity}</a> 属性を使って、任意のアクティビティのアフィニティを変更できます。 + +</p> + +<p><a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">{@code taskAffinity}</a> 属性には文字列を指定します。これは、<a href="{@docRoot}guide/topics/manifest/manifest-element.html">{@code <manifest>}</a> エレメントに宣言されたデフォルトのパッケージ名とは異なる一意のものでなければなりません。理由は、システムがアプリケーションに対するデフォルトのタスク アフィニティを識別するためにこの名前を使用するためです。 + + + + +</p> + +<p>アフィニティは、以下の 2 つの状況で役立ちます。</p> +<ul> + <li>アクティビティを開始するインテントが {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} フラグを含んでいる場合 + + + +<p>新しいアクティビティは、デフォルトで、{@link android.app.Activity#startActivity startActivity()} を呼び出したアクティビティのタスクで開始されます。 +呼び出し元と同じバックスタックにプッシュされます。 +しかし、{@link android.app.Activity#startActivity startActivity()} に渡されたインテントに {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} フラグが含まれると、システムは新しいアクティビティを収容する別のタスクを捜します。 + + +これは、通常新しいタスクですが、新しいタスクである必要はありません。 +新しいアクティビティとして同じアフィニティを持つ既存のタスクが存在する場合は、アクティビティはそのタスクで開始されます。 +存在しない場合は、新しいタスクを開始します。</p> + +<p>このフラグによってアクティビティが新しいタスクを開始し、ユーザーが [<em>ホーム</em>] ボタンを押してタスクを離れる場合には、ユーザーがそのタスクに戻るための手段が必要です。 + +エンティティの中には(通知マネージャーなど)、自身の一部としてではなく、常に外部タスクでアクティビティを開始するものがあります。そのために、これらのエンティティが {@link android.app.Activity#startActivity startActivity()} に渡すインテントには常に {@code FLAG_ACTIVITY_NEW_TASK} が含まれます。このフラグを使った外部エンティティにより起動される可能性があるアクティビティがある場合は、起動アイコンなどを使って、アクティビティが開始したタスクにユーザーが戻れるよう独立した手段を確保します。(タスクのルート アクティビティには {@link android.content.Intent#CATEGORY_LAUNCHER} インテント フィルタがあります。後述の<a href="#Starting">タスクを開始する</a>セクションをご覧ください)。 + + + + + + +</p> +</li> + + <li>アクティビティの <a href="{@docRoot}guide/topics/manifest/activity-element.html#reparent">{@code allowTaskReparenting}</a> 属性が {@code "true"} に設定されている場合。 + + <p>この場合は、タスクがフォアグラウンドに移動した時に、アクティビティは自身が開始したタスクから、アフィニティがあるタスクへと移動できます。 +</p> + <p>たとえば、選ばれた都市の天気を予報するアクティビティが旅行アプリケーションの一部として定義されているケースを考えてみましょう。 +このアクティビティは、アプリケーション内のその他のアクティビティと同じアフィニティ(デフォルトのアプリケーション アフィニティ)を持ち、この属性による親への再割り当てが許可されています。いずれかのアクティビティにより開始された天気予報アクティビティは、最初はそのアクティビティと同じタスクに属しています。 + + +しかし、旅行アプリケーションのタスクがフォアグラウンドに移動すると、天気予報アクティビティはそのタスクに再度割り当てられ、タスク内に表示されます。 +</p> +</li> +</ul> + +<p class="note"><strong>ヒント:</strong> {@code .apk} ファイルがユーザーの視点で 1 つ以上の「アプリケーション」を含んでいる場合は、各「アプリケーション」に関連付けられたアクティビティに <a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">{@code taskAffinity}</a> 属性を使って異なるアフィニティを割り当てることをお勧めします。 + +</p> + + + +<h3 id="Clearing">バックスタックをクリアする</h3> + +<p>ユーザーがタスクを長時間離れると、システムはルート アクティビティを除くすべてのアクティビティをタスクからクリアします。 +ユーザーが再びタスクに戻ると、ルート アクティビティのみが復元されます。システムがこの動作を行うのは、しばらく時間が経過した後は、ユーザーが前に行っていた作業を放棄した可能性が高く、新しいことを始めるためにタスクに戻ったとみなされるためです。 + + </p> + +<p>この動作を変更するために、以下のアクティビティ属性を使用できます。 </p> + +<dl> +<dt><code><a +href="{@docRoot}guide/topics/manifest/activity-element.html#always">alwaysRetainTaskState</a></code> +</dt> +<dd>タスクのルート アクティビティでこの属性が {@code "true"} に設定されていると、上記のデフォルトの動作は発生しません。長時間が経過しても、タスクはすべてのアクティビティをスタックに保持します。 + +</dd> + +<dt><code><a +href="{@docRoot}guide/topics/manifest/activity-element.html#clear">clearTaskOnLaunch</a></code></dt> +<dd>タスクのルート アクティビティでこの属性が {@code "true"} に設定されている場合、ユーザーがタスクを離れて戻るたびに、スタックがルート アクティビティまでクリアされます。 + +つまり、<a href="{@docRoot}guide/topics/manifest/activity-element.html#always">{@code alwaysRetainTaskState}</a> の逆の動作となります。 + +ユーザーがタスクをほんの少しの間離れた場合でも、タスクは常に初期状態に戻ります。 +</dd> + +<dt><code><a +href="{@docRoot}guide/topics/manifest/activity-element.html#finish">finishOnTaskLaunch</a></code> +</dt> +<dd>この属性は、<a href="{@docRoot}guide/topics/manifest/activity-element.html#clear">{@code clearTaskOnLaunch}</a> に似ていますが、タスク全体ではなく 1 つのアクティビティに作用します。 + +ルート アクティビティを含むあらゆるアクティビティを消すことができます。 +この属性が {@code "true"} に設定されていると、アクティビティは現在のセッションが開かれている間のみタスクの一部として留まります。 +ユーザーがタスクから離れて戻ると、アクティビティは消えています。 +</dd> +</dl> + + + + +<h3 id="Starting">タスクを開始する</h3> + +<p>指定するアクションとして {@code "android.intent.action.MAIN"}、指定するカテゴリとして {@code "android.intent.category.LAUNCHER"} を持つインテント フィルタを付加することによって、アクティビティをタスクのエントリ ポイントとして設定できます。 + + +次に例を示します。</p> + +<pre> +<activity ... > + <intent-filter ... > + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + ... +</activity> +</pre> + +<p>この種類のインテント フィルタを使うことによって、アクティビティのアイコンとラベルがアプリケーション ランチャーに表示されるようになります。これにより、ユーザーは、アクティビティを起動し、アクティビティの起動後は、作成されたタスクにいつでも戻ることができるようになります。 + + +</p> + +<p>ユーザーがタスクを離れた後に、このアクティビティ ランチャーを使って戻ってくることが可能でなければならないため、2 番目の機能が重要になります。 +アクティビティが {@link android.content.Intent#ACTION_MAIN} と {@link android.content.Intent#CATEGORY_LAUNCHER} フィルタを持つ場合のみに、アクティビティが常にタスクを開始することを示す {@code "singleTask"} と {@code "singleInstance"} の 2 つの<a href="#LaunchModes">起動モード</a>を使用すべきなのはこのためです。 + + + +たとえば、フィルタがない場合にどうなるのかを想像してみてください。 +インテントが {@code "singleTask"} アクティビティを起動し、新しいタスクを開始し、ユーザーがそのタスクでしばらくの間作業を行います。 +その後、ユーザーは [<em>ホーム</em>] ボタンを押します。 +タスクはバックグラウンドに移動し、見えなくなります。タスクはアプリケーション ランチャーに表示されていないため、この状態ではユーザーがタスクに戻る手段がありません。 +</p> + +<p>ユーザーがアクティビティに戻るのを防ぐには、<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> エレメントの <a href="{@docRoot}guide/topics/manifest/activity-element.html#finish">{@code finishOnTaskLaunch}</a> を {@code "true"} に設定します(<a href="#Clearing">スタックをクリアする</a>をご覧ください)。 + + + +</p> + +<p>オーバービュー画面でのタスクとアクティビティの表示方法と管理方法の詳細については、「<a href="{@docRoot}guide/components/recents.html">オーバービュー画面</a>」をご覧ください。 + +</p> + +<!-- +<h2>Beginner's Path</h2> + +<p>For more information about how to use intents to +activate other application components and publish the intents to which your components +respond, continue with the <b><a +href="{@docRoot}guide/components/intents-filters.html">Intents and Intent +Filters</a></b> document.</p> +--> |