diff options
author | David Friedman <dmail@google.com> | 2015-07-24 19:52:06 -0700 |
---|---|---|
committer | David Friedman <dmail@google.com> | 2015-10-02 14:10:56 -0700 |
commit | bfbd27b84fb310ed007705f18cf13aeeda098096 (patch) | |
tree | b64d8ca46bee1fbbef0427f50450b8b1fdfdb2a6 /docs/html-intl/intl/ja/guide | |
parent | 586f56aa790b84a59981c1ef32857765e58393d2 (diff) |
Localization for Android fundamentals
Bug: 20503562
Change-Id: Ia98618932aef2b92a48e4d6e69749c220161722f
Diffstat (limited to 'docs/html-intl/intl/ja/guide')
31 files changed, 20550 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> +--> diff --git a/docs/html-intl/intl/ja/guide/index.jd b/docs/html-intl/intl/ja/guide/index.jd new file mode 100644 index 000000000000..07688b63ec20 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/index.jd @@ -0,0 +1,74 @@ +page.title=Android 入門 + +@jd:body + + +<div class="sidebox" style="width:220px"><!-- width to match col-4 below --> +<p>アプリの動作方法について学ぶには、「<a href="{@docRoot}guide/components/fundamentals.html">App Fundamentals</a>」をご覧ください。 +</p> +<p>今すぐコーディングを始める場合は、「<a href="{@docRoot}training/basics/firstapp/index.html">Building Your First App</a>」をご覧ください。</p> +</div> + +<p>Android は、モバイル端末用の画期的なアプリやゲームを Java 言語環境でビルドできる、充実したアプリケーション フレームワークを提供します。 +左側のナビゲーションに表示されているドキュメントには、さまざまな Android API を使ってアプリをビルドする詳しい方法が記載されています。 +</p> + +<p>Android 開発の経験がない場合は、Android アプリのフレームワークについて次の基本的な概念を理解していることが重要になります。 +</p> + + +<div class="landing-banner"> + +<div class="col-6"> + +<h4>アプリには複数のエントリ ポイントがある</h4> + +<p>Android のアプリは、個別に呼び出し可能な異なるコンポーネントを組み合わせてビルドされます。 +たとえば、1 つの<em>アクティビティ</em>が 1 つの画面でユーザー インターフェースを提供し、<em>サービス</em>がバックグラウンドで個別に処理を実行します。 + +</p> + +<p><em>インテント</em>を使って、1 つのコンポーネントから別のコンポーネントを開始できます。地図アプリで住所を表示するアクティビティなどのように、別のアプリでコンポーネントを開始することもできます。 +このモデルでは、1 つのアプリに複数のエントリ ポイントを提供し、あらゆるアプリを他のアプリが呼び出すアクションの「デフォルト」として動作させることができます。 + +</p> + + +<p><b>詳細を見る</b></p> +<ul class="nolist"> +<li><a href="{@docRoot}guide/components/fundamentals.html">App Fundamentals</a> +<li><a href="{@docRoot}guide/components/intents-filters.html">インテントとインテント フィルタ</a> +<li><a href="{@docRoot}guide/components/activities.html">Activities</a> +</ul> + +</div> + + +<div class="col-6"> + +<h4>さまざまな端末に対応するアプリ</h4> + +<p>Android は、さまざまな端末の構成に独自のリソースを提供できる柔軟なアプリ フレームワークを提供します。 +たとえば、画面サイズごとに個別の XML レイアウト ファイルを作成し、システムが使用中の端末の画面サイズに基づいて適用するレイアウトを決定します。 + +</p> + +<p>アプリの機能に特定のハードウェア(カメラなど)が必要な場合は、実行時に端末機能の使用可能状況をクエリできます。 +必要に応じて、アプリに必要な機能を宣言することもできます。これによって、Google Play ストアなどのアプリ マーケットでは、宣言した機能に対応していない端末へのインストールが許可されません。 + +</p> + + +<p><b>詳細を見る</b></p> +<ul class="nolist"> +<li><a href="{@docRoot}guide/practices/compatibility.html">Device Compatibility</a> +<li><a href="{@docRoot}guide/topics/resources/overview.html">リソースの概要</a> +<li><a href="{@docRoot}guide/topics/ui/overview.html">ユーザー インターフェースの概要</a> +</ul> + +</div> + +</div><!-- end landing-banner --> + + + diff --git a/docs/html-intl/intl/ja/guide/topics/manifest/manifest-intro.jd b/docs/html-intl/intl/ja/guide/topics/manifest/manifest-intro.jd new file mode 100644 index 000000000000..7d9e8ac588f8 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/manifest/manifest-intro.jd @@ -0,0 +1,517 @@ +page.title=アプリ マニフェスト +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + +<h2>本書の内容</h2> +<ol> +<li><a href="#filestruct">マニフェスト ファイルの構造</a></li> +<li><a href="#filec">ファイルの規則</a> +<li><a href="#filef">ファイルの特徴</a> + <ol> + <li><a href="#ifs">インテント フィルタ</a></li> + <li><a href="#iconlabel">アイコンとラベル</a></li> + <li><a href="#perms">パーミッション</a></li> + <li><a href="#libs">ライブラリ</a></li> + </ol></li> +</ol> +</div> +</div> + +<p> + すべてのアプリケーションには、そのルート ディレクトリに AndroidManifest.xml ファイル(名前はこのまま)が必要です。 + <span itemprop="description">マニフェスト ファイルはアプリに関する重要な情報を Android システムに提示します。これは、システムがアプリのコードを実行する前に必要な情報です。 + + +</span> その他、マニフェスト ファイルでは次のことを行います。 +</p> + +<ul> +<li>アプリケーションの Java パッケージ名を指定します。パッケージ名は、アプリケーションの一意の識別子としての機能を果たします。 +</li> + +<li>アプリケーションのコンポーネント(アプリケーションを構成するアクティビティ、サービス、ブロードキャスト レシーバー、コンテンツ プロバイダ)を記述します。 + +各コンポーネントを実装するクラスの名前を指定し、その機能(対応可能な {@link android.content.Intent Intent} メッセージなど)を公開します。 + +これらの宣言によって、Android システムは、どんなコンポーネントがあり、それらのコンポーネントがどのような条件で起動されるのかを把握できます。 +</li> + +<li>アプリケーション コンポーネントをホストするプロセスを決定します。</li> + +<li>アプリケーションが API の保護された部分にアクセスしたり他のアプリケーションとやり取りしたりする際に必要となるパーミッションを宣言します。 +</li> + +<li>他のアプリケーションがアプリケーションのコンポーネントとやり取りするために必要なパーミッションを宣言します。 +</li> + +<li>アプリケーションの実行時にプロファイリングやその他の情報を提供する {@link android.app.Instrumentation} クラスを記載します。 +これらの宣言は、アプリケーションの開発時やテスト時にのみマニフェストに含まれ、アプリケーションの公開前に削除されます。 + +</li> + +<li>アプリケーションに必要な Android API の最小限のレベルを宣言します。 +</li> + +<li>アプリケーションにリンクする必要があるライブラリを記載します。</li> +</ul> + + +<h2 id="filestruct">マニフェスト ファイルの構造</h2> + +<p> +次の図は、マニフェスト ファイルの一般的な構造とファイルに含むことができるすべてのエレメントを示します。 +各エレメントとそれぞれの属性はすべて別のファイルに記述されます。 +エレメントの詳細を見るには、図中、図の下にあるアルファベット順のエレメント一覧、またはその他の説明文に表示されているエレメント名をクリックしてください。 + + + +</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> + +<a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a> + + <a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission /></a> + <a href="{@docRoot}guide/topics/manifest/permission-element.html"><permission /></a> + <a href="{@docRoot}guide/topics/manifest/permission-tree-element.html"><permission-tree /></a> + <a href="{@docRoot}guide/topics/manifest/permission-group-element.html"><permission-group /></a> + <a href="{@docRoot}guide/topics/manifest/instrumentation-element.html"><instrumentation /></a> + <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><uses-sdk /></a> + <a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html"><uses-configuration /></a> <!-- ##api level 3## --> + <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><uses-feature /></a> <!-- ##api level 4## --> + <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><supports-screens /></a> <!-- ##api level 4## --> + <a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html"><compatible-screens /></a> <!-- ##api level 9## --> + <a href="{@docRoot}guide/topics/manifest/supports-gl-texture-element.html"><supports-gl-texture /></a> <!-- ##api level 11## --> + + <a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a> + + <a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a> + <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a> + <a href="{@docRoot}guide/topics/manifest/action-element.html"><action /></a> + <a href="{@docRoot}guide/topics/manifest/category-element.html"><category /></a> + <a href="{@docRoot}guide/topics/manifest/data-element.html"><data /></a> + <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"></intent-filter></a> + <a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data /></a> + <a href="{@docRoot}guide/topics/manifest/activity-element.html"></activity></a> + + <a href="{@docRoot}guide/topics/manifest/activity-alias-element.html"><activity-alias></a> + <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a> . . . <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"></intent-filter></a> + <a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data /></a> + <a href="{@docRoot}guide/topics/manifest/activity-alias-element.html"></activity-alias></a> + + <a href="{@docRoot}guide/topics/manifest/service-element.html"><service></a> + <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a> . . . <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"></intent-filter></a> + <a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data/></a> + <a href="{@docRoot}guide/topics/manifest/service-element.html"></service></a> + + <a href="{@docRoot}guide/topics/manifest/receiver-element.html"><receiver></a> + <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a> . . . <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"></intent-filter></a> + <a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data /></a> + <a href="{@docRoot}guide/topics/manifest/receiver-element.html"></receiver></a> + + <a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a> + <a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html"><grant-uri-permission /></a> + <a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data /></a> + <a href="{@docRoot}guide/topics/manifest/path-permission-element.html"><path-permission /></a> + <a href="{@docRoot}guide/topics/manifest/provider-element.html"></provider></a> + + <a href="{@docRoot}guide/topics/manifest/uses-library-element.html"><uses-library /></a> + + <a href="{@docRoot}guide/topics/manifest/application-element.html"></application></a> + +<a href="{@docRoot}guide/topics/manifest/manifest-element.html"></manifest></a> +</pre> + +<p> +以下は、マニフェスト ファイルに含むことができるすべてのエレメントをアルファベット順に並べたものです。 +使用が許可されているのはこれらのエレメントのみです。独自のエレメントや属性は追加できません。 + +</p> + +<p style="margin-left: 2em"> +<code><a href="{@docRoot}guide/topics/manifest/action-element.html"><action></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html"><activity-alias></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/category-element.html"><category></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/data-element.html"><data></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html"><grant-uri-permission></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/instrumentation-element.html"><instrumentation></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/permission-element.html"><permission></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html"><permission-group></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/permission-tree-element.html"><permission-tree></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/receiver-element.html"><receiver></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/service-element.html"><service></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><supports-screens></a></code> <!-- ##api level 4## --> +<br/><code><a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html"><uses-configuration></a></code> <!-- ##api level 3## --> +<br/><code><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><uses-feature></a></code> <!-- ##api level 4## --> +<br/><code><a href="{@docRoot}guide/topics/manifest/uses-library-element.html"><uses-library></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a></code> +<br/><code><a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><uses-sdk></a></code> +</p> + + + + +<h2 id="filec">ファイルの規則</h2> + +<p> +マニフェスト ファイルに含まれるエレメントと属性には、通常、次の規則とルールが適用されます。 + +</p> + +<dl> +<dt><b>エレメント</b></dt> +<dd>必須のエレメントは<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code> と <code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code> のみです。両方のエレメントを提示する必要があり、使用できるのはそれぞれ 1 回のみです。 + + +その他のほとんどのエレメントは、複数回使ってもまったく使わなくてもかまいませんが、意味のあるマニフェストを行うにはいくつかのエレメントが必要です。 + + + + +<p> +内容のあるエレメントには他のエレメントが含まれているためです。すべての値は属性によって設定され、エレメント内に文字データが設定されることはありません。 + +</p> + +<p> +同じレベルにあるエレメントに順番はありません。たとえば、<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> や <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a></code>、<code><a href="{@docRoot}guide/topics/manifest/service-element.html"><service></a></code> エレメントは、どのような順で並べてもかまいません。 + + + +(<code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html"><activity-alias></a></code> エレメントは例外となります。 + +エイリアスとなっている <code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> のすぐ後に記述する必要があります)。 + + +</p></dd> + +<dt><b>属性</b></dt> +<dd>正式には、すべての属性はオプションです。しかし、エレメントが目的を達成するために設定しなければならない属性もあります。 +このドキュメントはガイドとしてお使いください。 +真の意味でオプションの属性には、デフォルト値または指定がない場合の動作が記述されています。 + + +<p>ルートの <code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code> エレメントの属性の一部を除き、すべての属性名は {@code android:} 接頭辞で始まります(例: {@code android:alwaysRetainTaskState})。 + + +この接頭辞は共通であるため、ドキュメントで属性が名前で参照されている場合は通常省略されます。 + +</p></dd> + +<dt><b>クラス名の宣言</b></dt> +<dd>多くのエレメントは Java オブジェクトと一致しています。これらのエレメントには、アプリケーション自体(<code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code> エレメント)とその主要なコンポーネントであるアクティビティ(<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code>)、サービス(<code><a href="{@docRoot}guide/topics/manifest/service-element.html"><service></a></code>)、ブロードキャスト レシーバー(<code><a href="{@docRoot}guide/topics/manifest/receiver-element.html"><receiver></a></code>)やコンテンツ プロバイダ(<code><a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a></code>)が含まれます。 + + + + + + + + + + + +<p> +サブクラスを定義する場合は、コンポーネント クラス({@link android.app.Activity}、{@link android.app.Service}、{@link android.content.BroadcastReceiver}、{@link android.content.ContentProvider})でいつも行うように、サブクラスは {@code name} 属性で宣言されます。 + + +この名前には、完全なパッケージ名を含む必要があります。 +たとえば、{@link android.app.Service} サブクラスの宣言は以下のようになります。 + +</p> + +<pre><manifest . . . > + <application . . . > + <service android:name="com.example.project.SecretService" . . . > + . . . + </service> + . . . + </application> +</manifest></pre> + +<p> +ただし、簡素化する方法として、文字列の最初の文字がピリオドの場合、文字列はアプリケーションのパッケージ名に付加されます(<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code> エレメントの <code><a href="{@docRoot}guide/topics/manifest/manifest-element.html#package">package</a></code> 属性によって指定されるため)。 + + + + +以下は、上記のものと同じ内容です。 +</p> + +<pre><manifest package="com.example.project" . . . > + <application . . . > + <service android:name=".SecretService" . . . > + . . . + </service> + . . . + </application> +</manifest></pre> + +<p> +コンポーネントの開始時に、Android は名前が指定されたサブクラスのインスタンスを作成します。サブクラスが指定されていない場合は、基底クラスのインスタンスを作成します。 + +</p></dd> + +<dt><b>複数の値</b></dt> +<dd>1 つ以上の値が指定されている場合は、1 つのエレメントに複数の値が記載されているのではなく、エレメントが繰り返されているケースがほとんどです。 +たとえば、インテント フィルタには複数のアクションが記載されている場合があります。 + + +<pre><intent-filter . . . > + <action android:name="android.intent.action.EDIT" /> + <action android:name="android.intent.action.INSERT" /> + <action android:name="android.intent.action.DELETE" /> + . . . +</intent-filter></pre></dd> + +<dt><b>リソースの値</b></dt> +<dd>属性には、ユーザーに対して表示する値を含むものもあります。たとえば、アクティビティのラベルやアイコンです。 +これらの属性の値は、ローカライズされていなければならないため、リソースまたはテーマから設定する必要があります。 +リソースの値は、以下の形式で記述されます。 +</p> + +<p style="margin-left: 2em">{@code @[<i>package</i>:]<i>type</i>:<i>name</i>}</p> + +<p> +リソースがアプリケーションと同じパッケージ内にある場合は package 名を省略できます。type はリソースのタイプ(「string」や「drawable」など)、name は特定のリソースの名前です。<i></i> +<i></i> +<i></i>次に例を示します。 + +</p> + +<pre><activity android:icon="@drawable/smallPic" . . . ></pre> + +<p> +テーマからの値も同様の方法で表記されますが、冒頭は '{@code @}' ではなく '{@code ?}' となります。 + +</p> + +<p style="margin-left: 2em">{@code ?[<i>package</i>:]<i>type</i>:<i>name</i>} +</p></dd> + +<dt><b>文字列の値</b></dt> +<dd>属性値が文字列で文字をエスケープする場合はダブル バックスラッシュ('{@code \\}')を使う必要があります。たとえば、改行は '{@code \\n}'、Unicode の文字は '{@code \\uxxxx}' となります。 + +</dd> +</dl> + + +<h2 id="filef">ファイルの特徴</h2> + +<p> +以下のセクションでは、Android の機能がどのようにマニフェスト ファイルに反映されるのかを説明します。 + +</p> + + +<h3 id="ifs">インテント フィルタ</h3> + +<p> +アプリケーションのコア コンポーネント(アクティビティ、サービス、ブロードキャスト レシーバー)はインテントによって開始されます。 +<i></i>インテントとは、目的とするアクションを記述している情報の束({@link android.content.Intent} オブジェクト)で、使用されるデータやアクションを実行するコンポーネントのカテゴリ、その他の関連する指示を含みます。 + + +Android は、インテントに対応する適切なコンポーネントを捜し出し、必要に応じて新しいインスタンスを起動し、それにインテント オブジェクトを渡します。 + + + +</p> + +<p> +コンポーネントはインテント フィルタを使ってその機能(対応できるインテントの種類)を通知します。 +<i></i>Android システムはコンポーネントを起動する前にコンポーネントが対応できるインテントを知っておく必要があるため、インテント フィルタはマニフェスト ファイルの <code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a></code> エレメントで指定されます。 + + + +コンポーネントは、それぞれが異なる機能を記述しているフィルタをいくつでも持つことができます。 + +</p> + +<p> +対象となるコンポーネントの名前を明示的に指定しているインテントは、コンポーネントを起動します。この場合、フィルタは適用されません。 +対象の名前が指定されていない場合は、コンポーネントのフィルタを通過したインテントのみがコンポーネントを起動できます。 + + +</p> + +<p> +インテント フィルタに対してインテント オブジェクトをテストする方法については、「<a href="{@docRoot}guide/components/intents-filters.html">インテントとインテント フィルタ</a>」ドキュメントをご覧ください。 + + + +</p> + + +<h3 id="iconlabel">アイコンとラベル</h3> + +<p> +エレメントは、小さなアイコンやテキスト ラベルをユーザーに表示するために、{@code icon} と {@code label} 属性を持つ場合があります。 +画面に長い説明文を表示するための {@code description} 属性を持つエレメントもあります。 + +たとえば、<code><a href="{@docRoot}guide/topics/manifest/permission-element.html"><permission></a></code> エレメントはこれらすべての属性を持っています。これによって、アプリケーションがユーザーにパーミッションを付与するかどうかを尋ねる際に、ユーザーに対して、パーミッションを示すアイコン、パーミッションの名前、パーミッションについての説明文を提示できます。 + + + + + +</p> + +<p> +どの場合においても、属性を含むエレメントに設定されたアイコンとラベルが、そのすべてのサブエレメントの {@code icon} と {@code label} のデフォルト設定となります。 +そのため、<code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code> エレメントに設定されたアイコンとラベルは、アプリケーションの各コンポーネントのデフォルトのアイコンとラベルとなります。 + + +同様に、コンポーネントに設定されたアイコンとラベルは、— <code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> エレメントのように — それぞれのコンポーネントの <code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a></code> エレメントのデフォルト設定となります。 + + + + +<code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code> エレメントにラベルを設定し、アクティビティとそのインテント フィルタに設定しない場合は、アプリケーション ラベルはアクティビティとインテント フィルタの両方のラベルとして取り扱われます。 + + + + +</p> + +<p> +インテント フィルタに設定されるアイコンとラベルは、コンポーネントがユーザーに対して提示されるときはいつでも、そのフィルタにより通知されている機能を提供するコンポーネントを示すために使用されます。 + +たとえば、「{@code android.intent.action.MAIN}」と「{@code android.intent.category.LAUNCHER}」が設定されているフィルタは、アプリケーションを起動するアクティビティを通知しています — つまり、アプリケーション ランチャーに表示されるということです。 + + + +そのため、このフィルタに設定されているアイコンとラベルがランチャーに表示されるものとなります。 + +</p> + + +<h3 id="perms">パーミッション</h3> + +<p> +パーミッションは、コードの一部や端末上のデータへのアクセスを制限する機能を提供します。<i></i> + 誤用や悪用によってユーザーの利用を妨げたり有害な作用をもたらす恐れのある重要なデータやコードを保護したりするための制限を設定します。 + +</p> + +<p> +それぞれのパーミッションは一意のラベルで識別されています。通常、ラベルは制限されるアクションを示します。 +以下は、Android により定義されているパーミッションの例です。 + +</p> + +<p style="margin-left: 2em">{@code android.permission.CALL_EMERGENCY_NUMBERS} +<br/>{@code android.permission.READ_OWNER_DATA} +<br/>{@code android.permission.SET_WALLPAPER} +<br/>{@code android.permission.DEVICE_POWER}</p> + +<p> +1 つの機能は、1 つのパーミッションでのみ保護できます。 +</p> + +<p> +アプリケーションがパーミッションにより保護されている機能へのアクセスを必要としている場合は、<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a></code> エレメントをマニフェスト ファイルに記述し、そのパーミッションが必要であることを宣言する必要があります。 + + +これによって、アプリケーションが端末にインストールされた際に、インストーラーは、アプリケーションの証明書に署名した関係機関を確認し、場合によってはユーザーに尋ねることで、要求されたパーミッションを付与するかどうかを決定します。 + + +パーミッションが付与されると、アプリケーションは保護された機能を使用できるようになります。 + +パーミッションが付与されなかった場合は、アプリケーションは機能にアクセスできず、ユーザーに通知が表示されることもありません。 + +</p> + +<p> +アプリケーションは、パーミッションを使って自身のコンポーネント(アクティビティ、サービス、ブロードキャスト レシーバー、コンテンツ プロバイダ)を保護することもできます。 +Android により定義されているパーミッション({@link android.Manifest.permission android.Manifest.permission} に記載)や他のアプリケーションにより宣言されたパーミッションであればどれでも使用できます。 + + +独自のパーミッションを定義することもできます。新しいパーミッションは、<code><a href="{@docRoot}guide/topics/manifest/permission-element.html"><permission></a></code> エレメントを使って宣言します。 + + +たとえば、次のようにアクティビティを保護できます。 +</p> + +<pre> +<manifest . . . > + <permission android:name="com.example.project.DEBIT_ACCT" . . . /> + <uses-permission android:name="com.example.project.DEBIT_ACCT" /> + . . . + <application . . .> + <activity android:name="com.example.project.FreneticActivity" + android:permission="com.example.project.DEBIT_ACCT" + . . . > + . . . + </activity> + </application> +</manifest> +</pre> + +<p> +この例では、{@code DEBIT_ACCT} パーミッションは <code><a href="{@docRoot}guide/topics/manifest/permission-element.html"><permission></a></code> エレメントで宣言されているだけではなく、その使用が <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a></code> エレメントで要求されている点に注意してください。 + + + + +アプリケーション自身によって保護が設定されている場合でも、アプリケーションの他のコンポーネントが保護されたアクティビティを起動するために、その使用を要求する必要があります。 + + +</p> + +<p> +同じ例で、別の場所で宣言されたパーミッションに {@code permission} 属性が設定されている場合({@code android.permission.CALL_EMERGENCY_NUMBERS} など)は、<code><a href="{@docRoot}guide/topics/manifest/permission-element.html"><permission></a></code> エレメントを使って再度宣言する必要があります。 + + + + +その場合も <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a></code> でその使用を要求する必要があります。 + +</p> + +<p> +<code><a href="{@docRoot}guide/topics/manifest/permission-tree-element.html"><permission-tree></a></code> エレメントは、コードに定義されるパーミッションの集まりに対するネームスペースを宣言します。 + + +<code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html"><permission-group></a></code> エレメントは、パーミッションのセットに対するラベル(マニフェスト ファイルに <code><a href="{@docRoot}guide/topics/manifest/permission-element.html"><permission></a></code> エレメントを使って宣言されたもの、その他の場所で宣言されたものの両方)を定義します。 + + + +これは、ユーザーに提示される際のパーミッションのグループ分けのみに影響します。 +<code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html"><permission-group></a></code> エレメントでは、パーミッションのグループへの所属は指定されません。グループ名のみが指定されます。 + + +パーミッションは、<code><a href="{@docRoot}guide/topics/manifest/permission-element.html"><permission></a></code> エレメントの <code><a href="{@docRoot}guide/topics/manifest/permission-element.html#pgroup">permissionGroup</a></code> 属性にグループ名を割り当てることによって、グループに配置されます。 + + + + + +</p> + + +<h3 id="libs">ライブラリ</h3> + +<p> +すべてのアプリケーションはデフォルトの Android ライブラリにリンクされています。このライブラリには、Activity、Service、Intent、View、Button、Application、ContentProvider などの共通クラスを含む、アプリケーションをビルドするための基本パッケージが含まれています。 + + + +</p> + +<p> +しかし、独自のライブラリに含まれているパッケージもあります。開発中のアプリケーションがこれらのパッケージのコードを使用している場合は、該当するライブラリにリンクするよう明示的に求める必要があります。 + +この場合は、マニフェスト ファイルに各ライブラリを指定する <code><a href="{@docRoot}guide/topics/manifest/uses-library-element.html"><uses-library></a></code> エレメントが別途含まれている必要があります。 + +(ライブラリ名は該当するパッケージのドキュメントに記載されています)。 + +</p> diff --git a/docs/html-intl/intl/ja/guide/topics/providers/calendar-provider.jd b/docs/html-intl/intl/ja/guide/topics/providers/calendar-provider.jd new file mode 100644 index 000000000000..7b97c3083341 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/providers/calendar-provider.jd @@ -0,0 +1,1184 @@ +page.title=カレンダー プロバイダ +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + <h2>本書の内容</h2> + <ol> + <li><a href="#overview">基本</a></li> + <li><a href="#manifest">ユーザー パーミッション</a></li> + <li><a href="#calendar">Calendars テーブル</a> +<ol> + <li><a href="#query">カレンダーへのクエリ</a></li> + <li><a href="#modify-calendar">カレンダーの変更</a></li> + <li><a href="#insert-calendar">カレンダーの挿入</a></li> + </ol> + </li> + <li><a href="#events">Events テーブル</a> +<ol> + <li><a href="#add-event">イベントの追加</a></li> + <li><a href="#update-event">イベントのアップデート</a></li> + <li><a href="#delete-event">イベントの削除</a></li> + </ol> + </li> + <li><a href="#attendees">Attendees テーブル</a> +<ol> + <li><a href="#add-attendees">参加者の追加</a></li> + </ol> + </li> + <li><a href="#reminders">Reminders テーブル</a> +<ol> + <li><a href="#add-reminders">リマインダーの追加</a></li> + </ol> + </li> + <li><a href="#instances">Instances テーブル</a> + <ol> + <li><a href="#query-instances">Instances テーブルへのクエリ</a></li> + </ol></li> + <li><a href="#intents">カレンダーのインテント</a> + <ol> + <li><a href="#intent-insert">インテントを使用したイベントの挿入</a></li> + <li><a href="#intent-edit">インテントを使用したイベントの編集</a></li> + <li><a href="#intent-view">インテントを使用したカレンダー データの参照</a></li> + </ol> + </li> + + <li><a href="#sync-adapter">同期アダプタ</a></li> +</ol> + + <h2>キークラス</h2> + <ol> + <li>{@link android.provider.CalendarContract.Calendars}</li> + <li>{@link android.provider.CalendarContract.Events}</li> + <li>{@link android.provider.CalendarContract.Attendees}</li> + <li>{@link android.provider.CalendarContract.Reminders}</li> + </ol> +</div> +</div> + +<p>カレンダー プロバイダは、ユーザーのカレンダー イベントのためのリポジトリです。カレンダー プロバイダ API を使用すると、カレンダー、イベント、参加者、リマインダーなどに対するクエリ、挿入、アップデート、削除の操作を実行できます。 + +</p> + + +<p>カレンダー プロバイダ API は、アプリケーションや同期アダプタで使用できます。ルールは、呼び出しを実行しているプログラムのタイプによって異なります。 +本書では主に、カレンダー プロバイダ API のアプリケーションとしての使用について説明します。 +同期アダプタの場合の違いについては、<a href="#sync-adapter">同期アダプタ</a>をご覧ください。 + +</p> + + +<p>通常、カレンダー データを読み取ったり書き込んだりするためには、アプリケーションのマニフェストに<a href="#manifest">ユーザー パーミッション</a>で説明している適切なパーミッションが含まれている必要があります。 + +一般的な操作を簡単に実行できるようにするため、カレンダー プロバイダには、いくつかのインテントが用意されています。これらについては、<a href="#intents">カレンダーのインテント</a>で説明しています。 + +これらのインテントは、ユーザーをカレンダー アプリケーションに誘導して、イベントを挿入、参照、編集できるようにします。 +ユーザーは、カレンダー アプリケーションを操作した後、元のアプリケーションに戻ります。 +これにより、アプリケーションがパーミッションを要求したり、イベントの参照や作成のためのインターフェースを提供したりする必要がなくなります。 +</p> + +<h2 id="overview">基本</h2> + +<p><a href="{@docRoot}guide/topics/providers/content-providers.html">コンテンツ プロバイダ</a>は、データを保存してアプリケーションからアクセスできるようにします。 +Android プラットフォームによって提供されるコンテンツ プロバイダ(カレンダー プロバイダを含む)は、一般にリレーショナル データベース モデルに基づくテーブルのセットとしてデータを公開します。このモデルにおいて、各行はレコード、各列は特定のタイプと意味のデータになっています。 + +アプリケーションと同期アダプタは、ユーザーのカレンダー データを保持するデータベース テーブルの読み取りおよび書き込みアクセスを、カレンダー プロバイダ API を使用して取得できます。 + +</p> + +<p>各コンテンツ プロバイダは、データセットを一意に指定するパブリック URI({@link android.net.Uri} オブジェクトとしてラップされています)を公開します。 + +複数のデータセット(複数のテーブル)を制御するコンテンツ プロバイダは、データセットごとに個別の URI を公開します。 +プロバイダの URI はすべて、文字列「content://」で始まります。 +これは、コンテンツ プロバイダによって管理されているデータであることを示します。 +カレンダー プロバイダは、クラス(テーブル)それぞれの URI のための定数を定義します。 +URI の形式は <code><em><class></em>.CONTENT_URI</code> です。 +たとえば、{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI} のようになります。 +</p> + +<p>図 1 に、カレンダー プロバイダのデータモデルを図示します。メイン テーブルとそれらを相互にリンクしているフィールドが示されています。 +</p> + +<img src="{@docRoot}images/providers/datamodel.png" alt="Calendar Provider Data Model" /> +<p class="img-caption"><strong>図 1.</strong> カレンダー プロバイダのデータモデル。</p> + +<p>ユーザーは複数のカレンダーを持つことができ、カレンダーをそれぞれ異なるタイプのアカウント(Google カレンダー、Exchange など)と関連付けることができます。</p> + +<p>{@link android.provider.CalendarContract} は、カレンダーのデータモデルとイベント関連の情報を定義します。データは、次に示すいくつかのテーブルに保存されます。</p> + +<table> + <tr> + <th>テーブル(クラス)</th> + <th>説明</th> + </tr> + <tr> + <td><p>{@link android.provider.CalendarContract.Calendars}</p></td> + + <td>このテーブルは、該当するカレンダー固有の情報を保持します。 +各行には、名前、色、同期情報など、1 つのカレンダーに関する詳細が格納されます。 +</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.Events}</td> + + <td>このテーブルは、該当するイベント固有の情報を保持します。 +各行には、1 つのイベントに関する情報が格納されます—イベントのタイトル、場所、開始時刻、終了時刻などが該当します。 + +イベントは、単発だったり繰り返し発生したりすることが考えられます。参加者、リマインダー、拡張プロパティは、個別のテーブルに格納されます。 +これらのテーブルにはそれぞれ、Events テーブルの {@link android.provider.BaseColumns#_ID} を参照する {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} があります。 + +</td> + + </tr> + <tr> + <td>{@link android.provider.CalendarContract.Instances}</td> + + <td>このテーブルは、あるイベントの発生ごとの開始時刻と終了時刻を保持します。 +各行は、イベントの発生 1 回を表します。 +単発イベントには、イベントのインスタンスが 1 対 1 で対応します。 +繰り返しのイベントには、そのイベントの複数回の発生それぞれに対応する複数の行が自動生成されます。 +</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.Attendees}</td> + + <td>このテーブルは、イベントの参加者(ゲスト)の情報を保持します。 +各行は、1 回のイベントの 1 人のゲストを表します。 +ゲストのタイプと、ゲストのイベントへの出欠の回答を指定します。 +</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.Reminders}</td> + + <td>このテーブルは、アラートや通知のデータを保持します。 +各行は、1 回のイベントの 1 つのアラートを表します。1 つのイベントが複数のリマインダーを持つことができます。 +1 イベントあたりの最大リマインダー数は {@link android.provider.CalendarContract.CalendarColumns#MAX_REMINDERS} で指定され、指定されたカレンダーを所有する同期アダプタによって設定されます。 + + + +リマインダーは、イベント開始前の分単位で指定され、ユーザーに注意喚起する手段を示す情報を保持します。 +</td> + </tr> + +</table> + +<p>カレンダー プロバイダ API は、柔軟で効果的な設計になっています。ですが同時に、エンドユーザーにとって使いやすくすることや、カレンダーとそのデータの整合性を保護することが重要です。 + +次に、そのために API の使用に際して留意すべきことを示します。 +</p> + +<ul> + +<li><strong>カレンダー イベントの挿入、アップデート、参照</strong>カレンダー プロバイダからイベントの挿入、変更、読み取りを直接実行するためには、適切な<a href="#manifest">パーミッション</a>が必要です。ただし、作成しているのが本格的なカレンダー アプリケーションや同期アダプタではない場合は、そうしたパーミッションを要求する必要はありません。その代わりに、Android のカレンダー アプリケーションがサポートしているインテントを使用し、読み取りと書き込みの操作をそのアプリケーションに引き渡すことができます。インテントを使用すると、アプリケーションがユーザーをカレンダー アプリケーションに誘導し、自動入力されたフォームで目的の操作を実行するようになります。 +操作を完了したユーザーは、アプリケーションに戻されます。一般的な操作をカレンダーを介して実行するようにアプリケーションを設計することで、ユーザーに一貫性のある堅牢なユーザー インターフェースが提供できます。 + +これが推奨アプローチです。 +詳細については、<a href="#intents">カレンダーのインテント</a>をご覧ください。 +</p> + + +<li><strong>同期アダプタ。</strong>同期アダプタは、ユーザーの端末上にあるカレンダー データを別のサーバーやデータソースと同期します。 +{@link android.provider.CalendarContract.Calendars} テーブルと {@link android.provider.CalendarContract.Events} テーブルには、同期アダプタ用に予約された列があります。プロバイダやアプリケーションがそれらを変更しないようにする必要があります。 + + + +実際には、同期アダプタとしてアクセスしない限り、それらの列は参照できません。 +同期アダプタの詳細については、<a href="#sync-adapter">同期アダプタ</a>をご覧ください。 +</li> + +</ul> + + +<h2 id="manifest">ユーザー パーミッション</h2> + +<p>カレンダー データを読み込むためには、アプリケーションはマニフェスト ファイルに {@link android.Manifest.permission#READ_CALENDAR} パーミッションを含める必要があります。 +カレンダー データを削除、挿入、アップデートするためには、{@link android.Manifest.permission#WRITE_CALENDAR} パーミッションを含める必要があります。 + +</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android"...> + <uses-sdk android:minSdkVersion="14" /> + <uses-permission android:name="android.permission.READ_CALENDAR" /> + <uses-permission android:name="android.permission.WRITE_CALENDAR" /> + ... +</manifest> +</pre> + + +<h2 id="calendar">Calendars テーブル</h2> + +<p>{@link android.provider.CalendarContract.Calendars} テーブルには、個々のカレンダーの詳細情報が格納されます。 +次に示す Calendars の列は、アプリケーションと<a href="#sync-adapter">同期アダプタ</a>のどちらからも書き込み可能です。 +サポートされているすべてのフィールドの一覧については、{@link android.provider.CalendarContract.Calendars} のリファレンスをご覧ください。 + +</p> +<table> + <tr> + <th>定数</th> + <th>説明</th> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.Calendars#NAME}</td> + <td>カレンダーの名前。</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.Calendars#CALENDAR_DISPLAY_NAME}</td> + <td>ユーザーに表示されるこのカレンダーの名前。</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.Calendars#VISIBLE}</td> + + <td>カレンダーが表示対象として選択されているかどうかを示すブール値。値 0 は、このカレンダーに関連付けられているイベントを表示しないことを示します。 + +値 1 は、このカレンダーに関連付けられているイベントを表示することを示します。 +この値は、{@link android.provider.CalendarContract.Instances} テーブルの行の生成に影響を与えます。 +</td> + + + </tr> + <tr> + <td>{@link android.provider.CalendarContract.CalendarColumns#SYNC_EVENTS}</td> + + <td>カレンダーを同期してそのイベントを端末に格納するかどうかを示すブール値。 +値 0 は、このカレンダーを同期せず、イベントを端末に格納しないことを指定します。 +値 1 は、このカレンダーのイベントを同期し、イベントを端末に格納することを指定します。 +</td> + </tr> +</table> + +<h3 id="query">カレンダーへのクエリ</h3> + +<p>次の例は、特定のユーザーが所有するカレンダーを取得する方法を示しています。 +簡潔にするため、この例のクエリ操作はユーザー インターフェース スレッド(「メインスレッド」)内に示されています。 +実際には、メインスレッドではなく非同期スレッドで実行してください。 +詳細については、「<a href="{@docRoot}guide/components/loaders.html">ローダ</a>」をご覧ください。 +データを読み込むだけでなく変更する場合は、{@link android.content.AsyncQueryHandler} をご覧ください。 + +</p> + + +<pre> +// Projection array. Creating indices for this array instead of doing +// dynamic lookups improves performance. +public static final String[] EVENT_PROJECTION = new String[] { + Calendars._ID, // 0 + Calendars.ACCOUNT_NAME, // 1 + Calendars.CALENDAR_DISPLAY_NAME, // 2 + Calendars.OWNER_ACCOUNT // 3 +}; + +// The indices for the projection array above. +private static final int PROJECTION_ID_INDEX = 0; +private static final int PROJECTION_ACCOUNT_NAME_INDEX = 1; +private static final int PROJECTION_DISPLAY_NAME_INDEX = 2; +private static final int PROJECTION_OWNER_ACCOUNT_INDEX = 3;</pre> + + +<div class="sidebox-wrapper"> <div class="sidebox"> <h3>ACCOUNT_TYPE を含める必要がある理由 +</h3> <p>{@link android.provider.CalendarContract.Calendars#ACCOUNT_NAME Calendars.ACCOUNT_NAME} にクエリする場合は、このセクションに {@link android.provider.CalendarContract.Calendars#ACCOUNT_TYPE Calendars.ACCOUNT_TYPE} も含める必要があります。 + + + +これは、指定されたアカウントは <code>ACCOUNT_NAME</code> とその <code>ACCOUNT_TYPE</code> がどちらも与えられることで一意とみなされるからです。 + +<code>ACCOUNT_TYPE</code> は、そのアカウントが {@link android.accounts.AccountManager} で登録されたときに使用されたアカウント認証システムです。 + +また、端末アカウントに関連付けられていないカレンダー用に、{@link android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} という特殊なタイプのアカウントがあります。{@link android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} アカウントは同期されません。 + + + +</p> </div> </div> + + +<p> この例の次の部分では、クエリを作成します。クエリの条件は selection に指定しています。 +この例のクエリは、<code>ACCOUNT_NAME</code> が「sampleuser@google.com」で、<code>ACCOUNT_TYPE</code> が「com.google」で、<code>OWNER_ACCOUNT</code> が「sampleuser@google.com」であるカレンダーを検索します。 + + + +ユーザーが所有しているだけでなく参照したことのあるすべてのカレンダーを確認するには、<code>OWNER_ACCOUNT</code> を省略します。このクエリは、データベース クエリが返した結果セットをトラバースするのに使用できる {@link android.database.Cursor} オブジェクトを返します。 + + + +コンテンツ プロバイダでのクエリの使用については、「<a href="{@docRoot}guide/topics/providers/content-providers.html">コンテンツ プロバイダ</a>」をご覧ください。 +</p> + + +<pre>// Run query +Cursor cur = null; +ContentResolver cr = getContentResolver(); +Uri uri = Calendars.CONTENT_URI; +String selection = "((" + Calendars.ACCOUNT_NAME + " = ?) AND (" + + Calendars.ACCOUNT_TYPE + " = ?) AND (" + + Calendars.OWNER_ACCOUNT + " = ?))"; +String[] selectionArgs = new String[] {"sampleuser@gmail.com", "com.google", + "sampleuser@gmail.com"}; +// Submit the query and get a Cursor object back. +cur = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);</pre> + +<p>次のセクションでは、カーソルを使用して結果セットをステップ単位で移動します。例の冒頭で設定した定数を使用して各フィールドの値を返します。 + +</p> + +<pre>// Use the cursor to step through the returned records +while (cur.moveToNext()) { + long calID = 0; + String displayName = null; + String accountName = null; + String ownerName = null; + + // Get the field values + calID = cur.getLong(PROJECTION_ID_INDEX); + displayName = cur.getString(PROJECTION_DISPLAY_NAME_INDEX); + accountName = cur.getString(PROJECTION_ACCOUNT_NAME_INDEX); + ownerName = cur.getString(PROJECTION_OWNER_ACCOUNT_INDEX); + + // Do something with the values... + + ... +} +</pre> + +<h3 id="modify-calendar">カレンダーの変更</h3> + +<p>カレンダーのアップデートを実行する場合、カレンダーの {@link android.provider.BaseColumns#_ID} を、URI({@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()})の末尾に追加された ID として、または最初の selection 項目として指定できます。 + + + + +先ほどの selection を <code>"_id=?"</code> で始め、最初の <code>selectionArg</code> をカレンダーの {@link android.provider.BaseColumns#_ID} にする必要があります。 + + +URL に含まれる ID をエンコードすることでも、アップデートを実行できます。この例では、カレンダーの表示名をこの({@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()} を使用する)アプローチで変更しています。 + + + +</p> + +<pre>private static final String DEBUG_TAG = "MyActivity"; +... +long calID = 2; +ContentValues values = new ContentValues(); +// The new display name for the calendar +values.put(Calendars.CALENDAR_DISPLAY_NAME, "Trevor's Calendar"); +Uri updateUri = ContentUris.withAppendedId(Calendars.CONTENT_URI, calID); +int rows = getContentResolver().update(updateUri, values, null, null); +Log.i(DEBUG_TAG, "Rows updated: " + rows);</pre> + +<h3 id="insert-calendar">カレンダーの挿入</h2> + +<p>カレンダーは主に同期アダプタで管理するように設計されているため、新しいカレンダーは必ず同期アダプタとして挿入してください。 +ほとんどの場合、アプリケーションはカレンダーに対し、表示名の変更のような表面的な変更しかできません。 +アプリケーションがローカル カレンダーを作成する必要がある場合は、{@link android.provider.CalendarContract.SyncColumns#ACCOUNT_TYPE} として {@link android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} を使用し、カレンダーの挿入を同期アダプタとして実行することで作成できます。{@link android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} は、端末アカウントと関連付けられていないカレンダー用の特殊なアカウント タイプです。 + + + + + + +このタイプのカレンダーは、サーバーと同期されません。同期アダプタの詳細については、<a href="#sync-adapter">同期アダプタ</a>をご覧ください。 +</p> + +<h2 id="events">Events テーブル</h2> + +<p>{@link android.provider.CalendarContract.Events} テーブルには、個々のイベントの詳細情報が格納されます。 + +イベントを追加、アップデート、削除するためには、アプリケーションは<a href="#manifest">マニフェスト ファイル</a>に {@link android.Manifest.permission#WRITE_CALENDAR} パーミッションを含める必要があります。 +</p> + +<p>次に示す Events の列は、アプリケーションと同期アダプタのどちらからも書き込み可能です。 +サポートされているすべてのフィールドの一覧については、{@link android.provider.CalendarContract.Events} のリファレンスをご覧ください。 +</p> + +<table> + <tr> + <th>定数</th> + <th>説明</th> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.EventsColumns#CALENDAR_ID}</td> + <td>イベントが属するカレンダーの {@link android.provider.BaseColumns#_ID}。</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.EventsColumns#ORGANIZER}</td> + <td>イベントの主催者(所有者)のメールアドレス。</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.EventsColumns#TITLE}</td> + <td>イベントのタイトル。</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.EventsColumns#EVENT_LOCATION}</td> + <td>イベントが開催される場所。 </td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.EventsColumns#DESCRIPTION}</td> + <td>イベントの説明。</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.EventsColumns#DTSTART}</td> + <td>エポックからの UTC ミリ秒単位で表現されたイベント開始時刻。 </td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.EventsColumns#DTEND}</td> + <td>エポックからの UTC ミリ秒単位で表現されたイベント終了時刻。 </td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.EventsColumns#EVENT_TIMEZONE}</td> + <td>イベントのタイムゾーン。</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.EventsColumns#EVENT_END_TIMEZONE}</td> + <td>イベントの終了時刻のタイムゾーン。</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.EventsColumns#DURATION}</td> + + <td><a href="http://tools.ietf.org/html/rfc5545#section-3.8.2.5">RFC5545</a> 形式でのイベントの期間。たとえば、<code>"PT1H"</code> という値はイベントが 1 時間であること、<code>"P2W"</code> という値は期間が 2 週間であることを示します。 + + + </td> + + + </tr> + <tr> + <td>{@link android.provider.CalendarContract.EventsColumns#ALL_DAY}</td> + + <td>値 1 は、そのイベントがローカルのタイムゾーンで定義された終日を占めることを示します。 +値 0 は、1 日のどこかで始まって終わる定例のイベントであることを示します。 +</td> + + + </tr> + + + <tr> + <td>{@link android.provider.CalendarContract.EventsColumns#RRULE}</td> + + <td>イベント形式の繰り返し発生ルール。たとえば、<code>"FREQ=WEEKLY;COUNT=10;WKST=SU"</code> のようになります。 +その他の例については、<a href="http://tools.ietf.org/html/rfc5545#section-3.8.5.3">こちら</a>をご覧ください。 +</td> + + </tr> + + <tr> + <td>{@link android.provider.CalendarContract.EventsColumns#RDATE}</td> + <td>イベントの繰り返し発生日。通常、{@link android.provider.CalendarContract.EventsColumns#RDATE} は {@link android.provider.CalendarContract.EventsColumns#RRULE} と組み合わせて、繰り返し発生全体を定義するのに使用します。 + + + +詳細については、<a href="http://tools.ietf.org/html/rfc5545#section-3.8.5.2">RFC5545 の仕様</a>をご覧ください。</td> +</tr> + + <tr> + <td>{@link android.provider.CalendarContract.EventsColumns#AVAILABILITY}</td> + + <td>このイベントを埋まっている時間に数えるか、それともスケジュールのやり直しが利く空き時間とみなすか。 + </td> + + </tr> + <tr> + <td>{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_MODIFY}</td> + <td>ゲストがイベントを変更できるかどうか。 </td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_INVITE_OTHERS}</td> + <td>ゲストが他のゲストを招待できるかどうか。 </td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_SEE_GUESTS}</td> + <td>ゲストが他の参加者のリストを参照できるかどうか。</td> + </tr> +</table> + +<h3 id="add-event">イベントの追加</h3> + +<p>アプリケーションが新しいイベントを挿入する場合は、{@link android.content.Intent#ACTION_INSERT INSERT} インテントを使用することをお勧めします。詳細については、<a href="#intent-insert">インテントを使用したイベントの挿入</a>をご覧ください。 +ただし、必要があればイベントを直接挿入できます。 +ここではその方法について説明します。 +</p> + + +<p>新しいイベントを挿入するためのルールは次のとおりです。 </p> +<ul> + + <li>{@link android.provider.CalendarContract.EventsColumns#CALENDAR_ID} と {@link android.provider.CalendarContract.EventsColumns#DTSTART} を含める必要があります。 + +</li> + +<li>{@link android.provider.CalendarContract.EventsColumns#EVENT_TIMEZONE} を含める必要があります。 +システムにインストールされているタイムゾーン ID のリストを取得するには、{@link java.util.TimeZone#getAvailableIDs()} を使用します。 + +<a href="#intent-insert">インテントを使用したイベントの挿入</a>で説明しているように、{@link android.content.Intent#ACTION_INSERT INSERT} インテントを使用してイベントを挿入している場合、このルールは該当しません—その場合はデフォルトのタイムゾーンが指定されます。 + + +</li> + + <li>繰り返されないイベントには、{@link android.provider.CalendarContract.EventsColumns#DTEND} を含める必要があります。 + </li> + + + <li>繰り返されるイベントには、{@link android.provider.CalendarContract.EventsColumns#RRULE} と {@link android.provider.CalendarContract.EventsColumns#RDATE} に加えて {@link android.provider.CalendarContract.EventsColumns#DURATION} を含める必要があります。 + + +<a href="#intent-insert">インテントを使用したイベントの挿入</a>で説明しているように、{@link android.content.Intent#ACTION_INSERT INSERT} インテントを使用してイベントを挿入している場合、このルールは該当しません—その場合は、{@link android.provider.CalendarContract.EventsColumns#RRULE} を {@link android.provider.CalendarContract.EventsColumns#DTEND} と {@link android.provider.CalendarContract.EventsColumns#DTSTART} と組み合わせて使用でき、カレンダー アプリケーションはこれを自動で期間に変換します。 + + + + +</li> + +</ul> + +<p>イベントの挿入の例を次に示します。簡潔にするため、この例は UI スレッドで実行されています。 +実際には、挿入やアップデートは非同期スレッドで実行して、アクションをバックグラウンド スレッドに移してください。 +詳細については、{@link android.content.AsyncQueryHandler} をご覧ください。 +</p> + + +<pre> +long calID = 3; +long startMillis = 0; +long endMillis = 0; +Calendar beginTime = Calendar.getInstance(); +beginTime.set(2012, 9, 14, 7, 30); +startMillis = beginTime.getTimeInMillis(); +Calendar endTime = Calendar.getInstance(); +endTime.set(2012, 9, 14, 8, 45); +endMillis = endTime.getTimeInMillis(); +... + +ContentResolver cr = getContentResolver(); +ContentValues values = new ContentValues(); +values.put(Events.DTSTART, startMillis); +values.put(Events.DTEND, endMillis); +values.put(Events.TITLE, "Jazzercise"); +values.put(Events.DESCRIPTION, "Group workout"); +values.put(Events.CALENDAR_ID, calID); +values.put(Events.EVENT_TIMEZONE, "America/Los_Angeles"); +Uri uri = cr.insert(Events.CONTENT_URI, values); + +// get the event ID that is the last element in the Uri +long eventID = Long.parseLong(uri.getLastPathSegment()); +// +// ... do something with event ID +// +//</pre> + +<p class="note"><strong>注:</strong> イベントの作成後にイベント ID を取得していることに注目してください。 +これがイベント ID を取得する最も簡単な方法です。他のカレンダー操作を実行するためにイベント ID が必要になることはよくあります—イベントに対する参加者やリマインダーの追加などが該当します。 + +</p> + + +<h3 id="update-event">イベントのアップデート</h3> + +<p>アプリケーションでユーザーによるイベントの編集を許可する場合は、{@link android.content.Intent#ACTION_EDIT EDIT} インテントを使用することをお勧めします。詳細については、<a href="#intent-edit">インテントを使用したイベントの挿入</a>をご覧ください。ただし、イベントは必要に応じて直接編集できます。 + + +イベントのアップデートを実行する場合は、イベントの <code>_ID</code> を、URI({@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()})の末尾に追加された ID として、または前出の selection の最初の項目として指定できます。 + + + +前出の selection を <code>"_id=?"</code> で始め、最初の <code>selectionArg</code> をカレンダーの <code>_ID</code> にする必要があります。 + +ID なしの selection を使用してアップデートすることもできます。次に、イベントのアップデートの例を示します。 + +ここでは、{@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()} を使用するアプローチでイベントのタイトルを変更しています。 + +</p> + + +<pre>private static final String DEBUG_TAG = "MyActivity"; +... +long eventID = 188; +... +ContentResolver cr = getContentResolver(); +ContentValues values = new ContentValues(); +Uri updateUri = null; +// The new title for the event +values.put(Events.TITLE, "Kickboxing"); +updateUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID); +int rows = getContentResolver().update(updateUri, values, null, null); +Log.i(DEBUG_TAG, "Rows updated: " + rows); </pre> + +<h3 id="delete-event">イベントの削除</h3> + +<p>イベントは、目的のイベントの {@link android.provider.BaseColumns#_ID} を URI の末尾に追加する ID として使用するか、標準的な選択を使用して削除できます。 + +ID の追加で削除を実行する場合、選択はできません。削除には、アプリケーションとして実行する方法と同期アダプタとして実行する方法の 2 種類があります。 +アプリケーションとしての削除では、削除される<em></em>列が 1 に設定されます。 +このフラグは同期アダプタに対して、その行が削除されたことを通知し、この削除をサーバーに通知するよう指示します。 + +同期アダプタとしての削除では、すべての関連データとともにデータベースからイベントが削除されます。 +次の例では、アプリケーションがイベントをその {@link android.provider.BaseColumns#_ID} を使用して削除しています。 +</p> + + +<pre>private static final String DEBUG_TAG = "MyActivity"; +... +long eventID = 201; +... +ContentResolver cr = getContentResolver(); +ContentValues values = new ContentValues(); +Uri deleteUri = null; +deleteUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID); +int rows = getContentResolver().delete(deleteUri, null, null); +Log.i(DEBUG_TAG, "Rows deleted: " + rows); +</pre> + +<h2 id="attendees">Attendees テーブル</h2> + +<p>{@link android.provider.CalendarContract.Attendees} テーブルの各行は、あるイベントの 1 人の参加者ないしゲストを表します。 +{@link android.provider.CalendarContract.Reminders#query(android.content.ContentResolver, long, java.lang.String[]) query()} を呼び出すと、指定された {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} を持つイベントの参加者リストが返されます。 + + +この {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} は特定のイベントの {@link android.provider.BaseColumns#_ID} と一致している必要があります。 + + +</p> + +<p>次の表に、書き込み可能なフィールドを示します。 +新しい参加者を挿入する際には、<code>ATTENDEE_NAME</code> を除くすべてを含める必要があります。 + +</p> + + +<table> + <tr> + <th>定数</th> + <th>説明</th> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID}</td> + <td>イベントの ID。</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_NAME}</td> + <td>参加者の名前。</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_EMAIL}</td> + <td>参加者のメールアドレス。</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_RELATIONSHIP}</td> + <td><p>参加者のイベントに対する関係。次のどれかです。</p> + <ul> + <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_ATTENDEE}</li> + <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_NONE}</li> + <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_ORGANIZER}</li> + <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_PERFORMER}</li> + <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_SPEAKER}</li> + </ul> + </td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_TYPE}</td> + <td><p>参加者のタイプ。次のどれかです。 </p> + <ul> + <li>{@link android.provider.CalendarContract.AttendeesColumns#TYPE_REQUIRED}</li> + <li>{@link android.provider.CalendarContract.AttendeesColumns#TYPE_OPTIONAL}</li> + </ul></td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS}</td> + <td><p>参加者の出席ステータス。次のどれかです。</p> + <ul> + <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_ACCEPTED}</li> + <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_DECLINED}</li> + <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_INVITED}</li> + <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_NONE}</li> + <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_TENTATIVE}</li> + </ul></td> + </tr> +</table> + +<h3 id="add-attendees">参加者の追加</h3> + +<p>次の例では、あるイベントに 1 人の参加者を挿入しています。{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} は必須です。 + +</p> + +<pre> +long eventID = 202; +... +ContentResolver cr = getContentResolver(); +ContentValues values = new ContentValues(); +values.put(Attendees.ATTENDEE_NAME, "Trevor"); +values.put(Attendees.ATTENDEE_EMAIL, "trevor@example.com"); +values.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE); +values.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_OPTIONAL); +values.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_INVITED); +values.put(Attendees.EVENT_ID, eventID); +Uri uri = cr.insert(Attendees.CONTENT_URI, values); +</pre> + +<h2 id="reminders">Reminders テーブル</h2> + +<p>{@link android.provider.CalendarContract.Reminders} テーブルの各行は、あるイベントの 1 つのリマインダーを表します。 +{@link android.provider.CalendarContract.Reminders#query(android.content.ContentResolver, long, java.lang.String[]) query()} を呼び出すと、指定された {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} を持つイベントのリマインダー リストが返されます。 + + +</p> + + +<p>次の表に、リマインダーに関する書き込み可能なフィールドを示します。新しいリマインダーを挿入する際には、これらをすべて含める必要があります。 +同期アダプタは、サポートするリマインダーのタイプを {@link android.provider.CalendarContract.Calendars} テーブルで指定しています。 + +詳細については、{@link android.provider.CalendarContract.CalendarColumns#ALLOWED_REMINDERS} をご覧ください。 + +</p> + + +<table> + <tr> + <th>定数</th> + <th>説明</th> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.RemindersColumns#EVENT_ID}</td> + <td>イベントの ID。</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.RemindersColumns#MINUTES}</td> + <td>リマインダーが通知されるまでの分単位の時間。</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.RemindersColumns#METHOD}</td> + <td><p>アラーム手段。サーバーに設定されます。次のどれかです。</p> + <ul> + <li>{@link android.provider.CalendarContract.RemindersColumns#METHOD_ALERT}</li> + <li>{@link android.provider.CalendarContract.RemindersColumns#METHOD_DEFAULT}</li> + <li>{@link android.provider.CalendarContract.RemindersColumns#METHOD_EMAIL}</li> + <li>{@link android.provider.CalendarContract.RemindersColumns#METHOD_SMS}</li> + </ul></td> + </tr> +</table> + +<h3 id="add-reminders">リマインダーの追加</h3> + +<p>この例では、イベントにリマインダーを追加します。このリマインダーは、イベントの 15 分前に通知されます。 +</p> +<pre> +long eventID = 221; +... +ContentResolver cr = getContentResolver(); +ContentValues values = new ContentValues(); +values.put(Reminders.MINUTES, 15); +values.put(Reminders.EVENT_ID, eventID); +values.put(Reminders.METHOD, Reminders.METHOD_ALERT); +Uri uri = cr.insert(Reminders.CONTENT_URI, values);</pre> + +<h2 id="instances">Instances テーブル</h2> + +<p>{@link android.provider.CalendarContract.Instances} テーブルは、あるイベントの発生の開始時刻と終了時刻を保持します。 + +各行は、イベントの発生 1 回を表します。 +Instances テーブルは書き込みできません。イベントの発生をクエリする手段を提供するためだけのものです。 + </p> + +<p>次の表に、インスタンスに関してクエリできるフィールドの一部を示します。タイムゾーンは {@link android.provider.CalendarContract.CalendarCache#KEY_TIMEZONE_TYPE} と {@link android.provider.CalendarContract.CalendarCache#KEY_TIMEZONE_INSTANCES} で定義されます。 + + + +</p> + + +<table> + <tr> + <th>定数</th> + <th>説明</th> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.Instances#BEGIN}</td> + <td>インスタンスの開始時刻(UTC ミリ秒単位)。</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.Instances#END}</td> + <td>インスタンスの終了時刻(UTC ミリ秒単位)。</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.Instances#END_DAY}</td> + + <td>インスタンスの、カレンダーのタイムゾーンにおけるユリウス暦での終了日。 + + +</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.Instances#END_MINUTE}</td> + + <td>カレンダーのタイムゾーンにおける午前零時を基準にしたインスタンスの終了分。 +</td> + + </tr> + <tr> + <td>{@link android.provider.CalendarContract.Instances#EVENT_ID}</td> + <td>このインスタンスのイベントの <code>_ID</code>。</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.Instances#START_DAY}</td> + <td>インスタンスの、カレンダーのタイムゾーンにおけるユリウス暦での開始日。 + </td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.Instances#START_MINUTE}</td> + + <td>カレンダーのタイムゾーンにおける午前零時を基準にしたインスタンスの開始分。 + +</td> + + </tr> + +</table> + +<h3 id="query-instances">Instances テーブルへのクエリ</h3> + +<p>Instances テーブルにクエリするには、クエリの範囲を示す時刻を URI に指定する必要があります。この例で、{@link android.provider.CalendarContract.Instances} は {@link android.provider.CalendarContract.EventsColumns} インターフェースの実装を介して {@link android.provider.CalendarContract.EventsColumns#TITLE} フィールドへのアクセスを取得します。 + + + +言い換えると、{@link android.provider.CalendarContract.EventsColumns#TITLE} はデータベースの参照に対して返されているのであって、{@link android.provider.CalendarContract.Instances} テーブルそのものへのクエリに対して返されているのではありません。 + + + +</p> + +<pre> +private static final String DEBUG_TAG = "MyActivity"; +public static final String[] INSTANCE_PROJECTION = new String[] { + Instances.EVENT_ID, // 0 + Instances.BEGIN, // 1 + Instances.TITLE // 2 + }; + +// The indices for the projection array above. +private static final int PROJECTION_ID_INDEX = 0; +private static final int PROJECTION_BEGIN_INDEX = 1; +private static final int PROJECTION_TITLE_INDEX = 2; +... + +// Specify the date range you want to search for recurring +// event instances +Calendar beginTime = Calendar.getInstance(); +beginTime.set(2011, 9, 23, 8, 0); +long startMillis = beginTime.getTimeInMillis(); +Calendar endTime = Calendar.getInstance(); +endTime.set(2011, 10, 24, 8, 0); +long endMillis = endTime.getTimeInMillis(); + +Cursor cur = null; +ContentResolver cr = getContentResolver(); + +// The ID of the recurring event whose instances you are searching +// for in the Instances table +String selection = Instances.EVENT_ID + " = ?"; +String[] selectionArgs = new String[] {"207"}; + +// Construct the query with the desired date range. +Uri.Builder builder = Instances.CONTENT_URI.buildUpon(); +ContentUris.appendId(builder, startMillis); +ContentUris.appendId(builder, endMillis); + +// Submit the query +cur = cr.query(builder.build(), + INSTANCE_PROJECTION, + selection, + selectionArgs, + null); + +while (cur.moveToNext()) { + String title = null; + long eventID = 0; + long beginVal = 0; + + // Get the field values + eventID = cur.getLong(PROJECTION_ID_INDEX); + beginVal = cur.getLong(PROJECTION_BEGIN_INDEX); + title = cur.getString(PROJECTION_TITLE_INDEX); + + // Do something with the values. + Log.i(DEBUG_TAG, "Event: " + title); + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(beginVal); + DateFormat formatter = new SimpleDateFormat("MM/dd/yyyy"); + Log.i(DEBUG_TAG, "Date: " + formatter.format(calendar.getTime())); + } + }</pre> + +<h2 id="intents">カレンダーのインテント</h2> +<p>アプリケーションがカレンダー データの読み取りや書き込みを実行するのに<a href="#manifest">パーミッション</a>は要りません。その代わり、Android のカレンダー アプリケーションがサポートするインテントを使用し、読み取りと書き込みの操作をそのアプリケーションに引き渡します。次の表に、カレンダー プロバイダによってサポートされているインテントを示します。</p> +<table> + <tr> + <th>アクション</th> + <th>URI</th> + + <th>説明</th> + <th>エクストラ</th> + </tr> + <tr> + <td><br> + {@link android.content.Intent#ACTION_VIEW VIEW} <br></td> + <td><p><code>content://com.android.calendar/time/<ms_since_epoch></code></p> + URI は、{@link android.provider.CalendarContract#CONTENT_URI CalendarContract.CONTENT_URI} を使用しても参照できます。 +このインテントの使用例については、<a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-view">インテントを使用したカレンダー データの参照</a>をご覧ください。 + + + </td> + <td><code><ms_since_epoch></code> に指定された時刻でカレンダーを開きます。</td> + <td>なし</td> + </tr> + <tr> + <td><p>{@link android.content.Intent#ACTION_VIEW VIEW} </p> + + </td> + <td><p><code>content://com.android.calendar/events/<event_id></code></p> + + URI は、{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI} を使用しても参照できます。 +このインテントの使用例については、<a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-view">インテントを使用したカレンダー データの参照</a>をご覧ください。 + + + </td> + <td><code><event_id></code> で指定されたイベントを参照します。</td> + + <td>{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_BEGIN_TIME}<br> + <br> + <br> + {@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME CalendarContract.EXTRA_EVENT_END_TIME}</td> + </tr> + + <tr> + <td>{@link android.content.Intent#ACTION_EDIT EDIT} </td> + <td><p><code>content://com.android.calendar/events/<event_id></code></p> + + URI は、{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI} を使用しても参照できます。 +このインテントの使用例については、<a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-edit">インテントを使用したカレンダー データの編集</a>をご覧ください。 + + + + </td> + <td><code><event_id></code> で指定されたイベントを編集します。</td> + + <td>{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_BEGIN_TIME}<br> + <br> + <br> + {@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME CalendarContract.EXTRA_EVENT_END_TIME}</td> + </tr> + + <tr> + <td>{@link android.content.Intent#ACTION_EDIT EDIT} <br> + <br> + {@link android.content.Intent#ACTION_INSERT INSERT} </td> + <td><p><code>content://com.android.calendar/events</code></p> + + URI は、{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI} を使用しても参照できます。 +このインテントの使用例については、<a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-insert">インテントを使用したカレンダー データの挿入</a>をご覧ください。 + + + </td> + + <td>イベントを作成します。</td> + <td>次の表に示された任意のエクストラ。</td> + </tr> +</table> + +<p>次の表に、カレンダー プロバイダによってサポートされているインテント エクストラを示します。 +</p> +<table> + <tr> + <th>インテント エクストラ</th> + <th>説明</th> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.EventsColumns#TITLE Events.TITLE}</td> + <td>イベントの名前。</td> + </tr> + <tr> + + <td>{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_BEGIN_TIME} +</td> + <td>イベントの開始時刻(エポックからのミリ秒単位)。</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME CalendarContract.EXTRA_EVENT_END_TIME} +</td> + + <td>イベントの終了時刻(エポックからのミリ秒単位)。</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract#EXTRA_EVENT_ALL_DAY CalendarContract.EXTRA_EVENT_ALL_DAY} +</td> + + <td>イベントが終日かどうかを示すブール値。使用できる値は <code>true</code> または <code>false</code> です。 +</td> </tr> + <tr> + <td>{@link android.provider.CalendarContract.EventsColumns#EVENT_LOCATION Events.EVENT_LOCATION} +</td> + + <td>イベントの場所。</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.EventsColumns#DESCRIPTION Events.DESCRIPTION} +</td> + + <td>イベントの説明。</td> + </tr> + <tr> + <td> + {@link android.content.Intent#EXTRA_EMAIL Intent.EXTRA_EMAIL}</td> + <td>招待者のメールアドレス(コンマ区切りリスト形式)。</td> + </tr> + <tr> + <td> + {@link android.provider.CalendarContract.EventsColumns#RRULE Events.RRULE}</td> + <td>イベントの反復ルール。</td> + </tr> + <tr> + <td> + {@link android.provider.CalendarContract.EventsColumns#ACCESS_LEVEL Events.ACCESS_LEVEL} +</td> + + <td>イベントが公開か非公開か。</td> + </tr> + <tr> + <td>{@link android.provider.CalendarContract.EventsColumns#AVAILABILITY Events.AVAILABILITY} +</td> + + <td>このイベントを埋まっている時間に数えるか、それともスケジュールのやり直しが利く空き時間とみなすか。</td> + +</table> +<p>次のセクションでは、これらのインテント使用方法を説明します。</p> + + +<h3 id="intent-insert">インテントを使用したイベントの挿入</h3> + +<p>{@link android.content.Intent#ACTION_INSERT INSERT} インテントを使用すると、アプリケーションはイベント挿入タスクをカレンダーそのものに引き渡すことができます。このアプローチでは、アプリケーションは {@link android.Manifest.permission#WRITE_CALENDAR} パーミッションを<a href="#manifest">マニフェスト ファイル</a>に含める必要さえなくなります。 + + +</p> + + +<p>このアプローチのアプリケーションをユーザーが実行すると、アプリケーションによってユーザーがカレンダーに誘導されイベントを追加できるようになります。 +{@link android.content.Intent#ACTION_INSERT INSERT} インテントは、追加フィールドを使用して、カレンダーに格納されている詳細情報をフォームに自動入力します。 + +それに対して、ユーザーはイベントのキャンセル、必要に応じたイベントの編集、イベントのカレンダーへの保存ができます。 + +</p> + + + +<p>次に示すのは、2012 年 1 月 19 日の午前 7:30 から 午前 8:30 までのイベントをスケジュールするコード スニペットです。 +このコード スニペットの以下の点に注目してください。</p> + +<ul> + <li>URI として {@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI} を指定しています。 +</li> + + <li>{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_BEGIN_TIME} と {@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME CalendarContract.EXTRA_EVENT_END_TIME} の各エクストラ フィールドを使用して、イベントの時間をフォームに自動入力しています。 + + + + +これらの値は、エポックからの UTC ミリ秒単位であることが必要です。 +</li> + + <li>{@link android.content.Intent#EXTRA_EMAIL Intent.EXTRA_EMAIL} エクストラ フィールドを使用して、参加者をメールアドレスで示したコンマ区切りリストを指定しています。 +</li> + +</ul> +<pre> +Calendar beginTime = Calendar.getInstance(); +beginTime.set(2012, 0, 19, 7, 30); +Calendar endTime = Calendar.getInstance(); +endTime.set(2012, 0, 19, 8, 30); +Intent intent = new Intent(Intent.ACTION_INSERT) + .setData(Events.CONTENT_URI) + .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis()) + .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis()) + .putExtra(Events.TITLE, "Yoga") + .putExtra(Events.DESCRIPTION, "Group class") + .putExtra(Events.EVENT_LOCATION, "The gym") + .putExtra(Events.AVAILABILITY, Events.AVAILABILITY_BUSY) + .putExtra(Intent.EXTRA_EMAIL, "rowan@example.com,trevor@example.com"); +startActivity(intent); +</pre> + +<h3 id="intent-edit">インテントを使用したイベントの編集</h3> + +<p>イベントは、<a href="#update-event">イベントのアップデート</a>で説明したように、直接アップデートできます。ただし、{@link android.content.Intent#ACTION_EDIT EDIT} インテントを使用すれば、パーミッションのないアプリケーションが、カレンダー アプリケーションにイベント編集を引き渡すことができます。カレンダーでのイベント編集を終えたユーザーは、元のアプリケーションに戻ります。 + + + +</p> <p>次の例のインテントは、指定されたイベントの新しいタイトルを設定して、ユーザーがそのイベントをカレンダーで編集できるようにしています。 +</p> + + +<pre>long eventID = 208; +Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID); +Intent intent = new Intent(Intent.ACTION_EDIT) + .setData(uri) + .putExtra(Events.TITLE, "My New Title"); +startActivity(intent);</pre> + +<h3 id="intent-view">インテントを使用したカレンダー データの参照</h3> +<p>カレンダー プロバイダには、{@link android.content.Intent#ACTION_VIEW VIEW} インテントを使用する次の 2 つの方法が用意されています。</p> +<ul> + <li>特定の日付のカレンダーを開く方法。</li> + <li>イベントを参照する方法。</li> + +</ul> +<p>次の例は、特定の日付のカレンダーを開く方法を示しています。</p> +<pre>// A date-time specified in milliseconds since the epoch. +long startMillis; +... +Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon(); +builder.appendPath("time"); +ContentUris.appendId(builder, startMillis); +Intent intent = new Intent(Intent.ACTION_VIEW) + .setData(builder.build()); +startActivity(intent);</pre> + +<p>次の例は、参照するためにイベントを開く方法を示しています。</p> +<pre>long eventID = 208; +... +Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID); +Intent intent = new Intent(Intent.ACTION_VIEW) + .setData(uri); +startActivity(intent); +</pre> + + +<h2 id="sync-adapter">同期アダプタ</h2> + + +<p>アプリケーションと同期アダプタとの間で、カレンダー プロバイダにアクセスする方法の違いは、次のいくつかだけです。 +</p> + +<ul> + <li>同期アダプタは、{@link android.provider.CalendarContract#CALLER_IS_SYNCADAPTER} を <code>true</code> に設定して、それが同期アダプタであることを示す必要があります。</li> + + + <li>同期アダプタは、{@link android.provider.CalendarContract.SyncColumns#ACCOUNT_NAME} と {@link android.provider.CalendarContract.SyncColumns#ACCOUNT_TYPE} をクエリ パラメータとして URI に指定する必要があります。 + + </li> + + <li>同期アダプタは、アプリケーションやウィジェットより多くの列に書き込みアクセスできます。 + たとえば、アプリケーションで変更できるのは、名前、表示名、可視性の設定、カレンダーが同期対象かどうかなど、カレンダーの特性の一部のみです。 + +それに対し、同期アダプタはこれらの列の他に、カレンダーの色、タイムゾーン、アクセスレベル、場所など、数多くにアクセスできます。ただし、<code>ACCOUNT_NAME</code> と <code>ACCOUNT_TYPE</code> で指定されるものだけに限定されます。 + + +</li> </ul> + +<p>次に示すヘルパー メソッドを使用すると、同期アダプタで使用するための URI が返されます。</p> +<pre> static Uri asSyncAdapter(Uri uri, String account, String accountType) { + return uri.buildUpon() + .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER,"true") + .appendQueryParameter(Calendars.ACCOUNT_NAME, account) + .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build(); + } +</pre> +<p>同期アダプタの実装例(カレンダーに特化されたものではありません)については、<a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">SampleSyncAdapter</a> をご覧ください。 + diff --git a/docs/html-intl/intl/ja/guide/topics/providers/contacts-provider.jd b/docs/html-intl/intl/ja/guide/topics/providers/contacts-provider.jd new file mode 100644 index 000000000000..60154b25a390 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/providers/contacts-provider.jd @@ -0,0 +1,2356 @@ +page.title=連絡先プロバイダ +@jd:body +<div id="qv-wrapper"> +<div id="qv"> +<h2>クイックビュー</h2> +<ul> + <li>人の情報に関する Android のリポジトリ。</li> + <li> + ウェブとの同期。 + </li> + <li> + ソーシャル ストリーム データの統合。 + </li> +</ul> +<h2>本書の内容</h2> +<ol> + <li> + <a href="#InformationTypes">連絡先プロバイダの構成</a> + </li> + <li> + <a href="#RawContactBasics">未加工連絡先</a> + </li> + <li> + <a href="#DataBasics">データ</a> + </li> + <li> + <a href="#ContactBasics">連絡先</a> + </li> + <li> + <a href="#Sources">同期アダプタからのデータ</a> + </li> + <li> + <a href="#Permissions">必要なパーミッション</a> + </li> + <li> + <a href="#UserProfile">ユーザー プロファイル</a> + </li> + <li> + <a href="#ContactsProviderMetadata">連絡先プロバイダのメタデータ</a> + </li> + <li> + <a href="#Access">連絡先プロバイダへのアクセス</a> + <li> + </li> + <li> + <a href="#SyncAdapters">連絡先プロバイダの同期アダプタ</a> + </li> + <li> + <a href="#SocialStream">ソーシャル ストリーム データ</a> + </li> + <li> + <a href="#AdditionalFeatures">連絡先プロバイダの追加機能</a> + </li> +</ol> +<h2>キークラス</h2> +<ol> + <li>{@link android.provider.ContactsContract.Contacts}</li> + <li>{@link android.provider.ContactsContract.RawContacts}</li> + <li>{@link android.provider.ContactsContract.Data}</li> + <li>{@link android.provider.ContactsContract.StreamItems}</li> +</ol> +<h2>関連サンプル</h2> +<ol> + <li> + <a href="{@docRoot}resources/samples/ContactManager/index.html"> Contact Manager </a> + + + </li> + <li> + <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html"> サンプル同期アダプタ</a> + + </li> +</ol> +<h2>関連ドキュメント</h2> +<ol> + <li> + <a href="{@docRoot}guide/topics/providers/content-provider-basics.html"> コンテンツ プロバイダの基本 </a> + + + </li> +</ol> +</div> +</div> +<p> + 連絡先プロバイダは、人のデータに関する端末の中央リポジトリを管理する、柔軟で効果的な Android コンポーネントです。 +連絡先プロバイダは、端末の連絡先アプリケーションに表示されるデータのソースであり、さらに独自アプリケーションで連絡先プロバイダのデータにアクセスし、端末とオンライン サービスとの間でデータを転送することもできます。 + +このプロバイダは幅広いデータソースに対応しており、各人に関してできるだけ多くのデータを管理しようとするため、複雑な構造をしています。 + +そのため、連絡先プロバイダの API には、データの取得と変更をどちらもやりやすくするクラスやインターフェースが多数用意されています。 + + +</p> +<p> + このガイドでは、以下について説明します。 +</p> + <ul> + <li> + プロバイダの基本構造。 + </li> + <li> + プロバイダからのデータの取得方法。 + </li> + <li> + プロバイダでのデータの変更方法。 + </li> + <li> + サーバーから連絡先プロバイダとデータを同期する同期アダプタの作成方法。 + + </li> + </ul> +<p> + このガイドは、Android のコンテンツ プロバイダの基礎知識がある読者を対象としています。Android のコンテンツ プロバイダについて詳しくは、「<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">コンテンツ プロバイダの基本</a>」をご覧ください。 + + +<a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">サンプル同期アダプタ</a> サンプルアプリは、同期アダプタを使用して連絡先プロバイダと Google ウェブ サービスでホストされているサンプル アプリケーションとの間でデータを転送する例です。 + + + +</p> +<h2 id="InformationTypes">連絡先プロバイダの構成</h2> +<p> + 連絡先プロバイダは、Android のコンテンツ プロバイダ コンポーネントです。人に関する 3 種類のデータを保持しており、それぞれがコンテンツ プロバイダによって提供される 1 つのテーブルに対応しています。この構成を図 1 に示します。 + + +</p> +<img src="{@docRoot}images/providers/contacts_structure.png" alt="" height="364" id="figure1" /> +<p class="img-caption"> + <strong>図 1.</strong> 連絡先プロバイダのテーブル構造。 +</p> +<p> + この 3 つのテーブルは、一般にそれぞれのコントラクト クラス名で呼ばれます。各クラスは、テーブルによって使用されるコンテンツ URI、列名、列の値のための定数を定義しています。 + +</p> +<dl> + <dt> + {@link android.provider.ContactsContract.Contacts} テーブル + </dt> + <dd> + 各行は、未加工連絡先の行の集約に基づいて異なる人を表します。 + </dd> + <dt> + {@link android.provider.ContactsContract.RawContacts} テーブル + </dt> + <dd> + 各行には、ユーザーのアカウントとタイプに固有の、人に関するデータの概要が格納されています。 + </dd> + <dt> + {@link android.provider.ContactsContract.Data} テーブル + </dt> + <dd> + 各行には、メールアドレスや電話番号など、未加工連絡先の詳細情報が格納されています。 + </dd> +</dl> +<p> + {@link android.provider.ContactsContract} に含まれるコントラクト クラスによって表現される他のテーブルは補助テーブルであり、連絡先プロバイダがその操作を管理したり、端末の連絡先アプリや電話アプリの特定機能をサポートしたりするために使用します。 + + +</p> +<h2 id="RawContactBasics">未加工連絡先</h2> +<p> + 未加工連絡先は、アカウント タイプとアカウント名の 1 つのペアを使用して得られる人に関するデータです。 +連絡先プロバイダでは、1 人に関するデータのソースとして複数のオンライン サーバーを使用できるため、同じ個人に対して複数の未加工連絡先が許されます。 + + 未加工連絡先が複数ある場合、ユーザーは同じアカウント タイプの複数のアカウントから取得したその人のデータを組み合わせることができます。 + +</p> +<p> + 未加工連絡先データの大半は、{@link android.provider.ContactsContract.RawContacts} テーブルには格納されません。 +その代わり、{@link android.provider.ContactsContract.Data} テーブルの 1 つまたは複数の行に格納されています。 +各データ行には列 {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID Data.RAW_CONTACT_ID} があり、親 {@link android.provider.ContactsContract.RawContacts} 行の {@link android.provider.BaseColumns#_ID RawContacts._ID} 値が格納されています。 + + + +</p> +<h3 id="RawContactsColumns">重要な未加工連絡先列</h3> +<p> + 表 1 に、{@link android.provider.ContactsContract.RawContacts} の重要な列を示します。 +表の後の注もお読みください。 +</p> +<p class="table-caption" id="table1"> + <strong>表 1.</strong> 重要な未加工連絡先列。 +</p> +<table> + <tr> + <th scope="col">列名</th> + <th scope="col">用途</th> + <th scope="col">注</th> + </tr> + <tr> + <td> + {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_NAME} + </td> + <td> + この未加工連絡先のソースであるアカウント タイプにおけるアカウント名。 + たとえば、Google アカウントのアカウント名は、デバイス オーナーの Gmail アドレスのどれかです。 +詳しくは、次の {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_TYPE} の項目をご覧ください。 + + + </td> + <td> + この名前の形式は、アカウント タイプによって異なります。必ずしもメールアドレスとは限りません。 + + </td> + </tr> + <tr> + <td> + {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_TYPE} + </td> + <td> + この未加工連絡先のソースであるアカウント タイプ。たとえば、Google アカウントのアカウント タイプは <code>com.google</code> です。 +アカウント タイプは必ず、所有または管理しているドメインのドメイン ID で修飾してください。 +そうすることで、アカウント タイプが確実に一意になります。 + + </td> + <td> + 連絡先データを提供するアカウント タイプには、通常、連絡先プロバイダと同期する関連同期アダプタが用意されています。 + + </tr> + <tr> + <td> + {@link android.provider.ContactsContract.RawContactsColumns#DELETED} + </td> + <td> + 未加工連絡先の「削除済み」フラグ。 + </td> + <td> + 連絡先プロバイダは、同期アダプタが該当行をサーバーから削除し、最終的にリポジトリから削除するまで、このフラグを基に行を内部的に管理します。 + + + </td> + </tr> +</table> +<h4>注</h4> +<p> + 次に、{@link android.provider.ContactsContract.RawContacts} テーブルに関する重要な注を示します。 + +</p> +<ul> + <li> + 未加工連絡先の名前は、{@link android.provider.ContactsContract.RawContacts} の行には格納されません。 +その代わり、{@link android.provider.ContactsContract.Data} テーブルの {@link android.provider.ContactsContract.CommonDataKinds.StructuredName} 行に格納されます。 + +未加工連絡先は、このタイプの行を {@link android.provider.ContactsContract.Data} テーブルに 1 行だけ持ちます。 + + </li> + <li> + <strong>警告:</strong> 未加工連絡先の行で独自のアカウント データを使用する場合は、まずそれを {@link android.accounts.AccountManager} に登録する必要があります。 +登録するには、ユーザーに対し、アカウントのリストにアカウント タイプとアカウント名を追加するよう求めます。 +そうしないと、連絡先プロバイダによって未加工連絡先の行が自動的に削除されてしまいます。 + + <p> + たとえば、ドメインが {@code com.example.dataservice} であるウェブベースのサービス用に連絡先データをアプリで管理する場合、そのサービス用のユーザー アカウントが {@code becky.sharp@dataservice.example.com} であれば、そのユーザーが先にそのアカウントの「タイプ」({@code com.example.dataservice})と「名前」({@code becky.smart@dataservice.example.com})を追加しておくことで、アプリが未加工連絡先の行を追加できるようになります。 + + + + + この要件については、文書で説明するか、ユーザーにタイプと名前を追加するよう求めるか、あるいはその両方を実施してください。 +アカウントのタイプと名前については、次のセクションで詳しく説明します。 + + </li> +</ul> +<h3 id="RawContactsExample">未加工連絡先データのソース</h3> +<p> + 未加工連絡先の働きを理解するために、「Emily Dickinson」というユーザーについて考えてみましょう。彼女は自分の端末に次の 3 つのアカウントを定義しています。 + +</p> +<ul> + <li><code>emily.dickinson@gmail.com</code></li> + <li><code>emilyd@gmail.com</code></li> + <li>Twitter アカウント「belle_of_amherst」</li> +</ul> +<p> + このユーザーは、[<em>アカウント</em>] の設定でこの 3 つのアカウントすべてについて [<em>連絡先を同期</em>] を有効にしています。 + +</p> +<p> + Emily Dickinson がブラウザのウィンドウを開き、Gmail に <code>emily.dickinson@gmail.com</code> としてログインし、[連絡先] を開いて「Thomas Higginson」を追加したとしましょう。 + +後日、彼女が Gmail に <code>emilyd@gmail.com</code> としてログインし、メールを「Thomas Higginson」宛てに送信すると、彼は自動的に連絡先として追加されます。 + +彼女はまた、Twitter で「colonel_tom」(Thomas Higginson の Twitter ID)をフォローしています。 + +</p> +<p> + 連絡先プロバイダは、この操作の結果として次の 3 行の未加工連絡先を作成します。 +</p> +<ol> + <li> + 「Thomas Higginson」の、<code>emily.dickinson@gmail.com</code> に関連付けられた未加工連絡先。 + ユーザー アカウントのタイプは Google です。 + </li> + <li> + 「Thomas Higginson」の、<code>emilyd@gmail.com</code> に関連付けられた新たな未加工連絡先。 + ユーザー アカウントのタイプはやはり Google です。名前が前の行とまったく同じなのに新たな未加工連絡先が作成されたのは、この個人が異なるユーザー アカウントに追加されたからです。 + + + </li> + <li> + 「Thomas Higginson」の、「belle_of_amherst」に関連付けられた未加工連絡先。ユーザー アカウントのタイプは Twitter です。 + + </li> +</ol> +<h2 id="DataBasics">データ</h2> +<p> + 前にも説明したように、未加工連絡先のデータは未加工連絡先の <code>_ID</code> 値にリンクされている {@link android.provider.ContactsContract.Data} 行に格納されます。 + +これにより、1 つの未加工連絡先が同じタイプのデータ(メールアドレスや電話番号など)のインスタンスを複数持つことができます。 +たとえば、{@code emilyd@gmail.com} に対する「Thomas Higginson」(Google アカウント <code>emilyd@gmail.com</code> に関連付けられた、Thomas Higginson の未加工連絡先の行)には、<code>thigg@gmail.com</code> という個人用アドレスと <code>thomas.higginson@gmail.com</code> という仕事用アドレスがあり、連絡先プロバイダはこの 2 つのメールアドレスの行を格納し、両方とも同じ未加工連絡先にリンクします。 + + + + + +</p> +<p> + 異なるタイプのデータが同じテーブルに格納されることに注目してください。表示名、電話番号、メール、住所、写真、ウェブサイトに関する詳細行はすべて、{@link android.provider.ContactsContract.Data} テーブルにあります。 + +これを管理しやすくするため、{@link android.provider.ContactsContract.Data} テーブルの一部の行には説明的な名前が、それ以外には一般的な名前がそれぞれ付いています。 + +説明的な名前が付いた列の内容は、行データのタイプによらず意味が同じなのに対し、一般的な名前が付いた列の内容は、データのタイプによって意味が異なります。 + + +</p> +<h3 id="DescriptiveColumns">説明的な名前の列</h3> +<p> + 説明的な名前が付いた列の例をいくつか示します。 +</p> +<dl> + <dt> + {@link android.provider.ContactsContract.Data#RAW_CONTACT_ID} + </dt> + <dd> + このデータの、未加工連絡先の <code>_ID</code> 列の値。 + </dd> + <dt> + {@link android.provider.ContactsContract.Data#MIMETYPE} + </dt> + <dd> + カスタム MIME タイプで表現した、この行に格納されているデータのタイプ。連絡先プロバイダは、{@link android.provider.ContactsContract.CommonDataKinds} のサブクラスに定義されている MIME タイプを使用します。 + +これらの MIME タイプはオープンソースで、連絡先プロバイダと連携する任意のアプリケーションまたは同期アダプタで使用できます。 + + </dd> + <dt> + {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY} + </dt> + <dd> + このタイプのデータ行が 1 つの未加工連絡先に対して複数発生する場合、{@link android.provider.ContactsContract.DataColumns#IS_PRIMARY} 列はそのタイプに対するプライマリ データを含むデータ行を示します。 + +たとえば、ユーザーがある連絡先の電話番号を長押しし、[<strong>デフォルトに設定</strong>] を選択すると、その番号を含む {@link android.provider.ContactsContract.Data} 行の {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY} 列にゼロでない値が設定されます。 + + + + + </dd> +</dl> +<h3 id="GenericColumns">汎用名の列</h3> +<p> + 自由に使用できる <code>DATA1</code> ~ <code>DATA15</code> という 15 個の汎用列の他に、同期アダプタしか使用してはいけない <code>SYNC1</code> ~ <code>SYNC4</code> という 4 個の列があります。 + + +汎用名列の定数は、行に指定されているデータのタイプによらず、常に機能します。 + +</p> +<p> + <code>DATA1</code> 列はインデックス付きです。連絡先プロバイダは常に、この列を、最も頻繁にクエリの対象となるとプロバイダが予想するデータ用の列として使用します。 +たとえば、メールの行では、この列には実際のメールアドレスが格納されます。 + +</p> +<p> + <code>DATA15</code> は慣例として、写真サムネイルのようなバイナリ ラージ オブジェクト(BLOB)データ用に予約されています。 + +</p> +<h3 id="TypeSpecificNames">タイプ固有の列名</h3> +<p> + 特定タイプの行に含まれる列に対する作業をやりやすくするため、連絡先プロバイダではタイプ固有の列名定数もあり、たとえば {@link android.provider.ContactsContract.CommonDataKinds} のサブクラスに定義されています。 + +こうした定数は、同じ列名に異なる定数名を充てて、特定タイプの行に含まれるデータにアクセスしやすくしているだけのものです。 + + +</p> +<p> + たとえば、{@link android.provider.ContactsContract.CommonDataKinds.Email} クラスには、MIME タイプが {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE Email.CONTENT_ITEM_TYPE} である{@link android.provider.ContactsContract.Data} 行向けにタイプ固有の列名定数が定義されています。 + + + +このクラスには、メールアドレス 列用に {@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS} という定数が含まれています。 + +{@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS} の実際の値は「data1」で、これはこの列の汎用名と同じです。 + + +</p> +<p class="caution"> + <strong>警告:</strong> 連絡先プロバイダにあらかじめ定義されている MIME タイプのどれかである行を使用している {@link android.provider.ContactsContract.Data} テーブルには、独自のカスタムデータを追加しないでください。 + +追加すると、データが失われたり、連絡先プロバイダが誤動作したりすることがあります。 +たとえば、メールアドレスではなくユーザー名が格納されている MIME タイプ {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE Email.CONTENT_ITEM_TYPE} の行は、列 <code>DATA1</code> には追加しないでください。 + + +一方、行に独自のカスタム MIME タイプを使用している場合は、独自のタイプ固有名を定義して列を自由に使用してかまいません。 + +</p> +<p> + 図 2 に、説明的な名前の列とデータ列で {@link android.provider.ContactsContract.Data} 行がどう見えるか、そしてタイプ固有の列名が汎用列名をどう「オーバーレイ」するかを示します。 + + +</p> +<img src="{@docRoot}images/providers/data_columns.png" alt="How type-specific column names map to generic column names" height="311" id="figure2" /> +<p class="img-caption"> + <strong>図 2.</strong> タイプ固有の列名と汎用列名 +</p> +<h3 id="ColumnMaps">タイプ固有列名が使用されるクラス</h3> +<p> + 表 2 に、最もよく用いられるタイプ固有列名クラスを示します。 +</p> +<p class="table-caption" id="table2"> + <strong>表 2.</strong> タイプ固有列名が使用されるクラス</p> +<table> + <tr> + <th scope="col">対応クラス</th> + <th scope="col">データのタイプ</th> + <th scope="col">注</th> + </tr> + <tr> + <td>{@link android.provider.ContactsContract.CommonDataKinds.StructuredName}</td> + <td>このデータ行に関連付けられている未加工連絡先の名前データ。</td> + <td>1 つの未加工連絡先は、この行を 1 行だけ持ちます。</td> + </tr> + <tr> + <td>{@link android.provider.ContactsContract.CommonDataKinds.Photo}</td> + <td>このデータ行に関連付けられている未加工連絡先のメインの写真。</td> + <td>1 つの未加工連絡先は、この行を 1 行だけ持ちます。</td> + </tr> + <tr> + <td>{@link android.provider.ContactsContract.CommonDataKinds.Email}</td> + <td>このデータ行に関連付けられている未加工連絡先のメールレアドレス。</td> + <td>1 つの未加工連絡先は複数のメールアドレスを持つことができます。</td> + </tr> + <tr> + <td>{@link android.provider.ContactsContract.CommonDataKinds.StructuredPostal}</td> + <td>このデータ行に関連付けられている未加工連絡先の住所。</td> + <td>1 つの未加工連絡先は複数の住所を持つことができます。</td> + </tr> + <tr> + <td>{@link android.provider.ContactsContract.CommonDataKinds.GroupMembership}</td> + <td>その未加工連絡先を連絡先プロバイダのグループのどれかにリンクする識別子。</td> + <td> + グループは、アカウント タイプとアカウント名のオプション機能です。詳しくは、<a href="#Groups">連絡先グループ</a>をご覧ください。 + + </td> + </tr> +</table> +<h3 id="ContactBasics">連絡先</h3> +<p> + 連絡先プロバイダは、すべてのアカウント タイプとアカウント名にわたって未加工連絡先の行を結び付けて 1 つの<strong>連絡先</strong>を形成します。 +これにより、1 人の人についてユーザーが集めた全データを表示したり変更したりしやすくなります。 +連絡先プロバイダは、新しい連絡先の行の作成と、既存の連絡先の行を使用した未加工連絡先の集約とを管理します。 +アプリケーションと同期アダプタは連絡先の追加はできず、連絡先の行の一部の列は読み取り専用です。 + +</p> +<p class="note"> + <strong>注:</strong> 連絡先を連絡先プロバイダに {@link android.content.ContentResolver#insert(Uri,ContentValues) insert()} を使用して追加しようとすると、{@link java.lang.UnsupportedOperationException} 例外が発生します。 + +「読み取り専用」になっている列をアップデートしようとしても、そのアップデートは無視されます。 + +</p> +<p> + 連絡先プロバイダは、既存の連絡先と一致しない新しい未加工連絡先が追加されると、それに対して新しい連絡先を作成します。 +また、既存の未加工連絡先のデータが変更され、それまで関連付けられていた連絡先と一致しなくなった場合にも、同じ処理がなされます。 + +アプリケーションまたは同期アダプタが、既存の連絡先と一致する新しい未加工連絡先を作成すると、その新しい未加工連絡先は既存の連絡先に集約されます。<em></em> + + +</p> +<p> + 連絡先プロバイダは、連絡先の行を未加工連絡先とリンクするのに、{@link android.provider.ContactsContract.Contacts Contacts} テーブルの <code>_ID</code> 列を使用します。 + +未加工連絡先テーブル {@link android.provider.ContactsContract.RawContacts} の <code>CONTACT_ID</code> 列には、未加工連絡先の各行に関連付けられている連絡先の行の <code>_ID</code> 値が格納されます。 + + +</p> +<p> + {@link android.provider.ContactsContract.Contacts} テーブルには列 {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} もあり、こちらは連絡先の行への「永久」リンクです。 + +連絡先プロバイダは連絡先を自動的に管理するため、集約や同期が行われると、それに応じて連絡先の行の {@link android.provider.BaseColumns#_ID} 値が変更される場合があります。 + +この処理が行われても、コンテンツ URI {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI} と連絡先の {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} の組み合わせは、引き続きその連絡先の行を指すため、{@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} を使用して「お気に入り」の連絡先へのリンクを管理するなどができます。 + + + + +この列には、{@link android.provider.BaseColumns#_ID} 列の形式と関係のない独自の形式があります。 + +</p> +<p> + 図 3 に、3 つのテーブルの相互関係を示します。 +</p> +<img src="{@docRoot}images/providers/contacts_tables.png" alt="Contacts provider main tables" height="514" id="figure4" /> +<p class="img-caption"> + <strong>図 3.</strong> Contacts、RawContacts、Data の各テーブル間の関係。 +</p> +<h2 id="Sources">同期アダプタからのデータ</h2> +<p> + ユーザーは端末に連絡先データを直接入力しますが、データはウェブサービスから<strong>同期アダプタ</strong>を経由して連絡先プロバイダにも流れます。同期アダプタは、端末とサービスの間のデータ転送を自動化します。 + +同期アダフタはシステムの管理下でバックグラウンドで実行され、{@link android.content.ContentResolver} のメソッドを呼び出してデータを管理します。 + + +</p> +<p> + Android では、同期アダプタと連携するウェブサービスをアカウント タイプで識別します。 + 各同期アダプタが扱うアカウント タイプは 1 つですが、そのタイプのアカウント名を複数サポートできます。 +アカウント名とアカウント タイプについては、<a href="#RawContactsExample">未加工連絡先データのソース</a>で簡単に説明しています。 +次に、アカウント タイプとアカウント名が同期アダプタやサービスとどのような関係にあるかを詳しく説明します。 + +</p> +<dl> + <dt> + アカウント タイプ + </dt> + <dd> + ユーザーがデータを格納しているサービスを示します。ほとんどの場合、ユーザーにはサービスに対する認証が求められます。 +たとえば、Google Contacts はアカウント タイプの 1 つで、コード <code>google.com</code> で識別されます。 +この値は、{@link android.accounts.AccountManager} によって使用されるアカウント タイプに対応します。 + + </dd> + <dt> + アカウント名 + </dt> + <dd> + あるアカウント タイプで使用する特定のアカウントまたはログインを示します。Google Contacts アカウントは Google アカウントと同じで、アカウント名としてメールアドレスを使用します。 + + 他のサービスでは、1 語のユーザー名や数字の ID が使われていることもあります。 + </dd> +</dl> +<p> + アカウント タイプは、一意である必要はありません。1 人のユーザーが複数の Google Contacts アカウントを設定し、それぞれのデータを連絡先プロバイダにダウンロードする、ということが可能です。このような使い方は、そのユーザーが個人用のアカウント名で私用の連絡先を、仕事用のアカウント名で仕事用の連絡先を管理している場合にありえます。 + +アカウント名は、普通は一意です。 +この 2 つを組み合わせて、連絡先プロバイダと外部サービスとの間のある決まったデータフローを識別します。 + +</p> +<p> + 独自サービスのデータを連絡先プロバイダに転送する場合は、独自の同期アダプタを作成する必要があります。 +詳しくは、<a href="#SyncAdapters">連絡先プロバイダの同期アダプタ</a>をご覧ください。 + +</p> +<p> + 図 4 に、人に関するデータの流れにおける連絡先プロバイダの位置付けを示します。 +右から 2 列目の各ボックス内のアダプタには、そのアダプタのアカウント タイプが示されています。 +</p> +<img src="{@docRoot}images/providers/ContactsDataFlow.png" alt="Flow of data about people" height="252" id="figure5" /> +<p class="img-caption"> + <strong>図 4.</strong> 連絡先プロバイダに絡んだデータフロー。 +</p> +<h2 id="Permissions">必要なパーミッション</h2> +<p> + 連絡先プロバイダにアクセスするアプリケーションは、次のパーミッションを要求する必要があります。 + +</p> +<dl> + <dt>1 つ以上のテーブルに対する読み取りアクセス</dt> + <dd> + {@link android.Manifest.permission#READ_CONTACTS}。<code>AndroidManifest.xml</code> に <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"> + <uses-permission></a></code> 要素を使用して <code><uses-permission android:name="android.permission.READ_CONTACTS"></code> のように指定します。 + + + + </dd> + <dt>1 つ以上のテーブルに対する書き込みアクセス</dt> + <dd> + {@link android.Manifest.permission#WRITE_CONTACTS}。<code>AndroidManifest.xml</code> に <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"> + <uses-permission></a></code> 要素を使用して <code><uses-permission android:name="android.permission.WRITE_CONTACTS"></code> のように指定します。 + + + + </dd> +</dl> +<p> + これらのパーミッションは、ユーザー プロファイル データにまでは拡張されません。ユーザー プロファイルとそれに必要なパーミッションについては、次のセクションである<a href="#UserProfile">ユーザー プロファイル</a>で説明しています。 + + +</p> +<p> + ユーザーの連絡先データは個人的で秘密性の高い情報であることを再度ご確認ください。ユーザーはプライバシーに敏感であり、アプリケーションが自分や自分の連絡先に関するデータを集めることを望みません。 + + 連絡先データにアクセスするためのパーミッションが必要な理由が明らかでないと、ユーザーがアプリケーションを低く評価したりインストールを拒否したりすることがあります。 + +</p> +<h2 id="UserProfile">ユーザー プロファイル</h2> +<p> + {@link android.provider.ContactsContract.Contacts} テーブルには、その端末のユーザーのプロファイル データを格納している行が 1 行あります。 +このデータが記述しているのは端末の <code>user</code> であって、そのユーザーの連絡先ではありません。 +プロファイルの連絡先の行は、プロファイルを使用する各システムの未加工連絡先の行にリンクされています。 + + プロファイルの未加工連絡先の各行は、複数のデータ行を持つことができます。ユーザー プロファイルにアクセスするための定数は、{@link android.provider.ContactsContract.Profile} クラスに用意されています。 + +</p> +<p> + ユーザー プロファイルにアクセスするには、特別なパーミッションが必要です。読み取りと書き込みに必要な {@link android.Manifest.permission#READ_CONTACTS} パーミッションと {@link android.Manifest.permission#WRITE_CONTACTS} パーミッションの他に、ユーザー プロファイルに対する読み取りと書き込みのために {@link android.Manifest.permission#READ_PROFILE} パーミッションと {@link android.Manifest.permission#WRITE_PROFILE} パーミッションがそれぞれ必要です。 + + + + + +</p> +<p> + ユーザーのプロファイルは秘密性の高い情報であることを再度ご確認ください。パーミッション {@link android.Manifest.permission#READ_PROFILE} を使用すると、端末ユーザーの個人識別データにアクセスできます。 + +アプリケーションの説明には、ユーザー プロファイルへのアクセス パーミッションが必要な理由を必ず記載してください。 + +</p> +<p> + ユーザーのプロファイルが格納された連絡先の行を取得するには、{@link android.content.ContentResolver#query(Uri,String[], String, String[], String) ContentResolver.query()} を呼び出します。 + +コンテンツ URI を {@link android.provider.ContactsContract.Profile#CONTENT_URI} に設定し、選択条件は何も指定しません。 + +このコンテンツ URI は、そのプロファイルの未加工連絡先やデータを取得するためのベース URI としても使用できます。 +たとえば、次のスニペットは指定されたプロファイルのデータを取得します。 +</p> +<pre> +// Sets the columns to retrieve for the user profile +mProjection = new String[] + { + Profile._ID, + Profile.DISPLAY_NAME_PRIMARY, + Profile.LOOKUP_KEY, + Profile.PHOTO_THUMBNAIL_URI + }; + +// Retrieves the profile from the Contacts Provider +mProfileCursor = + getContentResolver().query( + Profile.CONTENT_URI, + mProjection , + null, + null, + null); +</pre> +<p class="note"> + <strong>注:</strong> 連絡先の行を複数取得する場合、そのなかの 1 つがユーザー プロファイルかどうかを確認するには、行の {@link android.provider.ContactsContract.ContactsColumns#IS_USER_PROFILE} 列をテストします。 + +その連絡先がユーザー プロファイルであれば、この列は「1」に設定されています。 + +</p> +<h2 id="ContactsProviderMetadata">連絡先プロバイダのメタデータ</h2> +<p> + 連絡先プロバイダは、連絡先データの状態を継続的に追跡するためのデータをリポジトリで管理します。 +リポジトリに関するこのメタデータは、RawContacts、Data、Contacts の各テーブルの行、{@link android.provider.ContactsContract.Settings} テーブル、{@link android.provider.ContactsContract.SyncState} テーブルなど、さまざまな場所に格納されています。 + + +次の表に、各メタデータの効果を示します。 + +</p> +<p class="table-caption" id="table3"> + <strong>表 3.</strong> 連絡先プロバイダに用意されているメタデータ</p> +<table> + <tr> + <th scope="col">テーブル</th> + <th scope="col">列</th> + <th scope="col">値</th> + <th scope="col">意味</th> + </tr> + <tr> + <td rowspan="2">{@link android.provider.ContactsContract.RawContacts}</td> + <td rowspan="2">{@link android.provider.ContactsContract.SyncColumns#DIRTY}</td> + <td>「0」 - 前回の同期以降、変更はありません。</td> + <td rowspan="2"> + 端末上で変更があり、サーバーと同期する必要がある未加工連絡先をマークします。 +Android アプリケーションが行をアップデートすると、連絡先プロバイダによって値が自動的に設定されます。 + + <p> + 未加工連絡先やデータのテーブルを変更する同期アダプタは、使用するコンテンツ URI の末尾に文字列 {@link android.provider.ContactsContract#CALLER_IS_SYNCADAPTER} を必ず追加してください。 + +これにより、プロバイダが行をダーティとマークするのを防ぐことができます。 + こうしないと、同期アダプタによる変更がローカルな変更と認識され、変更のソースがサーバーであるにもかかわらず、その変更がサーバーに送信されます。 + + </p> + </td> + </tr> + <tr> + <td>「1」 - 前回の同期以降に変更があり、サーバーへの同期が必要です。</td> + </tr> + <tr> + <td>{@link android.provider.ContactsContract.RawContacts}</td> + <td>{@link android.provider.ContactsContract.SyncColumns#VERSION}</td> + <td>この行のバージョン番号。</td> + <td> + この行またはその関連データが変更されるたび、連絡先プロバイダがこの値を自動的にインクリメントします。 + + </td> + </tr> + <tr> + <td>{@link android.provider.ContactsContract.Data}</td> + <td>{@link android.provider.ContactsContract.DataColumns#DATA_VERSION}</td> + <td>この行のバージョン番号。</td> + <td> + このデータ行が変更されるたび、連絡先プロバイダがこの値を自動的にインクリメントします。 + + </td> + </tr> + <tr> + <td>{@link android.provider.ContactsContract.RawContacts}</td> + <td>{@link android.provider.ContactsContract.SyncColumns#SOURCE_ID}</td> + <td> + この未加工連絡先をそれが作成されたアカウントと一意に結び付ける文字列値。 + + </td> + <td> + 同期アダプタが新しい未加工連絡先を作成するたび、この列はその未加工連絡先に対するサーバーの一意の ID に設定される必要があります。 +Android アプリケーションが新しい未加工連絡先を作成した場合、そのアプリケーションはこの列を空欄のままにする必要があります。 +同期アダプタはこれを確認して、サーバー上に新しい未加工連絡先を作成し、{@link android.provider.ContactsContract.SyncColumns#SOURCE_ID} の値を取得します。 + + + <p> + 特に、ソース ID はアカウント タイプごとに<strong>一意</strong>で、同期中に安定している必要があります。 + + </p> + <ul> + <li> + Unique: アカウントの各未加工連絡先には独自のソース ID が必要です。これを強制しないと、連絡先アプリケーションに問題を引き起こすことになります。 + + 同じアカウント <em>タイプ</em>に対する 2 つの未加工連絡先が、同じソース ID を持つことがありえます。 +たとえば、アカウント {@code emily.dickinson@gmail.com} の未加工連絡先「Thomas Higginson」は、アカウント {@code emilyd@gmail.com} の未加工連絡先「Thomas Higginson」と同じソース ID を持つことができます。 + + + + </li> + <li> + Stable: ソース ID は、未加工連絡先のオンライン サービス データにおいて変わらない部分です。 +たとえば、ユーザーが [アプリ] 設定から [連絡先ストレージ] を消去し、再同期したとしても、復元された未加工連絡先のソース ID は以前と同じになります。 + +これを強制しないと、ショートカットが機能しなくなります。 + + </li> + </ul> + </td> + </tr> + <tr> + <td rowspan="2">{@link android.provider.ContactsContract.Groups}</td> + <td rowspan="2">{@link android.provider.ContactsContract.GroupsColumns#GROUP_VISIBLE}</td> + <td>「0」 - このグループに属する連絡先が Android アプリケーションの UI に表示されなくなります。</td> + <td> + この列は、ユーザーが特定のグループに属する連絡先を非表示にすることを許可するサーバーに対して互換性を確保するために用意されています。 + + </td> + </tr> + <tr> + <td>「1」 - このグループに属する連絡先を Android アプリケーションの UI に表示できます。</td> + </tr> + <tr> + <td rowspan="2">{@link android.provider.ContactsContract.Settings}</td> + <td rowspan="2"> + {@link android.provider.ContactsContract.SettingsColumns#UNGROUPED_VISIBLE}</td> + <td> + 「0」 - このアカウントとアカウント タイプについて、グループに属さない連絡先は Android アプリケーションの UI に表示されなくなります。 + + </td> + <td rowspan="2"> + デフォルトでは、グループに属する未加工連絡先がないなら連絡先は表示されません(未加工連絡先のグループ メンバーシップは、{@link android.provider.ContactsContract.Data} テーブルの 1 つないし複数の {@link android.provider.ContactsContract.CommonDataKinds.GroupMembership} 行によって示されます)。 + + + + あるアカウントとアカウント タイプについて、{@link android.provider.ContactsContract.Settings} テーブルの行でこのフラグを設定すると、グループのない連絡先を強制的に表示できます。 + + このフラグの用途の 1 つとして、グループを使用しないサーバーから連絡先を取得して表示することが考えられます。 + </td> + </tr> + <tr> + <td> + 「0」 - このアカウントとアカウント タイプについて、グループに属さない連絡先が Android アプリケーションの UI に表示されます。 + + </td> + + </tr> + <tr> + <td>{@link android.provider.ContactsContract.SyncState}</td> + <td>(すべて)</td> + <td> + このテーブルを使用して、同期アダプタのメタデータを格納します。 + </td> + <td> + このテーブルを使用すると、同期状態などの同期関連データを永続的に端末上に格納できます。 + + </td> + </tr> +</table> +<h2 id="Access">連絡先プロバイダへのアクセス</h2> +<p> + このセクションでは、連絡先プロバイダからのデータにアクセスするためのガイドラインについて、以下に注目して説明します。 + +</p> +<ul> + <li> + エンティティ クエリ。 + </li> + <li> + バッチ変更。 + </li> + <li> + インテントを使用した取得と変更。 + </li> + <li> + データ整合性。 + </li> +</ul> +<p> + 同期アダプタからの変更については、<a href="#SyncAdapters">連絡先プロバイダの同期アダプタ</a>でも詳しく説明しています。 + +</p> +<h3 id="Entities">エンティティのクエリ</h3> +<p> + 連絡先プロバイダのテーブルは階層構造になっており、ある行とその「子」の行すべてを取得すると便利なことがよくあります。 +たとえば、ある人に関するすべての情報を表示するために、{@link android.provider.ContactsContract.Contacts} 行 1 行に対するすべての {@link android.provider.ContactsContract.RawContacts} 行や、{@link android.provider.ContactsContract.RawContacts} 行 1 行に対するすべての {@link android.provider.ContactsContract.CommonDataKinds.Email} 行を取得することが考えられます。 + + + + +こうした処理をやりやすくするため、連絡先プロバイダには<strong>エンティティ</strong>構造が用意されています。これは、テーブル間でのデータベースの和集合のように機能します。 + + +</p> +<p> + 1 つのエンティティは、ある親テーブルとその子テーブルから選ばれた列からなるテーブルのようなものです。 + エンティティをクエリする場合は、そのエンティティで使用できる列に基づいてプロジェクションと検索の条件を指定します。 +その結果が {@link android.database.Cursor} で、取得された各子テーブル行につき 1 行を含みます。 +たとえば、ある連絡先名と、その名前のすべての未加工連絡先の {@link android.provider.ContactsContract.CommonDataKinds.Email} 行について、{@link android.provider.ContactsContract.Contacts.Entity} をクエリすると、各 {@link android.provider.ContactsContract.CommonDataKinds.Email} 行につき 1 行を含む {@link android.database.Cursor} が得られます。 + + + + +</p> +<p> + エンティティにより、クエリが簡素化されます。エンティティを使用することで、ある連絡先または未加工連絡先の連絡先データをすべて取得できるため、まず親テーブルにクエリして ID を取得し、次にその ID 使用して子テーブルにクエリする必要がありません。また、連絡先プロバイダは、エンティティに対するクエリを 1 回のトランザクションで処理することから、取得されたデータの内部的な整合性が保証されます。 + + + + +</p> +<p class="note"> + <strong>注:</strong> エンティティには通常、親テーブルと子テーブルのすべての列が含まれるわけではありません。 +そのエンティティの列名定数のリストにない列名に対して作業しようとすると、{@link java.lang.Exception} が発生します。 + +</p> +<p> + 次のスニペットは、ある連絡先のすべての未加工連絡先を取得する方法を示しています。このスニペットは、「メイン」と「詳細」という 2 つのアクティビティを持つ、もっと大きなアプリケーションの一部です。 +メイン アクティビティは、連絡先の行の一覧を示します。ユーザーが 1 つを選択すると、このアクティビティはその ID を詳細アクティビティに送ります。 + +詳細アクティビティは {@link android.provider.ContactsContract.Contacts.Entity} を使用して、選択した連絡先と関連付けられているすべての未加工連絡先から取得したすべてのデータ行を示します。 + + +</p> +<p> + このスニペットは「詳細」アクティビティからの抜粋です。 +</p> +<pre> +... + /* + * Appends the entity path to the URI. In the case of the Contacts Provider, the + * expected URI is content://com.google.contacts/#/entity (# is the ID value). + */ + mContactUri = Uri.withAppendedPath( + mContactUri, + ContactsContract.Contacts.Entity.CONTENT_DIRECTORY); + + // Initializes the loader identified by LOADER_ID. + getLoaderManager().initLoader( + LOADER_ID, // The identifier of the loader to initialize + null, // Arguments for the loader (in this case, none) + this); // The context of the activity + + // Creates a new cursor adapter to attach to the list view + mCursorAdapter = new SimpleCursorAdapter( + this, // the context of the activity + R.layout.detail_list_item, // the view item containing the detail widgets + mCursor, // the backing cursor + mFromColumns, // the columns in the cursor that provide the data + mToViews, // the views in the view item that display the data + 0); // flags + + // Sets the ListView's backing adapter. + mRawContactList.setAdapter(mCursorAdapter); +... +@Override +public Loader<Cursor> onCreateLoader(int id, Bundle args) { + + /* + * Sets the columns to retrieve. + * RAW_CONTACT_ID is included to identify the raw contact associated with the data row. + * DATA1 contains the first column in the data row (usually the most important one). + * MIMETYPE indicates the type of data in the data row. + */ + String[] projection = + { + ContactsContract.Contacts.Entity.RAW_CONTACT_ID, + ContactsContract.Contacts.Entity.DATA1, + ContactsContract.Contacts.Entity.MIMETYPE + }; + + /* + * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw + * contact collated together. + */ + String sortOrder = + ContactsContract.Contacts.Entity.RAW_CONTACT_ID + + " ASC"; + + /* + * Returns a new CursorLoader. The arguments are similar to + * ContentResolver.query(), except for the Context argument, which supplies the location of + * the ContentResolver to use. + */ + return new CursorLoader( + getApplicationContext(), // The activity's context + mContactUri, // The entity content URI for a single contact + projection, // The columns to retrieve + null, // Retrieve all the raw contacts and their data rows. + null, // + sortOrder); // Sort by the raw contact ID. +} +</pre> +<p> + 読み込みが完了すると、{@link android.app.LoaderManager} は {@link android.app.LoaderManager.LoaderCallbacks#onLoadFinished(Loader, D) onLoadFinished()} に対するコールバックを起動します。 + +このメソッドへの入力引数の 1 つは、クエリの結果を含む {@link android.database.Cursor} です。 +独自アプリでは、データをこの {@link android.database.Cursor} から取得して表示したりさらに処理したりできます。 + +</p> +<h3 id="Transactions">バッチ変更</h3> +<p> + 可能であれば必ず、連絡先プロバイダのデータを「バッチモード」で挿入、アップデート、削除してください。そのためには、{@link android.content.ContentProviderOperation} オブジェクトの {@link java.util.ArrayList} を作成し、{@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} を呼び出します。 + + +連絡先プロバイダはすべての操作を 1 つのトランザクションの 1 つの {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} で行うため、変更内容が連絡先リポジトリで不整合のままになることは決してありません。 + + + +また、バッチ変更では、未加工連絡先とその詳細データを同時に挿入しやすくなっています。 + +</p> +<p class="note"> + <strong>注:</strong> <em>1 つ</em>の未加工連絡先を変更する場合は、変更を独自アプリ内で処理するのではなく、インテントを端末の連絡先アプリケーションに送信することを検討してください。この方法については、<a href="#Intents">インテントを使用した取得と変更</a>で詳しく説明しています。 + + + +</p> +<h4>明け渡し点</h4> +<p> + 多数の操作を伴うバッチ変更は、他のプロセスをブロックしてユーザーにとっての全体的な使用感を悪化させかねません。 +意図したすべての変更をできるだけ少ない個別リストに整理するとともに、それらがシステムをブロックしないようにするために、1 つまたは複数の操作に<strong>明け渡し点</strong>を設定してください。 + + + 明け渡し点の実体は、{@link android.content.ContentProviderOperation#isYieldAllowed()} の値が <code>true</code> に設定された {@link android.content.ContentProviderOperation} オブジェクトです。 + +連絡先プロバイダが明け渡し点に遭遇すると、作業を一時中断して他のプロセスを実行させ、現在のトランザクションをクローズします。 +作業を再開した連絡先プロバイダは、{@link java.util.ArrayList} に含まれている次の操作を行い、新しいトランザクションを始めます。 + + +</p> +<p> + 明け渡し点により、{@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} の呼び出し 1 回につき複数のトランザクションが発生します。 +そのため、明け渡し点は 1 組の関連する行への最後の操作に設定してください。 + + たとえば、未加工連絡先の行とその関連データ行を追加する一連の操作の最後に、あるいは 1 人の連絡先に関連する 1 組の行に対する最後の操作に、明け渡し点を設定します。 + + +</p> +<p> + 明け渡し点は、アトミック操作の単位でもあります。2 つの明け渡し点間のすべてのアクセスは、1 つのまとまりとして成功または失敗します。 +明け渡し点を設定しない場合、最小のアトミック操作は操作のバッチ全体になります。 +明け渡し点を使用すると、操作がシステムのパフォーマンスを低下させるのを防ぐと同時に、操作の一部分が確実にアトミックになります。 + + +</p> +<h4>変更の後方参照</h4> +<p> + 新しい未加工連絡先の行とその関連データの行を 1 組の {@link android.content.ContentProviderOperation} オブジェクトとして挿入している場合は、データの行を未加工連絡先の行にリンクする必要があります。そのためには、未加工連絡先の {@link android.provider.BaseColumns#_ID} 値を {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID} 値として挿入します。 + + + +ただし、この値は、データの行のために{@link android.content.ContentProviderOperation} を作成している間は使用できません。未加工連絡先に {@link android.content.ContentProviderOperation} 操作がまだ適用されていないからです。 + + +これを回避するため、{@link android.content.ContentProviderOperation.Builder} クラスにはメソッド {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()} が用意されています。 + + + このメソッドを使用すると、前の操作の結果を使用して列を挿入または変更できます。 + +</p> +<p> + {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()} メソッドには引数が 2 つあります。 + +</p> + <dl> + <dt> + <code>key</code> + </dt> + <dd> + キーと値のペアのキーです。この引数の値は、変更中のテーブルに含まれる列であることが必要です。 + + </dd> + <dt> + <code>previousResult</code> + </dt> + <dd> + {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} から取得した {@link android.content.ContentProviderResult} オブジェクトの配列に含まれる値の、0 ベースのインデックスです。 + +バッチ操作が適用されると、各操作の結果は結果用の中間配列に格納されます。 + +<code>previousResult</code> 値はそうした結果の 1 つのインデックスで、<code>key</code> 値を使用して取得され、格納されます。 + +これにより、新しい未加工連絡先レコードを挿入してその {@link android.provider.BaseColumns#_ID} 値に戻り、次に {@link android.provider.ContactsContract.Data} 行を追加するときにその値を「後方参照」できます。 + + + <p> + {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} を初めて呼び出すと、指定した {@link android.content.ContentProviderOperation} オブジェクトの {@link java.util.ArrayList} と同じサイズを使用して、結果配列全体が作成されます。 + + +ただし、結果配列に含まれるすべての要素は <code>null</code> に設定され、そのためまだ適用されていない操作から結果を後方参照しようとすると {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()} が {@link java.lang.Exception} をスローします。 + + + + + + </p> + </dd> + </dl> +<p> + 次のスニペットは、新しい未加工連絡先とデータをバッチで挿入する方法を示しています。その中には、明け渡し点を指定し、後方参照を使用するコードが含まれています。 +これらのスニペットは、<code><a href="{@docRoot}resources/samples/ContactManager/index.html"> + Contact Manager</a></code> サンプル アプリケーションの <code>ContactAdder</code> クラスの一部である <code>createContacEntry()</code> メソッドの拡張版です。 + + + +</p> +<p> + 最初のスニペットは、連絡先データを UI から取得します。この時点で、ユーザーは新しい未加工連絡先の追加先となるアカウントを既に選択してあります。 + +</p> +<pre> +// Creates a contact entry from the current UI values, using the currently-selected account. +protected void createContactEntry() { + /* + * Gets values from the UI + */ + String name = mContactNameEditText.getText().toString(); + String phone = mContactPhoneEditText.getText().toString(); + String email = mContactEmailEditText.getText().toString(); + + int phoneType = mContactPhoneTypes.get( + mContactPhoneTypeSpinner.getSelectedItemPosition()); + + int emailType = mContactEmailTypes.get( + mContactEmailTypeSpinner.getSelectedItemPosition()); +</pre> +<p> + 次のスニペットは、未加工連絡先の行を {@link android.provider.ContactsContract.RawContacts} テーブルに挿入する操作を作成します。 + +</p> +<pre> + /* + * Prepares the batch operation for inserting a new raw contact and its data. Even if + * the Contacts Provider does not have any data for this person, you can't add a Contact, + * only a raw contact. The Contacts Provider will then add a Contact automatically. + */ + + // Creates a new array of ContentProviderOperation objects. + ArrayList<ContentProviderOperation> ops = + new ArrayList<ContentProviderOperation>(); + + /* + * Creates a new raw contact with its account type (server type) and account name + * (user's account). Remember that the display name is not stored in this row, but in a + * StructuredName data row. No other data is required. + */ + ContentProviderOperation.Builder op = + ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) + .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType()) + .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName()); + + // Builds the operation and adds it to the array of operations + ops.add(op.build()); +</pre> +<p> + 次に、表示名、電話、メールのデータ行を作成します。 +</p> +<p> + 操作の各ビルダー オブジェクトは、{@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()} を使用して {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID} を取得します。 + + +この参照が最初の操作からの {@link android.content.ContentProviderResult} オブジェクトを後方参照しており、それが未加工連絡先の行を追加し、新しい {@link android.provider.BaseColumns#_ID} 値を返します。 + + +その結果、各データ行はその {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID} によって、属する新しい {@link android.provider.ContactsContract.RawContacts} 行に自動的にリンクされます。 + + +</p> +<p> + メール行を追加する {@link android.content.ContentProviderOperation.Builder} オブジェクトは、明け渡し点を設定する {@link android.content.ContentProviderOperation.Builder#withYieldAllowed(boolean) withYieldAllowed()} でフラグ付けされます。 + + +</p> +<pre> + // Creates the display name for the new raw contact, as a StructuredName data row. + op = + ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) + /* + * withValueBackReference sets the value of the first argument to the value of + * the ContentProviderResult indexed by the second argument. In this particular + * call, the raw contact ID column of the StructuredName data row is set to the + * value of the result returned by the first operation, which is the one that + * actually adds the raw contact row. + */ + .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) + + // Sets the data row's MIME type to StructuredName + .withValue(ContactsContract.Data.MIMETYPE, + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) + + // Sets the data row's display name to the name in the UI. + .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name); + + // Builds the operation and adds it to the array of operations + ops.add(op.build()); + + // Inserts the specified phone number and type as a Phone data row + op = + ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) + /* + * Sets the value of the raw contact id column to the new raw contact ID returned + * by the first operation in the batch. + */ + .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) + + // Sets the data row's MIME type to Phone + .withValue(ContactsContract.Data.MIMETYPE, + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) + + // Sets the phone number and type + .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) + .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType); + + // Builds the operation and adds it to the array of operations + ops.add(op.build()); + + // Inserts the specified email and type as a Phone data row + op = + ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) + /* + * Sets the value of the raw contact id column to the new raw contact ID returned + * by the first operation in the batch. + */ + .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) + + // Sets the data row's MIME type to Email + .withValue(ContactsContract.Data.MIMETYPE, + ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) + + // Sets the email address and type + .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email) + .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType); + + /* + * Demonstrates a yield point. At the end of this insert, the batch operation's thread + * will yield priority to other threads. Use after every set of operations that affect a + * single contact, to avoid degrading performance. + */ + op.withYieldAllowed(true); + + // Builds the operation and adds it to the array of operations + ops.add(op.build()); +</pre> +<p> + 最後のスニペットは、新しい未加工連絡先とデータ行を挿入する {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} を呼び出しています。 + + +</p> +<pre> + // Ask the Contacts Provider to create a new contact + Log.d(TAG,"Selected account: " + mSelectedAccount.getName() + " (" + + mSelectedAccount.getType() + ")"); + Log.d(TAG,"Creating contact: " + name); + + /* + * Applies the array of ContentProviderOperation objects in batch. The results are + * discarded. + */ + try { + + getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); + } catch (Exception e) { + + // Display a warning + Context ctx = getApplicationContext(); + + CharSequence txt = getString(R.string.contactCreationFailure); + int duration = Toast.LENGTH_SHORT; + Toast toast = Toast.makeText(ctx, txt, duration); + toast.show(); + + // Log exception + Log.e(TAG, "Exception encountered while inserting contact: " + e); + } +} +</pre> +<p> + バッチ処理を使用すると、<strong>楽観的並行性制御</strong>を実装できます。これは、背後のリポジトリをロックする必要なく変更トランザクションを適用する手法です。 + + この手法を使用するには、トランザクションを適用してから、同時に行うことのできる可能性のある他の変更をチェックします。 +一貫性のない変更が発生していることがわかった場合は、トランザクションをロールバックしてやり直します。 + +</p> +<p> + 楽観的並行性制御は、一度に使用するユーザーが 1 人でデータリポジトリへの同時アクセスがまれなモバイル端末に便利です。 +ロックが使用されないため、ロックの設定や他のトランザクションによるロックの解放待ちで時間を無駄にしません。 + +</p> +<p> + {@link android.provider.ContactsContract.RawContacts} 行を 1 行更新している間に楽観的並行性制御を使用する方法は次のとおりです。 + +</p> +<ol> + <li> + 取得する他のデータとともに、未加工連絡先の {@link android.provider.ContactsContract.SyncColumns#VERSION} 列を取得します。 + + </li> + <li> + 制約を強制するのに適した {@link android.content.ContentProviderOperation.Builder} オブジェクトを、メソッド {@link android.content.ContentProviderOperation#newAssertQuery(Uri)} を使用して作成します。 + +コンテンツ URI に、未加工連絡先の {@link android.provider.BaseColumns#_ID} が末尾に追加された {@link android.provider.ContactsContract.RawContacts#CONTENT_URI RawContacts.CONTENT_URI} を使用します。 + + + + </li> + <li> + {@link android.content.ContentProviderOperation.Builder} オブジェクトに対し、{@link android.content.ContentProviderOperation.Builder#withValue(String, Object) withValue()} を呼び出して、{@link android.provider.ContactsContract.SyncColumns#VERSION} 列と取得したばかりのバージョン番号を比較します。 + + + + </li> + <li> + 同じ {@link android.content.ContentProviderOperation.Builder} に対し、{@link android.content.ContentProviderOperation.Builder#withExpectedCount(int) withExpectedCount()} を呼び出して、このアサーションで 1 行だけがテストされるようにします。 + + + </li> + <li> + {@link android.content.ContentProviderOperation.Builder#build()} を呼び出して {@link android.content.ContentProviderOperation} オブジェクトを作成し、次のこのオブジェクトを {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} に渡す {@link java.util.ArrayList} に先頭オブジェクトとして追加します。 + + + + </li> + <li> + バッチトランザクションを適用します。 + </li> +</ol> +<p> + 目的の未加工連絡先の行が、行の読み込みからその変更の試行までの間に別の操作によってアップデートされた場合、{@link android.content.ContentProviderOperation} の「アサート」が失敗し、操作のバッチ全体がバックアウトされます。 + +バックアウトが終わったら、バッチをやり直すこと、または他のアクションを行うことができます。 + +</p> +<p> + 次のスニペットは、{@link android.content.CursorLoader} を使用して未加工連絡先を 1 つクエリした後に、{@link android.content.ContentProviderOperation} を「アサート」します。 + + +</p> +<pre> +/* + * The application uses CursorLoader to query the raw contacts table. The system calls this method + * when the load is finished. + */ +public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { + + // Gets the raw contact's _ID and VERSION values + mRawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID)); + mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION)); +} + +... + +// Sets up a Uri for the assert operation +Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, mRawContactID); + +// Creates a builder for the assert operation +ContentProviderOperation.Builder assertOp = ContentProviderOperation.netAssertQuery(rawContactUri); + +// Adds the assertions to the assert operation: checks the version and count of rows tested +assertOp.withValue(SyncColumns.VERSION, mVersion); +assertOp.withExpectedCount(1); + +// Creates an ArrayList to hold the ContentProviderOperation objects +ArrayList ops = new ArrayList<ContentProviderOperationg>; + +ops.add(assertOp.build()); + +// You would add the rest of your batch operations to "ops" here + +... + +// Applies the batch. If the assert fails, an Exception is thrown +try + { + ContentProviderResult[] results = + getContentResolver().applyBatch(AUTHORITY, ops); + + } catch (OperationApplicationException e) { + + // Actions you want to take if the assert operation fails go here + } +</pre> +<h3 id="Intents">インテントを使用した取得と変更</h3> +<p> + インテントを端末の連絡先アプリケーションに送信すると、連絡先プロバイダに間接的にアクセスできます。 +インテントが端末の連絡先アプリケーション UI を起動し、ユーザーはそこで連絡先関連の作業を行えます。 +このタイプのアクセスで、ユーザーは次の作業ができます。 + <ul> + <li>連絡先をリストから選び、アプリケーションに返してさらに作業する。</li> + <li>既存の連絡先データを編集する。</li> + <li>任意のアカウントに新しい未加工連絡先を挿入する。</li> + <li>連絡先または連絡先データを削除する。</li> + </ul> +<p> + ユーザーがデータを挿入またはアップデートしている場合は、まずデータを収集し、次にそれをインテントの一部として送信できます。 + +</p> +<p> + インテントを使用して端末の連絡先アプリケーション経由で連絡先プロバイダにアクセスする場合、連絡先プロバイダにアクセスするための独自の UI やコードを作成する必要はありません。 +また、連絡先プロバイダに対する読み取りや書き込みのパーミッションを要求する必要もありません。 +端末の連絡先アプリケーションは、連絡先に対する読み取りパーミッションをデリゲートできます。また、連絡先プロバイダへの変更を他のアプリケーション経由で行っていることから、書き込みパーミッションは不要です。 + + +</p> +<p> + プロバイダにアクセスするためのインテントを送信する汎用プロセスについては、<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">コンテンツ プロバイダの基本</a>のセクション「インテント経由のデータアクセス」で詳しく説明しています。 + +表 4 に、利用可能なタスクで使用できるアクション、MIME タイプ、データ値をまとめます。{@link android.content.Intent#putExtra(String, String) putExtra()} で使用できるエクストラ値については、{@link android.provider.ContactsContract.Intents.Insert} のリファレンス ドキュメントに一覧があります。 + + + + +</p> +<p class="table-caption" id="table4"> + <strong>表 4.</strong> 連絡先プロバイダのインテント +</p> +<table style="width:75%"> + <tr> + <th scope="col" style="width:10%">タスク</th> + <th scope="col" style="width:5%">アクション</th> + <th scope="col" style="width:10%">データ</th> + <th scope="col" style="width:10%">MIME タイプ</th> + <th scope="col" style="width:25%">注</th> + </tr> + <tr> + <td><strong>連絡先をリストから選ぶ</strong></td> + <td>{@link android.content.Intent#ACTION_PICK}</td> + <td> + 次のどれかです。 + <ul> + <li> +{@link android.provider.ContactsContract.Contacts#CONTENT_URI Contacts.CONTENT_URI}。連絡先のリストを表示します。 + + </li> + <li> +{@link android.provider.ContactsContract.CommonDataKinds.Phone#CONTENT_URI Phone.CONTENT_URI}。未加工連絡先の電話番号のリストを表示します。 + + </li> + <li> +{@link android.provider.ContactsContract.CommonDataKinds.StructuredPostal#CONTENT_URI StructuredPostal.CONTENT_URI}。未加工連絡先の住所のリストを表示します。 + + + </li> + <li> +{@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_URI Email.CONTENT_URI}。未加工連絡先のメールアドレスのリストを表示します。 + + </li> + </ul> + </td> + <td> + 使用せず + </td> + <td> + 指定したコンテンツ URI のタイプに応じて、未加工連絡先のリストか、未加工連絡先から取得されたデータのリストを表示します。 + + <p> + {@link android.app.Activity#startActivityForResult(Intent, int) startActivityForResult()} を呼び出してください。それにより、選択した行のコンテンツ URI が返されます。 + +URI の形式は、テーブルのコンテンツ URI の末尾にその行の <code>LOOKUP_ID</code> が追加されたものです。 + + 端末の連絡先アプリは、このアクティビティの実行中を通して、読み取りと書き込みのパーミッションをこのコンテンツ URI にデリゲートします。 +詳しくは、「<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">コンテンツ プロバイダの基本</a>」をご覧ください。 + + + </p> + </td> + </tr> + <tr> + <td><strong>新しい未加工連絡先を挿入する</strong></td> + <td>{@link android.provider.ContactsContract.Intents.Insert#ACTION Insert.ACTION}</td> + <td>該当せず</td> + <td> + {@link android.provider.ContactsContract.RawContacts#CONTENT_TYPE RawContacts.CONTENT_TYPE}。未加工連絡先のセットに対する MIME タイプです。 + + </td> + <td> + 端末の連絡先アプリケーションの [<strong>連絡先の追加</strong>] 画面を表示します。インテントに追加したエクストラ値が表示されます。 +{@link android.app.Activity#startActivityForResult(Intent, int) startActivityForResult()} を使用して送信すると、新たに追加された未加工連絡先の URI が、アクティビティの {@link android.app.Activity#onActivityResult(int, int, Intent) onActivityResult()} コールバック メソッドの {@link android.content.Intent} 引数の「data」フィールドに格納されて戻ってきます。 + + + + +この値を取得するには、{@link android.content.Intent#getData()} を呼び出します。 + </td> + </tr> + <tr> + <td><strong>連絡先を編集する</strong></td> + <td>{@link android.content.Intent#ACTION_EDIT}</td> + <td> + 連絡先の {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}。 +エディタ アクティビティを使用すると、ユーザーがその連絡先に関連付けられている任意のデータを編集できます。 + + </td> + <td> + {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE Contacts.CONTENT_ITEM_TYPE}。1 つの連絡先です。 +</td> + <td> + 連絡先アプリケーションに連絡先の編集画面を表示します。インテントに追加したエクストラ値が表示されます。 +ユーザーが [<strong>完了</strong>] をタップして編集内容を保存すると、アクティビティがフォアグラウンドに戻ります。 + + </td> + </tr> + <tr> + <td><strong>ピッカー(やはりデータを追加できる)を表示する。</strong></td> + <td>{@link android.content.Intent#ACTION_INSERT_OR_EDIT}</td> + <td> + 該当せず + </td> + <td> + {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE} + </td> + <td> + このインテントは、連絡先アプリのピッカー画面を常に表示します。ユーザーは、編集する連絡先を選ぶか、新しい連絡先を追加できます。 +ユーザーの選択に応じて編集画面か追加画面が開き、インテントに含めて渡したエクストラ データが表示されます。 + +メールアドレスや電話番号などの連絡先データを独自アプリに表示する場合は、このインテントを使用すると、ユーザーが既存の連絡先にデータを追加できます。 + + + <p class="note"> + <strong>注:</strong> このインテントのエクストラで名前の値を送信する必要はありません。ユーザーは必ず既存の名前を選ぶか新しい名前を追加するからです。 +そのうえ、アプリが名前を送信し、ユーザーが編集することを選んだ場合、連絡先アプリは送信した名前を表示し、以前の値を上書きします。 + +ユーザーがこのことに気付かず、編集内容を保存すると、以前の値が失われます。 + + </p> + </td> + </tr> +</table> +<p> + 端末の連絡先アプリは、インテントを使用して未加工連絡先や任意のデータを削除することを許可しません。 +そのため、未加工連絡先を削除するには {@link android.content.ContentResolver#delete(Uri, String, String[]) ContentResolver.delete()} または {@link android.content.ContentProviderOperation#newDelete(Uri) ContentProviderOperation.newDelete()} を使用してください。 + + + +</p> +<p> + 次のスニペットは、新しい未加工連絡先とデータをバッチで挿入するインテントをコンストラクトして送信する方法を示しています。 + +</p> +<pre> +// Gets values from the UI +String name = mContactNameEditText.getText().toString(); +String phone = mContactPhoneEditText.getText().toString(); +String email = mContactEmailEditText.getText().toString(); + +String company = mCompanyName.getText().toString(); +String jobtitle = mJobTitle.getText().toString(); + +// Creates a new intent for sending to the device's contacts application +Intent insertIntent = new Intent(ContactsContract.Intents.Insert.ACTION); + +// Sets the MIME type to the one expected by the insertion activity +insertIntent.setType(ContactsContract.RawContacts.CONTENT_TYPE); + +// Sets the new contact name +insertIntent.putExtra(ContactsContract.Intents.Insert.NAME, name); + +// Sets the new company and job title +insertIntent.putExtra(ContactsContract.Intents.Insert.COMPANY, company); +insertIntent.putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle); + +/* + * Demonstrates adding data rows as an array list associated with the DATA key + */ + +// Defines an array list to contain the ContentValues objects for each row +ArrayList<ContentValues> contactData = new ArrayList<ContentValues>(); + + +/* + * Defines the raw contact row + */ + +// Sets up the row as a ContentValues object +ContentValues rawContactRow = new ContentValues(); + +// Adds the account type and name to the row +rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType()); +rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName()); + +// Adds the row to the array +contactData.add(rawContactRow); + +/* + * Sets up the phone number data row + */ + +// Sets up the row as a ContentValues object +ContentValues phoneRow = new ContentValues(); + +// Specifies the MIME type for this data row (all data rows must be marked by their type) +phoneRow.put( + ContactsContract.Data.MIMETYPE, + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE +); + +// Adds the phone number and its type to the row +phoneRow.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone); + +// Adds the row to the array +contactData.add(phoneRow); + +/* + * Sets up the email data row + */ + +// Sets up the row as a ContentValues object +ContentValues emailRow = new ContentValues(); + +// Specifies the MIME type for this data row (all data rows must be marked by their type) +emailRow.put( + ContactsContract.Data.MIMETYPE, + ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE +); + +// Adds the email address and its type to the row +emailRow.put(ContactsContract.CommonDataKinds.Email.ADDRESS, email); + +// Adds the row to the array +contactData.add(emailRow); + +/* + * Adds the array to the intent's extras. It must be a parcelable object in order to + * travel between processes. The device's contacts app expects its key to be + * Intents.Insert.DATA + */ +insertIntent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData); + +// Send out the intent to start the device's contacts app in its add contact activity. +startActivity(insertIntent); +</pre> +<h3 id="DataIntegrity">データの整合性</h3> +<p> + 連絡先リポジトリにはユーザーによる修正や更新が予想される重要で秘密性の高いデータが格納されるため、連絡先プロバイダにはデータの整合性に関して明確に定義されたルールがあります。 +連絡先データを変更する際にこれらのルールを守ることは、開発側の責任です。 +ここでは、重要なルールを示します。 + +</p> +<dl> + <dt> + {@link android.provider.ContactsContract.CommonDataKinds.StructuredName} 行を、追加する {@link android.provider.ContactsContract.RawContacts} 行ごとに必ず追加してください。 + + </dt> + <dd> + {@link android.provider.ContactsContract.Data} テーブルに {@link android.provider.ContactsContract.CommonDataKinds.StructuredName} 行のない {@link android.provider.ContactsContract.RawContacts} 行は、集約中に問題を引き起こすことがあります。 + + + + </dd> + <dt> + 新しい {@link android.provider.ContactsContract.Data} 行を、その親 {@link android.provider.ContactsContract.RawContacts} 行に必ずリンクしてください。 + + </dt> + <dd> + {@link android.provider.ContactsContract.RawContacts} にリンクされていない {@link android.provider.ContactsContract.Data} 行は端末の連絡先アプリケーションで可視にならず、同期アダプタで問題になることがあります。 + + + </dd> + <dt> + 変更するのは、所有する未加工連絡先のデータに限ってください。 + </dt> + <dd> + 通常、連絡先プロバイダは複数の異なるアカウント タイプやオンライン サービスから取得したデータを管理しています。 +そのため、アプリケーションが所有しているデータのみ変更または削除されるようにし、アプリケーションが管理しているアカウント タイプとアカウント名のデータのみ挿入するようにすることが必要です。 + + + </dd> + <dt> + 権限、コンテンツ URI、URI パス、列名、MIME タイプ、{@link android.provider.ContactsContract.CommonDataKinds.CommonColumns#TYPE} 値については、{@link android.provider.ContactsContract} とそのサブクラスに定義されている定数を必ず使用してください。 + + + </dt> + <dd> + そのような定数を使用することがエラーの予防に役立ちます。また、使われなくなった定数があれば、コンパイラーから警告として通知されます。 + + </dd> +</dl> +<h3 id="CustomData">カスタムデータ行</h3> +<p> + 独自のカスタム MIME タイプを作成して使用すると、{@link android.provider.ContactsContract.Data} テーブルで独自データ行を挿入、編集、削除、取得できます。 +独自行で使用できるのは {@link android.provider.ContactsContract.DataColumns} に定義された列だけですが、独自タイプに固有の列名をデフォルトの列名にマッピングできます。 + + +端末の連絡先アプリケーションで、独自行のデータは表示されますが、編集または削除はできず、ユーザーはデータの追加ができません。 + +ユーザーがカスタムデータ行を変更できるようにするには、独自のアプリケーションでエディタ アクティビティを提供する必要があります。 + +</p> +<p> + カスタムデータを表示するには、1 つの <code><ContactsAccountType></code> 要素と 1 つまたは複数の <code><ContactsDataKind></code> 子要素を含む <code>contacts.xml</code> ファイルを提供します。 + +詳しくは、<a href="#SocialStreamDataKind"><code><ContactsDataKind> element</code></a>に関するセクションで説明しています。 + +</p> +<p> + カスタム MIME タイプについて詳しくは、「<a href="{@docRoot}guide/topics/providers/content-provider-creating.html">コンテンツ プロバイダの作成</a>」をご覧ください。 + + +</p> +<h2 id="SyncAdapters">連絡先プロバイダの同期アダプタ</h2> +<p> + 連絡先プロバイダは、特に端末とオンライン サービスとの間における連絡先データの<strong>同期</strong>を処理するために設計されています。 +これを使用することで、ユーザーは既存のデータを新しい端末にダウンロードしたり、既存のデータを新しいアカウントにアップロードしたりできています。 + + また、同期によって、追加や変更のソースに関係なく、ユーザーは最新データを入手できます。 +同期の利点としては他にも、端末がネットワークに接続されていなくても連絡先データを使用できるようになることが挙げられます。 + +</p> +<p> + 同期はさまざまな手法で実装できますが、Android システムでは次のタスクを自動化するプラグイン同期フレームワークを提供しています。 + + <ul> + + <li> + ネットワークの可用性のチェック。 + </li> + <li> + ユーザーのプリファレンスに基づく同期のスケジュールと実施。 + </li> + <li> + 停止された同期の再開。 + </li> + </ul> +<p> + このフレームワークを使用するには、同期アダプタ プラグインを提供する必要があります。各同期アダプタはサービスと連絡先プロバイダに対して一意ですが、同じサービスに対して複数のアカウント名を処理できます。 +また、このフレームワークでは同じサービスとプロバイダに対して複数の同期アダプタが可能です。 + +</p> +<h3 id="SyncClassesFiles">同期アダプタのクラスとファイル</h3> +<p> + 同期アダプタは、{@link android.content.AbstractThreadedSyncAdapter} のサブクラスとして実装し、Android アプリケーションの一部としてインストールします。 + +システムは同期アダプタに関する知識を、アプリケーション マニフェストの要素からと、マニフェストが指す専用の XML ファイルから取得します。 +この XML ファイルは、オンライン サービスのアカウント タイプと連絡先プロバイダに絡む権限を定義しており、この組み合わせでアダプタを一意に識別します。 + +同期アダプタは、ユーザーが同期アダプタのアカウント タイプに対してアカウントを追加し、同期アダプタの同期対象である連絡先プロバイダで同期を有効にすることで、アクティブになります。 + +この時点で、システムはアダプタの管理を開始し、連絡先プロバイダとサーバーとの同期が必要になるとそれを呼び出します。 + +</p> +<p class="note"> + <strong>注:</strong> アカウント タイプを同期アダプタの識別の一環として使用することにより、システムは同じ組織から異なるサービスにアクセスする同期アダプタを検出してグループ化できます。 + +たとえば、Google オンライン サービス用の同期アダプタでは、すべて同じアカウント タイプ <code>com.google</code> です。 +ユーザーが Google アカウントを端末に追加すると、Google サービス用にインストールされているすべての同期アダプタがひとまとめにリストされ、リストされている各同期アダプタは端末上の異なる連絡先プロバイダと同期します。 + + +</p> +<p> + データにアクセスするたび、ほとんどのサービスがユーザーに ID の確認を要求するため、Android システムでは、同期アダプタ フレームワークと類似した認証フレームワークを提供しており、往々にして同期アダプタ フレームワークと組み合わせて使用します。 + +この認証フレームワークでは、{@link android.accounts.AbstractAccountAuthenticator} のサブクラスであるプラグイン認証システムを使用します。 + +認証システムは、次の手順でユーザーの身元を検証します。 + + <ol> + <li> + ユーザー名とパスワードか、それに準ずる情報(ユーザーの<strong>資格情報</strong>)を収集します。 + + </li> + <li> + 収集した資格情報をサービスに送信します。 + </li> + <li> + サービスの返答を検証します。 + </li> + </ol> +<p> + サービスが資格情報を受け入れた場合、認証システムはその資格情報を後での使用のために格納します。 +{@link android.accounts.AccountManager} はプラグイン認証フレームワークのおかげで、OAuth2 認証トークンなど、認証システムがサポートして公開することを選択している任意の認証トークンへのアクセスを提供できます。 + + +</p> +<p> + 認証は必須ではありませんが、たいていの連絡先サービスが使用しています。 + ただし、認証に Android 認証フレームワークを使用する必要はありません。 +</p> +<h3 id="SyncAdapterImplementing">同期アダプタの実装</h3> +<p> + 連絡先プロバイダ用の同期アダプタを実装するには、まず以下を備えた Android アプリケーションを作成します。 + +</p> + <dl> + <dt> + システムからの同期アダプタとのバインド要求に対処する {@link android.app.Service} コンポーネント。 + + </dt> + <dd> + システムは、同期しようとするとき、サービスの {@link android.app.Service#onBind(Intent) onBind()} メソッドを呼び出して、同期アダプタの {@link android.os.IBinder} を取得します。 + +これにより、システムはアダプタのメソッドに対するプロセス間呼び出しを実行できます。 + + <p> + <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">サンプル同期アダプタ</a>のサンプルアプリで、このサービスのクラス名は <code>com.example.android.samplesync.syncadapter.SyncService</code> です。 + + + </p> + </dd> + <dt> + {@link android.content.AbstractThreadedSyncAdapter} の具象サブクラスとして実装された、実際の同期アダプタ。 + + </dt> + <dd> + このクラスが、サーバーからのデータのダウンロード、端末からのデータのアップロード、競合の解消といった作業を実施します。 +アダフタの主な作業は、メソッド {@link android.content.AbstractThreadedSyncAdapter#onPerformSync( Account, Bundle, String, ContentProviderClient, SyncResult) onPerformSync()} で実行されます。 + + +このクラスは、シングルトンとしてインスタンス化する必要があります。 + <p> + <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">サンプル同期アダプタ</a>のサンプルアプリで、同期アダプタはクラス <code>com.example.android.samplesync.syncadapter.SyncAdapter</code> に定義されています。 + + + </p> + </dd> + <dt> + {@link android.app.Application} のサブクラス。 + </dt> + <dd> + このクラスは同期アダプタ シングルトンのファクトリとして機能します。同期アダプタのインスタンス化には {@link android.app.Application#onCreate()} メソッドを使用し、同期アダプタ シングルトンを同期アダプタのサービスの {@link android.app.Service#onBind(Intent) onBind()} メソッドに返すための静的な「getter」メソッドを提供します。 + + + + + </dd> + <dt> + <strong>省略可能:</strong> システムからのユーザー認証要求に対処する {@link android.app.Service} コンポーネント。 + + </dt> + <dd> + {@link android.accounts.AccountManager} は、このサービスを開始することによって認証プロセスを始めます。 +サービスの {@link android.app.Service#onCreate()} メソッドは、認証システム オブジェクトをインスタンス化します。 +システムは、アプリケーションの同期アダプタのためにユーザー アカウントを認証しようとするとき、サービスの {@link android.app.Service#onBind(Intent) onBind()} メソッドを呼び出して、認証システムの {@link android.os.IBinder} を取得します。 + + +これにより、システムは認証システムのメソッドに対するプロセス間呼び出しを実行できます。 + + <p> + <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">サンプル同期アダプタ</a>のサンプルアプリで、このサービスのクラス名は <code>com.example.android.samplesync.authenticator.AuthenticationService</code> です。 + + + </p> + </dd> + <dt> + <strong>省略可能:</strong> 認証の要求を処理する {@link android.accounts.AbstractAccountAuthenticator} の具象サブクラス。 + + + </dt> + <dd> + このクラスは、ユーザーの資格情報をサーバーに対して認証するために {@link android.accounts.AccountManager} が呼び出すメソッドを提供します。認証プロセスの詳細は、使用されているサーバー技術に応じて多岐にわたります。 + +認証について詳しくは、使用するサーバー ソフトウェアのドキュメントをご覧ください。 + + <p> + <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">サンプル同期アダプタ</a>のサンプルアプリで、認証はクラス <code>com.example.android.samplesync.authenticator.Authenticator</code> に定義されています。 + + + </p> + </dd> + <dt> + システムに対する同期アダプタと認証システムを定義する XML ファイル。 + </dt> + <dd> + 前述の同期アダプタと認証システム サービスのコンポーネントは、アプリケーション マニフェストの <code><<a href="{@docRoot}guide/topics/manifest/service-element.html">service</a>></code> 要素に定義されます。 + + +これらの要素には、特定のデータをシステムに提供する次のような <code><<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>></code> 子要素が含まれます。 + + + + + <ul> + <li> + 同期アダプタ サービス用の <code><<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>></code> 要素は、XML ファイル <code>res/xml/syncadapter.xml</code> を指します。 + + +このファイルが、連絡先プロバイダと同期されるウェブサービスの URI と、そのウェブサービスで使用するアカウント タイプを指定します。 + + + </li> + <li> + <strong>省略可能:</strong> 認証システム用の <code><<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>></code> 要素は、XML ファイル <code>res/xml/authenticator.xml</code> を指します。 + + +このファイルが、この認証システムがサポートするアカウント タイプと、認証プロセスの最中に表示される UI リソースを指定します。 + +この要素に指定されるアカウント タイプは、同期アダプタ用に指定されるアカウント タイプと同じであることが必要です。 + + + </li> + </ul> + </dd> + </dl> +<h2 id="SocialStream">ソーシャル ストリーム データ</h2> +<p> + {@link android.provider.ContactsContract.StreamItems} テーブルと {@link android.provider.ContactsContract.StreamItemPhotos} テーブルは、ソーシャル ネットワークからの受信データを管理します。 + +独自ネットワークからのストリーム データをこれらのテーブルに追加する同期アダプタを作成したり、ストリーム データをこれらのテーブルから読み込んで独自アプリケーションに表示したり、この両方を行ったりできます。 + +このような機能があると、ソーシャル ネットワーキングのサービスやアプリケーションを Android のソーシャル ネットワーキング機能に統合できます。 + +</p> +<h3 id="StreamText">ソーシャル ストリーム テキスト</h3> +<p> + ストリーム アイテムは、必ず未加工連絡先に関連付けられます。{@link android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID} は、未加工連絡先の <code>_ID</code> 値にリンクされます。 + +未加工連絡先のアカウント タイプとアカウント名は、ストリーム アイテム行にも格納されます。 + +</p> +<p> + ストリームからのデータを次の列に格納します。 +</p> +<dl> + <dt> + {@link android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_TYPE} + </dt> + <dd> + <strong>必須</strong>。このストリーム アイテムに関連付けられている未加工連絡先の、ユーザーのアカウント タイプ。 +ストリーム アイテムを挿入する際には、この値を忘れずに設定してください。 + </dd> + <dt> + {@link android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_NAME} + </dt> + <dd> + <strong>必須</strong>。このストリーム アイテムに関連付けられている未加工連絡先の、ユーザーのアカウント名。 +ストリーム アイテムを挿入する際には、この値を忘れずに設定してください。 + </dd> + <dt> + 識別用列 + </dt> + <dd> + <strong>必須</strong>。ストリーム アイテムを挿入する際には、次の識別用列を挿入する必要があります。 + + <ul> + <li> + {@link android.provider.ContactsContract.StreamItemsColumns#CONTACT_ID}:このストリーム アイテムが関連付けられている連絡先の {@link android.provider.BaseColumns#_ID} 値。 + + + </li> + <li> + {@link android.provider.ContactsContract.StreamItemsColumns#CONTACT_LOOKUP_KEY}: このストリーム アイテムが関連付けられている連絡先の {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} 値。 + + + </li> + <li> + {@link android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID}:このストリーム アイテムが関連付けられている未加工連絡先の {@link android.provider.BaseColumns#_ID} 値。 + + + </li> + </ul> + </dd> + <dt> + {@link android.provider.ContactsContract.StreamItemsColumns#COMMENTS} + </dt> + <dd> + 省略可能。ストリーム アイテムの冒頭に表示できる概要情報を格納します。 + </dd> + <dt> + {@link android.provider.ContactsContract.StreamItemsColumns#TEXT} + </dt> + <dd> + ストリーム アイテムのテキスト。アイテムのソースによって投稿されたコンテンツか、そのストリーム アイテムを生成した何らかのアクションに関する説明です。 +この列には、{@link android.text.Html#fromHtml(String) fromHtml()} でレンダリングできる任意の書式や埋め込みリソース画像を含めることができます。 + +プロバイダは、長いコンテンツを切り捨てたり省いたりすることがありますが、タグは壊さないようにします。 + + </dd> + <dt> + {@link android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP} + </dt> + <dd> + ストリーム アイテムが挿入またはアップデートされた時刻を含むテキスト。エポックからのミリ秒<em></em>の形式です。 +ストリーム アイテムを挿入またはアップデートするアプリケーションは、この列の管理を担当します。この列は、連絡先プロバイダによって自動的に管理されるわけではありません。 + + + </dd> +</dl> +<p> + ストリーム アイテムの識別情報を表示するには、{@link android.provider.ContactsContract.StreamItemsColumns#RES_ICON}、{@link android.provider.ContactsContract.StreamItemsColumns#RES_LABEL}、{@link android.provider.ContactsContract.StreamItemsColumns#RES_PACKAGE} を使用してアプリケーション内のリソースにリンクします。 + + + + +</p> +<p> + {@link android.provider.ContactsContract.StreamItems} テーブルには、同期アダプタ専用に列 {@link android.provider.ContactsContract.StreamItemsColumns#SYNC1} ~ {@link android.provider.ContactsContract.StreamItemsColumns#SYNC4} も格納されます。 + + + +</p> +<h3 id="StreamPhotos">ソーシャル ストリーム フォト</h3> +<p> + {@link android.provider.ContactsContract.StreamItemPhotos} テーブルには、ストリーム アイテムに関連付けられた写真が格納されます。 +このテーブルの {@link android.provider.ContactsContract.StreamItemPhotosColumns#STREAM_ITEM_ID} 列は、{@link android.provider.ContactsContract.StreamItems} テーブルの {@link android.provider.BaseColumns#_ID} 列の値にリンクされます。 + + +写真の参照は、テーブルの次の列に格納されます。 + +</p> +<dl> + <dt> + {@link android.provider.ContactsContract.StreamItemPhotos#PHOTO} 列(BLOB)。 + </dt> + <dd> + 写真のバイナリ表現。格納や表示のためにプロバイダによってサイズが変更されます。 + この列は、写真を格納するために使用されていた連絡先プロバイダの従来のバージョンとの下方互換性のために用意されています。 +ただし、現在のバージョンでは、写真の格納にこの列を使用しないでください。 +代わりに、{@link android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID} または {@link android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI}(どちらについても次の項目で説明します)を使用して、写真をファイルに保存します。 + + +現状では、この列には写真のサムネイルが格納されており、読み出し可能です。 + + </dd> + <dt> + {@link android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID} + </dt> + <dd> + 未加工連絡先の写真の数値 ID。この値を定数 {@link android.provider.ContactsContract.DisplayPhoto#CONTENT_URI DisplayPhoto.CONTENT_URI} の末尾に追加して、1 つの写真ファイルを指すコンテンツ URI を取得し、{@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String) openAssetFileDescriptor()} を呼び出して、その写真ファイルのハンドルを取得します。 + + + + + </dd> + <dt> + {@link android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI} + </dt> + <dd> + この行によって表されている写真の写真ファイルを直接指すコンテンツ URI。 + この URI を使用して {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String) openAssetFileDescriptor()} を呼び出して、写真ファイルのハンドルを取得します。 + + </dd> +</dl> +<h3 id="SocialStreamTables">ソーシャル ストリーム テーブルの使用</h3> +<p> + これらのテーブルは、連絡先プロバイダの他の主なテーブルと同じように機能しますが、次のような例外があります。 +</p> + <ul> + <li> + これらのテーブルには、追加のアクセス パーミッションが必要です。これらからの読み出しには、アプリケーションにパーミッション {@link android.Manifest.permission#READ_SOCIAL_STREAM} が必要です。 +これらの変更には、アプリケーションにパーミッション {@link android.Manifest.permission#WRITE_SOCIAL_STREAM} が必要です。 + + + </li> + <li> + {@link android.provider.ContactsContract.StreamItems} テーブルについては、各未加工連絡先に格納できる行数に上限があります。 +上限に達すると、連絡先プロバイダは最も古い {@link android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP} を持つ行を自動的に削除して、新しいストリーム アイテムのための領域を作ります。 + + +この上限を取得するには、コンテンツ URI {@link android.provider.ContactsContract.StreamItems#CONTENT_LIMIT_URI} にクエリを発行します。 + +コンテンツ URI を除くすべての引数は、<code>null</code> のままでかまいません。 +このクエリは、列 {@link android.provider.ContactsContract.StreamItems#MAX_ITEMS} だけの 1 行を含む Cursor を返します。 + + + </li> + </ul> + +<p> + クラス {@link android.provider.ContactsContract.StreamItems.StreamItemPhotos} は、1 つのストリーム アイテムの写真行を含む {@link android.provider.ContactsContract.StreamItemPhotos} のサブテーブルを定義します。 + + +</p> +<h3 id="SocialStreamInteraction">ソーシャル ストリーム操作</h3> +<p> + 連絡先プロバイダによって端末の連絡先アプリケーションと連携して管理されるソーシャル ストリーム データは、ソーシャル ネットワーキング システムと既存の連絡先を接続するためのとても便利な手段を用意しています。 + +利用できる機能は次のとおりです。 +</p> + <ul> + <li> + ソーシャル ネットワーキング サービスを連絡先プロバイダに同期アダプタを使用して同期することで、ユーザーの連絡先による最近のアクティビティを取得し、それを {@link android.provider.ContactsContract.StreamItems} テーブルや {@link android.provider.ContactsContract.StreamItemPhotos} テーブルに格納して後で使えるようにできます。 + + + + </li> + <li> + ユーザーが連絡先を選択して表示したときには、定期的な同期とは別に同期アダプタを起動して追加データを取得できます。 +この機能により、同期アダプタは連絡先の高解像度の写真や直近のストリーム アイテムを取得できます。 + + </li> + <li> + 端末の連絡先アプリケーションと連絡先プロバイダに関する通知を登録すると、連絡先が表示された場合にインテントを受信<em></em>し、その時点で連絡先のステータスをサービスからアップデートできます。 + +このアプローチは、同期アダプタを使用してフル同期を実施するより、処理が速く、帯域幅が節約されます。 + + </li> + <li> + ユーザーが端末の連絡先アプリケーションで連絡先を見ている間に、その連絡先をソーシャル ネットワーキング サービスに追加できます。 +この機能は「連絡先の招待」機能を使用して実現できます。連絡先の招待は、既存の連絡先をネットワークに追加するアクティビティと、端末の連絡先アプリケーションと連絡先プロバイダにアプリケーションの詳細を提供する XML ファイルとを組み合わせて実現できます。 + + + + </li> + </ul> +<p> + 連絡先プロバイダを使用したストリーム アイテムの定期的な同期は、他の同期と同じです。 +同期について詳しくは、<a href="#SyncAdapters">連絡先プロバイダの同期アダプタ</a>をご覧ください。 +通知の登録と連絡先の招待については、次の 2 つのセクションで説明します。 + +</p> +<h4>ソーシャル ネットワーキング表示を処理するための登録</h4> +<p> + 同期アダプタを登録し、同期アダプタによって管理されている連絡先をユーザーが表示したときに通知されるようにする方法は、次のとおりです。 + +</p> +<ol> + <li> + <code>contacts.xml</code> という名前のファイルをプロジェクトの <code>res/xml/</code> ディレクトリに作成します。 +このファイルが既に存在する場合は、この手順を省略できます。 + </li> + <li> + このファイルに要素 <code><ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"></code> を追加します。 + + この要素が既に存在する場合は、この手順を省略できます。 + </li> + <li> + ユーザーが端末の連絡先アプリケーションで連絡先の詳細ページを開いたときに通知されるサービスを登録するには、属性 <code>viewContactNotifyService="<em>serviceclass</em>"</code> を要素に追加します。<code><em>serviceclass</em></code> は、端末の連絡先アプリケーションからインテントを受け取ることになるサービスの完全修飾クラス名です。 + + + +通知側サービスのために、{@link android.app.IntentService} を機能拡張したクラスを使用して、そのサービスがインテントを受け取れるようにします。 + +受け取るインテントに含まれるデータには、ユーザーがクリックした未加工連絡先のコンテンツ URI が格納されます。 +通知側サービスから、同期アダプタをバインドして呼び出し、未加工連絡先のデータをアップデートできます。 + + </li> +</ol> +<p> + ユーザーがストリーム アイテムかストリーム フォトかその両方をクリックしたときに呼び出されるアクティビティを登録する方法は次のとおりです。 +</p> +<ol> + <li> + <code>contacts.xml</code> という名前のファイルをプロジェクトの <code>res/xml/</code> ディレクトリに作成します。 +このファイルが既に存在する場合は、この手順を省略できます。 + </li> + <li> + このファイルに要素 <code><ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"></code> を追加します。 + + この要素が既に存在する場合は、この手順を省略できます。 + </li> + <li> + アクティビティのどれかを登録して、ユーザーが端末の連絡先アプリケーションでストリーム アイテムをタップしたことに対処するには、属性 <code>viewStreamItemActivity="<em>activityclass</em>"</code> を要素に追加します。<code><em>activityclass</em></code> は、端末の連絡先アプリケーションからインテントを受け取ることになるアクティビティの完全修飾クラス名です。 + + + + + </li> + <li> + アクティビティのどれかを登録して、ユーザーが端末の連絡先アプリケーションでストリーム フォトをタップしたことに対処するには、属性 <code>viewStreamItemPhotoActivity="<em>activityclass</em>"</code> を要素に追加します。<code><em>activityclass</em></code> は、端末の連絡先アプリケーションからインテントを受け取ることになるアクティビティの完全修飾クラス名です。 + + + + + </li> +</ol> +<p> + <code><ContactsAccountType></code> 要素については、<a href="#SocialStreamAcctType"><ContactsAccountType> 要素</a>で詳しく説明しています。 + +</p> +<p> + 受け取るインテントには、ユーザーがクリックしたアイテムまたは写真のコンテンツ URI が格納されます。 + テキスト アイテムと写真とで異なるアクティビティを使用するには、同じファイルで両方の属性を使用します。 +</p> +<h4>ソーシャル ネットワーキング サービスの操作</h4> +<p> + ユーザーは、連絡先をソーシャル ネットワーキング サービスに招待するのに、端末の連絡先アプリケーションを離れる必要はありません。 +その代わりとして、連絡先をアクティビティのどれかに招待するインテントを端末の連絡先アプリケーションに送信させることができます。 +これをセットアップする方法は次のとおりです。 +</p> +<ol> + <li> + <code>contacts.xml</code> という名前のファイルをプロジェクトの <code>res/xml/</code> ディレクトリに作成します。 +このファイルが既に存在する場合は、この手順を省略できます。 + </li> + <li> + このファイルに要素 <code><ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"></code> を追加します。 + + この要素が既に存在する場合は、この手順を省略できます。 + </li> + <li> + 次の属性を追加します。 + <ul> + <li><code>inviteContactActivity="<em>activityclass</em>"</code></li> + <li> + <code>inviteContactActionLabel="@string/<em>invite_action_label</em>"</code> + </li> + </ul> + <code><em>activityclass</em></code> 値は、インテントを受信するアクティビティの完全修飾クラス名です。 +<code><em>invite_action_label</em></code> 値は、端末の連絡先アプリケーションの [<strong>Add Connection</strong>] メニューに表示される文字列です。 + + + </li> +</ol> +<p class="note"> + <strong>注:</strong> <code>ContactsSource</code> は廃止されたタグ名で、<code>ContactsAccountType</code> に置き換わっています。 + +</p> +<h3 id="ContactsFile">contacts.xml リファレンス</h3> +<p> + ファイル <code>contacts.xml</code> には、同期アダプタやアプリケーションと連絡先アプリケーションや連絡先プロバイダとのやり取りを管理する XML 要素が含まれています。 +これらの要素について、以降のセクションで説明します。 + +</p> +<h4 id="SocialStreamAcctType"><ContactsAccountType> 要素</h4> +<p> + <code><ContactsAccountType></code> 要素は、アプリケーションと連絡先アプリケーションとのやり取りを管理します。 +構文は次のとおりです。 +</p> +<pre> +<ContactsAccountType + xmlns:android="http://schemas.android.com/apk/res/android" + inviteContactActivity="<em>activity_name</em>" + inviteContactActionLabel="<em>invite_command_text</em>" + viewContactNotifyService="<em>view_notify_service</em>" + viewGroupActivity="<em>group_view_activity</em>" + viewGroupActionLabel="<em>group_action_text</em>" + viewStreamItemActivity="<em>viewstream_activity_name</em>" + viewStreamItemPhotoActivity="<em>viewphotostream_activity_name</em>"> +</pre> +<p> + <strong>含まれているファイル:</strong> +</p> +<p> + <code>res/xml/contacts.xml</code> +</p> +<p> + <strong>含めることのできる要素:</strong> +</p> +<p> + <strong><code><ContactsDataKind></code></strong> +</p> +<p> + <strong>説明:</strong> +</p> +<p> + ユーザーが連絡先の 1 人をソーシャル ネットワーキングに招待できるようにしたり、ソーシャル ネットワーキング ストリームのどれかがアップデートされたらユーザーに通知したりするための、Android コンポーネントや UI ラベルを宣言します。 + + +</p> +<p> + 属性プレフィックス <code>android:</code> は、<code><ContactsAccountType></code> の属性に必須ではないことに注目してください。 + +</p> +<p> + <strong>属性:</strong> +</p> +<dl> + <dt>{@code inviteContactActivity}</dt> + <dd> + ユーザーが端末の連絡先アプリケーションで [<strong>Add Connection</strong>] を選択したときに起動する、アプリケーション内のアクティビティの完全修飾クラス名。 + + + </dd> + <dt>{@code inviteContactActionLabel}</dt> + <dd> + [<strong>Add Connection</strong>] メニューで、{@code inviteContactActivity} に指定されたアクティビティ用に表示されるテキスト。 + + たとえば、文字列「Follow in my network」を指定できます。このラベルには文字列リソース ID を使用できます。 + + </dd> + <dt>{@code viewContactNotifyService}</dt> + <dd> + ユーザーが連絡先を表示したときに通知を受け取ることになる、独自アプリケーション内のサービスの完全修飾クラス名。 +この通知は端末の連絡先アプリケーションによって送信されます。これを使用することで、アプリケーションはデータ処理の多い操作を必要になるまで延期できます。 + +たとえば、アプリケーションはこの通知への対応として、連絡先の高解像度写真と直近のソーシャル ストリーム アイテムを読み込んで表示できます。 + +この機能について詳しくは、<a href="#SocialStreamInteraction">ソーシャル ストリーム操作</a>で説明しています。 +<code>NotifierService.java</code> ファイルに指定された通知サービスの例は、<a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">SampleSyncAdapter</a> サンプル アプリケーションにあります。 + + + + </dd> + <dt>{@code viewGroupActivity}</dt> + <dd> + グループ情報を表示できる、独自アプリケーション内のアクティビティの完全修飾クラス名。 +ユーザーが端末の連絡先アプリケーションでグループラベルをタップすると、このアクティビティの UI が表示されます。 + + </dd> + <dt>{@code viewGroupActionLabel}</dt> + <dd> + ユーザーがアプリケーションでグループを表示できるようにする UI コントロールに対し、連絡先アプリケーションが表示するラベル。 + + <p> + たとえば、端末に Google+ アプリケーションをインストールし、Google+ を連絡先アプリケーションと同期すると、Google+ のサークルが連絡先アプリケーションの [<strong>グループ</strong>] タブにグループとして表示されます。 + +Google+ サークルのどれかをクリックすると、そのサークルに所属する人が「グループ」として表示されます。 +表示の最上部に、Google+ アイコンが表示されます。それをクリックすると、制御が Google+ アプリに移ります。連絡先アプリケーションはこれを {@code viewGroupActivity} を使用して行い、Google+ アイコンを {@code viewGroupActionLabel} の値として使用します。 + + + + + </p> + <p> + この属性には、文字列リソース ID を使用できます。 + </p> + </dd> + <dt>{@code viewStreamItemActivity}</dt> + <dd> + ユーザーが未加工連絡先のストリーム アイテムをタップしたときに端末の連絡先アプリケーションが起動する、独自アプリケーション内のアクティビティの完全修飾クラス名。 + + </dd> + <dt>{@code viewStreamItemPhotoActivity}</dt> + <dd> + ユーザーが未加工連絡先のストリーム アイテムで写真をタップしたときに端末の連絡先アプリケーションが起動する、独自アプリケーション内のアクティビティの完全修飾クラス名。 + + + </dd> +</dl> +<h4 id="SocialStreamDataKind"><ContactsDataKind> 要素</h4> +<p> + <code><ContactsDataKind></code> 要素は、連絡先アプリケーションにおける独自アプリケーションのカスタムデータ行の表示を管理します。構文は次のとおりです。 + +</p> +<pre> +<ContactsDataKind + android:mimeType="<em>MIMEtype</em>" + android:icon="<em>icon_resources</em>" + android:summaryColumn="<em>column_name</em>" + android:detailColumn="<em>column_name</em>"> +</pre> +<p> + <strong>含まれているファイル:</strong> +</p> +<code><ContactsAccountType></code> +<p> + <strong>説明:</strong> +</p> +<p> + この要素は、カスタムデータ行のコンテンツを未加工連絡先の詳細の一部として連絡先アプリケーションに表示させるために使用します。 +<code><ContactsAccountType></code> の各 <code><ContactsDataKind></code> 子要素は、同期アダプタが {@link android.provider.ContactsContract.Data} テーブルに追加するカスタムデータ行のタイプを表します。 + +使用するカスタム MIME タイプごとに <code><ContactsDataKind></code> 要素を 1 つ追加します。 +データを表示しないカスタムデータ行がある場合は、この要素を追加する必要はありません。 + +</p> +<p> + <strong>属性:</strong> +</p> +<dl> + <dt>{@code android:mimeType}</dt> + <dd> + {@link android.provider.ContactsContract.Data} テーブルに含まれるカスタムデータ行のどれかに定義したカスタム MIME タイプ。 +たとえば、値 <code>vnd.android.cursor.item/vnd.example.locationstatus</code> は、連絡先の最新の場所情報を記録するデータ行のためのカスタム MIME タイプということが考えられます。 + + + </dd> + <dt>{@code android:icon}</dt> + <dd> + 連絡先アプリケーションがデータの隣に表示する Android <a href="{@docRoot}guide/topics/resources/drawable-resource.html">ドローアブル リソース</a>。 + +そのデータが独自サービスからのものであることを示すのに使用します。 + + </dd> + <dt>{@code android:summaryColumn}</dt> + <dd> + データ行から取得された 2 つの値で最初の列名。この値は、このデータ行のエントリの先頭行として表示されます。 +この先頭行は、データの要約として使われることを狙ったものですが、省略可能です。 +<a href="#detailColumn">android:detailColumn</a> もご覧ください。 + + </dd> + <dt>{@code android:detailColumn}</dt> + <dd> + データ行から取得された 2 つの値で 2 番目の列名。この値は、このデータ行のエントリの 2 行目として表示されます。 +{@code android:summaryColumn} もご覧ください。 + + </dd> +</dl> +<h2 id="AdditionalFeatures">連絡先プロバイダの追加機能</h2> +<p> + ここまでのセクションで説明した主な機能の他に、連絡先プロバイダには連絡先データの作業用として次のような便利な機能が用意されています。 + +</p> + <ul> + <li>連絡先グループ</li> + <li>写真機能</li> + </ul> +<h3 id="Groups">連絡先グループ</h3> +<p> + 連絡先プロバイダでは、オプションで、関連連絡先のコレクションを<strong>グループ</strong> データでラベル付けできます。 +あるユーザー アカウントに関連付けられているサーバーがグループを管理する場合、そのアカウントのアカウント タイプ用の同期アダプタが、連絡先プロバイダとサーバーとの間でグループデータを転送する必要があります。 + +ユーザーが新しい連絡先をサーバーに追加し、その連絡先を新しいグループに入れた場合、同期アダプタはその新しいグループを {@link android.provider.ContactsContract.Groups} テーブルに追加する必要があります。 + +ある未加工連絡先が属するグループ(複数の場合あり)は、{@link android.provider.ContactsContract.Data} テーブルに、{@link android.provider.ContactsContract.CommonDataKinds.GroupMembership} MIME タイプを使用して格納されます。 + + +</p> +<p> + サーバーからの未加工連絡先データを連絡先プロバイダに追加する同期アダプタを設計している場合、グループを使用しないのであれば、連絡先プロバイダに対してデータが可視であることを通知する必要があります。 + +ユーザーがアカウントを端末に追加したときに実行されるコード内で、連絡先プロバイダがそのアカウントに対して追加する {@link android.provider.ContactsContract.Settings} 行をアップデートします。 + +この行で、{@link android.provider.ContactsContract.SettingsColumns#UNGROUPED_VISIBLE Settings.UNGROUPED_VISIBLE} 列の値を 1 に設定します。 + +こうすると、連絡先プロバイダは、グループを使用していない場合でも、独自の連絡先データを可視にします。 + +</p> +<h3 id="Photos">連絡先の写真</h3> +<p> + {@link android.provider.ContactsContract.Data} テーブルは、写真を MIME タイプ {@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE Photo.CONTENT_ITEM_TYPE} の行として格納します。 + +この行の {@link android.provider.ContactsContract.RawContactsColumns#CONTACT_ID} 列は、それが属する未加工連絡先の {@link android.provider.BaseColumns#_ID} 列にリンクされます。 + + + クラス {@link android.provider.ContactsContract.Contacts.Photo} は、連絡先のプライマリ フォトの写真情報を格納する {@link android.provider.ContactsContract.Contacts} のサブテーブルを定義します。ここでプライマリ フォトとは、連絡先のプライマリ未加工連絡先のプライマリ フォトのことを示します。 + +同様に、クラス {@link android.provider.ContactsContract.RawContacts.DisplayPhoto} は、未加工連絡先のプライマリ フォトに関する情報を含む {@link android.provider.ContactsContract.RawContacts} のサブテーブルを定義します。 + + + +</p> +<p> + {@link android.provider.ContactsContract.Contacts.Photo} と {@link android.provider.ContactsContract.RawContacts.DisplayPhoto} の参照ドキュメントには、写真情報の取得例が含まれています。 + +未加工連絡先のプライマリ サムネイルを取得するための便利なクラスはありませんが、{@link android.provider.ContactsContract.Data} テーブルにクエリを送信して、未加工連絡先の {@link android.provider.BaseColumns#_ID}、{@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE Photo.CONTENT_ITEM_TYPE}、{@link android.provider.ContactsContract.Data#IS_PRIMARY} 列を選んでその未加工連絡先のプライマリ フォト行を探すことができます。 + + + + + + +</p> +<p> + 人のソーシャル ストリーム データにも写真が含まれていることがあります。その場合は {@link android.provider.ContactsContract.StreamItemPhotos} テーブルに格納されています。このテーブルについては、<a href="#StreamPhotos">ソーシャル ストリーム フォト</a>で詳しく説明しています + + +</p> diff --git a/docs/html-intl/intl/ja/guide/topics/providers/content-provider-basics.jd b/docs/html-intl/intl/ja/guide/topics/providers/content-provider-basics.jd new file mode 100644 index 000000000000..9eef5d6eed46 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/providers/content-provider-basics.jd @@ -0,0 +1,1196 @@ +page.title=コンテンツ プロバイダの基本 +@jd:body +<div id="qv-wrapper"> +<div id="qv"> +<!-- In this document --> +<h2>本書の内容</h2> +<ol> + <li> + <a href="#Basics">概要</a> + <ol> + <li> + <a href="#ClientProvider">プロバイダにアクセスする</a> + </li> + <li> + <a href="#ContentURIs">コンテンツ URI</a> + </li> + </ol> + </li> + <li> + <a href="#SimpleQuery">プロバイダからデータを取得する</a> + <ol> + <li> + <a href="#RequestPermissions">読み取りアクセス パーミッションを要求する</a> + </li> + <li> + <a href="#Query">クエリを作成する</a> + </li> + <li> + <a href="#DisplayResults">クエリ結果を表示する</a> + </li> + <li> + <a href="#GettingResults">クエリ結果を取得する</a> + </li> + </ol> + </li> + <li> + <a href="#Permissions">コンテンツ プロバイダ パーミッション</a> + </li> + <li> + <a href="#Modifications">データを挿入、更新、削除する</a> + <ol> + <li> + <a href="#Inserting">データを挿入する</a> + </li> + <li> + <a href="#Updating">データを更新する</a> + </li> + <li> + <a href="#Deleting">データを削除する</a> + </li> + </ol> + </li> + <li> + <a href="#DataTypes">プロバイダ データタイプ</a> + </li> + <li> + <a href="#AltForms">プロバイダ アクセスの別の形式</a> + <ol> + <li> + <a href="#Batch">バッチアクセス</a> + </li> + <li> + <a href="#Intents">インテント経由のデータアクセス</a> + </li> + </ol> + </li> + <li> + <a href="#ContractClasses">コントラクト クラス</a> + </li> + <li> + <a href="#MIMETypeReference">MIME タイプ リファレンス</a> + </li> +</ol> + + <!-- Key Classes --> +<h2>キークラス</h2> + <ol> + <li> + {@link android.content.ContentProvider} + </li> + <li> + {@link android.content.ContentResolver} + </li> + <li> + {@link android.database.Cursor} + </li> + <li> + {@link android.net.Uri} + </li> + </ol> + + <!-- Related Samples --> +<h2>関連サンプル</h2> + <ol> + <li> + <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List2.html"> + Cursor (People)</a> + </li> + <li> + <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List7.html"> + Cursor (Phones)</a> + </li> + </ol> + + <!-- See also --> +<h2>関連ドキュメント</h2> + <ol> + <li> + <a href="{@docRoot}guide/topics/providers/content-provider-creating.html"> + コンテンツ プロバイダの作成</a> + </li> + <li> + <a href="{@docRoot}guide/topics/providers/calendar-provider.html"> + カレンダー プロバイダ</a> + </li> + </ol> +</div> +</div> + + <!-- Intro paragraphs --> +<p> + コンテンツ プロバイダは、データの中央リポジトリへのアクセスを管理します。プロバイダは Android アプリケーションの一部であり、通常、データを処理するための独自の UI を備えています。 + +ただし、コンテンツ プロバイダは主に他のアプリケーションでの使用を意図したものです。アプリケーションはプロバイダ クライアント オブジェクトを使用してプロバイダにアクセスします。 +さらに、プロバイダとプロバイダ クライアントにはデータを扱うための一貫性のある標準のインターフェースが備わっており、プロセス間の通信や安全なデータ アクセスを処理します。 + + +</p> +<p> + このトピックでは、次の項目に関する基本的な内容を説明します。 +</p> + <ul> + <li>コンテンツ プロバイダの仕組み。</li> + <li>コンテンツ プロバイダからのデータの取得に使用する API。</li> + <li>コンテンツ プロバイダへのデータの挿入、データの更新や削除に使用する API。</li> + <li>プロバイダでの作業に役立つその他の API 機能。</li> + </ul> + + <!-- Basics --> +<h2 id="Basics">概要</h2> +<p> + 外部アプリケーションでは、コンテンツ プロバイダのデータは、リレーショナル データベースで使用する表と同様に、1 つ以上の表として表示されます。 +行はプロバイダが収集するデータの何らかのタイプのインスタンスを表しており、行内のそれぞれの列はインスタンスに対して収集した個々のデータを表しています。 + + +</p> +<p> + たとえば、Android プラットフォームに組み込まれているプロバイダの 1 つに単語リストがありますが、ここにはユーザーが保存しておく標準以外の単語のスペリングが格納されます +表 1 は、このプロバイダの表にデータがどのように格納されているのかを表しています。 + +</p> +<p class="table-caption"> + <strong>表 1:</strong> サンプルの単語リスト表。 +</p> +<table id="table1" style="width: 50%;"> + <tr> + <th style="width:20%" align="center" scope="col">word</th> + <th style="width:20%" align="center" scope="col">app id</th> + <th style="width:20%" align="center" scope="col">frequency</th> + <th style="width:20%" align="center" scope="col">locale</th> + <th style="width:20%" align="center" scope="col">_ID</th> + </tr> + <tr> + <td align="center" scope="row">mapreduce</td> + <td align="center">user1</td> + <td align="center">100</td> + <td align="center">en_US</td> + <td align="center">1</td> + </tr> + <tr> + <td align="center" scope="row">precompiler</td> + <td align="center">user14</td> + <td align="center">200</td> + <td align="center">fr_FR</td> + <td align="center">2</td> + </tr> + <tr> + <td align="center" scope="row">applet</td> + <td align="center">user2</td> + <td align="center">225</td> + <td align="center">fr_CA</td> + <td align="center">3</td> + </tr> + <tr> + <td align="center" scope="row">const</td> + <td align="center">user1</td> + <td align="center">255</td> + <td align="center">pt_BR</td> + <td align="center">4</td> + </tr> + <tr> + <td align="center" scope="row">int</td> + <td align="center">user5</td> + <td align="center">100</td> + <td align="center">en_UK</td> + <td align="center">5</td> + </tr> +</table> +<p> + 表 1 の各行は、標準の辞書には含まれていない単語のインスタンスを表しています。 +各列は、該当する単語のデータの一部(その単語が最初に見つかったロケールなど)を表しています。 +列の見出しは、プロバイダに格納される列の名前です。 +行のロケールを調べるには、<code>locale</code> 列を参照します。このプロバイダの場合、<code>_ID</code> 列が「プライマリキー」の列の役割を果たし、プロバイダはこの列を自動的に保持します。 + + +</p> +<p class="note"> + <strong>注:</strong> プロバイダはプライマリキーを持つ必要がなく、プライマリキーがある場合は <code>_ID</code> をプライマリキーの列名として使用する必要はありません。 +ただし、プロバイダのデータを {@link android.widget.ListView} にバインドする場合は、いずれかの列の名前を <code>_ID</code> とする必要があります。 + +この要件についての詳細は、<a href="#DisplayResults">クエリ結果を表示する</a>セクションをご覧ください。 + +</p> +<h3 id="ClientProvider">プロバイダにアクセスする</h3> +<p> + アプリケーションは、{@link android.content.ContentResolver} クライアント オブジェクトを使用して、コンテンツ プロバイダのデータにアクセスします。 +このオブジェクトには、プロバイダ オブジェクトの同名のメソッドを呼び出すメソッドが備わっています。これは、{@link android.content.ContentProvider} の具体的なサブクラスのインスタンスのいずれかになります。 + +{@link android.content.ContentResolver} メソッドには、永続ストレージの基本的な「CRUD」(作成、取得、更新、削除)機能が備わっています。 + + +</p> +<p> + クライアント アプリケーションのプロセスにおける {@link android.content.ContentResolver} オブジェクトと、プロバイダを所有するアプリケーションの {@link android.content.ContentProvider} オブジェクトが、プロセス間の通信を自動的に処理します。さらに、{@link android.content.ContentProvider} は、データのリポジトリと、外部に表形式で表示されるデータの間の抽象化レイヤーとして機能します。 + + + + +</p> +<p class="note"> + <strong>注:</strong> 通常、アプリケーションがプロバイダにアクセスする場合、そのマニフェスト ファイルで特定のパーミッションを要求する必要があります。 +詳細は、<a href="#Permissions">コンテンツ プロバイダ パーミッション</a>セクションをご覧ください。 + +</p> +<p> + たとえば、単語リスト プロバイダから単語とそのロケールの一覧を取得するには、{@link android.content.ContentResolver#query ContentResolver.query()} を呼び出します。 + + {@link android.content.ContentResolver#query query()} メソッドによって、単語リスト プロバイダが定義する{@link android.content.ContentProvider#query ContentProvider.query()} メソッドが呼び出されます。 + +コードの次の行は、{@link android.content.ContentResolver#query ContentResolver.query()} 呼び出しを表しています。 + +<p> +<pre> +// Queries the user dictionary and returns results +mCursor = getContentResolver().query( + UserDictionary.Words.CONTENT_URI, // The content URI of the words table + mProjection, // The columns to return for each row + mSelectionClause // Selection criteria + mSelectionArgs, // Selection criteria + mSortOrder); // The sort order for the returned rows +</pre> +<p> + 表 2 は、query(Uri,projection,selection,selectionArgs,sortOrder)} の引数が SQL SELECT 文にどのように一致しているかを示しています。 + + +</p> +<p class="table-caption"> + <strong>表 2:</strong> SQL クエリと比較した Query()。 +</p> +<table id="table2" style="width: 75%;"> + <tr> + <th style="width:25%" align="center" scope="col">query() 引数</th> + <th style="width:25%" align="center" scope="col">SELECT キーワード / パラメータ</th> + <th style="width:50%" align="center" scope="col">注</th> + </tr> + <tr> + <td align="center"><code>Uri</code></td> + <td align="center"><code>FROM <em>table_name</em></code></td> + <td><code>Uri</code> は、<em>table_name</em> という名前のプロバイダの表にマッピングされます。</td> + </tr> + <tr> + <td align="center"><code>projection</code></td> + <td align="center"><code><em>col,col,col,...</em></code></td> + <td> + <code>projection</code> は、取得するそれぞれの行に含まれる列の配列です。 + + </td> + </tr> + <tr> + <td align="center"><code>selection</code></td> + <td align="center"><code>WHERE <em>col</em> = <em>value</em></code></td> + <td><code>selection</code> は、行を選択する際の基準を指定します。</td> + </tr> + <tr> + <td align="center"><code>selectionArgs</code></td> + <td align="center"> + (正確に一致するものはありません。選択句では、<code>?</code> プレースホルダーが選択引数に置き換わります) + + </td> + </tr> + <tr> + <td align="center"><code>sortOrder</code></td> + <td align="center"><code>ORDER BY <em>col,col,...</em></code></td> + <td> + <code>sortOrder</code> は、返される {@link android.database.Cursor} 内で行が表示される順番を指定します。 + + </td> + </tr> +</table> +<h3 id="ContentURIs">コンテンツ URI</h3> +<p> + <strong>コンテンツ URI</strong> は、プロバイダのデータを特定する URI です。コンテンツ URI には、プロバイダ全体の識別名(<strong>認証局</strong>)と表をポイントする名前(<strong>パス</strong>)が含まれます。 + +プロバイダの表にアクセスするためのクライアント メソッドを呼び出す場合、その引数の 1 つがコンテンツ URI になります。 + + +</p> +<p> + コードの前半の行では、定数 {@link android.provider.UserDictionary.Words#CONTENT_URI} に、単語リストの「words」表のコンテンツ URI が入ります。 + +{@link android.content.ContentResolver} オブジェクトは URI の認証局をパースし、認証局を既知のプロバイダのシステム表と比較して、プロバイダを「解決」します。 + +その後、{@link android.content.ContentResolver} は、クエリ引数を正しいプロバイダに送信できます。 + + +</p> +<p> + {@link android.content.ContentProvider} は、アクセスする表を選択するのに、コンテンツ URI のパス部分を使用します。 +通常、プロバイダは公開する各表の<strong>パス</strong>を持ちます。 +</p> +<p> + コードの前半の行では、「words」表の完全な URI は次のようになります。 +</p> +<pre> +content://user_dictionary/words +</pre> +<p> + ここで、<code>user_dictionary</code> 文字列はプロバイダの認証局になり、<code>words</code> 文字列は表のパスになります。 +文字列 <code>content://</code>(<strong>スキーム</strong>)は常に存在し、これがコンテンツ URI であることを示します。 + + +</p> +<p> + 多くのプログラムでは、URI の末尾に ID 値を付加することで、表内の 1 つの行にアクセスできます。たとえば、<code>_ID</code> が <code>4</code> の行を単語リストから取得するには、次のコンテンツ URI を使用します。 + + +</p> +<pre> +Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI,4); +</pre> +<p> + 通常は、一連の行を取得してからいずれかの行を更新、削除するような場合に ID 値を使用します。 + +</p> +<p class="note"> + <strong>注:</strong> {@link android.net.Uri} クラスと {@link android.net.Uri.Builder} クラスには、正しい形式の URI オブジェクトを文字列から作成するための、便利なメソッドが用意されています。 +{@link android.content.ContentUris} には、URI に ID 値を付加するための便利なメソッドが用意されています。前述のスニペットは {@link android.content.ContentUris#withAppendedId + withAppendedId()} を使用して、UserDictionary コンテンツ URI に ID を付加しています。 + + +</p> + + + <!-- Retrieving Data from the Provider --> +<h2 id="SimpleQuery">プロバイダからデータを取得する</h2> +<p> + このセクションでは、単語リスト プロバイダの例を使い、プロバイダからデータを取得する方法を説明します。 + +</p> +<p class="note"> + わかりやすくするために、このセクションのコード スニペットは「UI スレッド」の {@link android.content.ContentResolver#query ContentResolver.query()} を呼び出しています。 +ただし、実際のコードでは、個別のスレッドで非同期にクエリを実行する必要があります。 +この操作は、{@link android.content.CursorLoader} クラスを使用して行うこともできます。このクラスについての詳細は、「<a href="{@docRoot}guide/components/loaders.html">ローダ</a>」に関するガイドをご覧ください。 + + +さらに、コードの行はスニペットのみであり、完全なアプリケーションにはなっていません。 + +</p> +<p> + プロバイダからデータを取得するには、次の基本的な手順に従います。 +</p> +<ol> + <li> + プロバイダの読み取りアクセスを要求します。 + </li> + <li> + プロバイダにクエリを送信するコードを定義します。 + </li> +</ol> +<h3 id="RequestPermissions">読み取りアクセス パーミッションを要求する</h3> +<p> + プロバイダからデータを取得するには、アプリケーションからプロバイダの読み取りアクセスを要求します。 +実行時にはこのパーミッションを要求できません。その代わりに、<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a></code> 要素とプロバイダで定義した正確なパーミッション名を使用して、このパーミッションを必要としていることをマニフェストで指定する必要があります。 + + + +この要素をマニフェストで指定すると、実際に、このパーミッションをアプリケーションに「要求」することになります。 +ユーザーがアプリケーションをインストールすると、この要求が暗黙的に付与されることになります。 + +</p> +<p> + 使用する読み取りアクセス パーミッションの正確な名前と、プロバイダが使用するその他のアクセス パーミッションの名前については、プロバイダのドキュメントをご覧ください。 + + +</p> +<p> + プロバイダにアクセスする際のパーミッションのロールの詳細は、<a href="#Permissions">コンテンツ プロバイダ パーミッション</a>セクションをご覧ください。 + +</p> +<p> + 単語リスト プロバイダはパーミッション <code>android.permission.READ_USER_DICTIONARY</code> をマニフェスト ファイルで定義するため、プロバイダからの読み取りを行うアプリケーションはこのパーミッションを要求する必要があります。 + + +</p> +<!-- Constructing the query --> +<h3 id="Query">クエリを作成する</h3> +<p> + プロバイダからのデータの取得の次の手順では、クエリを作成します。最初のスニペットで、単語リスト プロバイダにアクセスするための変数をいくつか定義します。 + +</p> +<pre class="prettyprint"> + +// A "projection" defines the columns that will be returned for each row +String[] mProjection = +{ + UserDictionary.Words._ID, // Contract class constant for the _ID column name + UserDictionary.Words.WORD, // Contract class constant for the word column name + UserDictionary.Words.LOCALE // Contract class constant for the locale column name +}; + +// Defines a string to contain the selection clause +String mSelectionClause = null; + +// Initializes an array to contain selection arguments +String[] mSelectionArgs = {""}; + +</pre> +<p> + 次のスニペットでは、単語リスト プロバイダの例を使って、{@link android.content.ContentResolver#query ContentResolver.query()} を使用する方法を示しています。 + +プロバイダ クライアント クエリは SQL クエリに似たものであり、戻り値となる一連の列、一連の選択基準、並べ替えの順番を含みます。 + +</p> +<p> + クエリの戻り値となる一連の列は、<strong>投影</strong>(変数 <code>mProjection</code>)と呼ばれます。 + +</p> +<p> + 取得する行を指定する式は、選択句と選択引数に分割されます。 +選択句は論理式やブール式、列名、値(変数 <code>mSelectionClause</code>)の組み合わせになります。 +値の代わりに置き換え可能パラメータ <code>?</code> を指定すると、クエリ メソッドによって、選択引数の配列(変数 <code>mSelectionArgs</code>)から値が取得されます。 + + +</p> +<p> + 次のスニペットでは、ユーザーが単語を入力しない場合、選択句が <code>null</code> に設定され、クエリによってプロバイダのすべての単語が返されます。 +ユーザーが単語を入力すると、選択句が <code>UserDictionary.Words.WORD + " = ?"</code> に設定され、選択引数の配列の最初の要素が、ユーザーが入力した単語に設定されます。 + + +</p> +<pre class="prettyprint"> +/* + * This defines a one-element String array to contain the selection argument. + */ +String[] mSelectionArgs = {""}; + +// Gets a word from the UI +mSearchString = mSearchWord.getText().toString(); + +// Remember to insert code here to check for invalid or malicious input. + +// If the word is the empty string, gets everything +if (TextUtils.isEmpty(mSearchString)) { + // Setting the selection clause to null will return all words + mSelectionClause = null; + mSelectionArgs[0] = ""; + +} else { + // Constructs a selection clause that matches the word that the user entered. + mSelectionClause = UserDictionary.Words.WORD + " = ?"; + + // Moves the user's input string to the selection arguments. + mSelectionArgs[0] = mSearchString; + +} + +// Does a query against the table and returns a Cursor object +mCursor = getContentResolver().query( + UserDictionary.Words.CONTENT_URI, // The content URI of the words table + mProjection, // The columns to return for each row + mSelectionClause // Either null, or the word the user entered + mSelectionArgs, // Either empty, or the string the user entered + mSortOrder); // The sort order for the returned rows + +// Some providers return null if an error occurs, others throw an exception +if (null == mCursor) { + /* + * Insert code here to handle the error. Be sure not to use the cursor! You may want to + * call android.util.Log.e() to log this error. + * + */ +// If the Cursor is empty, the provider found no matches +} else if (mCursor.getCount() < 1) { + + /* + * Insert code here to notify the user that the search was unsuccessful. This isn't necessarily + * an error. You may want to offer the user the option to insert a new row, or re-type the + * search term. + */ + +} else { + // Insert code here to do something with the results + +} +</pre> +<p> + このクエリは、 SQL 文に似ています。 +</p> +<pre> +SELECT _ID, word, locale FROM words WHERE word = <userinput> ORDER BY word ASC; +</pre> +<p> + この SQL 文では、コントラクト クラスの定数ではなく、実際の列の名前が使用されます。 +</p> +<h4 id="Injection">悪意のある入力から保護する</h4> +<p> + コンテンツ プロバイダが管理するデータが SQL データベース内にある場合、外部の信頼されていないデータを未処理の SQL 文に含めると SQL インジェクションが発生することがあります。 + +</p> +<p> + 次のような選択句を考えてみます。 +</p> +<pre> +// Constructs a selection clause by concatenating the user's input to the column name +String mSelectionClause = "var = " + mUserInput; +</pre> +<p> + このようにすれば、ユーザーが悪意のある SQL を SQL 文に連結できるようになります。 + たとえば、ユーザーが <code>mUserInput</code> に「nothing; DROP TABLE *;」と入力すると、選択句は <code>var = nothing; DROP TABLE *;</code> となります。 +選択句は SQL 文として処理されるため、この場合、基本的な SQLite データベースのすべての表が消去されることがあります(プロバイダに <a href="http://en.wikipedia.org/wiki/SQL_injection">SQL インジェクション</a>の試みの検出が設定されていない場合)。 + + + +</p> +<p> + この問題を回避するには、<code>?</code> を置き換え可能パラメータとして使う選択句と、選択引数の個別の配列を使用します。 +そうすることで、ユーザー入力は、SQL 文の一部として解釈されずに、クエリに直接バインドされます。 + + SQL として扱われないため、ユーザー入力によって悪意のある SQL が挿入されることはありません。ユーザー入力を含める際に連結を使用しないで、次の選択句を使用します。 + +</p> +<pre> +// Constructs a selection clause with a replaceable parameter +String mSelectionClause = "var = ?"; +</pre> +<p> + 選択引数の配列を次のように設定します。 +</p> +<pre> +// Defines an array to contain the selection arguments +String[] selectionArgs = {""}; +</pre> +<p> + 選択引数の配列に次のように値を格納します。 +</p> +<pre> +// Sets the selection argument to the user's input +selectionArgs[0] = mUserInput; +</pre> +<p> + プロバイダが SQL データベースに基づいたものではない場合でも、選択内容を指定する場合は、<code>?</code> を置き換え可能パラメータとして使う選択句と、選択引数の配列を使用することをお勧めします。 + + +</p> +<!-- Displaying the results --> +<h3 id="DisplayResults">クエリ結果を表示する</h3> +<p> + {@link android.content.ContentResolver#query ContentResolver.query()} クライアント メソッドは、常に {@link android.database.Cursor} を返します。これには、クエリの選択基準に一致する、行へのクエリの投影によって指定される列が含まれます。 + +{@link android.database.Cursor} オブジェクトは、含まれる行と列へのランダム読み取りアクセスを提供します。 + +{@link android.database.Cursor} メソッドを使用すると、結果の行の繰り返し、各列のデータタイプの識別、列からのデータの取得、結果のその他のプロパティの確認といった操作が可能となります。 + +一部の {@link android.database.Cursor} を実装すると、プロバイダのデータが変更された場合にオブジェクトが自動的に送信されたり、{@link android.database.Cursor} が変更された場合にオブザーバ オブジェクトのメソッドがトリガーされたり、その両方が実行されたりします。 + + +</p> +<p class="note"> + <strong>注:</strong> クエリを作成するオブジェクトの特性に基づいて、プロバイダによって列へのアクセスが制限されることがあります。 +たとえば、連絡先プロバイダにより同期アダプタは一部の列へのアクセスが制限されるため、その場合はアクティビティやサービスを返しません。 + +</p> +<p> + 選択基準に一致する行がない場合は、{@link android.database.Cursor#getCount Cursor.getCount()} が 0(空のカーソル)の {@link android.database.Cursor} オブジェクトを返します。 + + +</p> +<p> + 内部エラーが発生した場合、クエリの結果はプロバイダによって異なります。<code>null</code> が返されることもあれば、{@link java.lang.Exception} がスローされることもあります。 + +</p> +<p> + {@link android.database.Cursor} は行の「一覧」であることから、{@link android.database.Cursor} のコンテンツを表示する場合は、{@link android.widget.SimpleCursorAdapter} 経由で {@link android.widget.ListView} にリンクすることをお勧めします。 + + +</p> +<p> + 次のスニペットは前のスニペットのコードの続きです。クエリによって取得する {@link android.database.Cursor} を含む {@link android.widget.SimpleCursorAdapter} オブジェクトを作成し、このオブジェクトを {@link android.widget.ListView} のアダプタに設定します。 + + + +</p> +<pre class="prettyprint"> +// Defines a list of columns to retrieve from the Cursor and load into an output row +String[] mWordListColumns = +{ + UserDictionary.Words.WORD, // Contract class constant containing the word column name + UserDictionary.Words.LOCALE // Contract class constant containing the locale column name +}; + +// Defines a list of View IDs that will receive the Cursor columns for each row +int[] mWordListItems = { R.id.dictWord, R.id.locale}; + +// Creates a new SimpleCursorAdapter +mCursorAdapter = new SimpleCursorAdapter( + getApplicationContext(), // The application's Context object + R.layout.wordlistrow, // A layout in XML for one row in the ListView + mCursor, // The result from the query + mWordListColumns, // A string array of column names in the cursor + mWordListItems, // An integer array of view IDs in the row layout + 0); // Flags (usually none are needed) + +// Sets the adapter for the ListView +mWordList.setAdapter(mCursorAdapter); +</pre> +<p class="note"> + <strong>注:</strong> {@link android.database.Cursor} によって {@link android.widget.ListView} を戻すには、カーソルに <code>_ID</code> という名前の列を含める必要があります。 + + そのため、{@link android.widget.ListView} には表示されまませんが、前述のクエリは「words」表に <code>_ID</code> 列を取得します。 + + また、このような制限があることから、大部分のプロバイダがそれぞれの表に <code>_ID</code> 列を持ちます。 + +</p> + + <!-- Getting data from query results --> +<h3 id="GettingResults">クエリ結果を取得する</h3> +<p> + クエリ結果を単に表示するだけでなく、他のタスクに使用することもできます。たとえば、単語リストからスペリングを取得して、それを他のプロバイダで検索するといった操作も可能です。 + +そのためには、次のように {@link android.database.Cursor} の行に操作を繰り返します。 +</p> +<pre class="prettyprint"> + +// Determine the column index of the column named "word" +int index = mCursor.getColumnIndex(UserDictionary.Words.WORD); + +/* + * Only executes if the cursor is valid. The User Dictionary Provider returns null if + * an internal error occurs. Other providers may throw an Exception instead of returning null. + */ + +if (mCursor != null) { + /* + * Moves to the next row in the cursor. Before the first movement in the cursor, the + * "row pointer" is -1, and if you try to retrieve data at that position you will get an + * exception. + */ + while (mCursor.moveToNext()) { + + // Gets the value from the column. + newWord = mCursor.getString(index); + + // Insert code here to process the retrieved word. + + ... + + // end of while loop + } +} else { + + // Insert code here to report an error if the cursor is null or the provider threw an exception. +} +</pre> +<p> + {@link android.database.Cursor} の実装には「取得」メソッドがいくつか備わっており、オブジェクトからさまざまなタイプのデータを取得できます。 +たとえば、前述のスニペットは {@link android.database.Cursor#getString getString()} を使用しています。 +さらに、列のデータタイプを示す値を返す {@link android.database.Cursor#getType getType()} メソッドも使用しています。 + + +</p> + + + <!-- Requesting permissions --> +<h2 id="Permissions">コンテンツ プロバイダ パーミッション</h2> +<p> + プロバイダのアプリケーションでは、他のアプリケーションがプロバイダのデータにアクセスするのに必要なパーミッションを指定できます。 +これらのパーミッションを設定しておけば、ユーザーはアプリケーションがアクセスしようとしているデータの種類を把握できます。 +他のアプリケーションは、プロバイダの要件に基づき、そのプロバイダにアクセスするのに必要なパーミッションを要求します。 +エンドユーザーがアプリケーションをインストールする際には、要求されたパーミッションを確認できます。 + +</p> +<p> + プロバイダのアプリケーションでパーミッションを指定していない場合は、他のアプリケーションはプロバイダのデータにアクセスできません。 +ただし、指定したパーミッションに関係なく、プロバイダのアプリケーションのコンポーネントには完全な読み取り権限と書き込み権限を常に付与する必要があります。 + +</p> +<p> + 前述のとおり、単語リスト プロバイダには、データを取得するための <code>android.permission.READ_USER_DICTIONARY</code> パーミッションが必要です。 + + プロバイダには、データの挿入、更新、削除に対してそれぞれ個別の <code>android.permission.WRITE_USER_DICTIONARY</code> パーミッションがあります。 + +</p> +<p> + プロバイダにアクセスするのに必要なパーミッションを取得するには、アプリケーションのマニフェスト ファイルの <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a></code> 要素を使用してパーミッションを要求する必要があります。 + +Android Package Manager でアプリケーションをインストールする場合は、ユーザーがアプリケーションが要求するすべてのパーミッションを承認する必要があります。 +ユーザーがすべてのパーミッションを承認すると、Package Manager がインストールを続行します。ユーザーが承認しない場合は、Package Manager がインストールを中止します。 + + +</p> +<p> + 次の <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a></code> 要素は、単語リスト プロバイダへの読み取りアクセスを要求します。 + + +</p> +<pre> + <uses-permission android:name="android.permission.READ_USER_DICTIONARY"> +</pre> +<p> + プロバイダ アクセスへのパーミッションの影響については、<a href="{@docRoot}guide/topics/security/security.html">セキュリティとパーミッション</a>に関するガイドをご覧ください。 + +</p> + + +<!-- Inserting, Updating, and Deleting Data --> +<h2 id="Modifications">データを挿入、更新、削除する</h2> +<p> + データを収集するには、プロバイダからデータを取得するのと同様に、プロバイダ クライアントとプロバイダの {@link android.content.ContentProvider} 間で操作を行います。 + + 対応する {@link android.content.ContentProvider} のメソッドに渡した引数を使用して、{@link android.content.ContentResolver} のメソッドを呼び出します。 +プロバイダとプロバイダ クライアントが、セキュリティとプロセス間の通信を自動的に処理します。 + +</p> +<h3 id="Inserting">データを挿入する</h3> +<p> + プロバイダにデータを挿入するには、{@link android.content.ContentResolver#insert ContentResolver.insert()} メソッドを呼び出します。 + +このメソッドはプロバイダに新しい行を挿入し、その行のコンテンツ URI を返します。 + このスニペットは、単語リスト プロバイダに新しい単語を挿入する方法を示しています。 +</p> +<pre class="prettyprint"> +// Defines a new Uri object that receives the result of the insertion +Uri mNewUri; + +... + +// Defines an object to contain the new values to insert +ContentValues mNewValues = new ContentValues(); + +/* + * Sets the values of each column and inserts the word. The arguments to the "put" + * method are "column name" and "value" + */ +mNewValues.put(UserDictionary.Words.APP_ID, "example.user"); +mNewValues.put(UserDictionary.Words.LOCALE, "en_US"); +mNewValues.put(UserDictionary.Words.WORD, "insert"); +mNewValues.put(UserDictionary.Words.FREQUENCY, "100"); + +mNewUri = getContentResolver().insert( + UserDictionary.Word.CONTENT_URI, // the user dictionary content URI + mNewValues // the values to insert +); +</pre> +<p> + 新しい行のデータは 1 つの {@link android.content.ContentValues} オブジェクトに入ります。これは 1 行カーソルの形式に似ています。 +このオブジェクト内の列は同じデータタイプを持つ必要はなく、値をまったく指定しない場合は、{@link android.content.ContentValues#putNull ContentValues.putNull()} を使用して列を <code>null</code> に設定できます。 + + +</p> +<p> + この列は自動的に保持されるため、スニペットは <code>_ID</code> 列を追加しません。 +プロバイダは、追加するそれぞれの行に、<code>_ID</code> の一意の値を割り当てます。 +通常、プロバイダはこの値を表のプライマリキーとして使用します。 +</p> +<p> + <code>newUri</code> で返されるコンテンツ URI は、新たに追加された行を特定するものであり、次の形式となります。 + +</p> +<pre> +content://user_dictionary/words/<id_value> +</pre> +<p> + <code><id_value></code> は、新しい行の <code>_ID</code> のコンテンツです。 + ほとんどのプロバイダではコンテンツ URI のこの形式を自動的に検出し、特定の行で要求された操作を実行します。 + +</p> +<p> + 返された {@link android.net.Uri} から <code>_ID</code> の値を取得するには、{@link android.content.ContentUris#parseId ContentUris.parseId()} を呼び出します。 + +</p> +<h3 id="Updating">データを更新する</h3> +<p> + 行を更新するには、挿入操作と同じように、値を更新した {@link android.content.ContentValues} オブジェクトと、クエリ操作のときと同じように選択基準を使用します。 + + 使用するクライアント メソッドは {@link android.content.ContentResolver#update ContentResolver.update()} です。 +更新する列の {@link android.content.ContentValues} オブジェクトに値を追加する操作のみが必要になります。 +列のコンテンツを消去する場合は、値を <code>null</code> に設定します。 + +</p> +<p> + 次のスニペットは、ロケール言語が「en」となっているすべての行のロケールを <code>null</code> に変更します。 +戻り値は、更新された行の数となります。 +</p> +<pre> +// Defines an object to contain the updated values +ContentValues mUpdateValues = new ContentValues(); + +// Defines selection criteria for the rows you want to update +String mSelectionClause = UserDictionary.Words.LOCALE + "LIKE ?"; +String[] mSelectionArgs = {"en_%"}; + +// Defines a variable to contain the number of updated rows +int mRowsUpdated = 0; + +... + +/* + * Sets the updated value and updates the selected words. + */ +mUpdateValues.putNull(UserDictionary.Words.LOCALE); + +mRowsUpdated = getContentResolver().update( + UserDictionary.Words.CONTENT_URI, // the user dictionary content URI + mUpdateValues // the columns to update + mSelectionClause // the column to select on + mSelectionArgs // the value to compare to +); +</pre> +<p> + また、{@link android.content.ContentResolver#update ContentResolver.update()} を呼び出すときには、ユーザー入力をサニタイズする必要があります。 +詳細は、<a href="#Injection">悪意のある入力から保護する</a>セクションをご覧ください。 + +</p> +<h3 id="Deleting">データを削除する</h3> +<p> + 行の削除は行データの取得と似た操作になります。削除する行の選択基準を指定することで、クライアント メソッドが削除した行の数を返します。 + + 次のスニペットは appid が「user」となっている行を削除します。メソッドによって削除された行の数が返されます。 + +</p> +<pre> + +// Defines selection criteria for the rows you want to delete +String mSelectionClause = UserDictionary.Words.APP_ID + " LIKE ?"; +String[] mSelectionArgs = {"user"}; + +// Defines a variable to contain the number of rows deleted +int mRowsDeleted = 0; + +... + +// Deletes the words that match the selection criteria +mRowsDeleted = getContentResolver().delete( + UserDictionary.Words.CONTENT_URI, // the user dictionary content URI + mSelectionClause // the column to select on + mSelectionArgs // the value to compare to +); +</pre> +<p> + また、{@link android.content.ContentResolver#delete ContentResolver.delete()} を呼び出すときには、ユーザー入力をサニタイズする必要があります。 +詳細は、<a href="#Injection">悪意のある入力から保護する</a>セクションをご覧ください。 + +</p> +<!-- Provider Data Types --> +<h2 id="DataTypes">プロバイダ データタイプ</h2> +<p> + コンテンツ プロバイダではさまざまなデータタイプを利用できます。単語リスト プロバイダで提供できるのはテキストのみですが、次のような形式を提供できます。 + +</p> + <ul> + <li> + 整数 + </li> + <li> + long 整数(long) + </li> + <li> + 浮動小数点 + </li> + <li> + long 浮動小数点(double) + </li> + </ul> +<p> + それ以外にも、プロバイダでは 64KB バイト配列として実装されるバイナリ ラージ オブジェクト(BLOB)もよく使用されます。 +利用可能なデータタイプについては、{@link android.database.Cursor} クラスの「get」メソッドをご覧ください。 + +</p> +<p> + プロバイダの各列のデータタイプは、通常、そのドキュメントに一覧が記載されています。 + 単語リスト プロバイダのデータタイプは、コントラクト クラス {@link android.provider.UserDictionary.Words} のリファレンスに一覧が記載されています(コントラクト クラスの詳細は、<a href="#ContractClasses">コントラクト クラス</a>セクションをご覧ください)。 + + + さらに、{@link android.database.Cursor#getType + Cursor.getType()} を呼び出すことで、データタイプを判断することもできます。 +</p> +<p> + プロバイダは、プロバイダによって定義される各コンテンツ URI の MIME データタイプも保持します。MIME タイプ情報を使用すると、プロバイダが提供するデータをアプリケーションが処理できるかを判断したり、MIME タイプに基づいて処理のタイプを選択したりできます。 + +通常は、複雑なデータ構造やファイルを持つプロバイダで作業をする際に MIME タイプが必要になります。 + +たとえば、連絡先プロバイダの {@link android.provider.ContactsContract.Data} 表は MIME タイプを使用して、それぞれの行に格納される連絡先データのタイプをラベル付けします。 + +コンテンツ URI に対応する MIME タイプを取得するには、{@link android.content.ContentResolver#getType ContentResolver.getType()} を呼び出します。 + +</p> +<p> + 「<a href="#MIMETypeReference">MIME タイプ リファレンス</a>」セクションでは、標準とカスタムの両方の MIME タイプについて説明しています。 + +</p> + + +<!-- Alternative Forms of Provider Access --> +<h2 id="AltForms">プロバイダ アクセスの別の形式</h2> +<p> + アプリケーションの開発では、次に示すプロバイダ アクセスの別の 3 つの形式が重要になります。 +</p> +<ul> + <li> + <a href="#Batch">バッチアクセス</a>: {@link android.content.ContentProviderOperation} クラスのメソッドを使用したアクセス呼び出しのバッチを作成し、{@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()} に適用できます。 + + + </li> + <li> + 非同期クエリ: クエリは個別のスレッドで実行する必要があります。この操作は、{@link android.content.CursorLoader} オブジェクトを使用して行うこともできます。 +「<a href="{@docRoot}guide/components/loaders.html">ローダ</a>」のガイドには、この操作の例が記載されています。 + + + </li> + <li> + <a href="#Intents">インテント経由のデータアクセス</a>: インテントをプロバイダに直接送信できませんが、プロバイダのアプリケーションにはインテントを送信できます。通常、プロバイダのデータの修正に最適な機能を備えたアプリケーションになります。 + + + </li> +</ul> +<p> + バッチアクセスとインテント経由の修正については、次のセクションで説明しています。 +</p> +<h3 id="Batch">バッチアクセス</h3> +<p> + 多数の行を挿入する場合や、同じメソッド呼び出しで複数の表に行を挿入する場合は、プロバイダへのバッチアクセスを使用すると便利です。また、一般的には、境界をまたいでプロセス全体にトランザクションとして一連の操作を実行する場合にもバッチアクセスが便利です。 + + +</p> +<p> + 「バッチモード」でプロバイダにアクセスするには、{@link android.content.ContentProviderOperation} オブジェクトの配列を作成してから、{@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()} を使用してそれらのオブジェクトをコンテンツ プロバイダに送信します。 + + +このメソッドには、特定のコンテンツ URI ではなく、コンテンツ プロバイダの<em>認証局</em>を渡します。そうすることで、配列内のそれぞれの {@link android.content.ContentProviderOperation} オブジェクトを別々の表に対して機能するようになります。 + + +{@link android.content.ContentResolver#applyBatch + ContentResolver.applyBatch()} への呼び出しでは、結果の配列が返されます。 +</p> +<p> + {@link android.provider.ContactsContract.RawContacts} コントラクト クラスの説明には、バッチ挿入を示したコード スニペットが記載されています。 +<a href="{@docRoot}resources/samples/ContactManager/index.html">Contact Manager</a> のサンプル アプリケーションでは、<code>ContactAdder.java</code> ソースファイルでのバッチアクセスの例が紹介されています。 + + + +</p> +<div class="sidebox-wrapper"> +<div class="sidebox"> +<h2>ヘルパーアプリでデータを表示する</h2> +<p> + アプリケーションにアクセス パーミッションが<em>付与されている</em>場合でも、インテントを使用して別のアプリケーションにデータを表示できます。 +たとえば、カレンダー アプリケーションは {@link android.content.Intent#ACTION_VIEW} インテントにアクセスしますが、このインテントは特定の日付やイベントを表示するものです。 + + これにより、独自の UI を作成しなくても、カレンダー情報を表示できます。この機能の詳細は、「<a href="{@docRoot}guide/topics/providers/calendar-provider.html">カレンダー プロバイダ</a>」のガイドをご覧ください。 + + +</p> +<p> + インテントの送信先アプリケーションは、必ずしもプロバイダに関連付けられたアプリケーションである必要はありません。 +たとえば、連絡先プロバイダから連絡先を取得してから、連絡先の画像のコンテンツ URI を含む {@link android.content.Intent#ACTION_VIEW} インテントを画像ビューワに送信するといった操作が可能です。 + + +</p> +</div> +</div> +<h3 id="Intents">インテント経由のデータアクセス</h3> +<p> + インテントを使用すれば、コンテンツ プロバイダに間接的にアクセスできます。アプリケーションにアクセス パーミッションがない場合でも、パーミッションを持つアプリケーションから結果のインテントを取得したり、パーミッションを持つアプリケーションをアクティベートしてそのアプリケーションをユーザーに使用させたりすることで、ユーザーがプロバイダのデータにアクセスできるようになります。 + + + +</p> +<h4>一時的なパーミッションによりアクセスを取得する</h4> +<p> + 適切なアクセス パーミッションがない場合でも、パーミッションを持つアプリケーションにインテントを送信し、「URI」パーミッションを含む結果のインテントを受け取ることで、コンテンツ プロバイダのデータにアクセスできます。 + + + これらのパーミッションは特定のコンテンツ URI のパーミッションであり、パーミッションを受け取ったアクティビティが終了するまで効力を持ちます。 +永続的なパーミッションを持つアプリケーションは、次のように結果のインテントにフラグを設定し、一時的なパーミッションを付与します。 + +</p> +<ul> + <li> + <strong>読み取りパーミッション:</strong> {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} + + </li> + <li> + <strong>書き込みパーミッション:</strong> {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION} + + </li> +</ul> +<p class="note"> + <strong>注:</strong> これらのフラグは、認証局がコンテンツ URI に含まれるプロバイダへの全般的な読み取りと書き込みアクセスを付与するものではありません。アクセスは URI 自身に限定されます。 + +</p> +<p> + プロバイダは、<code><a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a></code> 要素の <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">android:grantUriPermission</a></code> 属性や、<code><a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a></code> 要素の <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html"><grant-uri-permission></a></code> 子要素を使用して、コンテンツ URI の URI パーミッションを自身のマニフェストで定義します。 + + + + + + + +URI パーミッションのメカニズムについての詳細は、URI パーミッション セクションの<a href="{@docRoot}guide/topics/security/security.html">セキュリティとパーミッション</a>に関するガイドをご覧ください。 + + +</p> +<p> + たとえば、{@link android.Manifest.permission#READ_CONTACTS} パーミッションを持たない場合でも、連絡先プロバイダの連絡先のデータを取得できます。 +連絡先の誕生日にグリーティング カードをオンラインで送信するアプリケーションなどにこのメカニズムを利用できます。 +ユーザーのすべての連絡先やそのすべての情報へのアクセス件を付与する {@link android.Manifest.permission#READ_CONTACTS} を要求する代わりに、アプリケーションで使用する連絡先をユーザーが制御できるように設定することもできます。 + + +そのためには、次の手順を使用します。 +</p> +<ol> + <li> + アプリケーションが、メソッド {@link android.app.Activity#startActivityForResult + startActivityForResult()} を使用して、アクション {@link android.content.Intent#ACTION_PICK} と「連絡先」MIME タイプ {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE} を含むインテントを送信します。 + + + + </li> + <li> + このインテントは連絡帳アプリの「selection」アクティビティのインテント フィルタに一致するため、アクティビティがフォアグラウンドに移動します。 + + </li> + <li> + selection アクティビティでは、更新する連絡先をユーザーが選択します。 +この操作が行われると、selection が {@link android.app.Activity#setResult setResult(resultcode, intent)} を呼び出し、アプリケーションに戻すインテントを設定します。 + +インテントには、ユーザーが選択した連絡先のコンテンツ URI と、「エクストラ」フラグ {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} が含まれます。 + +これらのフラグがあることで、コンテンツ URI がポイントする連絡先のデータを読み取るための URI パーミッションがアプリに付与されます。その後、selection アクティビティによって、アプリケーションに制御を返すための {@link android.app.Activity#finish()} が呼び出されます。 + + + + </li> + <li> + アクティビティがフォアグラウンドに戻り、システムがアクティビティの {@link android.app.Activity#onActivityResult onActivityResult()} メソッドを呼び出します。 + +このメソッドは、連絡帳アプリの selection アクティビティによって作成された結果のインテントを受け取ります。 + + </li> + <li> + 結果のインテントのコンテンツ URI を使用すれば、マニフェストで永続的なアクセス パーミッションをプロバイダに要求していなくても、連絡先プロバイダから連絡先のデータを読み取ることができます。 + +その後、連絡先の誕生日情報やメールアドレスを取得し、グリーティング カードをオンラインで送信できます。 + + </li> +</ol> +<h4>別のアプリケーションを使用する</h4> +<p> + パーミッションを持つアプリケーションをアクティベートし、そのアプリケーションをユーザーが使用すれば、アクセス パーミッションを持たないデータをユーザーが修正できるようになります。 + +</p> +<p> + たとえば、アプリケーションの挿入 UI をアクティベートできる {@link android.content.Intent#ACTION_INSERT} インテントをカレンダー アプリケーションが受け入れるとします。このインテントに「エクストラ」データを渡すことで、アプリケーションがそのデータを使用して、事前に入力された UI を作成します。繰り返し発生するイベントは複雑な構文を持つため、カレンダー プロバイダにイベントを挿入する場合は、{@link android.content.Intent#ACTION_INSERT} でカレンダー アプリをアクティベートしてから、ユーザーにイベントを挿入してもらうことをお勧めします。 + + + + + +</p> +<!-- Contract Classes --> +<h2 id="ContractClasses">コントラクト クラス</h2> +<p> + コントラクト クラスは、アプリケーションがコンテンツ URI、列名、インテント アクション、コンテンツのその他の機能で作業する際に役立つ定数を定義します。 +プロバイダでコントラクト クラスが自動的に含まれることはありません。プロバイダのデベロッパーはコントラクト クラスを定義して、その他のデベロッパーが使用できるようにする必要があります。 + +Android プラットフォームに含まれる多くのプロバイダは、パッケージ {@link android.provider} 内に対応するコントラクト クラスを持ちます。 + +</p> +<p> + たとえば、単語リスト プロバイダは、コンテンツ URI と列名の定数を含む、コントラクト クラス {@link android.provider.UserDictionary} を持つとします。 +「words」表のコンテンツ URI は、定数 {@link android.provider.UserDictionary.Words#CONTENT_URI UserDictionary.Words.CONTENT_URI} で定義されます。 + + + さらに、{@link android.provider.UserDictionary.Words} クラスは、このガイドのサンプルのスニペットで使用される、列名の定数を持ちます。 +たとえば、クエリの投影は次のように定義できます。 + +</p> +<pre> +String[] mProjection = +{ + UserDictionary.Words._ID, + UserDictionary.Words.WORD, + UserDictionary.Words.LOCALE +}; +</pre> +<p> + もう一方のコントラクト クラスは、連絡先プロバイダのクラス {@link android.provider.ContactsContract} です。 + このクラスのリファレンスには、サンプルのコード スニペットが記載されています。サブクラスの 1 つである {@link android.provider.ContactsContract.Intents.Insert} は、インテントとインテント データの定数を含むコントラクト クラスです。 + + +</p> + + +<!-- MIME Type Reference --> +<h2 id="MIMETypeReference">MIME タイプ リファレンス</h2> +<p> + コンテンツ プロバイダは、標準の MIME メディア タイプかカスタムの MIME タイプ文字列、またはその両方を返すことができます。 +</p> +<p> + MIME タイプは次の形式となります +</p> +<pre> +<em>type</em>/<em>subtype</em> +</pre> +<p> + たとえば、よく利用される MIME タイプ <code>text/html</code> は、<code>text</code> タイプと <code>html</code> サブタイプを持ちます。 +プロバイダから URI に対してこのタイプが返される場合、その URI を使用するクエリは HTML タグを含むテキストを返すことになります。 + +</p> +<p> + 「ベンダー固有の」MIME タイプとも呼ばれるカスタムの MIME タイプ文字列には、より複雑な <em>type</em> と <em>subtype</em> の値が含まれます。 +複数行の場合、<em>type</em> 値は常に +</p> +<pre> +vnd.android.cursor.<strong>dir</strong> +</pre> +<p> + となり、1 つの行の場合は +</p> +<pre> +vnd.android.cursor.<strong>item</strong> +</pre> +<p> + となります。 +</p> +<p> + <em>subtype</em> はプロバイダ固有の値になります。通常、Android 組み込みプロバイダは単純な subtype を使用します。 +たとえば、連絡先アプリケーションが電話番号の行を作成すると、行には次のように MIME タイプが設定されます。 + +</p> +<pre> +vnd.android.cursor.item/phone_v2 +</pre> +<p> + subtype の値は単純に <code>phone_v2</code> となっていることがわかります。 +</p> +<p> + 他のプロバイダ デベロッパーは、プロバイダの認証局と表明に基づいて独自のパターンの subtype を作成できます。 +たとえば、列車の時刻表を含むプロバイダについて考えてみます。 + プロバイダの認証局は <code>com.example.trains</code> であり、表 Line1、Line2、Line3 を持ちます。 +表 Line1 のコンテンツ URI +</p> +<p> +<pre> +content://com.example.trains/Line1 +</pre> +<p> + に対しては、プロバイダは次の MIME タイプを返します +</p> +<pre> +vnd.android.cursor.<strong>dir</strong>/vnd.example.line1 +</pre> +<p> + 表 Line2 の行 5 のコンテンツ URI +</p> +<pre> +content://com.example.trains/Line2/5 +</pre> +<p> + に対しては、プロバイダは次の MIME タイプを返します +</p> +<pre> +vnd.android.cursor.<strong>item</strong>/vnd.example.line2 +</pre> +<p> + ほとんどのコンテンツ プロバイダが、使用する MIME タイプに対してコントラクト クラス定数を定義します。たとえば、連絡先プロバイダのコントラクト クラス {@link android.provider.ContactsContract.RawContacts} は、1 つの未加工連絡先行の MIME タイプに、定数 {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE} を定義します。 + + + + +</p> +<p> + 1 つの行のコンテンツ URI については、<a href="#ContentURIs">コンテンツ URI</a> セクションをご覧ください。 + +</p> diff --git a/docs/html-intl/intl/ja/guide/topics/providers/content-provider-creating.jd b/docs/html-intl/intl/ja/guide/topics/providers/content-provider-creating.jd new file mode 100644 index 000000000000..af2181482d33 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/providers/content-provider-creating.jd @@ -0,0 +1,1214 @@ +page.title=コンテンツ プロバイダの作成 +@jd:body +<div id="qv-wrapper"> +<div id="qv"> + + +<h2>本書の内容</h2> +<ol> + <li> + <a href="#DataStorage">データ ストレージを設計する</a> + </li> + <li> + <a href="#ContentURI">コンテンツ URI を設計する</a> + </li> + <li> + <a href="#ContentProvider">ContentProvider クラスを実装する</a> + <ol> + <li> + <a href="#RequiredAccess">必須メソッド</a> + </li> + <li> + <a href="#Query">query() メソッドを実装する</a> + </li> + <li> + <a href="#Insert">insert() メソッドを実装する</a> + </li> + <li> + <a href="#Delete">delete() メソッドを実装する</a> + </li> + <li> + <a href="#Update">update() メソッドを実装する</a> + </li> + <li> + <a href="#OnCreate">onCreate() メソッドを実装する</a> + </li> + </ol> + </li> + <li> + <a href="#MIMETypes">コンテンツ プロバイダ MIME を実装する</a> + <ol> + <li> + <a href="#TableMIMETypes">テーブルの MIME タイプ</a> + </li> + <li> + <a href="#FileMIMETypes">ファイルの MIME タイプ</a> + </li> + </ol> + </li> + <li> + <a href="#ContractClass">コントラクト クラスを実装する</a> + </li> + <li> + <a href="#Permissions">コンテンツ プロバイダ パーミッションを実装する</a> + </li> + <li> + <a href="#ProviderElement"><provider> 要素</a> + </li> + <li> + <a href="#Intents">インテントとデータアクセス</a> + </li> +</ol> +<h2>キークラス</h2> + <ol> + <li> + {@link android.content.ContentProvider} + </li> + <li> + {@link android.database.Cursor} + </li> + <li> + {@link android.net.Uri} + </li> + </ol> +<h2>関連サンプル</h2> + <ol> + <li> + <a href="{@docRoot}resources/samples/NotePad/index.html"> + Note Pad のサンプル アプリケーション </a> + + </li> + </ol> +<h2>関連ドキュメント</h2> + <ol> + <li> + <a href="{@docRoot}guide/topics/providers/content-provider-basics.html"> + コンテンツ プロバイダの基本</a> + </li> + <li> + <a href="{@docRoot}guide/topics/providers/calendar-provider.html"> + カレンダー プロバイダ</a> + </li> + </ol> +</div> +</div> + + +<p> + コンテンツ プロバイダは、データの中央リポジトリへのアクセスを管理します。Android アプリケーションでは 1 つ以上のクラスとしてプロバイダを実装し、要素をマニフェスト ファイルで実装します。 + +いずれか 1 つのクラスがサブラス {@link android.content.ContentProvider} を実装します。これは、プロバイダと他のアプリケーションとの間のインターフェースになります。 + +コンテンツ プロバイダは他のアプリケーションへのデータの提供を意図したものですが、ユーザーがプロバイダに管理されるデータを照会、修正するアクティビティをアプリケーション内に設定することもできます。 + + +</p> +<p> + このトピックの残りの部分では、コンテンツ プロバイダと使用する API のリストをビルドするための基本的な手順を挙げていきます。 + +</p> + + +<!-- Before You Start Building --> +<h2 id="BeforeYouStart">ビルドを開始する前に</h2> +<p> + ビルドを開始する前に、次の操作を行います。 +</p> +<ol> + <li> + <strong>コンテンツ プロバイダが必要かどうかを決定します</strong>。次のような機能を 1 つ以上提供する場合に、コンテンツ プロバイダをビルドする必要があります。 + + <ul> + <li>他のアプリケーションに複雑なデータやファイルを提供する。</li> + <li>アプリから他のアプリへの複雑なデータのコピーをユーザーに許可する。</li> + <li>検索フレームワークを使用してカスタムの検索候補を提供する。</li> + </ul> + <p> + 完全に独自アプリケーション内だけで使用する場合は、SQLite データベースを使用するプロバイダは必要はありません。<em></em> + + </p> + </li> + <li> + 必要かどうかを決定していない場合は、プロバイダの詳細については「<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">コンテンツ プロバイダの基本</a>」のトピックをご覧ください。 + + + </li> +</ol> +<p> + 次に、以下の手順に従ってプロバイダをビルドします。 +</p> +<ol> + <li> + データの未処理のストレージを設計します。コンテンツ プロバイダは次の 2 つの方法でデータを提供します。 + <dl> + <dt> + ファイルデータ + </dt> + <dd> + 通常、写真、オーディオ、ビデオなどのファイルの形式となるデータです。 +ファイルはアプリケーションのプライベート スペースに格納します。 +ファイルに対する別のアプリケーションからの要求に応じて、プロバイダからファイルへのハンドルが提供されます。 + + </dd> + <dt> + 「構造化」データ + </dt> + <dd> + 通常、データベース、配列、類似の構造の形式となるデータです。 + テーブルの行と列に互換性を持つ形式でデータが格納されます。行は、担当者や在庫にあるアイテムなどのエンティティを表します。 +列は、担当者の名前やアイテムの価格などの、エンティティの一部のデータを表します。 +一般的にこのタイプのデータは SQLite データベースに格納しますが、任意のタイプの永続ストレージを使用できます。 + +Android システムで使用できるストレージ タイプの詳細は、<a href="#DataStorage">データ ストレージを設計する</a>をご覧ください。 + + + </dd> + </dl> + </li> + <li> + {@link android.content.ContentProvider} クラスの具体的な実装とそれに必要なメソッドを定義します。 +このクラスは、データと Android システムのそれ以外の部分とのインターフェースとなります。 +このクラスの詳細は、<a href="#ContentProvider">ContentProvider クラスを実装する</a>セクションをご覧ください。 + + </li> + <li> + プロバイダの認証局の文字列、コンテンツ URI、列名を定義します。プロバイダのアプリケーションでインテントを処理する場合は、インテント アクション、エクストラ データ、フラグも定義します。 + +さらに、データにアクセスするアプリケーションに必要なパーミッションも定義します。 +これらの値はすべて定数として個別のコントラクト クラスに定義するようにします。そうしておくと、後で他のデベロッパーに対してこのクラスを公開できます。 +コンテンツ URI の詳細は、<a href="#ContentURI">コンテンツ URI を設計する</a>セクションをご覧ください。 + + + インテントの使用に関する詳細については、<a href="#Intents">インテントとデータアクセス</a>セクションをご覧ください。 + + </li> + <li> + サンプルデータや、プロバイダとクラウドベースのデータの間でデータを同期する {@link android.content.AbstractThreadedSyncAdapter} の実装などの、その他のオプション部分を追加します。 + + + </li> +</ol> + + +<!-- Designing Data Storage --> +<h2 id="DataStorage">データ ストレージを設計する</h2> +<p> + コンテンツ プロバイダは、構造化された形式で保存されているデータへのインターフェースです。インターフェースを作成する前に、データの格納方法を決定しておく必要があります。 +データは任意の形式で保存でき、必要に応じてデータの読み取りと書き込みを行うためのインターフェースを設計できます。 + +</p> +<p> + Android には、次のように、いくつかのデータ格納テクノロジーがあります。 +</p> +<ul> + <li> + Android システムには、Android の独自のプロバイダがテーブル指向のデータを格納するために使用する、SQLite データベース API があります。 +{@link android.database.sqlite.SQLiteOpenHelper} クラスを使用すると、データベースを作成できます。また、{@link android.database.sqlite.SQLiteDatabase} クラスは、データベースにアクセスするための基本クラスです。 + + + + <p> + リポジトリを実装するのに、データベースを使用する必要がありません。外部的には、プロバイダはリレーショナル データベースに似た一連のテーブルとして表示されますが、プロバイダの内部実装をそのような形式にする必要はありません。 + + + </p> + </li> + <li> + ファイルデータを格納するために、Android にはファイル指向のさまざまな API があります。 + ファイル ストレージの詳細は、「<a href="{@docRoot}guide/topics/data/data-storage.html">Data Storage</a>」トピックをご覧ください。 +音楽やビデオのようにメディア関連のデータを提供するプロバイダを設計する場合は、テーブルデータとファイルを組み合わせるプロバイダを作成できます。 + + + </li> + <li> + ネットワーク ベースのデータで作業する場合は、{@link java.net} と {@link android.net} のクラスを使用します。 +また、ネットワーク ベースをデータベースなどのローカル データストアに同期させ、データをテーブルやファイルとして提供することもできます。 + + <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">サンプル同期アダプタ</a>のサンプル アプリケーションでは、このタイプの同期のデモを紹介しています。 + + </li> +</ul> +<h3 id="DataDesign"> + データ設計上の考慮事項 +</h3> +<p> + 次に、プロバイダのデータ構造を設計する際のヒントを示します。 +</p> +<ul> + <li> + テーブルデータには、プロバイダが各行の一意の数値として保持する「プライマリキー」列が常に必要です。 +この値を使用すると、行を他のテーブルの関連する行にリンクできます(「外部キー」として使用)。 +この列には任意の名前を設定できますが、プロバイダ クエリの結果を {@link android.widget.ListView} にリンクさせるには、取得する列のいずれかの名前が <code>_ID</code> になっている必要があるため、{@link android.provider.BaseColumns#_ID BaseColumns._ID} を使用することをお勧めします。 + + + + + </li> + <li> + ビットマップ画像やサイズが非常に大きなその他のファイル指向のデータを提供する場合は、テーブルにデータを直接格納するのではなく、データをファイルに格納し、データを間接的に提供します。 + +その場合、データにアクセスするには、{@link android.content.ContentResolver} ファイル メソッドの使用が必要であることをプロバイダのユーザーに通知する必要があります。 + + </li> + <li> + サイズや構造が異なるデータを格納するには、バイナリ ラージ オブジェクト(BLOB)データタイプを使用します。 +たとえば、<a href="http://code.google.com/p/protobuf">Protocol Buffer</a> や <a href="http://www.json.org">JSON 構造</a>を格納するには、BLOB 列を使用します。 + + + <p> + さらに、BLOB を使用してスキーマに依存しないテーブルを実装できます。<em></em>このタイプのテーブルでは、プライマリキー列、MIME タイプ列、1 つ以上の汎用列を BLOB として定義します。 + +BLOB 列内のデータの内容は、MIME タイプ列の値によって示されます。 +これにより、同じテーブルにさまざまな行タイプを格納できます。 +連絡先プロバイダの「データ」テーブル {@link android.provider.ContactsContract.Data} は、スキーマに依存しないテーブルの例です。 + + + </p> + </li> +</ul> +<!-- Designing Content URIs --> +<h2 id="ContentURI">コンテンツ URI を設計する</h2> +<p> + <strong>コンテンツ URI</strong> は、プロバイダのデータを特定する URI です。コンテンツ URI には、プロバイダ全体の識別名(<strong>認証局</strong>)とテーブルやファイルをポイントする名前(<strong>パス</strong>)が含まれます。 + +オプションの ID 部分は、テーブル内の個々の行を指します。 +{@link android.content.ContentProvider} のそれぞれのデータアクセス メソッドは引数としてコンテンツ URI を使用します。これにより、アクセスするテーブル、行、ファイルを決定できます。 + + +</p> +<p> + コンテンツ URI の基本については、「<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">コンテンツ プロバイダの基本</a>」トピックをご覧ください。 + + +</p> +<h3>認証局を設計する</h3> +<p> + 通常、プロバイダは、Android 内部の名前として使用される認証局を 1 つ持ちます。他のプロバイダとの競合を避けるためには、(逆に)プロバイダの認証局の基礎としてインターネット ドメインの所有権を使用する必要があります。 + +この推奨事項は Android パッケージ名にもあてはまるため、プロバイダを含むパッケージの名前の拡張子として、プロバイダの認証局を定義できます。 + +たとえば、Android パッケージ名が <code>com.example.<appname></code> の場合、プロバイダに認証局 <code>com.example.<appname>.provider</code> を付与する必要があります。 + + +</p> +<h3>パス構造を設計する</h3> +<p> + デベロッパーは通常、個々のテーブルを指すパスを末尾に追加して認証局からコンテンツ URI を作成します。 +たとえば、<em>table1</em> と <em>table2</em> の 2 つのテーブルがある場合、前の例の認証局を組み合わせてコンテンツ URI <code>com.example.<appname>.provider/table1</code> と <code>com.example.<appname>.provider/table2</code> を作成します。 + + + +パスは 1 つのセグメントに限定されず、パスの各レベルにテーブルを作成する必要はありません。 + +</p> +<h3>コンテンツ URI ID を処理する</h3> +<p> + 慣例として、URI の末尾にある行の ID 値を持つコンテンツ URI を受け取ることで、プロバイダはテーブル内の 1 つの行へのアクセスを提供します。さらに、慣例として、プロバイダは ID 値をテーブルの <code>_ID</code> 列とマッチングし、一致する行に対して要求されたアクセスを実行します。 + + + +</p> +<p> + この慣例により、プロバイダにアクセスするアプリの一般的なパターンを簡単に設計できます。アプリはプロバイダにクエリを実行し、{@link android.widget.CursorAdapter} を使用して、取得した {@link android.database.Cursor} を {@link android.widget.ListView} に表示します。 + + + {@link android.widget.CursorAdapter} の定義には、{@link android.database.Cursor} のいずれかの列を <code>_ID</code> に設定する必要があります + +</p> +<p> + その後、ユーザーはデータの確認や修正のために、表示された行のいずれかを UI から選択します。 +アプリは {@link android.widget.ListView} を返す {@link android.database.Cursor} から対応する行を取得し、この行の <code>_ID</code> 値を取得し、その値をコンテンツ URI の末尾に追加して、プロバイダにアクセス要求を送ります。 + +その後、プロバイダは、ユーザーが選択した行にクエリや修正を実行します。 + +</p> +<h3>コンテンツ URI パターン</h3> +<p> + 受け取ったコンテンツ URI に対するアクションを簡単に選択できるように、プロバイダ API には {@link android.content.UriMatcher} という便利なクラスが用意されています。このクラスはコンテンツ URI 「パターン」を正数値にマッピングします。 + +この正数値を <code>switch</code> 文で使用することで、特定のパターンに一致する 1 つ以上のコンテンツ URI に目的のアクションを選択できます。 + +</p> +<p> + コンテンツ URI パターンは、次のワイルドカード文字を使用するコンテンツ URI に一致します。 +</p> + <ul> + <li> + <strong><code>*</code>:</strong> 任意の長さの任意の有効な文字で構成される文字列に一致します。 + </li> + <li> + <strong><code>#</code>:</strong> 任意の長さの任意の数字で構成される文字列に一致します。 + </li> + </ul> +<p> + コンテンツ URI 処理の設計とコーディングの例として、テーブルを指す次のコンテンツ URI を認識する認証局 <code>com.example.app.provider</code> を持つプロバイダを考えてみます。 + + +</p> +<ul> + <li> + <code>content://com.example.app.provider/table1</code>: <code>table1</code> という名前のテーブル。 + </li> + <li> + <code>content://com.example.app.provider/table2/dataset1</code>: <code>dataset1</code> という名前のテーブル。 + + </li> + <li> + <code>content://com.example.app.provider/table2/dataset2</code>: <code>dataset2</code> という名前のテーブル。 + + </li> + <li> + <code>content://com.example.app.provider/table3</code>: <code>table3</code> という名前のテーブル。 + </li> +</ul> +<p> + さらに、行 ID が末尾に追加されていると、プロバイダではこれらのコンテンツ URI が認識されます。たとえば、<code>table3</code> の <code>1</code> で特定される行は <code>content://com.example.app.provider/table3/1</code> になります。 + + +</p> +<p> + 次のようなコンテンツ URI パターンを使用できます。 +</p> +<dl> + <dt> + <code>content://com.example.app.provider/*</code> + </dt> + <dd> + プロバイダの任意のコンテンツ URI に一致します。 + </dd> + <dt> + <code>content://com.example.app.provider/table2/*</code>: + </dt> + <dd> + テーブル <code>dataset1</code> と <code>dataset2</code> のコンテンツ URI に一致しますが、<code>table1</code> や <code>table3</code> のコンテンツ URI には一致しません。 + + + </dd> + <dt> + <code>content://com.example.app.provider/table3/#</code>: <code>table3</code> の 1 つの行のコンテンツ URI に一致します。<code>6</code> で特定される行は <code>content://com.example.app.provider/table3/6</code> になります。 + + + + </dt> +</dl> +<p> + 次のコード スニペットでは、{@link android.content.UriMatcher} のメソッドが機能する仕組みを示します。 + このコードでは、テーブルにコンテンツ URI パターン <code>content://<authority>/<path></code> を使用し、1 つの行に <code>content://<authority>/<path>/<id></code> を使用することで、表全体の URI と 1 つの行の URI を異なる方法で処理します。 + + + +</p> +<p> + メソッド {@link android.content.UriMatcher#addURI(String, String, int) addURI()} は認証局とパスを正数値にマッピングします。 +メソッド {@link android.content.UriMatcher#match(Uri) + match()} は URI に正数値を返します。次のように、<code>switch</code> 文によって、クエリをテーブル全体に実行するか、1 つのレコードに実行するかが決まります。 + +</p> +<pre class="prettyprint"> +public class ExampleProvider extends ContentProvider { +... + // Creates a UriMatcher object. + private static final UriMatcher sUriMatcher; +... + /* + * The calls to addURI() go here, for all of the content URI patterns that the provider + * should recognize. For this snippet, only the calls for table 3 are shown. + */ +... + /* + * Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used + * in the path + */ + sUriMatcher.addURI("com.example.app.provider", "table3", 1); + + /* + * Sets the code for a single row to 2. In this case, the "#" wildcard is + * used. "content://com.example.app.provider/table3/3" matches, but + * "content://com.example.app.provider/table3 doesn't. + */ + sUriMatcher.addURI("com.example.app.provider", "table3/#", 2); +... + // Implements ContentProvider.query() + public Cursor query( + Uri uri, + String[] projection, + String selection, + String[] selectionArgs, + String sortOrder) { +... + /* + * Choose the table to query and a sort order based on the code returned for the incoming + * URI. Here, too, only the statements for table 3 are shown. + */ + switch (sUriMatcher.match(uri)) { + + + // If the incoming URI was for all of table3 + case 1: + + if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC"; + break; + + // If the incoming URI was for a single row + case 2: + + /* + * Because this URI was for a single row, the _ID value part is + * present. Get the last path segment from the URI; this is the _ID value. + * Then, append the value to the WHERE clause for the query + */ + selection = selection + "_ID = " uri.getLastPathSegment(); + break; + + default: + ... + // If the URI is not recognized, you should do some error handling here. + } + // call the code to actually do the query + } +</pre> +<p> + 別の {@link android.content.ContentUris} には、コンテンツ URI の一部である <code>id</code> で作業するための便利なメソッドが備わっています。 +クラス {@link android.net.Uri} と {@link android.net.Uri.Builder} には、既存の {@link android.net.Uri} オブジェクトを解析して新しいオブジェクトをビルドするための便利なメソッドがあります。 + + +</p> + +<!-- Implementing the ContentProvider class --> +<h2 id="ContentProvider">ContentProvider クラスを実装する</h2> +<p> + {@link android.content.ContentProvider} インスタンスは、他のアプリケーションからの要求を処理することで、一連の構造化されたデータへのアクセスを管理します。 +どのような形式でアクセスする場合も、最終的には {@link android.content.ContentResolver} が呼び出されます。その後 {@link android.content.ContentProvider} の具象メソッドが呼び出され、アクセスを取得します。 + + +</p> +<h3 id="RequiredAccess">必須メソッド</h3> +<p> + 抽象クラス {@link android.content.ContentProvider} は 6 つの抽象メソッドを定義しますが、これらのメソッドは独自の具象サブクラスの一部として実装する必要があります。 +次のように、{@link android.content.ContentProvider#onCreate() onCreate()} を除くこれらのメソッドは、コンテンツ プロバイダへのアクセスを試みるクライアント アプリケーションによって呼び出されます。 + + +</p> +<dl> + <dt> + {@link android.content.ContentProvider#query(Uri, String[], String, String[], String) + query()} + </dt> + <dd> + プロバイダからデータを取得します。引数を使って、クエリを実行するテーブル、返す行と列、結果の並び順を選択します。 + + データは {@link android.database.Cursor} オブジェクトとして返されます。 + </dd> + <dt> + {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} + </dt> + <dd> + プロバイダに新しい行を挿入します。引数を使って、挿入先のテーブルを選択し、使用する列の値を取得します。 +新たに挿入した行のコンテンツ URI が返されます。 + + </dd> + <dt> + {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[]) + update()} + </dt> + <dd> + プロバイダ内の既存の行を更新します。引数を使って、更新するテーブルと行を選び、更新された列の値を取得します。 +更新された行の数が返されます。 + </dd> + <dt> + {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} + </dt> + <dd> + プロバイダから行を削除します。引数を使って、削除するテーブルと行を選びます。 +削除された行の数が返されます。 + </dd> + <dt> + {@link android.content.ContentProvider#getType(Uri) getType()} + </dt> + <dd> + コンテンツ URI に対応する MIME タイプを返します。このメソッドの詳細は、<a href="#MIMETypes">コンテンツ プロバイダ MIME を実装する</a>セクションをご覧ください。 + + </dd> + <dt> + {@link android.content.ContentProvider#onCreate() onCreate()} + </dt> + <dd> + プロバイダを初期化します。プロバイダが作成されると、Android システムがこのメソッドを即座に呼び出します。 +{@link android.content.ContentResolver} オブジェクトがアクセスを試みるまでは、プロバイダは作成されません。 + + </dd> +</dl> +<p> + これらのメソッドが持つ署名は、同じ名前の {@link android.content.ContentResolver} メソッドの署名と同じになります。 + +</p> +<p> + これらのメソッドを実装する場合は、次の点を考慮する必要があります。 +</p> +<ul> + <li> + {@link android.content.ContentProvider#onCreate() onCreate()} を除くこれらのすべてのメソッドは、複数のスレッドを使用して同時に呼び出すことができるため、スレッドに対応した設定にする必要があります。 +複数のスレッドの詳細は、<a href="{@docRoot}guide/components/processes-and-threads.html">プロセスとスレッド</a>をご覧ください。 + + + + </li> + <li> + {@link android.content.ContentProvider#onCreate() + onCreate()} では冗長な操作は行わないようにします。本当に必要になるまでは、タスクの初期化は行わないようにします。 + 詳細は、<a href="#OnCreate">onCreate() メソッドを実装する</a>をご覧ください。 + + </li> + <li> + これのメソッドの実装は必須ですが、コードでは予測されたデータタイプを返す以外の操作は必要ありません。 +たとえば、他のアプリケーションが一部のテーブルにデータを挿入できないように設定するとします。 +その場合、{@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} への呼び出しを無視して 0 を返します。 + + + </li> +</ul> +<h3 id="Query">query() メソッドを実装する</h3> +<p> + {@link android.content.ContentProvider#query(Uri, String[], String, String[], String) + ContentProvider.query()} メソッドは {@link android.database.Cursor} オブジェクトを返す必要があります。失敗した場合は、{@link java.lang.Exception} をスローします。 + +SQLite データベースをデータストレージとして使用する場合は、{@link android.database.sqlite.SQLiteDatabase} クラスのいずれかの <code>query()</code> メソッドが返す {@link android.database.Cursor} を返します。 + + + クエリがどの行にも一致しない場合は、{@link android.database.Cursor#getCount()} メソッドが 0 を返す {@link android.database.Cursor} インスタンスを返す必要があります。 + + クエリプロセス中にエラーが発生した場合にのみ <code>null</code> を返します。 +</p> +<p> + SQLite データベースをデータストレージとして使用しない場合は、{@link android.database.Cursor} クラスのいずれかの具象サブクラスを使用します。 +たとえば、{@link android.database.MatrixCursor} クラスは、各行が {@link java.lang.Object} の配列となるカーソルを実装します。 +このクラスでは、{@link android.database.MatrixCursor#addRow(Object[]) addRow()} を使って新しい行を追加します。 + +</p> +<p> + Android システムは、プロセスの境界をまたいで {@link java.lang.Exception} を送信できるように設定する必要があることにご注意ください。 +Android では、クエリエラーを処理するのに便利な、次の例外を送信できます。 + +</p> +<ul> + <li> + {@link java.lang.IllegalArgumentException}(プロバイダが無効なコンテンツ URI を受け取った場合にこの例外をスローするように選択できます) + + </li> + <li> + {@link java.lang.NullPointerException} + </li> +</ul> +<h3 id="Insert">insert() メソッドを実装する</h3> +<p> + {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} メソッドは、{@link android.content.ContentValues} 引数の値を使用して、適切なテーブルに新しい行を追加します。 + +列名が {@link android.content.ContentValues} 引数にない場合は、プロバイダ コードがデータベース スキーマのいずれかで、デフォルト値を設定できます。 + + +</p> +<p> + このメソッドは新しい行のコンテンツ URI を返します。作成するには、{@link android.content.ContentUris#withAppendedId(Uri, long) withAppendedId()} を使用して、新しい行の <code>_ID</code>(または他のプライマリキー)の値をテーブルのコンテンツ URI の末尾に追加します。 + + +</p> +<h3 id="Delete">delete() メソッドを実装する</h3> +<p> + {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} メソッドでは、データストレージから行を物理的に削除する必要はありません。 +プロバイダで同期アダプタを使用する場合は、行全体を削除するのではなく、削除された行に「削除」フラグを付けるようにします。 + +同期アダプタは削除された行を探して、プロバイダから削除される前に、サーバーから行を削除できます。 + +</p> +<h3 id="Update">update() メソッドを実装する</h3> +<p> + {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[]) + update()} メソッドは {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} が使用するのと同じ {@link android.content.ContentValues} 引数、{@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} と {@link android.content.ContentProvider#query(Uri, String[], String, String[], String) + ContentProvider.query()} が使用するのと同じ <code>selection</code> と <code>selectionArgs</code> 引数を使用します。 + + + +これにより、これらのメソッド間でコードを再利用できます。 +</p> +<h3 id="OnCreate">onCreate() メソッドを実装する</h3> +<p> + Android システムはプロバイダを起動する際に {@link android.content.ContentProvider#onCreate() + onCreate()} を呼び出します。このメソッドでは迅速に実行できる初期化タスクのみを実行するようにし、プロバイダが実際にデータの要求を受け取るまでは、データベースの作成とデータロードを保留します。 + +{@link android.content.ContentProvider#onCreate() onCreate()} で冗長なタスクを行う場合は、プロバイダの起動が遅くなります。 + +同様に、プロバイダから他のアプリケーションへの応答も遅くなります。 + +</p> +<p> + たとえば、SQLite データベースを使用すると、{@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()} に {@link android.database.sqlite.SQLiteOpenHelper} オブジェクトを作成し、データベースを初めて開くときに SQL テーブルを作成できます。 + + +この操作を簡単にするために、{@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase + getWritableDatabase()} を初めて呼び出すときには、{@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase) + SQLiteOpenHelper.onCreate()} メソッドが自動的に呼び出されます。 + + +</p> +<p> + 次の 2 つのスニペットは、{@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()} と {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase) + SQLiteOpenHelper.onCreate()} との間のやり取りを表しています。 + +最初のスニペットは {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()} の実装です。 + +</p> +<pre class="prettyprint"> +public class ExampleProvider extends ContentProvider + + /* + * Defines a handle to the database helper object. The MainDatabaseHelper class is defined + * in a following snippet. + */ + private MainDatabaseHelper mOpenHelper; + + // Defines the database name + private static final String DBNAME = "mydb"; + + // Holds the database object + private SQLiteDatabase db; + + public boolean onCreate() { + + /* + * Creates a new helper object. This method always returns quickly. + * Notice that the database itself isn't created or opened + * until SQLiteOpenHelper.getWritableDatabase is called + */ + mOpenHelper = new MainDatabaseHelper( + getContext(), // the application context + DBNAME, // the name of the database) + null, // uses the default SQLite cursor + 1 // the version number + ); + + return true; + } + + ... + + // Implements the provider's insert method + public Cursor insert(Uri uri, ContentValues values) { + // Insert code here to determine which table to open, handle error-checking, and so forth + + ... + + /* + * Gets a writeable database. This will trigger its creation if it doesn't already exist. + * + */ + db = mOpenHelper.getWritableDatabase(); + } +} +</pre> +<p> + 次のスニペットは {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase) + SQLiteOpenHelper.onCreate()} の実装であり、ヘルパークラスを含みます。 + +</p> +<pre class="prettyprint"> +... +// A string that defines the SQL statement for creating a table +private static final String SQL_CREATE_MAIN = "CREATE TABLE " + + "main " + // Table's name + "(" + // The columns in the table + " _ID INTEGER PRIMARY KEY, " + + " WORD TEXT" + " FREQUENCY INTEGER " + + " LOCALE TEXT )"; +... +/** + * Helper class that actually creates and manages the provider's underlying data repository. + */ +protected static final class MainDatabaseHelper extends SQLiteOpenHelper { + + /* + * Instantiates an open helper for the provider's SQLite data repository + * Do not do database creation and upgrade here. + */ + MainDatabaseHelper(Context context) { + super(context, DBNAME, null, 1); + } + + /* + * Creates the data repository. This is called when the provider attempts to open the + * repository and SQLite reports that it doesn't exist. + */ + public void onCreate(SQLiteDatabase db) { + + // Creates the main table + db.execSQL(SQL_CREATE_MAIN); + } +} +</pre> + + +<!-- Implementing ContentProvider MIME Types --> +<h2 id="MIMETypes">ContentProvider MIME タイプを実装する</h2> +<p> + {@link android.content.ContentProvider} クラスには、MIME タイプを返すための次の 2 つのクラスがあります。 +</p> +<dl> + <dt> + {@link android.content.ContentProvider#getType(Uri) getType()} + </dt> + <dd> + 任意のプロバイダに実装する必要がある必須メソッドの 1 つです。 + </dd> + <dt> + {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()} + </dt> + <dd> + ファイルを提供するプロバイダの場合に、実装が考えられるメソッドです。 + </dd> +</dl> +<h3 id="TableMIMETypes">テーブルの MIME タイプ</h3> +<p> + {@link android.content.ContentProvider#getType(Uri) getType()} メソッドは、MIME 形式で {@link java.lang.String} を返します。これは、コンテンツ URI 引数によって返されるデータのタイプを表します。 + +{@link android.net.Uri} 引数には特定の URI ではなくパターンを指定することもできます。この場合、パターンに一致するコンテンツ URI に関連付けられているデータのタイプを返します。 + + +</p> +<p> + テキスト、HTML、JPEG といった一般的なタイプのデータの場合、{@link android.content.ContentProvider#getType(Uri) getType()} では該当するデータの標準的な MIME タイプを返す必要があります。 + +利用できるこれらの標準的なタイプの詳細なリストは、「<a href="http://www.iana.org/assignments/media-types/index.htm">IANA MIME Media Types</a>」のウェブサイトをご覧ください。 + + +</p> +<p> + テーブル データの 1 つ以上の行を指すコンテンツ URI の場合、{@link android.content.ContentProvider#getType(Uri) getType()} は、Android のベンダー固有の MIME 形式で MIME タイプを返す必要があります。 + + +</p> +<ul> + <li> + タイプ部分: <code>vnd</code> + </li> + <li> + サブタイプ部分: + <ul> + <li> + URI パターンが 1 つの行の場合: <code>android.cursor.<strong>item</strong>/</code> + </li> + <li> + URI パターンが複数の行の場合: <code>android.cursor.<strong>dir</strong>/</code> + </li> + </ul> + </li> + <li> + プロバイダ固有の部分: <code>vnd.<name></code>.<code><type></code> + <p> + <code><name></code> と <code><type></code> を指定します。 + <code><name></code> の値はグローバルに一意の値とし、<code><type></code> の値は対応する URI パターンに一意のものとする必要があります。 + +<code><name></code> には、企業名や、アプリケーションの Android パッケージ名の一部を使うことをお勧めします。 +<code><type></code> には、URI に関連付けられているテーブルを特定する文字列を使うことをお勧めします。 + + + </p> + + </li> +</ul> +<p> + たとえば、プロバイダの認証局が <code>com.example.app.provider</code> の場合、テーブル名は <code>table1</code> となり、<code>table1</code> の複数行の MIME タイプは次のようになります。 + + +</p> +<pre> +vnd.android.cursor.<strong>dir</strong>/vnd.com.example.provider.table1 +</pre> +<p> + <code>table1</code> の 1 つの行の場合は、MIME タイプは次のようになります。 +</p> +<pre> +vnd.android.cursor.<strong>item</strong>/vnd.com.example.provider.table1 +</pre> +<h3 id="FileMIMETypes">ファイルの MIME タイプ</h3> +<p> + ファイルを提供するプロバイダの場合は、{@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()} を実装します。 + + このメソッドは、プロバイダが特定のコンテンツ URI に対して返すことができるファイルの MIME タイプの {@link java.lang.String} 配列を返します。クライアントで処理する MIME タイプのみを返すには、MIME タイプフィルタ引数によって、提供する MIME タイプをフィルタする必要があります。 + + +</p> +<p> + たとえば、写真画像を <code>.jpg</code>、<code>.png</code>、<code>.gif</code> 形式で提供するプロバイダについて考えてみます。 + + アプリケーションが {@link android.content.ContentResolver#getStreamTypes(Uri, String) + ContentResolver.getStreamTypes()} をフィルタ文字列 <code>image/*</code> (何らかの形式の「画像」)で呼び出す場合、{@link android.content.ContentProvider#getStreamTypes(Uri, String) + ContentProvider.getStreamTypes()} メソッドは次のような配列を返します。 + + +</p> +<pre> +{ "image/jpeg", "image/png", "image/gif"} +</pre> +<p> + アプリの対象が <code>.jpg</code> ファイルのみであり、アプリが {@link android.content.ContentResolver#getStreamTypes(Uri, String) + ContentResolver.getStreamTypes()} をフィルタ文字列 <code>*\/jpeg</code> で呼び出す場合、{@link android.content.ContentProvider#getStreamTypes(Uri, String) + ContentProvider.getStreamTypes()} は次の項目を返します。 + + +<pre> +{"image/jpeg"} +</pre> +<p> + プロバイダが、フィルタ文字列で要求した MIME タイプを提供していない場合、{@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()} は <code>null</code> を返します。 + + +</p> + + +<!-- Implementing a Contract Class --> +<h2 id="ContractClass">コントラクト クラスを実装する</h2> +<p> + コントラクト クラスは <code>public final</code> クラスであり、URI、列名、MIME タイプ、プロバイダに関連するその他のメタデータを含みます。 +このクラスは、URI や列名などの実際の値が変更された場合にも、プロバイダに正しくアクセスできることを保証することで、プロバイダとその他のアプリケーションとの間にコントラクトを構築します。 + + + +</p> +<p> + さらに、通常、コントラクト クラスではその定数にニーモニック名が設定されているため、デベロッパーが列名や URI に誤った値を使用しにくいようになっています。 +クラスであるため、Javadoc ドキュメントを含めることができます。 +Eclipse などの統合型開発環境では、コントラクト クラスから定数名が自動的に設定され、定数の Javadoc が表示されます。 + + +</p> +<p> + デベロッパーはアプリケーションからコントラクト クラスのクラスファイルにアクセスできませんが、提供する <code>.jar</code> ファイルからクラスファイルをアプリケーションに静的にコンパイルできます。 + +</p> +<p> + {@link android.provider.ContactsContract} クラスとそのネストされたクラスは、コントラクト クラスの例です。 + +</p> +<h2 id="Permissions">コンテンツ プロバイダ パーミッションを実装する</h2> +<p> + Android システムのあらゆる領域に対するパーミッションとクラスについては、「<a href="{@docRoot}guide/topics/security/security.html">セキュリティとパーミッション</a>」トピックをご覧ください。 + + また、トピック「<a href="{@docRoot}guide/topics/data/data-storage.html">Data Storage</a>」にも、ストレージのさまざまなタイプに有効なセキュリティとパーミッションについて記載されています。 + + 重要な点をまとめると次のようになります。 +</p> +<ul> + <li> + デフォルトでは、端末の内部ストレージに格納されるデータファイルは、アプリケーションとプロバイダでのみ使用できます。 + + </li> + <li> + 作成する {@link android.database.sqlite.SQLiteDatabase} データベースは、自分のアプリケーションとプロバイダにのみ公開されます。 + + </li> + <li> + デフォルトでは、外部ストレージに保存するデータファイルはパブリックとなり、誰もが読み取ることができます。<em></em><em></em> +他のアプリケーションは別の API 呼び出しを使用してファイルの読み取りと書き込みを実行できるため、コンテンツ プロバイダで外部ストレージにあるファイルへのアクセスは制限できません。 + + </li> + <li> + 端末の内部ストレージにあるファイルや SQLite データベースを開いたり作成したりするメソッド呼び出しは、他のすべてのアプリケーションに読み取りと書き込みの両方のアクセスを付与してしまう可能性があります。 +内部ファイルやデータベースをプロバイダのリポジトリとして使用する場合に、「誰でも読み取り可能」や「誰でも書き込み可能」なアクセスを付与してしまうと、マニフェストで設定したプロバイダのパーミッションでデータを保護できなくなってしまいます。 + + +内部ストレージのファイルとデータベースへのデフォルトのアクセスは「プライベート」になっているため、プロバイダのリポジトリの場合はこの設定を変更しないでください。 + + </li> +</ul> +<p> + コンテンツ プロバイダ パーミッションを使用してデータへのアクセスを制御する場合は、内部ファイル、SQLite データベース、「クラウド」(リモート サーバーなど)にデータを格納し、ファイルやデータベースを自分のアプリケーションにのみ公開するように設定します。 + + +</p> +<h3>パーミッションを実装する</h3> +<p> + デフォルトではプロバイダにはパーミッションが設定されていないため、基礎となるデータがプライベートに設定されている場合でも、すべてのアプリケーションは自分のプロバイダからの読み取りとプロバイダへの書き込みを実行できます。 +これを変更するには、<code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> + <provider></a></code> 要素の属性や子要素を使用して、マニフェスト ファイルでプロバイダのパーミッションを設定します。 + +プロバイダ全体に適用するパーミッションを設定することもできますし、特定のテーブル、特定のレコード、これら 3 つすべてに適用するパーミッションを設定することもできます。 + +</p> +<p> + マニフェスト ファイルで 1 つ以上の <code><a href="{@docRoot}guide/topics/manifest/permission-element.html"> + <permission></a></code> 要素を使用して、プロバイダのパーミッションを定義します。 +自分のプロバイダに独自のパーミッションを作成するには、<code><a href="{@docRoot}guide/topics/manifest/permission-element.html#nm"> + android:name</a></code> 属性に Java スタイルのスコーピングを使用します + +たとえば、読み取りパーミッションの名前を <code>com.example.app.provider.permission.READ_PROVIDER</code> とします。 + + +</p> +<p> + 次のリストは、プロバイダ パーミッションの範囲を示しています。プロバイダ全体に適用するパーミッションから始まり、より詳細な範囲のものになっています。 + + より広い範囲を持つパーミッションよりも、範囲が限定されるパーミッションの方が優先されます。 +</p> +<dl> + <dt> + プロバイダ レベルで 1 つの読み取りと書き込みのパーミッション + </dt> + <dd> + 1 つのパーミッションでプロバイダ全体の読み取りと書き込みのアクセスの両方を制御します。<code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> + <provider></a></code> 要素の <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn"> + android:permission</a></code> 属性で指定します。 + + + </dd> + <dt> + プロバイダ レベルで別々の読み取りと書き込みパーミッション + </dt> + <dd> + プロバイダ全体の読み取りパーミッションと書き込みパーミッションです。これらのパーミッションは <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> + <provider></a></code> 要素の <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#rprmsn"> + android:readPermission</a></code> 属性と <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#wprmsn"> + android:writePermission</a></code> 属性で指定します。 + + +これらは、<code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn"> + android:permission</a></code> で要求するパーミッションよりも優先されます。 + + </dd> + <dt> + パスレベルのパーミッション + </dt> + <dd> + プロバイダのコンテンツ URI の読み取り、書き込み、読み取り / 書き込みパーミッションです。<code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> + <provider></a></code> 要素の <code><a href="{@docRoot}guide/topics/manifest/path-permission-element.html"> + <path-permission></a></code> 子要素を使用して、制御対象の各 URI を指定します。 + + +指定する各コンテンツ URI に対して、読み取り / 書き込みパーミッション、読み取りパーミッション、書き込みパーミッション、3 つすべてを指定できます。 +読み取りパーミッションと書き込みパーミッションは、読み取り / 書き込みパーミッションに優先します。 +また、パスレベルのパーミッションはプロバイダ レベルのパーミッションに優先します。 + + </dd> + <dt> + 一時的なパーミッション + </dt> + <dd> + アプリケーションへの一時的なアクセスを付与するパーミッション レベルです。アプリケーションに通常必要とするパーミッションが付与されていない場合でも付与できます。 +一時的なアクセス機能により、アプリケーションのマニフェストに必要なパーミッションの数を減らせます。 + +一時的なパーミッションを有効にすると、プロバイダへの「永続的な」パーミッションを必要とするアプリケーションのみが、継続的にすべてのデータにアクセスできます。 + + + <p> + プロバイダからの写真の添付ファイルを外部の画像ビューワ アプリケーションで表示する場合に、メール プロバイダとアプリに実装するパーミッションを考えてみます。 + +パーミッションを要求しなくても、画像ビューワに必要なアクセスを付与するには、写真のコンテンツ URI に一時的なパーミッションを設定します。 +ユーザーが写真を表示しようとしたときに、アプリから写真のコンテンツ URI とパーミッション フラグを含むインテントを画像ビューワに送信するようにメール アプリを設計します。 + +ビューワにプロバイダの通常の読み取りパーミッションが付与されていない場合でも、画像ビューワはメール プロバイダにクエリを実行して写真を取得します。 + + + </p> + <p> + 一時的なパーミッションを有効にするには、<code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> + <provider></a></code> 要素の <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn"> + android:grantUriPermissions</a></code> 属性を設定するか、1 つ以上の <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html"> + <grant-uri-permission></a></code> 子要素を <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> + <provider></a></code> 要素に追加します。 + + + +一時的なパーミッションを使用する場合、プロバイダからのコンテンツ URI のサポートを削除したときは常に {@link android.content.Context#revokeUriPermission(Uri, int) + Context.revokeUriPermission()} を呼び出す必要があります。そうすると、コンテンツ URI が一時的なパーミッションに関連付けられます。 + + + </p> + <p> + 属性の値によって、プロバイダへのアクセスレベルが決まります。 + 属性を <code>true</code> に設定すると、システムによってプロバイダ全体への一時的なパーミッションが付与されます。このパーミッションは、プロバイダ レベルやパスレベルのパーミッションで必要になるその他のパーミッションよりも優先されます。 + + + </p> + <p> + このフラグを <code>false</code> に設定する場合は、<code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html"> + <grant-uri-permission></a></code> 子要素を <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> + <provider></a></code> 要素に追加する必要があります。 + +それぞれの子要素は、一時的なアクセスが付与される 1 つ以上のコンテンツ URI を指定します。 + + </p> + <p> + 一時的なアクセスをアプリケーションに委任するには、インテントに {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} フラグか {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION} フラグ、またはその両方を含める必要があります。 + +これらは、{@link android.content.Intent#setFlags(int) setFlags()} メソッドで設定します。 + + </p> + <p> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn"> + android:grantUriPermissions</a></code> 属性がない場合は、<code>false</code> であると仮定されます。 + + </p> + </dd> +</dl> + + + +<!-- The Provider Element --> +<h2 id="ProviderElement"><provider> 要素</h2> +<p> + {@link android.app.Activity} コンポーネントや {@link android.app.Service} コンポーネントと同様に、<code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> + <provider></a></code> 要素を使用して {@link android.content.ContentProvider} のサブクラスをアプリケーションのマニフェスト ファイルに定義する必要があります。 + + +Android システムは要素から次の情報を取得します。 + +<dl> + <dt> + 認証局(<a href="{@docRoot}guide/topics/manifest/provider-element.html#auth">{@code + android:authorities}</a>) + + </dt> + <dd> + システム内のプロバイダ全体を特定する識別名です。この属性の詳細は、<a href="#ContentURI">コンテンツ URI を設計する</a>セクションをご覧ください。 + + + </dd> + <dt> + プロバイダ クラス名(<code> +<a href="{@docRoot}guide/topics/manifest/provider-element.html#nm">android:name</a> + </code>) + + </dt> + <dd> + {@link android.content.ContentProvider} を実装するクラスです。このクラスの詳細は、<a href="#ContentProvider">ContentProvider クラスを実装する</a>セクションをご覧ください。 + + + </dd> + <dt> + パーミッション + </dt> + <dd> + 他のアプリケーションがプロバイダのデータにアクセスするのに必要なパーミッションを指定する属性です。 + + <ul> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn"> + android:grantUriPermssions</a></code>: 一時的なパーミッションのフラグです。 + </li> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn"> + android:permission</a></code>: 1 つのプロバイダ全体の読み取り / 書き込みパーミッションです。 + </li> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#rprmsn"> + android:readPermission</a></code>: プロバイダ全体の読み取りパーミッションです。 + </li> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#wprmsn"> + android:writePermission</a></code>: プロバイダ全体の書き込みパーミッションです。 + </li> + </ul> + <p> + パーミッションとそれに対応する属性の詳細は、<a href="#Permissions">コンテンツ プロバイダ パーミッションを実装する</a>セクションをご覧ください。 + + + </p> + </dd> + <dt> + 起動と制御の属性 + </dt> + <dd> + これらの属性は、Android システムの起動方法とそのタイミング、プロバイダのプロセスの特性、その他の実行時の設定を決定します。 + + <ul> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#enabled"> + android:enabled</a></code>: システムにプロバイダの起動を許可するフラグです。 + </li> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#exported"> + android:exported</a></code>: 他のアプリケーションにこのプロバイダの使用を許可するフラグです。 + </li> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#init"> + android:initOrder</a></code>: 同じプロセス内の他のプロバイダに対して、このプロバイダを起動する順番です。 + + </li> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#multi"> + android:multiProcess</a></code>: システムに呼び出しクライアントと同じプロセスでのプロバイダの開始を許可するフラグです。 + + </li> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#proc"> + android:process</a></code>: プロバイダを実行するプロセスの名前です。 + + </li> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#sync"> + android:syncable</a></code>: プロバイダのデータをサーバー上のデータと同期することを示すフラグです。 + + </li> + </ul> + <p> + 属性に関する詳細は、開発ガイドの <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> + <provider></a></code> 要素に関するトピックに記載されています。 + + + </p> + </dd> + <dt> + 情報に関する属性 + </dt> + <dd> + プロバイダのオプションのアイコンとラベルです。 + <ul> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#icon"> + android:icon</a></code>: プロバイダのアイコンを含むドローアブル リソースです。 + [設定] > [アプリ] > [すべて] にあるアプリのリストのプロバイダラベルの横に表示されるアイコンです。<em></em><em></em><em></em> + + </li> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#label"> + android:label</a></code>: プロバイダ、データ、その両方を説明する、情報ラベルです。 +[設定] > [アプリ] > [すべて] にあるアプリのリストのプロバイダラベルの横に表示されるアイコンです。<em></em><em></em><em></em> + + </li> + </ul> + <p> + 属性に関する詳細は、開発ガイドの <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> + <provider></a></code> 要素に関するトピックに記載されています。 + + </p> + </dd> +</dl> + +<!-- Intent Access --> +<h2 id="Intents">インテントとデータアクセス</h2> +<p> + {@link android.content.Intent} を使用すると、アプリケーションはコンテンツ プロバイダに間接的にアクセスできます。 + アプリケーションは、{@link android.content.ContentResolver} や {@link android.content.ContentProvider} のメソッドを呼び出しません。 +その代わりに、アクティビティを起動するインテントを送信します。これは通常、プロバイダ独自のアプリケーションの一部となっています。 +対象のアクティビティは UI のデータの取得と表示を担当します。インテントのアクションに応じて、対象のアクティビティにより、ユーザーにプロバイダのデータの修正を求めるメッセージが表示されることがあります。 + + + さらに、インテントには、対象のアクティビティが UI に表示する「エクストラ」データが含まれることがあります。ユーザーは使用前に、このデータを変更してプロバイダのデータを修正することもできます。 + + +</p> +<p> + +</p> +<p> + インテント アクセスを使用して、データの整合性を保証できます。プロバイダのデータの挿入、更新、削除は、厳格に定義されたビジネス ロジックによって規定されることがあります。 +この場合、他のアプリケーションにデータを直接修正できるように許可すると、無効なデータが発生することがあります。 + +デベロッパーがインテント アクセスを使用する場合は、すべての操作を完全に文書化します。 + コードを使用してデータを修正するよりも、独自のアプリケーションの UI を使用したインテント アクセスの方が優れている理由を説明します。 + +</p> +<p> + プロバイダのデータを修正するための受信インテントの処理は、その他のインテントの処理と同じです。 +インテントの使用についての詳細は、「<a href="{@docRoot}guide/components/intents-filters.html">インテントとインテント フィルタ</a>」をご覧ください。 + +</p> diff --git a/docs/html-intl/intl/ja/guide/topics/providers/content-providers.jd b/docs/html-intl/intl/ja/guide/topics/providers/content-providers.jd new file mode 100644 index 000000000000..918426ad1480 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/providers/content-providers.jd @@ -0,0 +1,108 @@ +page.title=コンテンツ プロバイダ +@jd:body +<div id="qv-wrapper"> +<div id="qv"> + + +<!-- In this document --> +<h2>トピック</h2> +<ol> + <li> + <a href="{@docRoot}guide/topics/providers/content-provider-basics.html"> コンテンツ プロバイダの基本</a> + + </li> + <li> + <a href="{@docRoot}guide/topics/providers/content-provider-creating.html"> コンテンツ プロバイダの作成</a> + + </li> + <li> + <a href="{@docRoot}guide/topics/providers/calendar-provider.html">カレンダー プロバイダ</a> + </li> + <li> + <a href="{@docRoot}guide/topics/providers/contacts-provider.html">連絡先プロバイダ</a> + </li> +</ol> + + <!-- Related Samples --> +<h2>関連サンプル</h2> + <ol> + <li> + <a href="{@docRoot}resources/samples/ContactManager/index.html"> Contact Manager</a> アプリケーション + + </li> + <li> + <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List2.html"> + "Cursor (People)" + </a> + </li> + <li> + <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List7.html"> + "Cursor (Phones)"</a> + </li> + <li> + <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html"> サンプル同期アダプタ</a> + + </li> + </ol> +</div> +</div> +<p> + コンテンツ プロバイダは、一連の構造化されたデータへのアクセスを管理します。データをカプセル化し、データ セキュリティの定義のためのメカニズムを提供します。 +コンテンツ プロバイダは、1 つのプロセス内のデータを別のプロセスで実行されているコードにつなげるための標準的なインターフェースです。 + +</p> +<p> + コンテンツ プロバイダのデータにアクセスする場合は、アプリケーションの {@link android.content.Context} の {@link android.content.ContentResolver} オブジェクトを使用し、クライアントとしてプロバイダとやり取りします。 + + + {@link android.content.ContentResolver} オブジェクトは、{@link android.content.ContentProvider} を実装するクラスのインスタンスである、プロバイダ オブジェクトとやり取りします。 +プロバイダ オブジェクトはクライアントからのデータ要求を受け取り、要求されたアクションを実行し、結果を返します。 + + +</p> +<p> + データを他のアプリケーションと共有しない場合は、独自のプロバイダを開発する必要はありません。 +ただし、独自のアプリケーションでカスタムの検索候補を提供する場合は、独自のプロバイダが必要になります。 +また、自分のアプリケーションから別のアプリケーションに複雑なデータやファイルをコピーして貼り付ける場合も、独自のプロバイダが必要になります。 + +</p> +<p> + Android 自身には、オーディオ、ビデオ、画像、個人的な連絡先情報などのデータを管理するコンテンツ プロバイダが用意されています。 +一部のプロバイダについては、<code><a href="{@docRoot}reference/android/provider/package-summary.html">android.provider</a> + </code> パッケージのリファレンスに一覧が記載されています。 + +いくつかの制限もありますが、これらのプロバイダにはすべての Android アプリケーションからアクセスできます。 + +</p><p> + コンテンツ プロバイダの詳細は、次のトピックをご覧ください。 +</p> +<dl> + <dt> + <strong><a href="{@docRoot}guide/topics/providers/content-provider-basics.html"> コンテンツ プロバイダの基本</a></strong> + + </dt> + <dd> + データが表形式にまとめられている場合の、コンテンツ プロバイダでのデータへのアクセス方法。 + </dd> + <dt> + <strong><a href="{@docRoot}guide/topics/providers/content-provider-creating.html"> コンテンツ プロバイダの作成</a></strong> + + </dt> + <dd> + 独自のコンテンツ プロバイダの作成方法。 + </dd> + <dt> + <strong><a href="{@docRoot}guide/topics/providers/calendar-provider.html"> カレンダー プロバイダ</a></strong> + + </dt> + <dd> + Android プラットフォームの一部であるカレンダー プロバイダへのアクセス方法。 + </dd> + <dt> + <strong><a href="{@docRoot}guide/topics/providers/contacts-provider.html"> 連絡先プロバイダ</a></strong> + + </dt> + <dd> + Android プラットフォームの一部である連絡先プロバイダへのアクセス方法。 + </dd> +</dl> diff --git a/docs/html-intl/intl/ja/guide/topics/providers/document-provider.jd b/docs/html-intl/intl/ja/guide/topics/providers/document-provider.jd new file mode 100644 index 000000000000..b4342dcdd750 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/providers/document-provider.jd @@ -0,0 +1,916 @@ +page.title=ストレージ アクセス フレームワーク +@jd:body +<div id="qv-wrapper"> +<div id="qv"> + +<h2>本書の内容 + <a href="#" onclick="hideNestedItems('#toc44',this);return false;" class="header-toggle"> + <span class="more">詳細を表示</span> + <span class="less" style="display:none">詳細を非表示</span></a></h2> +<ol id="toc44" class="hide-nested"> + <li> + <a href="#overview">概要</a> + </li> + <li> + <a href="#flow">コントロール フロー</a> + </li> + <li> + <a href="#client">クライアント アプリを作成する</a> + <ol> + <li><a href="#search">ドキュメントを検索する</a></li> + <li><a href="#process">プロセスの結果</a></li> + <li><a href="#metadata">ドキュメント メタデータを確認する</a></li> + <li><a href="#open">ドキュメントを開く</a></li> + <li><a href="#create">新しいドキュメントを作成する</a></li> + <li><a href="#delete">ドキュメントを削除する</a></li> + <li><a href="#edit">ドキュメントを編集する</a></li> + <li><a href="#permissions">パーミッションを固定する</a></li> + </ol> + </li> + <li><a href="#custom">カスタム ドキュメント プロバイダを作成する</a> + <ol> + <li><a href="#manifest">マニフェスト</a></li> + <li><a href="#contract">コントラクト</a></li> + <li><a href="#subclass">サブクラス DocumentsProvider</a></li> + <li><a href="#security">セキュリティ</a></li> + </ol> + </li> + +</ol> +<h2>キークラス</h2> +<ol> + <li>{@link android.provider.DocumentsProvider}</li> + <li>{@link android.provider.DocumentsContract}</li> +</ol> + +<h2>ビデオ</h2> + +<ol> + <li><a href="http://www.youtube.com/watch?v=zxHVeXbK1P4"> +DevBytes: Android 4.4 ストレージ アクセス フレームワーク: プロバイダ</a></li> + <li><a href="http://www.youtube.com/watch?v=UFj9AEz0DHQ"> +DevBytes: Android 4.4 ストレージ アクセス フレームワーク: クライアント</a></li> +</ol> + + +<h2>コードサンプル</h2> + +<ol> + <li><a href="{@docRoot}samples/StorageProvider/index.html"> +StorageProvider</a></li> + <li><a href="{@docRoot}samples/StorageClient/index.html"> +StorageClient</a></li> +</ol> + +<h2>関連ドキュメント</h2> +<ol> + <li> + <a href="{@docRoot}guide/topics/providers/content-provider-basics.html"> コンテンツ プロバイダの基本 </a> + + + </li> +</ol> + +</div> +</div> + + +<p>Android 4.4 (API レベル 19)は、ストレージ アクセス フレームワーク(SAF)を採用しています。SAF を利用することで、ユーザーは設定したドキュメント ストレージ プロバイダ全体から簡単にドキュメント、画像、その他のファイルを参照して開くことができます。 + +標準の使いやすい UI により、アプリやプロバイダを通じて一貫性のある方法でファイルを参照したり、最近使用したファイルにアクセスしたりできます。 +</p> + +<p>サービスをカプセル化する {@link android.provider.DocumentsProvider} を実装することで、クラウドやローカル ストレージ サービスをエコシステムに参加させることができます。 +プロバイダのドキュメントへのアクセスが必要なクライアントも、数行のコードだけで SAF と統合できます。 + +</p> + +<p>SAF には次の項目が含まれます。</p> + +<ul> +<li><strong>ドキュメント プロバイダ</strong>—ストレージ サービス(Google ドライブなど)が管理するファイルの表示を許可するコンテンツ プロバイダです。 +ドキュメント プロバイダは {@link android.provider.DocumentsProvider} クラスのサブクラスとして実装されます。document-provider スキーマは従来のファイル階層に基づくものですが、ドキュメント プロバイダが物理的にどのようにファイルを格納するかはその設定次第です。Android プラットフォームには、ダウンロード、画像、ビデオなどの組み込みのドキュメント プロバイダがいくつか用意されています。 + + + + +</li> + +<li><strong>クライアント アプリ</strong>—{@link android.content.Intent#ACTION_OPEN_DOCUMENT} または {@link android.content.Intent#ACTION_CREATE_DOCUMENT} インテントを呼び出し、ドキュメント プロバイダが返したファイルを受け取るカスタムアプリです。 + + +</li> + +<li><strong>ピッカー</strong>—クライアントアプリの検索条件を満たすすべてのドキュメント プロバイダのドキュメントにアクセスできるシステム UI です。 +</li> +</ul> + +<p>SAF は次のような機能も提供します。</p> +<ul> +<li>ユーザーは 1 つのアプリだけではなく、すべてのドキュメント プロバイダのコンテンツを参照できます。</li> +<li>アプリからドキュメント プロバイダが所有するドキュメントへの、長期間の固定アクセスを可能にします。 +このアクセスにより、ユーザーはプロバイダ上でのファイルの追加、編集、保存、削除が可能になります。 +</li> +<li>複数のユーザー アカウントと USB ストレージ プロバイダなどの一時的なルートをサポートします。一時的なルートはドライブを挿入した場合にのみ表示されます。 + </li> +</ul> + +<h2 id ="overview">概要</h2> + +<p>SAF は、{@link android.provider.DocumentsProvider} クラスのサブクラスであるコンテンツ プロバイダを中心に展開します。 +ドキュメント プロバイダでは、データは下図のように従来のファイル階層で構造化されます。<em></em> +</p> +<p><img src="{@docRoot}images/providers/storage_datamodel.png" alt="data model" /></p> +<p class="img-caption"><strong>図 1.</strong> ドキュメント プロバイダのデータモデル。ルートポイントが 1 つのドキュメントを指し、そこからツリー全体が広がります。 +</p> + +<p>注: </p> +<ul> + +<li>各ドキュメント プロバイダは、ドキュメントのツリーの検索の出発点である 1 つ以上の「ルート」を報告します。各ルートは一意の {@link android.provider.DocumentsContract.Root#COLUMN_ROOT_ID} を持ち、該当するルートの下のコンテンツを表すドキュメント(ディレクトリ)を指します。ルートはデザインによって動的に変化し、複数アカウント、一時的な USB ストレージ ドライブ、ユーザーのログインとログアウトなどのユースケースをサポートします。 + + + + + +</li> + +<li>各ルートの下のドキュメントは 1 つだけになります。そのドキュメントは、1 ~ <em>N</em> 個のドキュメントを指し、さらにそれぞれのドキュメントも 1 ~ <em>N</em> 個のドキュメントを指すことができます。 + </li> + +<li>各ストレージ バックエンドは、一意の {@link android.provider.DocumentsContract.Document#COLUMN_DOCUMENT_ID} を使って個々のファイルやディレクトリを参照して表示します。端末の再起動後も使用できる永続的な URI の付与に使用することから、ドキュメント ID は一意でなければならず、一度発行すると変更できません。 + + + +</li> + + +<li>ドキュメントには、開くことができるファイル(特定の MIME タイプを持つもの)か、追加のドキュメント({@link android.provider.DocumentsContract.Document#MIME_TYPE_DIR} MIME タイプを持つもの)を含むディレクトリのいずれかに設定できます。 + +</li> + +<li>各ドキュメントはさまざまな機能を持つことができ、{@link android.provider.DocumentsContract.Document#COLUMN_FLAGS COLUMN_FLAGS} を使って記述します。たとえば、{@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_WRITE}、{@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_DELETE}、{@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_THUMBNAIL} といった機能です。同一の {@link android.provider.DocumentsContract.Document#COLUMN_DOCUMENT_ID} は複数のディレクトリに含めることができます。 + + + + + +</li> +</ul> + +<h2 id="flow">コントロール フロー</h2> +<p>前述のように、ドキュメント プロバイダのデータモデルは従来のファイル階層を基本とします。 +ただし、{@link android.provider.DocumentsProvider} API でアクセスできるのであれば、任意の方法でデータを物理的に格納できます。たとえば、データにタグベースのクラウド ストレージを使用できます。 + +</p> + +<p>図 2 の例は、写真アプリが格納されたデータに SAF を使ってアクセスする様子を表しています。 +</p> +<p><img src="{@docRoot}images/providers/storage_dataflow.png" alt="app" /></p> + +<p class="img-caption"><strong>図 2.</strong> ストレージ アクセス フレームワーク フロー</p> + +<p>注: </p> +<ul> + +<li>SAF では、プロバイダとクライアントは直接やり取りできません。 +クライアントが、ファイルを操作(ファイルの読み取り、編集、作成、削除)するためのパーミッションを要求します。 +</li> + +<li>アプリケーション(この例では写真アプリ)がインテント {@link android.content.Intent#ACTION_OPEN_DOCUMENT} または {@link android.content.Intent#ACTION_CREATE_DOCUMENT} を起動すると、やり取りが始まります。 +インテントには、基準を詳細に調整するためのフィルタが含まれる場合があります。—たとえば、「画像」の MIME タイプを持つ、開くことができるすべてのファイルを取得する、のように設定できます。 + +</li> + +<li>インテントが起動すると、システム ピッカーが登録済みの各プロバイダに移動し、一致するコンテンツのルートをユーザーに表示します。 +</li> + +<li>基礎となるドキュメント プロバイダの種類に関係なく、ドキュメントにアクセスするための標準的なインターフェースがピッカーから提供されます。 +図 2 には、Google Drive プロバイダ、USB プロバイダ、クラウド プロバイダの例を示しています。 +</li> +</ul> + +<p>図 3 は、Google Drive アカウントを選択したユーザーが画像を検索するピッカーを表しています。 +</p> + +<p><img src="{@docRoot}images/providers/storage_picker.png" width="340" alt="picker" style="border:2px solid #ddd" /></p> + +<p class="img-caption"><strong>図 3.</strong> ピッカー</p> + +<p>ユーザーが Google Drive を選択すると、図 4 のように画像が表示されます。 +この時点から、ユーザーはプロバイダとクライアント アプリがサポートするすべての操作方法を使って、画像を操作できるようになります。 + + +<p><img src="{@docRoot}images/providers/storage_photos.png" width="340" alt="picker" style="border:2px solid #ddd" /></p> + +<p class="img-caption"><strong>図 4.</strong>画像</p> + +<h2 id="client">クライアント アプリを作成する</h2> + +<p>Android 4.3 以前では、別のアプリからファイルを取得する場合、{@link android.content.Intent#ACTION_PICK} や {@link android.content.Intent#ACTION_GET_CONTENT} といったインテントを呼び出す必要があります。 + +その後ユーザーは、ファイルを選択するためのアプリを 1 つ選びます。選択されたアプリはユーザーが使用可能なファイルを参照して選択するためのユーザー インターフェースを提供する必要があります。 + + </p> + +<p>Android 4.4 以降であれば、{@link android.content.Intent#ACTION_OPEN_DOCUMENT} インテントを使用するという選択肢もあります。このインテントではシステム制御のピッカー UI が表示され、ユーザーはそこから他のアプリで利用可能なすべてのファイル参照できます。 + + +ユーザーは、この 1 つの UI から、サポートされるすべてのアプリのファイルを選択できます。 +</p> + +<p>{@link android.content.Intent#ACTION_OPEN_DOCUMENT} は、{@link android.content.Intent#ACTION_GET_CONTENT} との置き換えを意図したものではありません。どちらを使用するかは、アプリのニーズによって異なります。 + +</p> + +<ul> +<li>アプリでデータの読み取りとインポートのみを行う場合は、{@link android.content.Intent#ACTION_GET_CONTENT} を使用します。 +この方法を使用すると、アプリは、画像ファイルなどのデータのコピーをインポートします。 +</li> + +<li>アプリからドキュメント プロバイダが所有するドキュメントへの、長期間の固定アクセスを可能にするには、{@link android.content.Intent#ACTION_OPEN_DOCUMENT} を使用します。 + +ドキュメント プロバイダに格納されている画像をユーザーが編集するための、写真編集アプリなどの例が挙げられます。 + </li> + +</ul> + + +<p>ここでは、{@link android.content.Intent#ACTION_OPEN_DOCUMENT} と {@link android.content.Intent#ACTION_CREATE_DOCUMENT} インテントに基づいたクライアント アプリの作成方法について説明します。 + +</p> + + +<h3 id="search">ドキュメントを検索する</h3> + +<p> +次のスニペットでは {@link android.content.Intent#ACTION_OPEN_DOCUMENT} を使って、画像ファイルがあるドキュメント プロバイダを検索します。 + +</p> + +<pre>private static final int READ_REQUEST_CODE = 42; +... +/** + * Fires an intent to spin up the "file chooser" UI and select an image. + */ +public void performFileSearch() { + + // ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's file + // browser. + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + + // Filter to only show results that can be "opened", such as a + // file (as opposed to a list of contacts or timezones) + intent.addCategory(Intent.CATEGORY_OPENABLE); + + // Filter to show only images, using the image MIME data type. + // If one wanted to search for ogg vorbis files, the type would be "audio/ogg". + // To search for all documents available via installed storage providers, + // it would be "*/*". + intent.setType("image/*"); + + startActivityForResult(intent, READ_REQUEST_CODE); +}</pre> + +<p>注: </p> +<ul> +<li>アプリが {@link android.content.Intent#ACTION_OPEN_DOCUMENT} インテントを開始すると、ピッカーが起動し、条件に一致するすべてのドキュメント プロバイダが表示されます。 +</li> + +<li>カテゴリ {@link android.content.Intent#CATEGORY_OPENABLE} をインテントに追加すると、結果がフィルタリングされ、画像ファイルなどの開くことができるドキュメントのみが表示されます。 +</li> + +<li>{@code intent.setType("image/*")} 文は結果をさらにフィルタリングし、画像 MIME データタイプを持つドキュメントのみを表示します。 +</li> +</ul> + +<h3 id="results">プロセスの結果</h3> + +<p>ユーザーがピッカーでドキュメントを選択すると、{@link android.app.Activity#onActivityResult onActivityResult()} が呼び出されます。選択したドキュメントを指す URI は {@code resultData} パラメータに含まれます。 + + +{@link android.content.Intent#getData getData()} を使って URI を抽出します。URI を抽出したら、その URI を使ってユーザーが希望するドキュメントを取得できます。 +次に例を示します。 +</p> + +<pre>@Override +public void onActivityResult(int requestCode, int resultCode, + Intent resultData) { + + // The ACTION_OPEN_DOCUMENT intent was sent with the request code + // READ_REQUEST_CODE. If the request code seen here doesn't match, it's the + // response to some other intent, and the code below shouldn't run at all. + + if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) { + // The document selected by the user won't be returned in the intent. + // Instead, a URI to that document will be contained in the return intent + // provided to this method as a parameter. + // Pull that URI using resultData.getData(). + Uri uri = null; + if (resultData != null) { + uri = resultData.getData(); + Log.i(TAG, "Uri: " + uri.toString()); + showImage(uri); + } + } +} +</pre> + +<h3 id="metadata">ドキュメント メタデータを確認する</h3> + +<p>ドキュメントのURI を取得したら、そのメタデータにアクセスできます。次のスニペットは、URI で指定したドキュメントのメタデータを取得して、ログに記録します。 +</p> + +<pre>public void dumpImageMetaData(Uri uri) { + + // The query, since it only applies to a single document, will only return + // one row. There's no need to filter, sort, or select fields, since we want + // all fields for one document. + Cursor cursor = getActivity().getContentResolver() + .query(uri, null, null, null, null, null); + + try { + // moveToFirst() returns false if the cursor has 0 rows. Very handy for + // "if there's anything to look at, look at it" conditionals. + if (cursor != null && cursor.moveToFirst()) { + + // Note it's called "Display Name". This is + // provider-specific, and might not necessarily be the file name. + String displayName = cursor.getString( + cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); + Log.i(TAG, "Display Name: " + displayName); + + int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE); + // If the size is unknown, the value stored is null. But since an + // int can't be null in Java, the behavior is implementation-specific, + // which is just a fancy term for "unpredictable". So as + // a rule, check if it's null before assigning to an int. This will + // happen often: The storage API allows for remote files, whose + // size might not be locally known. + String size = null; + if (!cursor.isNull(sizeIndex)) { + // Technically the column stores an int, but cursor.getString() + // will do the conversion automatically. + size = cursor.getString(sizeIndex); + } else { + size = "Unknown"; + } + Log.i(TAG, "Size: " + size); + } + } finally { + cursor.close(); + } +} +</pre> + +<h3 id="open-client">ドキュメントを開く</h3> + +<p>ドキュメントのURI を取得したら、そのドキュメントを開いてさまざまな操作を行うことができます。 +</p> + +<h4>ビットマップ</h4> + +<p>{@link android.graphics.Bitmap} を開く方法の例を次に示します。</p> + +<pre>private Bitmap getBitmapFromUri(Uri uri) throws IOException { + ParcelFileDescriptor parcelFileDescriptor = + getContentResolver().openFileDescriptor(uri, "r"); + FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor(); + Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor); + parcelFileDescriptor.close(); + return image; +} +</pre> + +<p>この操作を UI スレッドで実行しないでください。{@link android.os.AsyncTask} を使ってバックグラウンドで実行します。 +ビットマップを開いたら、{@link android.widget.ImageView} で表示できます。 + +</p> + +<h4>InputStream を取得する</h4> + +<p>URI から {@link java.io.InputStream} を取得する方法の例を次に示します。このスニペットでは、ファイルの行が文字列に読み込まれます。 +</p> + +<pre>private String readTextFromUri(Uri uri) throws IOException { + InputStream inputStream = getContentResolver().openInputStream(uri); + BufferedReader reader = new BufferedReader(new InputStreamReader( + inputStream)); + StringBuilder stringBuilder = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + stringBuilder.append(line); + } + fileInputStream.close(); + parcelFileDescriptor.close(); + return stringBuilder.toString(); +} +</pre> + +<h3 id="create">新しいドキュメントを作成する</h3> + +<p>{@link android.content.Intent#ACTION_CREATE_DOCUMENT} インテントを使用すると、アプリでドキュメント プロバイダに新しいドキュメントを作成できます。 + +ファイルを作成するには、インテントに MIME タイプとファイル名を渡し、一意の要求コードを使ってインテントを起動します。 +後は自分で設定します。</p> + + +<pre> +// Here are some examples of how you might call this method. +// The first parameter is the MIME type, and the second parameter is the name +// of the file you are creating: +// +// createFile("text/plain", "foobar.txt"); +// createFile("image/png", "mypicture.png"); + +// Unique request code. +private static final int WRITE_REQUEST_CODE = 43; +... +private void createFile(String mimeType, String fileName) { + Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); + + // Filter to only show results that can be "opened", such as + // a file (as opposed to a list of contacts or timezones). + intent.addCategory(Intent.CATEGORY_OPENABLE); + + // Create a file with the requested MIME type. + intent.setType(mimeType); + intent.putExtra(Intent.EXTRA_TITLE, fileName); + startActivityForResult(intent, WRITE_REQUEST_CODE); +} +</pre> + +<p>新しいドキュメントを作成したら、{@link android.app.Activity#onActivityResult onActivityResult()} で URI を取得して、ドキュメントに書き込み操作を実行できます。 + +</p> + +<h3 id="delete">ドキュメントを削除する</h3> + +<p>ドキュメントの URI と、{@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_DELETE SUPPORTS_DELETE} を含むドキュメントの {@link android.provider.DocumentsContract.Document#COLUMN_FLAGS Document.COLUMN_FLAGS} を取得すると、ドキュメントを削除できます。 + + + +次に例を示します。</p> + +<pre> +DocumentsContract.deleteDocument(getContentResolver(), uri); +</pre> + +<h3 id="edit">ドキュメントを編集する</h3> + +<p>SAF を使用するとテキスト ドキュメントを直接編集できます。このスニペットは {@link android.content.Intent#ACTION_OPEN_DOCUMENT} インテントを起動し、カテゴリ {@link android.content.Intent#CATEGORY_OPENABLE} を使って、開くことができるドキュメントのみを表示します。 + + + +次のように、テキスト ファイルのみを表示するようにフィルタリングします。</p> + +<pre> +private static final int EDIT_REQUEST_CODE = 44; +/** + * Open a file for writing and append some text to it. + */ + private void editDocument() { + // ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's + // file browser. + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + + // Filter to only show results that can be "opened", such as a + // file (as opposed to a list of contacts or timezones). + intent.addCategory(Intent.CATEGORY_OPENABLE); + + // Filter to show only text files. + intent.setType("text/plain"); + + startActivityForResult(intent, EDIT_REQUEST_CODE); +} +</pre> + +<p>次に、{@link android.app.Activity#onActivityResult onActivityResult()}(「<a href="#results">プロセスの結果</a>」をご覧ください)からコードを呼び出して、編集を行います。次のスニペットは {@link android.content.ContentResolver} から {@link java.io.FileOutputStream} を取得します。 + + +デフォルトでは、「書き込み」モードを使用します。必要最小限のアクセスのみを要求することをお勧めします。書き込みのみが必要な場合に読み込みと書き込みを要求しないでください。 + +</p> + +<pre>private void alterDocument(Uri uri) { + try { + ParcelFileDescriptor pfd = getActivity().getContentResolver(). + openFileDescriptor(uri, "w"); + FileOutputStream fileOutputStream = + new FileOutputStream(pfd.getFileDescriptor()); + fileOutputStream.write(("Overwritten by MyCloud at " + + System.currentTimeMillis() + "\n").getBytes()); + // Let the document provider know you're done by closing the stream. + fileOutputStream.close(); + pfd.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } +}</pre> + +<h3 id="permissions">パーミッションを固定する</h3> + +<p>アプリで読み込みや書き込み用にファイルを開くと、システムからアプリに対して、該当するファイルの URI パーミッションが付与されます。 +このパーミッションはユーザーが端末を再起動するまで有効です。ただし、画像アプリでユーザーが最近編集した 5 つの画像にアプリから直接アクセスできるようにするにはどうすればいいでしょう。ユーザーの端末が再起動されたら、ファイルを検索するためにユーザーをシステム ピッカーに戻す必要がありますが、これは明らかにいい方法とは言えません。 + + + +</p> + +<p>このような状況を避けるために、システムがアプリに付与するパーミッションを固定します。実際は、システムが提供する固定可能な URI パーミッションをアプリで「取得」します。 + +これにより、端末を再起動した場合でも、ユーザーはアプリからファイルに継続的にアクセスできます。 +</p> + + +<pre>final int takeFlags = intent.getFlags() + & (Intent.FLAG_GRANT_READ_URI_PERMISSION + | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); +// Check for the freshest data. +getContentResolver().takePersistableUriPermission(uri, takeFlags);</pre> + +<p>最後にもう 1 つ手順があります。アプリが最近アクセスした URI は、保存されていても既に無効になっている場合があります。—別のアプリによってドキュメントが削除されたり、修正されたりすることが考えられます。 + +そこで、最新のデータを確認するには、常に {@code getContentResolver().takePersistableUriPermission()} を呼び出す必要があります。 + +</p> + +<h2 id="custom">カスタム ドキュメント プロバイダを作成する</h2> + +<p> +ファイル用のストレージ サービスを提供するアプリ(クラウド保存サービスなど)を開発する場合、カスタム ドキュメント プロバイダを作成すれば、SAF を介してファイルを利用可能にできます。 + +ここではその方法について説明します。 +</p> + + +<h3 id="manifest">マニフェスト</h3> + +<p>カスタム ドキュメント プロバイダを実装するには、アプリケーションのマニフェストに次のものを追加します。 +</p> +<ul> + +<li>API レベル 19 以降のターゲット。</li> + +<li>カスタム ストレージ プロバイダを宣言する <code><provider></code> 要素。 + </li> + +<li>クラス名となる、プロバイダの名前。パッケージ名を含みます。例: <code>com.example.android.storageprovider.MyCloudProvider</code>。 +</li> + +<li>認証局の名前。これはパッケージ名(この例では <code>com.example.android.storageprovider</code>)とコンテンツ プロバイダのタイプを合わせたもの(<code>documents</code>)。 + +たとえば、{@code com.example.android.storageprovider.documents} のようになります。</li> + +<li><code>"true"</code> に設定された属性 <code>android:exported</code>。他のアプリで認識できるようにプロバイダをエクスポートする必要があります。 +</li> + +<li><code>"true"</code> に設定された属性 <code>android:grantUriPermissions</code>。 +この設定により、プロバイダのコンテンツにアクセスできるように、システムが他のアプリにアクセス権を付与します。 +特定のドキュメントへのアクセス権を固定する方法については、「<a href="#permissions">パーミッションを固定する</a>」をご覧ください。 +</li> + +<li>{@code MANAGE_DOCUMENTS} パーミッション。デフォルトでは、プロバイダはすべてのユーザーが利用可能です。 +このパーミッションを追加することで、プロバイダをシステムに制限できます。セキュリティ上この制限は重要です。 +</li> + +<li>リソース ファイルで定義したブール値に設定された {@code android:enabled} 属性。 +この属性は、Android 4.3 以前を実行する端末でプロバイダを無効にすることを目的としています。たとえば、{@code android:enabled="@bool/atLeastKitKat"} のようになります。 +マニフェストのこの属性に加え、次の操作を実行する必要があります。 + +<ul> +<li>{@code res/values/} にある {@code bool.xml} リソース ファイルに、次の行を追加します。 + <pre><bool name="atLeastKitKat">false</bool></pre></li> + +<li>{@code res/values-v19/} にある {@code bool.xml} リソース ファイルに、次の行を追加します。 + <pre><bool name="atLeastKitKat">true</bool></pre></li> +</ul></li> + +<li>{@code android.content.action.DOCUMENTS_PROVIDER} アクションを含むインテント フィルタ。システムがプロバイダを検索したときに、プロバイダがピッカーに表示されます。 + +</li> + +</ul> +<p>プロバイダを含むサンプル マニフェストの抜粋を次に示します。</p> + +<pre><manifest... > + ... + <uses-sdk + android:minSdkVersion="19" + android:targetSdkVersion="19" /> + .... + <provider + android:name="com.example.android.storageprovider.MyCloudProvider" + android:authorities="com.example.android.storageprovider.documents" + android:grantUriPermissions="true" + android:exported="true" + android:permission="android.permission.MANAGE_DOCUMENTS" + android:enabled="@bool/atLeastKitKat"> + <intent-filter> + <action android:name="android.content.action.DOCUMENTS_PROVIDER" /> + </intent-filter> + </provider> + </application> + +</manifest></pre> + +<h4 id="43">Android 4.3 以前を実行する端末をサポートする</h4> + +<p>{@link android.content.Intent#ACTION_OPEN_DOCUMENT} インテントは、Android 4.4 以降を実行する端末でのみ利用可能です。Android 4.3 以前を実行する端末に対応するためにアプリケーションで {@link android.content.Intent#ACTION_GET_CONTENT} をサポートするには、Android 4.4 以降を実行する端末のマニフェストで {@link android.content.Intent#ACTION_GET_CONTENT} インテント フィルタを無効にする必要があります。 + + + + + +ドキュメント プロバイダと {@link android.content.Intent#ACTION_GET_CONTENT} は互いに排他的な関係にあると考える必要があります。 + +両方を同時にサポートする場合、アプリはシステム ピッカー UI に 2 度表示され、格納されたデータへの 2 つの異なる方法を提供します。 + +これではユーザーも操作に迷ってしまいます。</p> + +<p>ここでは、Android バージョン 4.4 以降を実行する端末で {@link android.content.Intent#ACTION_GET_CONTENT} インテント フィルタを無効にする際に推奨される方法を紹介します。 + +</p> + +<ol> +<li>{@code res/values/} にある {@code bool.xml} リソース ファイルに、次の行を追加します。 + <pre><bool name="atMostJellyBeanMR2">true</bool></pre></li> + +<li>{@code res/values-v19/} にある {@code bool.xml} リソース ファイルに、次の行を追加します。 + <pre><bool name="atMostJellyBeanMR2">false</bool></pre></li> + +<li>4.4 (API レベル 19)以降のバージョンに対して {@link android.content.Intent#ACTION_GET_CONTENT} インテント フィルタを無効にするには、<a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">アクティビティ エイリアス</a>を追加します。 + + +次に例を示します。 + +<pre> +<!-- This activity alias is added so that GET_CONTENT intent-filter + can be disabled for builds on API level 19 and higher. --> +<activity-alias android:name="com.android.example.app.MyPicker" + android:targetActivity="com.android.example.app.MyActivity" + ... + android:enabled="@bool/atMostJellyBeanMR2"> + <intent-filter> + <action android:name="android.intent.action.GET_CONTENT" /> + <category android:name="android.intent.category.OPENABLE" /> + <category android:name="android.intent.category.DEFAULT" /> + <data android:mimeType="image/*" /> + <data android:mimeType="video/*" /> + </intent-filter> +</activity-alias> +</pre> +</li> +</ol> +<h3 id="contract">コントラクト</h3> + +<p>通常、カスタム コンテンツ プロバイダを作成するときには、<a href="{@docRoot}guide/topics/providers/content-provider-creating.html#ContractClass">コンテンツ プロバイダ</a>のデベロッパー ガイドに記載があるように、コントラクト クラスを実装するタスクが必要になります。 + + +コントラクト クラスは {@code public final} クラスであり、URI、列名、MIME タイプ、プロバイダに関連するその他のメタデータを含みます。 + +コントラクト クラスは SAF によって提供されるため、独自に作成する必要はありません。 + +</p> + +<ul> + <li>{@link android.provider.DocumentsContract.Document}</li> + <li>{@link android.provider.DocumentsContract.Root}</li> +</ul> + +<p>たとえば、ドキュメント プロバイダでドキュメントやルートを照会したときには、カーソルに次のような列が返されることがあります。 +</p> + +<pre>private static final String[] DEFAULT_ROOT_PROJECTION = + new String[]{Root.COLUMN_ROOT_ID, Root.COLUMN_MIME_TYPES, + Root.COLUMN_FLAGS, Root.COLUMN_ICON, Root.COLUMN_TITLE, + Root.COLUMN_SUMMARY, Root.COLUMN_DOCUMENT_ID, + Root.COLUMN_AVAILABLE_BYTES,}; +private static final String[] DEFAULT_DOCUMENT_PROJECTION = new + String[]{Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE, + Document.COLUMN_DISPLAY_NAME, Document.COLUMN_LAST_MODIFIED, + Document.COLUMN_FLAGS, Document.COLUMN_SIZE,}; +</pre> + +<h3 id="subclass">サブクラス DocumentsProvider</h3> + +<p>カスタム ドキュメント プロバイダの作成の次の手順では、抽象クラス {@link android.provider.DocumentsProvider} をサブクラス化します。 +少なくとも、次のメソッドを実装する必要があります。 +</p> + +<ul> +<li>{@link android.provider.DocumentsProvider#queryRoots queryRoots()}</li> + +<li>{@link android.provider.DocumentsProvider#queryChildDocuments queryChildDocuments()}</li> + +<li>{@link android.provider.DocumentsProvider#queryDocument queryDocument()}</li> + +<li>{@link android.provider.DocumentsProvider#openDocument openDocument()}</li> +</ul> + +<p>これらは実装する必要があるメソッドですが、これ以外にも多くのメソッドを実装できます。 +詳細については、{@link android.provider.DocumentsProvider} をご覧ください。 +</p> + +<h4 id="queryRoots">queryRoots を実装する</h4> + +<p>{@link android.provider.DocumentsProvider#queryRoots +queryRoots()} を実装すると、{@link android.provider.DocumentsContract.Root} で定義される列を使って、ドキュメント プロバイダのすべてのルート ディレクトリを指す {@link android.database.Cursor} が返されます。 + +</p> + +<p>次のスニペットの {@code projection} パラメータは、呼び出し側が取得する特定のフィールドを表します。 +スニペットは新しいカーソルを作成し、それに行を 1 つ追加します。—[ダウンロード] や [画像] と同じように、1 つのルートに対して最上位のディレクトリが 1 つになります。 + +ほとんどのプロバイダでルートは 1 つになります。複数のユーザー アカウントを使用するような場合は、1 つ以上のルートを設定できます。 +その場合、カーソルに 2 つ目の行を追加します。 +</p> + +<pre> +@Override +public Cursor queryRoots(String[] projection) throws FileNotFoundException { + + // Create a cursor with either the requested fields, or the default + // projection if "projection" is null. + final MatrixCursor result = + new MatrixCursor(resolveRootProjection(projection)); + + // If user is not logged in, return an empty root cursor. This removes our + // provider from the list entirely. + if (!isUserLoggedIn()) { + return result; + } + + // It's possible to have multiple roots (e.g. for multiple accounts in the + // same app) -- just add multiple cursor rows. + // Construct one row for a root called "MyCloud". + final MatrixCursor.RowBuilder row = result.newRow(); + row.add(Root.COLUMN_ROOT_ID, ROOT); + row.add(Root.COLUMN_SUMMARY, getContext().getString(R.string.root_summary)); + + // FLAG_SUPPORTS_CREATE means at least one directory under the root supports + // creating documents. FLAG_SUPPORTS_RECENTS means your application's most + // recently used documents will show up in the "Recents" category. + // FLAG_SUPPORTS_SEARCH allows users to search all documents the application + // shares. + row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | + Root.FLAG_SUPPORTS_RECENTS | + Root.FLAG_SUPPORTS_SEARCH); + + // COLUMN_TITLE is the root title (e.g. Gallery, Drive). + row.add(Root.COLUMN_TITLE, getContext().getString(R.string.title)); + + // This document id cannot change once it's shared. + row.add(Root.COLUMN_DOCUMENT_ID, getDocIdForFile(mBaseDir)); + + // The child MIME types are used to filter the roots and only present to the + // user roots that contain the desired type somewhere in their file hierarchy. + row.add(Root.COLUMN_MIME_TYPES, getChildMimeTypes(mBaseDir)); + row.add(Root.COLUMN_AVAILABLE_BYTES, mBaseDir.getFreeSpace()); + row.add(Root.COLUMN_ICON, R.drawable.ic_launcher); + + return result; +}</pre> + +<h4 id="queryChildDocuments">queryChildDocuments を実装する</h4> + +<p>{@link android.provider.DocumentsProvider#queryChildDocuments queryChildDocuments()} を実装すると、{@link android.provider.DocumentsContract.Document} で定義される列を使って、指定したディレクトリ内のすべてのファイルを指す {@link android.database.Cursor} が返されます。 + + + +</p> + +<p>ピッカー UI でアプリケーション ルートを選択すると、このメソッドが呼び出されます。ルートの下のディレクトリの子ドキュメントを取得します。 +ルートだけでなく、ファイル階層内の任意のレベルで呼び出せます。 +このスニペットでは、要求した列を持つ新しいカーソルが作成され、親ディレクトリのすぐ下のそれぞれの子の情報がカーソルに追加されます。子は、画像、別のディレクトリなど—任意のファイルとなります。 + + +</p> + +<pre>@Override +public Cursor queryChildDocuments(String parentDocumentId, String[] projection, + String sortOrder) throws FileNotFoundException { + + final MatrixCursor result = new + MatrixCursor(resolveDocumentProjection(projection)); + final File parent = getFileForDocId(parentDocumentId); + for (File file : parent.listFiles()) { + // Adds the file's display name, MIME type, size, and so on. + includeFile(result, null, file); + } + return result; +} +</pre> + +<h4 id="queryDocument">queryDocument を実装する</h4> + +<p>{@link android.provider.DocumentsProvider#queryDocument queryDocument()} を実装すると、{@link android.provider.DocumentsContract.Document} で定義される列を使って、指定したファイルを指す {@link android.database.Cursor} が返されます。 + + + +</p> + +<p>{@link android.provider.DocumentsProvider#queryDocument queryDocument()} メソッドでは、特定のファイルの情報ではなく、{@link android.provider.DocumentsProvider#queryChildDocuments queryChildDocuments()} に渡したのと同じ情報が返されます。 + + +</p> + + +<pre>@Override +public Cursor queryDocument(String documentId, String[] projection) throws + FileNotFoundException { + + // Create a cursor with the requested projection, or the default projection. + final MatrixCursor result = new + MatrixCursor(resolveDocumentProjection(projection)); + includeFile(result, documentId, null); + return result; +} +</pre> + +<h4 id="openDocument">openDocument を実装する</h4> + +<p>指定したファイルを表す {@link android.os.ParcelFileDescriptor} を返すには、{@link android.provider.DocumentsProvider#openDocument +openDocument()} を実装する必要があります。 +他のアプリは、返された {@link android.os.ParcelFileDescriptor} を使ってデータをストリーミングします。 +ユーザーがファイルを選択するとシステムがこのメソッドを呼び出し、クライアント アプリは {@link android.content.ContentResolver#openFileDescriptor openFileDescriptor()} を呼び出してファイルへのアクセスを要求します。次に例を示します。 + + +</p> + +<pre>@Override +public ParcelFileDescriptor openDocument(final String documentId, + final String mode, + CancellationSignal signal) throws + FileNotFoundException { + Log.v(TAG, "openDocument, mode: " + mode); + // It's OK to do network operations in this method to download the document, + // as long as you periodically check the CancellationSignal. If you have an + // extremely large file to transfer from the network, a better solution may + // be pipes or sockets (see ParcelFileDescriptor for helper methods). + + final File file = getFileForDocId(documentId); + + final boolean isWrite = (mode.indexOf('w') != -1); + if(isWrite) { + // Attach a close listener if the document is opened in write mode. + try { + Handler handler = new Handler(getContext().getMainLooper()); + return ParcelFileDescriptor.open(file, accessMode, handler, + new ParcelFileDescriptor.OnCloseListener() { + @Override + public void onClose(IOException e) { + + // Update the file with the cloud server. The client is done + // writing. + Log.i(TAG, "A file with id " + + documentId + " has been closed! + Time to " + + "update the server."); + } + + }); + } catch (IOException e) { + throw new FileNotFoundException("Failed to open document with id " + + documentId + " and mode " + mode); + } + } else { + return ParcelFileDescriptor.open(file, accessMode); + } +} +</pre> + +<h3 id="security">セキュリティ</h3> + +<p>たとえば、ドキュメント プロバイダがパスワードで保護されたクラウド ストレージ サービスであり、ファイル共有を開始する前にユーザーがログインしているかどうかを確認するとします。ユーザーがログインしていない場合、アプリはどのような動作を行う必要があるでしょうか。 + +このような場合、{@link android.provider.DocumentsProvider#queryRoots +queryRoots()} の実装のゼロルートを返すようにします。 +つまり、空のルートカーソルになります。</p> + +<pre> +public Cursor queryRoots(String[] projection) throws FileNotFoundException { +... + // If user is not logged in, return an empty root cursor. This removes our + // provider from the list entirely. + if (!isUserLoggedIn()) { + return result; +} +</pre> + +<p>その他に {@code getContentResolver().notifyChange()} を呼び出す手順もあります。{@link android.provider.DocumentsContract} については既に説明してあります。 +これを使ってこの URI を作成します。次のスニペットは、ユーザーのログイン ステータスが変わった場合に、ドキュメント プロバイダのルートを照会するようシステムに指示します。 + +ユーザーがログインしてない場合は、上述のように、{@link android.provider.DocumentsProvider#queryRoots queryRoots()} を呼び出すと空のカーソルが返されます。 + +こうすることで、ユーザーがプロバイダにログインしている場合にのみ、プロバイダのドキュメントを利用できます。 +</p> + +<pre>private void onLoginButtonClick() { + loginOrLogout(); + getContentResolver().notifyChange(DocumentsContract + .buildRootsUri(AUTHORITY), null); +} +</pre>
\ No newline at end of file diff --git a/docs/html-intl/intl/ja/guide/topics/resources/accessing-resources.jd b/docs/html-intl/intl/ja/guide/topics/resources/accessing-resources.jd new file mode 100644 index 000000000000..af8d005dac42 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/resources/accessing-resources.jd @@ -0,0 +1,337 @@ +page.title=リソースへのアクセス +parent.title=アプリケーション リソース +parent.link=index.html +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + <h2>クイックビュー</h2> + <ul> + <li>リソースは、{@code R.java} の整数を使うコード({@code R.drawable.myimage} など)を使用して参照できます。 +</li> + <li>リソースは、特殊な XML 構文({@code +@drawable/myimage} など)を使用して参照できます。</li> + <li>さらに、{@link android.content.res.Resources} のメソッドを使用すると、アプリ リソースにアクセスできます。 +</li> + </ul> + + <h2>キークラス</h2> + <ol> + <li>{@link android.content.res.Resources}</li> + </ol> + + <h2>本書の内容</h2> + <ol> + <li><a href="#ResourcesFromCode">コードからリソースにアクセスする</a></li> + <li><a href="#ResourcesFromXml">XML からリソースにアクセスする</a> + <ol> + <li><a href="#ReferencesToThemeAttributes">スタイル属性を参照する</a></li> + </ol> + </li> + <li><a href="#PlatformResources">プラットフォーム リソースにアクセスする</a></li> + </ol> + + <h2>関連ドキュメント</h2> + <ol> + <li><a href="providing-resources.html">リソースの提供</a></li> + <li><a href="available-resources.html">Resource Types</a></li> + </ol> +</div> +</div> + + + + +<p>アプリケーションでリソースを提供すると(詳細は「<a href="providing-resources.html">リソースの提供</a>」)、リソース ID を参照することで適用できるようになります。リソース ID はすべてプロジェクトの {@code R} クラスで定義します。これは {@code aapt} ツールが自動的に生成します。 + +</p> + +<p>アプリケーションをコンパイルすると、{@code aapt} が {@code R} クラスを生成します。このクラスには、{@code +res/} ディレクトリに含まれるの全リソースのリソース ID が入ります。 +リソースのそれぞれのタイプに対して、{@code R} サブクラス(例: ドローアブル リソースの場合はすべて {@code R.drawable})があり、そのタイプのそれぞれのリソースには、静的整数(例: {@code R.drawable.icon})があります。 + +この整数がリソース ID であり、リソースを取得するのに使用できます。 +</p> + +<p>{@code R} クラスではリソース ID を指定されていますが、リソース ID を探す必要はありません。リソース ID は常に次のように構成されます。 +</p> +<ul> + <li><em>リソースタイプ</em>: それぞれのリソースは、{@code +string}、{@code drawable}、{@code layout} のようなタイプにグループ化されます。さまざまなタイプに関する詳細は、「<a href="available-resources.html">Resource Types</a>」をご覧ください。 + </li> + <li><em>リソース名</em>。これは、拡張子を除外したファイル名か、XML {@code android:name} 属性(リソースが文字列などの単純な値の場合)のいずれかになります。 + +</li> +</ul> + +<p>リソースにアクセスするには次の 2 つの方法があります。</p> +<ul> + <li><strong>コード内:</strong> {@code R} クラスのサブクラスから次のような静的整数を使用します。 + + <pre class="classic no-pretty-print">R.string.hello</pre> + <p>{@code string} はリソースタイプ、{@code hello} はリソース名です。多くの Android API が、リソース ID をこの形式で指定してリソースにアクセスします。 +<a href="#ResourcesFromCode">コードでリソースにアクセスする</a>をご覧ください。 +</p> + </li> + <li><strong>XML 内:</strong> {@code R} クラスで定義するリソース ID に対応する、次のような特殊な XML 構文を使用します。 + + <pre class="classic no-pretty-print">@string/hello</pre> + <p>{@code string} はリソースタイプ、{@code hello} はリソース名です。この構文は、リソースで提供する値が想定される、XML リソース内の任意の場所に使用できます。 +<a href="#ResourcesFromXml">XML からリソースにアクセスする</a>をご覧ください。</p> + </li> +</ul> + + + +<h2 id="ResourcesFromCode">コードでリソースにアクセスする </h2> + +<p>リソース ID をメソッド パラメータとして渡すことで、コード内でリソースを使用できます。たとえば、{@link android.widget.ImageView#setImageResource(int) setImageResource()} を使って、{@link android.widget.ImageView} が {@code res/drawable/myimage.png} を使用するように設定できます。 + +</p> +<pre> +ImageView imageView = (ImageView) findViewById(R.id.myimageview); +imageView.setImageResource(<strong>R.drawable.myimage</strong>); +</pre> + +<p>さらに、{@link +android.content.res.Resources} のメソッドを使用して、個々のリソースを取得することもできます。{@link android.content.Context#getResources()} を使用すると、インスタンスを取得できます。 +</p> + +<div class="sidebox-wrapper"> +<div class="sidebox"> +<h2>元のファイルへのアクセス</h2> + +<p>一般的な操作ではありませんが、元のファイルやディレクトリへのアクセスが必要になることがあります。その場合、{@code res/} からリソースを読み込むにはリソース ID が必要なため、{@code res/} にファイルを保存しても機能しません。その代わりに、{@code assets/} ディレクトリにリソースを保存します。 + + +</p> +<p>{@code assets/} ディレクトリに保存したファイルにはリソース ID が付与されないため、<em></em>{@code R} クラスや XML リソースからはそれらのファイルを参照できません。 +その代わりに、通常のファイル システムのように {@code assets/} ディレクトリ内のファイルを照会し、{@link android.content.res.AssetManager} を使用して未処理のデータを読み込みます。 + +</p> +<p>ただし、単に(ビデオやオーディオなどの)未処理データの読み込みのみが必要となる場合は、ファイルを {@code res/raw/} ディレクトリに保存し、{@link +android.content.res.Resources#openRawResource(int) openRawResource()} を使用してバイトのストリームを読み込みます。 +</p> + +</div> +</div> + + +<h3>構文</h3> + +<p>次の構文を使用して、コード内のリソースを参照します。</p> + +<pre class="classic no-pretty-print"> +[<em><package_name></em>.]R.<em><resource_type></em>.<em><resource_name></em> +</pre> + +<ul> + <li><em>{@code <package_name>}</em> は、リソースが配置されるパッケージの名前です(独自のパッケージからリソースを参照する場合は必要ありません)。 +</li> + <li><em>{@code <resource_type>}</em> は、リソースタイプの {@code R} サブクラスです。</li> + <li><em>{@code <resource_name>}</em> は、拡張子以外のリソース ファイル名か、XML 要素の {@code android:name} 属性値(単純な値の場合)のいずれかになります。 + +</li> +</ul> +<p>リソースタイプの詳細やそれらの査証方法については、「<a href="available-resources.html">Resource Types</a>」をご覧ください。 +</p> + + +<h3>使用例</h3> + +<p>多くのメソッドでリソース ID パラメータを使うことができ、{@link android.content.res.Resources} のメソッドを使用すればリソースを取得できます。 +{@link +android.content.res.Resources} のインスタンスは、{@link android.content.Context#getResources +Context.getResources()} により取得できます。</p> + + +<p>次は、コードのリソースにアクセスする例です。</p> + +<pre> +// Load a background for the current screen from a drawable resource +{@link android.app.Activity#getWindow()}.{@link +android.view.Window#setBackgroundDrawableResource(int) +setBackgroundDrawableResource}(<strong>R.drawable.my_background_image</strong>) ; + +// Set the Activity title by getting a string from the Resources object, because +// this method requires a CharSequence rather than a resource ID +{@link android.app.Activity#getWindow()}.{@link android.view.Window#setTitle(CharSequence) +setTitle}(getResources().{@link android.content.res.Resources#getText(int) +getText}(<strong>R.string.main_title</strong>)); + +// Load a custom layout for the current screen +{@link android.app.Activity#setContentView(int) +setContentView}(<strong>R.layout.main_screen</strong>); + +// Set a slide in animation by getting an Animation from the Resources object +mFlipper.{@link android.widget.ViewAnimator#setInAnimation(Animation) +setInAnimation}(AnimationUtils.loadAnimation(this, + <strong>R.anim.hyperspace_in</strong>)); + +// Set the text on a TextView object using a resource ID +TextView msgTextView = (TextView) findViewById(<strong>R.id.msg</strong>); +msgTextView.{@link android.widget.TextView#setText(int) +setText}(<strong>R.string.hello_message</strong>); +</pre> + + +<p class="caution"><strong>警告:</strong> {@code +R.java} ファイルを手動で修正しないでください。—プロジェクトがコンパイルされると、{@code aapt} ツールによって生成されます。 +変更した場合は、次回のコンパイルの際に上書きされます。</p> + + + +<h2 id="ResourcesFromXml">XML からリソースにアクセスする</h2> + +<p>一部の XML 属性や要素の値は、既存のリソースへの参照を使用して定義できます。 +通常は、ウィジェットに文字列や画像を提供するレイアウト ファイルを作成する場合に、この方法を使用します。 +</p> + +<p>たとえば、レイアウトに {@link android.widget.Button} を追加する場合は、次のように、ボタンテキストの<a href="string-resource.html">文字列リソース</a>を使用します。 +</p> + +<pre> +<Button + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="<strong>@string/submit</strong>" /> +</pre> + + +<h3>構文</h3> + +<p>次の構文を使用して、XML リソース内のリソースを参照します。</p> + +<pre class="classic no-pretty-print"> +@[<em><package_name></em>:]<em><resource_type></em>/<em><resource_name></em> +</pre> + +<ul> + <li>{@code <package_name>} は、リソースが配置されるパッケージの名前です(同一のパッケージからリソースを参照する場合は必要ありません) +</li> + <li>{@code <resource_type>} は、リソースタイプの {@code R} サブクラスです +</li> + <li>{@code <resource_name>} は、拡張子以外のリソース ファイル名か、XML 要素の {@code android:name} 属性値(単純な値の場合)のいずれかになります。 + +</li> +</ul> + +<p>リソースタイプの詳細やそれらの査証方法については、「<a href="available-resources.html">Resource Types</a>」をご覧ください。 +</p> + + +<h3>使用例</h3> + +<p>場合によっては、XML の値にリソースを使用する必要がありますが(ウィジェットにドローアブル画像を適用するような場合など)、単純な値を受け入れる XML の任意の場所にリソースを使用できます。 +たとえば、<a href="more-resources.html#Color">カラーリソース</a>と<a href="string-resource.html">文字列リソース</a>を持つ、次のようなリソースがあるとします。 +</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<resources> + <color name="opaque_red">#f00</color> + <string name="hello">Hello!</string> +</resources> +</pre> + +<p>これらのリソースを次のようなレイアウト ファイルに使用して、テキストカラーとテキストの文字列を設定できます。 +</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<EditText xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:textColor="<strong>@color/opaque_red</strong>" + android:text="<strong>@string/hello</strong>" /> +</pre> + +<p>この場合、リソースは独自のパッケージ内のものであることから、リソースの参照でパッケージ名を指定する必要はありません。 +システム リソースを参照するには、パッケージ名を含める必要があります。 +次に例を示します。</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<EditText xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:textColor="<strong>@android:color/secondary_text_dark</strong>" + android:text="@string/hello" /> +</pre> + +<p class="note"><strong>注:</strong> アプリケーションを他の言語にローカライズできるように、常に文字列リソースを使用するようにします。 +代替リソース(ローカライズされた文字列など)の作成方法についての詳細は、<a href="providing-resources.html#AlternativeResources">代替リソースを提供する</a>をご覧ください。 + + +アプリケーションを他の言語にローカライズするための詳細なガイドは、「<a href="localization.html">Localization</a>」をご覧ください。 +</p> + +<p>XML でリソースを使用すれば、エイリアスを作成することもできます。たとえば、別のドローアブル リソースのエイリアスとなる、次のようなドローアブル リソースを作成できます。 +</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<bitmap xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/other_drawable" /> +</pre> + +<p>これは冗長のように思われますが、代替リソースを使用する場合に大変便利です。詳細は、<a href="providing-resources.html#AliasResources">エイリアス リソースを作成する</a>をご覧ください。 +</p> + + + +<h3 id="ReferencesToThemeAttributes">スタイル属性を参照する</h3> + +<p>スタイル属性リソースを使用すると、現在適用されているテーマの属性の値を参照できます。 +スタイル属性を参照すれば、ハードコードした値を指定しなくても、現在のテーマで与えられる標準的なバリエーションに合わせてスタイルを設定して、UI 要素の外観をカスタマイズできます。 + +本質的に、スタイル属性を参照するというのは、「現在のテーマのこの属性で定義されるスタイルを使用する」という意味になります。 +</p> + +<p>属性スタイルを参照する場合、名前構文は通常のリソース形式とほぼ同じですが、アットマーク({@code @})の代わりに疑問符({@code ?})を使用します。リソースタイプの部分は省略可能です。 + +例: </p> + +<pre class="classic"> +?[<em><package_name></em>:][<em><resource_type></em>/]<em><resource_name></em> +</pre> + +<p>たとえば、次の例では、属性を参照して、テキスト カラーをシステム テーマの「プライマリ」テキスト カラーに合わせて設定します。 +</p> + +<pre> +<EditText id="text" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:textColor="<strong>?android:textColorSecondary</strong>" + android:text="@string/hello_world" /> +</pre> + +<p>ここでは、{@code android:textColor} 属性が、現在のテーマのスタイル属性の名前を指定しています。 +Android は、{@code android:textColorSecondary} スタイル属性に適用された値を、このウィジェットの {@code android:textColor} の値として使用できるようになりました。 +このコンテキストで属性リソースが必要なことはシステム リソース ツールで認識されているため、タイプ(ここでは <code>?android:attr/textColorSecondary</code>)を明示的に指定する必要はありません — {@code attr} タイプを除外できます。 + + +</p> + + + + +<h2 id="PlatformResources">プラットフォーム リソースにアクセスする</h2> + +<p>Android には、スタイル、テーマ、レイアウトといった多数の標準的なリソースが用意されています。これらのリソースにアクセスするには、<code>android</code> パッケージ名でリソース参照を修飾します。 + +たとえば、Android には、{@link android.widget.ListAdapter} のリストアイテムに使用できるレイアウト リソースが用意されています。 +</p> + +<pre> +{@link android.app.ListActivity#setListAdapter(ListAdapter) +setListAdapter}(new {@link +android.widget.ArrayAdapter}<String>(this, <strong>android.R.layout.simple_list_item_1</strong>, myarray)); +</pre> + +<p>この例では、{@link android.R.layout#simple_list_item_1} は、プラットフォームによって {@link android.widget.ListView} のアイテム向けに定義されるレイアウト リソースです。 +リストアイテムに独自のレイアウトを作成する代わりに、このレイアウトを使用できます。 +詳細については、「<a href="{@docRoot}guide/topics/ui/layout/listview.html">List View</a>」のデベロッパー ガイドをご覧ください。 +</p> + diff --git a/docs/html-intl/intl/ja/guide/topics/resources/overview.jd b/docs/html-intl/intl/ja/guide/topics/resources/overview.jd new file mode 100644 index 000000000000..28ffa94970c0 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/resources/overview.jd @@ -0,0 +1,103 @@ +page.title=リソースの概要 +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + <h2>トピック</h2> + <ol> + <li><a href="providing-resources.html">リソースの提供</a></li> + <li><a href="accessing-resources.html">リソースへのアクセス</a></li> + <li><a href="runtime-changes.html">実行時の変更の処理</a></li> + <li><a href="localization.html">Localization</a></li> + </ol> + + <h2>リファレンス</h2> + <ol> + <li><a href="available-resources.html">Resource Types</a></li> + </ol> +</div> +</div> + + +<p>画像や文字列といったリソースは、常にアプリケーション コードの外部に置くようにすることで、独立して保持できるようになります。 +さらに、リソースを外部化することで、言語や画面サイズが異なるような特定の端末構成をサポートする代替リソースを提供できるようになります。異なる構成を持つ Android ベースの端末が増えていることから、この外部化がますます重要になってきています。 + + +異なる構成に互換性を持たせるには、リソースをタイプや構成ごとにグループ化するさまざまなサブディレクトリを使用して、プロジェクトの {@code res/} ディレクトリ内にリソースを整理する必要があります。 + + +</p> + +<div class="figure" style="width:429px"> +<img src="{@docRoot}images/resources/resource_devices_diagram1.png" height="167" alt="" /> +<p class="img-caption"> +<strong>図 1.</strong> デフォルト レイアウトを使用する 2 つの異なる端末(アプリによる代替レイアウトの提供なし)。 +</p> +</div> + +<div class="figure" style="width:429px"> +<img src="{@docRoot}images/resources/resource_devices_diagram2.png" height="167" alt="" /> +<p class="img-caption"> +<strong>図 2.</strong> 画面サイズが違うレイアウトを使用する 2 つの異なる端末 +</p> +</div> + +<p>すべてのリソースタイプに対して、アプリケーションの<em>デフォルト</em> レイアウトと複数の<em>代替</em>リソースを指定できます。 +</p> +<ul> + <li>デフォルト リソースは、端末構成に関係なく使われるものであり、現在の構成に一致する代替リソースがない場合に使用されます。 + +</li> + <li>代替リソースは、特定の構成で使うために作成したリソースです。 +リソースのグループを特定の構成に使用するよう指定するには、適切な構成修飾子をディレクトリ名の後ろに追加します。 +</li> +</ul> + +<p>たとえば、デフォルトの UI レイアウトが {@code res/layout/} ディレクトリに保存してある場合、{@code res/layout-land/} ディレクトリにレイアウトを保存しておくことで、横向きの画面を使用する際の別のレイアウトを指定できます。 + + +Android は、現在の端末の構成とリソースのディレクトリ名をマッチングさせ、適切なリソースを自動的に適用します。 +</p> + +<p>図 1 は、代替リソースがない場合に、システムが 2 つの異なる端末に同じレイアウトを適用する様子を表しています。 +図 2 は、大きい画面の代替レイアウト リソースを追加した場合の、レイアウトの適用の様子を表しています。 +</p> + +<p>次のドキュメントには、アプリケーション リソースの整理、代替リソースの指定、アプリケーションでのアクセスなどに関する情報が詳細に記載されています。 +</p> + +<dl> + <dt><strong><a href="providing-resources.html">リソースの提供</a></strong></dt> + <dd>アプリで提供可能なリソースの種類、保存場所、特定の端末構成用の代替リソースの作成方法。 +</dd> + <dt><strong><a href="accessing-resources.html">リソースへのアクセス</a></strong></dt> + <dd>アプリケーション コードまたは他の XML リソースからの参照による、提供済みリソースの使用方法。 +</dd> + <dt><strong><a href="runtime-changes.html">実行時の変更の処理</a></strong></dt> + <dd>アクティビティの実行中に生じた構成の変更の管理方法。</dd> + <dt><strong><a href="localization.html">Localization</a></strong></dt> + <dd>代替リソースを使用したアプリケーションのローカライズのためのボトムアップ ガイド。代替リソースの特定の使用方法を 1 つだけ解説していますが、複数のユーザーが利用する場合には非常に重要になります。 + +</dd> + <dt><strong><a href="available-resources.html">Resource Types</a></strong></dt> + <dd>提供可能な各種リソースタイプのリファレンス。XML 要素、属性、構文について説明しています。 +たとえば、このリファレンスには、アプリケーション メニュー、ドローアブル、アニメーションなどの作成方法が記載されています。 +</dd> +</dl> + +<!-- +<h2>Raw Assets</h2> + +<p>An alternative to saving files in {@code res/} is to save files in the {@code +assets/} directory. This should only be necessary if you need direct access to original files and +directories by name. Files saved in the {@code assets/} directory will not be given a resource +ID, so you can't reference them through the {@code R} class or from XML resources. Instead, you can +query data in the {@code assets/} directory like an ordinary file system, search through the +directory and +read raw data using {@link android.content.res.AssetManager}. For example, this can be more useful +when dealing with textures for a game. However, if you only need to read raw data from a file +(such as a video or audio file), then you should save files into the {@code res/raw/} directory and +then read a stream of bytes using {@link android.content.res.Resources#openRawResource(int)}. This +is uncommon, but if you need direct access to original files in {@code assets/}, refer to the {@link +android.content.res.AssetManager} documentation.</p> +--> diff --git a/docs/html-intl/intl/ja/guide/topics/resources/providing-resources.jd b/docs/html-intl/intl/ja/guide/topics/resources/providing-resources.jd new file mode 100644 index 000000000000..6729e8b6ee8a --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/resources/providing-resources.jd @@ -0,0 +1,1094 @@ +page.title=リソースの提供 +parent.title=アプリケーション リソース +parent.link=index.html +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + <h2>クイックビュー</h2> + <ul> + <li>{@code res/} のそれぞれのサブディレクトリにはさまざまなタイプのリソースがある</li> + <li>代替リソースは設定固有のリソース ファイルを提供する</li> + <li>特定の端末設定に依存しないように、デフォルトのリソースを常に入れておく +</li> + </ul> + <h2>本書の内容</h2> + <ol> + <li><a href="#ResourceTypes">リソースタイプをグループ化する</a></li> + <li><a href="#AlternativeResources">代替リソースを提供する</a> + <ol> + <li><a href="#QualifierRules">修飾子の名前のルール</a></li> + <li><a href="#AliasResources">エイリアス リソースを作成する</a></li> + </ol> + </li> + <li><a href="#Compatibility">リソースとの最適な端末の互換性を提供する</a></li> + <li><a href="#BestMatch">Android が最適なリソースを見つける仕組み</a></li> + </ol> + + <h2>関連ドキュメント</h2> + <ol> + <li><a href="accessing-resources.html">リソースへのアクセス</a></li> + <li><a href="available-resources.html">Resource Types</a></li> + <li><a href="{@docRoot}guide/practices/screens_support.html">複数のスクリーンをサポートする</a> +</li> + </ol> +</div> +</div> + +<p>画像や文字列といったアプリケーション リソースは、常にコードの外部に置くようにすることで、独立して保持できるようになります。 +さらに、特別に名前を設定したリソース ディレクトリにグループ化することで、特定の端末設定に代替リソースを提供する必要があります。 +実行時には、現在の設定に基づいて、Android は適切なリソースを使用します。 +たとえば、画面サイズに応じて異なる UI レイアウトを提供したり、言語設定に応じて異なる文字列を提供したりできます。 + +</p> + +<p>アプリケーション リソースを外部化したら、プロジェクトの {@code R} クラスで生成されるリソース ID を使用してそれらのリソースにアクセスできます。 +アプリケーションでのリソースの使用方法については、「<a href="accessing-resources.html">リソースへのアクセス</a>」をご覧ください。 + +このドキュメントでは、Android プロジェクトでリソースをグループ化する方法と、特定の端末設定に代替リソースを提供する方法を説明します。 +</p> + + +<h2 id="ResourceTypes">リソースタイプをグループ化する</h2> + +<p>それぞれのタイプのリソースを、プロジェクトの {@code res/} ディレクトリの特定のサブディレクトリに配置する必要があります。 +次は、単純なプロジェクトのファイル階層の例です。</p> + +<pre class="classic no-pretty-print"> +MyProject/ + src/ <span style="color:black"> + MyActivity.java </span> + res/ + drawable/ <span style="color:black"> + graphic.png </span> + layout/ <span style="color:black"> + main.xml + info.xml</span> + mipmap/ <span style="color:black"> + icon.png </span> + values/ <span style="color:black"> + strings.xml </span> +</pre> + +<p>この例を見てわかるように、{@code res/} ディレクトリには、画像リソース、2 つのレイアウト リソース、ランチャー アイコンの {@code mipmap/} ディレクトリ、文字列リソース ファイルといった、すべてのリソース(サブディレクトリ内)が入ります。 + +リソース ディレクトリ名は重要です。表 1 に説明があります。 +</p> + +<p class="note"><strong>注:</strong> Mipmap フォルダの使用方法については、「<a href="{@docRoot}tools/projects/index.html#mipmap">Managing Projects Overview</a>」をご覧ください。 +</p> + +<p class="table-caption" id="table1"><strong>表 1.</strong> プロジェクト {@code res/} ディレクトリ内でサポートされているリソース ディレクトリ。 +</p> + +<table> + <tr> + <th scope="col">ディレクトリ</th> + <th scope="col">リソースタイプ</th> + </tr> + + <tr> + <td><code>animator/</code></td> + <td><a href="{@docRoot}guide/topics/graphics/prop-animation.html">プロパティ アニメーション</a>を定義する XML ファイル。 +</td> + </tr> + + <tr> + <td><code>anim/</code></td> + <td><a href="{@docRoot}guide/topics/graphics/view-animation.html#tween-animation">トゥイーン アニメーション</a>を定義する XML ファイル。 +(プロパティ アニメーションをこのディレクトリに保存することもできますが、2 つのタイプを区別するために、プロパティ アニメーションは {@code animator/} ディレクトリに保存することをお勧めします)。 + +</td> + </tr> + + <tr> + <td><code>color/</code></td> + <td>色の状態リストを定義する XML ファイル。「<a href="color-list-resource.html">Color State List Resource</a>」をご覧ください。 +</td> + </tr> + + <tr> + <td><code>drawable/</code></td> + + <td><p>ビットマップ ファイル({@code .png}、{@code .9.png}、{@code .jpg}、{@code .gif})または次のドローアブル リソース サブタイプにコンパイルされる XML ファイル: +</p> + <ul> + <li>ビットマップ ファイル</li> + <li>Nine-Patche(リサイズ可能なビットマップ)</li> + <li>状態リスト</li> + <li>形状</li> + <li>アニメーション ドローアブル</li> + <li>その他のドローアブル</li> + </ul> + <p>「<a href="drawable-resource.html">Drawable Resources</a>」をご覧ください。</p> + </td> + </tr> + + <tr> + <td><code>mipmap/</code></td> + <td>さまざまなランチャー アイコン密度のドローアブル ファイル。{@code mipmap/} フォルダによるランチャー アイコンの管理方法については、「<a href="{@docRoot}tools/project/index.html#mipmap">Managing Projects Overview</a>」をご覧ください。 + +</td> + </tr> + + <tr> + <td><code>layout/</code></td> + <td>ユーザー インターフェースのレイアウトを定義する XML ファイル。 + 「<a href="layout-resource.html">Layout Resource</a>」をご覧ください。</td> + </tr> + + <tr> + <td><code>menu/</code></td> + <td>オプション メニュー、コンテキスト メニュー、サブ メニューといった、アプリケーション メニューを定義する XML ファイル。 +「<a href="menu-resource.html">Menu Resource</a>」をご覧ください。</td> + </tr> + + <tr> + <td><code>raw/</code></td> + <td><p>未加工の形式で保存する任意のファイル。これらのリソースを未加工の {@link java.io.InputStream} で開くには、{@link android.content.res.Resources#openRawResource(int) +Resources.openRawResource()} をリソース ID({@code R.raw.ファイル名<em></em>})とともに呼び出します。 +</p> + <p>ただし、元のファイル名とファイル階層にアクセスする必要がある場合は、一部のリソースを {@code +assets/} ディレクトリ({@code res/raw/} の代わりに)に保存することを検討します。 +{@code assets/} のファイルにはリソース ID が付与されていないため、読み込むには {@link android.content.res.AssetManager} が必要です。 +</p></td> + </tr> + + <tr> + <td><code>values/</code></td> + <td><p>文字列、整数、色など、単純な値を含む XML ファイル。</p> + <p>その他の {@code res/} サブディレクトリの XML リソース ファイルは XML ファイル名に基づいて 1 つのリソースを定義しますが、{@code values/} ディレクトリのファイルは複数のリソースを表します。このディレクトリのファイルの場合、{@code <resources>} 要素のそれぞれの子が 1 つのリソースを定義します。 + + +たとえば、{@code <string>} 要素は {@code R.string} リソースを作成し、{@code <color>} 要素は {@code R.color} リソースを作成します。 + +</p> + <p>各リソースの定義には XML 要素を使用するため、ファイルには任意の名前を設定でき、1 つのファイル内にさまざまなリソースを配置できます。 +ただし、わかりやすくするために、一意のリソースタイプをそれぞれのファイルに配置することもできます。 +次は、このディレクトリで作成できるリソースのファイル名の変換例です。 +</p> + <ul> + <li>リソースの配列の場合 arrays.xml(<a href="more-resources.html#TypedArray">型付き配列</a>)。</li> + <li><a href="more-resources.html#Color">色の値</a>の場合 colors.xml </li> + <li><a href="more-resources.html#Dimension">寸法の値</a>の場合 dimens.xml。</li> + <li><a href="string-resource.html">文字列の値</a>の場合 strings.xml。 +</li> + <li><a href="style-resource.html">スタイル</a>の場合 styles.xml。</li> + </ul> + <p>「<a href="string-resource.html">String Resources</a>」、「<a href="style-resource.html">Style Resource</a>」、「<a href="more-resources.html">More Resource Types</a>」をご覧ください。 + +</p> + </td> + </tr> + + <tr> + <td><code>xml/</code></td> + <td>{@link +android.content.res.Resources#getXml(int) Resources.getXML()} を呼び出すことによって、実行時に読み込むことができる任意の XML ファイル。ここには、<a href="{@docRoot}guide/topics/search/searchable-config.html">検索可能な設定</a>など、各種の XML 設定ファイルが保存されます。 + +<!-- or preferences configuration. --></td> + </tr> +</table> + +<p class="caution"><strong>警告:</strong> リソース ファイルを {@code res/} ディレクトリに直接保存しないでください。—コンパイラー エラーの原因になります。 +</p> + +<p>リソースの特定のタイプの詳細は、「<a href="available-resources.html">Resource Types</a>」のドキュメントをご覧ください。</p> + +<p>表 1 で定義したサブディレクトリに保存するリソースは、「デフォルト」のリソースとなります。 +つまり、これらのリソースはアプリケーションのデフォルトのデザインとコンテンツを定義します。ただし、Android が搭載された端末では別のタイプのリソースが呼び出されることがあります。たとえば、端末の画面サイズが通常のものよりも大きな場合、追加の画面スペースを利用する別のレイアウト リソースを提供する必要があります。 + + +また、端末の言語設定が異なる場合、使用するユーザー インターフェースのテキストを翻訳する、別の文字列リソースを提供します。 + +さまざまな端末設定にこれらの異なるリソースを提供するには、デフォルトのリソースに加えて、代替リソースを提供する必要があります。 + +</p> + + +<h2 id="AlternativeResources">代替リソースを提供する</h2> + + +<div class="figure" style="width:429px"> +<img src="{@docRoot}images/resources/resource_devices_diagram2.png" height="167" alt="" /> +<p class="img-caption"> +<strong>図 1.</strong> 別のレイアウト リソースを使用する、2 つの異なる端末。</p> +</div> + +<p>ほぼすべてのアプリケーションが、特定の端末設定をサポートするための代替リソースを提供します。 +たとえば、画面密度が異なる場合は代替ドローアブル リソースを含め、言語が異ならう場合は代替文字列リソースを含めます。 +実行時には、Android が現在の端末設定を検出し、アプリケーションに合ったリソースを読み込みます。 + +</p> + +<p>一連のリソースに設定固有の代替リソースを指定するには:</p> +<ol> + <li>{@code +<em><resources_name></em>-<em><config_qualifier></em>} の形式で名前を付けた {@code res/} に新しいディレクトリを作成します。 + <ul> + <li><em>{@code <resources_name>}</em> は、対応するディレクトリ リソースのディレクトリ名です(表 1 で定義)。 +</li> + <li><em>{@code <qualifier>}</em> は、リソースを使用する個々の設定を指定する名前です(表 2 で定義)。 +</li> + </ul> + <p>1 つ以上の <em>{@code <qualifier>}</em> を末尾に追加できます。それぞれの修飾子はダッシュを使用して区切ります。 +</p> + <p class="caution"><strong>警告:</strong> 複数の修飾子を末尾に追加する場合は、表 2 に記載されているのと同じ順番で配置する必要があります。 +修飾子の順番に誤りがあると、リソースが無視されます。 +</p> + </li> + <li>それぞれの代替リソースをこの新しいディレクトリに保存します。リソース ファイルの名前は、デフォルトのリソース ファイルと同じものにする必要があります。 +</li> +</ol> + +<p>次に、デフォルト リソースと代替リソースの例を示します。</p> + +<pre class="classic no-pretty-print"> +res/ + drawable/ <span style="color:black"> + icon.png + background.png </span> + drawable-hdpi/ <span style="color:black"> + icon.png + background.png </span> +</pre> + +<p>{@code hdpi} 修飾子は、ディレクトリ内のリソースが高密度画面を持つ端末用であることを表します。 +これらのドローアブル ディレクトリの画像は特定の画面密度に合わせたサイズになっていますが、ファイル名は完全に同じになります。 + +このように、{@code icon.png} や {@code +background.png} 画像を参照するのに使用するリソース ID は常に同じになりますが、Android はリソース ディレクトリ名の修飾子により端末設定情報を比較して、各リソースの現在の端末に最適なバージョンを選択します。 + +</p> + +<p>Android では複数の設定修飾子をサポートしており、それぞれの修飾子をダッシュで区切ることで、1 つのディレクトリ名に複数の修飾子を追加できます。 +表 2 には、有効な設定修飾子が優先度順に記載されています。—参照ディレクトリに複数の修飾子を使用する場合、表に記載されている順番にディレクトリ名に追加する必要があります。 + + +</p> + + +<p class="table-caption" id="table2"><strong>表 2.</strong> 設定修飾子の名前。 +</p> +<table> + <tr> + <th>設定</th> + <th>修飾子の値</th> + <th>説明</th> + </tr> + <tr id="MccQualifier"> + <td>MCC と MNC</td> + <td>例: <br/> + <code>mcc310</code><br/> + <code><nobr>mcc310-mnc004</nobr></code><br/> + <code>mcc208-mnc00</code><br/> + など + </td> + <td> + <p>モバイル カントリーコード(MCC)です。端末の SIM カードにあるモバイル ネットワーク コード(MNC)が続くことがあります。 +たとえば、<code>mcc310</code> は米国の任意の携帯通信会社、<code>mcc310-mnc004</code> は米国の Verizon、<code>mcc208-mnc00</code> はフランスの Orange となります。 + +</p> + <p>端末が無線通信接続(GSM 電話)を使用する場合、MCC と MNC の値は SIM カードの値となります。 +</p> + <p>さらに、MCC のみを使用することもできます(たとえば、アプリケーションに国固有の法に関するリソースを含める場合)。 +言語のみに基づいて指定する場合は、代わりに<em>言語と地域</em>の修飾子(次のセクションで解説)を使用します。 +MCC と MNC 修飾子を使用する場合は、慎重に設定し、予測のとおりに機能することをテストします。 +</p> + <p>さらに、設定フィールド {@link +android.content.res.Configuration#mcc}、{@link +android.content.res.Configuration#mnc} もご覧ください。これらは、それぞれ、現在のモバイル カントリーコードとモバイル ネットワーク コードを表します。 +</p> + </td> + </tr> + <tr id="LocaleQualifier"> + <td>言語と地域</td> + <td>例: <br/> + <code>en</code><br/> + <code>fr</code><br/> + <code>en-rUS</code><br/> + <code>fr-rFR</code><br/> + <code>fr-rCA</code><br/> + など + </td> + <td><p>言語は 2 文字の <a href="http://www.loc.gov/standards/iso639-2/php/code_list.php">ISO 639-1</a> 言語コードで定義し、オプションで、2 文字の <a href="http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html">ISO 3166-1-alpha-2</a> 地域コードを後ろに追加します(先頭に小文字の「{@code r}」が付きます)。 + + + + </p><p> + コードでは大文字と小文字が区別されません。<em></em>地域を区別するには、{@code r} 接頭辞を使用します。 + + 地域のみは指定できません。</p> + <p>ユーザーがシステム設定で言語を変更すると、アプリケーションの実行中にこの値が変更されます。 +実行時のアプリケーションに与える影響については、<a href="runtime-changes.html">実行時の変更の処理</a>をご覧ください。 +</p> + <p>アプリケーションを他の言語にローカライズするための詳細なガイドは、「<a href="localization.html">Localization</a>」をご覧ください。 +</p> + <p>さらに、{@link android.content.res.Configuration#locale} 設定フィールドもご覧ください。これは、現在のロケールを表します。 +</p> + </td> + </tr> + <tr id="LayoutDirectionQualifier"> + <td>レイアウトの方向</td> + <td><code>ldrtl</code><br/> + <code>ldltr</code><br/> + </td> + <td><p>アプリケーションのレイアウトの方向です。{@code ldrtl} は、「レイアウト方向は右から左」という意味になります。{@code ldltr} は、「レイアウト方向は左から右」という意味になります。この設定が暗黙的にデフォルト値となります。 + + </p> + <p>この設定は、レイアウト、ドローアブル、値など、任意のリソースに適用できます。 + </p> + <p>たとえば、アラビア語に何らかの特定なレイアウトを提供し、その他の「右から左」の言語(ペルシャ語やヘブライ語)に汎用的なレイアウトを提供する場合、次のように設定します。 + + </p> +<pre class="classic no-pretty-print"> +res/ + layout/ <span style="color:black"> + main.xml </span>(Default layout) + layout-ar/ <span style="color:black"> + main.xml </span>(Specific layout for Arabic) + layout-ldrtl/ <span style="color:black"> + main.xml </span>(Any "right-to-left" language, except + for Arabic, because the "ar" language qualifier + has a higher precedence.) +</pre> + <p class="note"><strong>注:</strong> アプリで右から左のレイアウト機能を有効にするには、<a href="{@docRoot}guide/topics/manifest/application-element.html#supportsrtl">{@code + supportsRtl}</a> を {@code "true"} に設定し、<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a> を 17 以上に設定します。 +</p> + <p>API レベル 17 で追加。<em></em></p> + </td> + </tr> + <tr id="SmallestScreenWidthQualifier"> + <td>smallestWidth</td> + <td><code>sw<N>dp</code><br/><br/> + 例: <br/> + <code>sw320dp</code><br/> + <code>sw600dp</code><br/> + <code>sw720dp</code><br/> + など + </td> + <td> + <p>使用可能な画面領域の最小寸法で指定する、画面の基本サイズ。 +具体的には、端末の smallestWidth は画面に使用できる高さと幅の最小サイズとなります(画面の「使用できる最小幅」と考えることもできます)。 +画面の現在の方向に関係なく、この修飾子を使用することで、アプリケーションの UI に少なくとも {@code <N>} dps の幅を使用できます。 + +</p> + <p>たとえば、画面領域のレイアウトの最小寸法を常に 600 dp とする必要がある場合、この修飾子を使用してレイアウト リソース {@code +res/layout-sw600dp/} を作成できます。 +システムは、600dp の側が縦になるか横になるか関係なく、使用可能な画面の最小寸法が 600dp 以上の場合にのみこれらのリソースを使用します。 + +smallestWidth は端末の固定された画面サイズ特性です。<strong>画面の向きが変わっても、端末の smallestWidth は変更されません。</strong> +</p> + <p>端末の smallestWidth では画面の装飾とシステム UI が考慮されます。たとえば、端末の画面に smallestWidth の軸に沿ったスペースを考慮した固定 UI 要素がある場合、これらの画面ピクセルは UI に使用できないことから、システムは実際の画面サイズよりも小さな smallestWidth を宣言します。つまり、使用する値は、レイアウトが必要とする実際の最小寸法とする必要があります(通常は、この値は、画面の現在の向きに関係なく、レイアウトがサポートする「最小幅」となります)。<em></em> + + + + +</p> + <p>次に、一般的な画面サイズに使用する値を示します。</p> + <ul> + <li>320。次のような画面設定を持つ端末。 + <ul> + <li>240x320 ldpi(QVGA ハンドセット)</li> + <li>320x480 mdpi(ハンドセット)</li> + <li>480x800 hdpi(高密度ハンドセット)</li> + </ul> + </li> + <li>480。480x800 mdpi(タブレットやハンドセット)などの画面。</li> + <li>600。600x1024 mdpi(7 インチタブレット)などの画面。</li> + <li>720。720x1280 mdpi(10 インチタブレット)などの画面。</li> + </ul> + <p>アプリケーションで smallestWidth 修飾子の値が異なる複数のリソース ディレクトリを提供する場合、システムは端末の smallestWidth に最も近い(かつ超過しない)ものを使用します。 + + </p> + <p>API レベル 13 で追加。<em></em></p> + <p>さらに、<a href="{@docRoot}guide/topics/manifest/supports-screens-element.html#requiresSmallest">{@code +android:requiresSmallestWidthDp}</a> 属性もご覧ください。これは、アプリケーションが互換性を持つ最小の smallestWidth と、端末の smallestWidth 値を保持する {@link +android.content.res.Configuration#smallestScreenWidthDp} 設定フィールドを宣言します。 + +</p> + <p>さまざまな画面の設計とこの修飾子の使用方法についての詳細は、「<a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a>」のデベロッパー ガイドをご覧ください。 + +</p> + </td> + </tr> + <tr id="ScreenWidthQualifier"> + <td>使用可能な幅</td> + <td><code>w<N>dp</code><br/><br/> + 例: <br/> + <code>w720dp</code><br/> + <code>w1024dp</code><br/> + など + </td> + <td> + <p>リソースを使用する、使用可能な最小の画面幅を {@code dp} 単位で指定します。—<code><N></code> の値で定義します。 +画面の向きの縦と横を変更すると、現在の実際の幅に合わせて、この設定値が変更されます。 + +</p> + <p>アプリケーションでこの設定が異なる複数のリソース ディレクトリを提供する場合、システムは端末の現在の画面の幅に最も近い(かつ超過しない)ものを使用します。 + +この値は画面の装飾を考慮します。つまり、端末のディスプレイの左や右に何らかの固定 UI 要素がある場合、これらの UI 要素を考慮し、アプリケーションの使用可能なスペースを減らして、実際の画面サイズよりも小さな幅を使用します。 + + + +</p> + <p>API レベル 13 で追加。<em></em></p> + <p>さらに、{@link android.content.res.Configuration#screenWidthDp} 設定フィールドもご覧ください。これは現在の画面の幅を保持します。 +</p> + <p>さまざまな画面の設計とこの修飾子の使用方法についての詳細は、「<a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a>」のデベロッパー ガイドをご覧ください。 + +</p> + </td> + </tr> + <tr id="ScreenHeightQualifier"> + <td>使用可能な高さ</td> + <td><code>h<N>dp</code><br/><br/> + 例: <br/> + <code>h720dp</code><br/> + <code>h1024dp</code><br/> + など + </td> + <td> + <p>リソースを使用する、使用可能な最小の画面幅を「dp」単位で指定します。—<code><N></code> の値で定義します。 +画面の向きの縦と横を変更すると、現在の実際の高さに合わせて、この設定値が変更されます。 + +</p> + <p>アプリケーションでこの設定が異なる複数のリソース ディレクトリを提供する場合、システムは端末の現在の画面の高さに最も近い(かつ超過しない)ものを使用します。 + +この値は画面の装飾を考慮します。つまり、端末のディスプレイの上や下に何らかの固定 UI 要素がある場合、これらの UI 要素を考慮し、アプリケーションの使用可能なスペースを減らして、実際の画面サイズよりも小さな高さを使用します。 + + + +固定されていない画面の装飾(全画面にした場合に非表示になる携帯電話のステータスバーなど)や、タイトルバーやアクションバーなどのウィンドウの装飾は、ここでは考慮されません。そのため、アプリケーションでは指定したスペースよりもやや小さなサイズに対処できるように準備をし置く必要があります。<em></em> + + + + + <p>API レベル 13 で追加。<em></em></p> + <p>さらに、{@link android.content.res.Configuration#screenHeightDp} 設定フィールドもご覧ください。これは現在の画面の幅を保持します。 +</p> + <p>さまざまな画面の設計とこの修飾子の使用方法についての詳細は、「<a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a>」のデベロッパー ガイドをご覧ください。 + +</p> + </td> + </tr> + <tr id="ScreenSizeQualifier"> + <td>画面サイズ</td> + <td> + <code>small</code><br/> + <code>normal</code><br/> + <code>large</code><br/> + <code>xlarge</code> + </td> + <td> + <ul class="nolist"> + <li>{@code small}: 低密度 QVGA 画面と同等のサイズを持つ画面です。 +小さい画面の最小レイアウト サイズは約 320x426 dp 単位です。 +たとえば、QVGA 低密度や VGA 高密度です。 +</li> + <li>{@code normal}: 中密度 HVGA 画面と同等のサイズを持つ画面です。 +通常の画面の最小レイアウト サイズは約 320x470 dp 単位です。 +たとえば、WQVGA 低密度、HVGA 中密度、WVGA 高密度といった画面になります。 + +</li> + <li>{@code large}: 中密度 VGA 画面と同等のサイズを持つ画面です。 + + 大きな画面の最小レイアウト サイズは約 480x640 dp 単位です。 + たとえば、VGA や WVGA の中密度といった画面です。</li> + <li>{@code xlarge}: 従来の中密度 HVGA 画面よりもはるかに大きなサイズの画面です。 +特大の画面の最小レイアウト サイズは約 720x960 dp 単位です。 +ほとんどの場合、特大の画面を持つ端末はポケットに入れて持ち運ぶことができないほど大きく、タブレット スタイルの端末になります。 + +API レベル 9 で追加。<em></em></li> + </ul> + <p class="note"><strong>注:</strong> サイズ識別子を持つ場合でも、リソースがそのサイズの画面以外には対応しないということではありません。<em></em> +現在の端末に最適な識別子を持つ代替リソースを提供していない場合でも、システムによって<a href="#BestMatch">最適な</a>リソースが使用されることがあります。 + +</p> + <p class="caution"><strong>警告:</strong> すべてのリソースが現在の画面よりも大きなサイズ識別子を使用している場合、システムはそれらのリソースを使用せず、アプリケーションが実行時にクラッシュしてしまいます(たとえば、すべてのリソースに {@code +xlarge} 識別子のタグが付いているが、端末は通常サイズの画面である場合)。<em></em><strong></strong> + +</p> + <p>API レベル 4 で追加。<em></em></p> + + <p>詳細については、「<a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a>」をご覧ください。 +</p> + <p>さらに、{@link android.content.res.Configuration#screenLayout} 設定フィールドもご覧ください。これは、画面のサイズが小、中、大のいずれかであるかを表します。 + +</p> + </td> + </tr> + <tr id="ScreenAspectQualifier"> + <td>画面アスペクト</td> + <td> + <code>long</code><br/> + <code>notlong</code> + </td> + <td> + <ul class="nolist"> + <li>{@code long}: WQVGA、WVGA、FWVGA のような長い画面</li> + <li>{@code notlong}: QVGA、HVGA、VGA のように長くない画面</li> + </ul> + <p>API レベル 4 で追加。<em></em></p> + <p>これは純粋に画面のアスペクト比を基準とします(「長い」画面は幅広の画面になります)。これは画面の向きには関係ありません。 +</p> + <p>さらに、{@link android.content.res.Configuration#screenLayout} 設定フィールドもご覧ください。これは、画面のサイズが長いかどうかを表します。 +</p> + </td> + </tr> + <tr id="OrientationQualifier"> + <td>画面の向き</td> + <td> + <code>port</code><br/> + <code>land</code> <!-- <br/> + <code>square</code> --> + </td> + <td> + <ul class="nolist"> + <li>{@code port}: 端末は縦向き(垂直)になっています</li> + <li>{@code land}: 端末は横向き(水平)になっています</li> + <!-- Square mode is currently not used. --> + </ul> + <p>ユーザーが画面を回転すると、アプリケーションの実行中にこの値が変更されます。 +実行時のアプリケーションに与える影響については、「<a href="runtime-changes.html">実行時の変更の処理</a>」をご覧ください。 +</p> + <p>さらに、{@link android.content.res.Configuration#orientation} 設定フィールドもご覧ください。これは、現在の端末の画面の向きを表します。 +</p> + </td> + </tr> + <tr id="UiModeQualifier"> + <td>UI モード</td> + <td> + <code>car</code><br/> + <code>desk</code><br/> + <code>television</code><br/> + <code>appliance</code> + <code>watch</code> + </td> + <td> + <ul class="nolist"> + <li>{@code car}: 端末は車載ドックで表示されています</li> + <li>{@code desk}: 端末はデスクドックで表示されています</li> + <li>{@code television}: 端末はテレビで表示されており、「10 フィート」離れた位置からの操作が可能です。UI はユーザーから離れた場所にある大きな画面に表示され、主に十字キーやポインタ以外のやり取りで操作します。 + + +</li> + <li>{@code appliance}: 端末をアプライアンスとして使用します。ディスプレイはありません +</li> + <li>{@code watch}: 端末にはディスプレイがあり、手首に装着して使用します</li> + </ul> + <p>API レベル 8 で追加。television は API 13 で追加。watch は API 20 で追加。<em></em></p> + <p>端末をホルダーに装着したり、取り外したりしたときのアプリの反応については、「<a href="{@docRoot}training/monitoring-device-state/docking-monitoring.html">Determining and Monitoring the Docking State and Type</a>」をご覧ください。 + +</p> + <p>ユーザーが端末をドックに装着すると、アプリケーションの実行中にこの値が変更されます。 +{@link +android.app.UiModeManager} を使用すると、これらのモードの一部を有効または無効にできます。実行時のアプリケーションに与える影響については、「<a href="runtime-changes.html">実行時の変更の処理</a>」をご覧ください。 +</p> + </td> + </tr> + <tr id="NightQualifier"> + <td>ナイトモード</td> + <td> + <code>night</code><br/> + <code>notnight</code> + </td> + <td> + <ul class="nolist"> + <li>{@code night}: 夜間</li> + <li>{@code notnight}: 昼間</li> + </ul> + <p>API レベル 8 で追加。<em></em></p> + <p>ナイトモードを自動モード(デフォルト)のままにしておくと、時間を基準にしてモードが変更された場合に、アプリケーションの実行中にこの値が変更されます。 +{@link android.app.UiModeManager} を使用すると、このモードを有効または無効にできます。 +実行時のアプリケーションに与える影響については、「<a href="runtime-changes.html">実行時の変更の処理</a>」をご覧ください。 +</p> + </td> + </tr> + <tr id="DensityQualifier"> + <td>画面ピクセル密度(dpi)</td> + <td> + <code>ldpi</code><br/> + <code>mdpi</code><br/> + <code>hdpi</code><br/> + <code>xhdpi</code><br/> + <code>xxhdpi</code><br/> + <code>xxxhdpi</code><br/> + <code>nodpi</code><br/> + <code>tvdpi</code> + </td> + <td> + <ul class="nolist"> + <li>{@code ldpi}: 低密度の画面。約 120dpi です。</li> + <li>{@code mdpi}: 中密度(従来の HVGA)の画面。約 160dpi です。 +</li> + <li>{@code hdpi}: 高密度の画面。約 240dpi です。</li> + <li>{@code xhdpi}: 超高密度の画面。約 320dpi です。API レベル 8 で追加。<em></em> +</li> + <li>{@code xxhdpi}: 超超高密度の画面。約 480dpi です。API レベル 16 で追加。<em></em> +</li> + <li>{@code xxxhdpi}: 超超高密度が使用(ランチャー アイコンのみ。「Supporting Multiple Screens」の<a href="{@docRoot}guide/practices/screens_support.html#xxxhdpi-note">注</a>をご覧ください)。約 640dpi です。<em></em> + +API レベル 18 で追加。<em></em> +</li> + <li>{@code nodpi}: 端末の密度に合わせてサイズを変更しないビットマップ リソースに使用します。 +</li> + <li>{@code tvdpi}: 密度が mdpi と hdpi の間の画面。約 213dpi です。これは「プライマリ」の密度グループとしては認識されません。 +ほとんどの場合、テレビ向けのものであり、大部分のアプリは必要としません。—通常、アプリの場合は mdpi と hdpi リソースを提供すれば十分であり、システムが必要に応じてサイズを変更します。 + +この識別子は API レベル 13 で導入されました。</li> + </ul> + <p>6 つのプライマリ密度のサイズの比率は 3:4:6:8:12:16 です(tvdpi 密度を除く)。 +そのため、ldpi では 9x9 のビットマップ、mdpi では 12x12 のビットマップ、hdpi では 18x18 のビットマップ、xhdpi では 24x24 のビットマップとなります。 +</p> + <p>画像リソースがテレビや他の特定の端末で正常に表示されず、tvdpi リソースを試す場合、拡張係数は 1.33*mdpi になります。 +たとえば、画面向けの 100px x 100px 画像は、tvdpi 向けにすると 133px x 133px となります。 +</p> + <p class="note"><strong>注:</strong> 密度識別子を持つ場合でも、リソースがその密度の画面以外には対応しないということではありません。<em></em> +現在の端末に最適な識別子を持つ代替リソースを提供していない場合でも、システムによって<a href="#BestMatch">最適な</a>リソースが使用されることがあります。 + +</p> + <p>異なる画面密度を処理する方法や、Android が現在の密度に合わせてビットマップのサイズを変更する方法については、「<a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a>」をご覧ください。 + +</p> + </td> + </tr> + <tr id="TouchscreenQualifier"> + <td>タッチスクリーン タイプ</td> + <td> + <code>notouch</code><br/> + <code>finger</code> + </td> + <td> + <ul class="nolist"> + <li>{@code notouch}: 端末にはタッチスクリーンが搭載されていません。</li> + <li>{@code finger}: 端末には、ユーザーの指先による指示操作で使用するためのタッチスクリーンが搭載されています。 +</li> + </ul> + <p>{@link android.content.res.Configuration#touchscreen} 設定フィールドもご覧ください。これは、端末上のタッチスクリーンのタイプを表します。 +</p> + </td> + </tr> + <tr id="KeyboardAvailQualifier"> + <td>キーボードの使用可能状況</td> + <td> + <code>keysexposed</code><br/> + <code>keyshidden</code><br/> + <code>keyssoft</code> + </td> + <td> + <ul class="nolist"> + <li>{@code keysexposed}: 端末ではキーボードを使用できます。端末でソフトウェア キーボードが有効な(と想定される)場合、端末にハードウェア キーボードが接続されておらず、ハードウェア キーボードがユーザーに提示されていない場合でも、この値が使用されることがあります。<em></em> + +ソフトウェア キーボードが提供されていない、または無効になっている場合は、ハードウェア キーボードが認識された場合にのみ使用されます。 + +</li> + <li>{@code keyshidden}: 端末には使用可能なハードウェア キーボードがありますが非表示になっています。また、端末ではソフトウェア キーボードが有効になっていません。<em></em><em></em> +</li> + <li>{@code keyssoft}: 表示されているかどうかに関係なく、端末ではソフトウェア キーボードが有効になっています。 +</li> + </ul> + <p><code>keysexposed</code> リソースを提供するが、<code>keyssoft</code> リソースを提供しない場合、システムのソフトウェア キーボードが有効になっている場合は、キーボードが表示されているかに関係なく、システムは <code>keysexposed</code> リソースを使用します。 + +</p> + <p>ユーザーがハードウェア キーボードを開くと、アプリケーションの実行中にこの値が変更されます。 +実行時のアプリケーションに与える影響については、「<a href="runtime-changes.html">実行時の変更の処理</a>」をご覧ください。 +</p> + <p>さらに、設定フィールド {@link +android.content.res.Configuration#hardKeyboardHidden} と {@link +android.content.res.Configuration#keyboardHidden} もご覧ください。これは、ハードウェア キーボードの可視性、任意のキーボード(ソフトウェアを含む)の可視性、それぞれの可視性を表します。 +</p> + </td> + </tr> + <tr id="ImeQualifier"> + <td>主なテキストの入力方法</td> + <td> + <code>nokeys</code><br/> + <code>qwerty</code><br/> + <code>12key</code> + </td> + <td> + <ul class="nolist"> + <li>{@code nokeys}: 端末にはテキスト入力用のハードウェア キーはありません。</li> + <li>{@code qwerty}: ユーザーに表示されているかどうかに関係なく、端末にはハードウェア クワーティ キーボードが搭載されています。 + +</li> + <li>{@code 12key}: ユーザーに表示されているかどうかに関係なく、端末にはハードウェア 12key キーボードが搭載されています。 +</li> + </ul> + <p>さらに、{@link android.content.res.Configuration#keyboard} 設定フィールドもご覧ください。これは、使用可能な主なテキストの入力方法を表します。 +</p> + </td> + </tr> + <tr id="NavAvailQualifier"> + <td>ナビゲーション キーの使用可能状況</td> + <td> + <code>navexposed</code><br/> + <code>navhidden</code> + </td> + <td> + <ul class="nolist"> + <li>{@code navexposed}: ユーザーはナビゲーション キーを使用できます。</li> + <li>{@code navhidden}: ナビゲーション キーは使用できません(閉じられた lid の背後になっている場合など)。 +</li> + </ul> + <p>ユーザーがナビゲーション キーを表示させると、アプリケーションの実行中にこの値が変更されます。 +実行時のアプリケーションに与える影響については、「<a href="runtime-changes.html">実行時の変更の処理</a>」をご覧ください。 +</p> + <p>さらに、{@link android.content.res.Configuration#navigationHidden} 設定フィールドもご覧ください。これは、ナビゲーション キーが非表示になっているかどうかを表します。 +</p> + </td> + </tr> + <tr id="NavigationQualifier"> + <td>タップ以外の主なナビゲーション方法</td> + <td> + <code>nonav</code><br/> + <code>dpad</code><br/> + <code>trackball</code><br/> + <code>wheel</code> + </td> + <td> + <ul class="nolist"> + <li>{@code nonav}: 端末には、タッチスクリーン以外のナビゲーション機能がありません。 +</li> + <li>{@code dpad}: 端末にはナビゲーション用の方向キー(十字キー)があります。</li> + <li>{@code trackball}: 端末にはナビゲーション用のトラックボールがあります。</li> + <li>{@code wheel}: 端末にはナビゲーション用の方向ホイールがあります(特殊)。</li> + </ul> + <p>{@link android.content.res.Configuration#navigation} 設定フィールドもご覧ください。これは、利用可能なナビゲーション方法のタイプを表します。 +</p> + </td> + </tr> +<!-- DEPRECATED + <tr> + <td>Screen dimensions</td> + <td>Examples:<br/> + <code>320x240</code><br/> + <code>640x480</code><br/> + etc. + </td> + <td> + <p>The larger dimension must be specified first. <strong>This configuration is deprecated +and should not be used</strong>. Instead use "screen size," "wider/taller screens," and "screen +orientation" described above.</p> + </td> + </tr> +--> + <tr id="VersionQualifier"> + <td>プラットフォーム バージョン(API レベル)</td> + <td>例: <br/> + <code>v3</code><br/> + <code>v4</code><br/> + <code>v7</code><br/> + など</td> + <td> + <p>端末がサポートする API レベル。たとえば、<code>v1</code> は API レベル 1(Android 1.0 以降の端末)、<code>v4</code> は API レベル 4(Android 1.6 以降の端末)となります。 + +これらの値の詳細については、「<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">Android API levels</a>」のドキュメントをご覧ください。 +</p> + </td> + </tr> +</table> + + +<p class="note"><strong>注:</strong> Android 1.0 以降、いくつかの設定識別子が追加されているため、すべてのバージョンの Android がすべての識別子をサポートしているわけではありません。 +新しい識別子を使用すると、旧式の端末がその識別子を無視できるように、プラットフォーム バージョンの識別子が暗黙的に追加されます。 +たとえば、available-width の識別子は API レベル 13 で新たに追加されたため、<code>w600dp</code> 識別子を使用すると、自動的に <code>v13</code> 識別子が追加されます。 + +問題を回避するために、常に一連のデフォルト リソースを含めるようにします(識別子のない一連のリソース)。<em></em> +詳細は、<a href="#Compatibility">リソースとの最適な端末の互換性を提供する</a>セクションをご覧ください。 + +</p> + + + +<h3 id="QualifierRules">修飾子の名前のルール</h3> + +<p>ここでは、設定修飾子の名前の使用方法に関するルールを説明します。</p> + +<ul> + <li>リソースの 1 つのセットに複数の修飾子を指定できます。その場合は、ダッシュで区切ります。たとえば、<code>drawable-en-rUS-land</code> は画面が横向きの米国英語の端末に適用されます。 + +</li> + <li>識別子は<a href="#table2">表 2</a> の順番で使用します。次に例を示します。 + + <ul> + <li>誤: <code>drawable-hdpi-port/</code></li> + <li>正: <code>drawable-port-hdpi/</code></li> + </ul> + </li> + <li>代替リソースのディレクトリはネストできません。<code>res/drawable/drawable-en/</code> などは使用できません。 +</li> + <li>値は大文字と小文字を区別します。大文字と小文字を区別するファイル システムの問題を回避するために、処理前にリソース コンパイラーがディレクトリ名を小文字に変換します。 + +読みやすくする場合にのみ、名前に大文字を使用します。</li> + <li>それぞれの修飾子タイプに使用できる値は 1 つだけです。たとえば、スペインとフランスの両方に同じドローアブル ファイルを使用する場合も、ディレクトリ名を <code>drawable-rES-rFR/</code> とすることはできません。<em></em> + +その代わりに、該当するファイルを含む <code>drawable-rES/</code> と <code>drawable-rFR/</code> という名前の 2 つのリソース ディレクトリが必要になります。ただし、実際のところ、両方の場所で同じファイルを重複させる必要はありません。 + +代わりに、リソースのエイリアスを作成できます。 +後述の<a href="#AliasResources">エイリアス リソースを作成する</a>をご覧ください。 +</li> +</ul> + +<p>これらの修飾子を名前に持つディレクトリに代替リソースを保存すると、現在の端末設定に基づいて、Android がアプリケーションにリソースを自動的に適用します。 + +リソースが要求されるたびに、Android は要求されたリソース ファイルを持つ代替リソース ディレクトリを探し、<a href="#BestMatch">最適なリソースを見つけます</a>(後述)。 + +特定の端末設定に合う代替リソースがない場合、Android は対応するデフォルト リソース(設定識別子を含まない特定のリソースタイプ用の一連のリソース)を使用します。 + + +</p> + + + +<h3 id="AliasResources">エイリアス リソースを作成する</h3> + +<p>複数の端末で使用するリソースがある場合(ただし、デフォルト リソースとして提供しない場合)、同じリソースを複数の代替リソース ディレクトリに配置する必要はありません。 + +その代わりに、(場合によっては)デフォルト リソースのディレクトリに保存したリソースのエイリアスとして機能する代替リソースを作成できます。 + +</p> + +<p class="note"><strong>注:</strong> すべてのリソースに、別のリソースへのエイリアスを作成できるメカニズムが備わっているわけではありません。 +特に、アニメーション、メニュー、未加工、{@code xml/} で指定されていないその他のリソースにはこの機能を使用できません。 +</p> + +<p>たとえば、アプリケーション アイコン {@code icon.png} について、ロケールごとに一意のバージョンが必要になるという状況を考えてみます。 +ただし、英語カナダとフランス語カナダの 2 つのロケールでは同じバージョンを使用する必要があります。 +英語カナダとフランス語カナダの両方のリソース ディレクトリに同じ画像をコピーする必要は実際にはありません。 + +代わりに、両方に使用する画像を {@code icon_ca.png} という名前({@code icon.png} 以外の名前)で保存し、デフォルトの {@code res/drawable/} ディレクトリに配置します。 + +次に {@code <bitmap>} 要素を使用して {@code icon_ca.png} リソースを参照する {@code icon.xml} ファイルを {@code +res/drawable-en-rCA/} と {@code res/drawable-fr-rCA/} に作成します。 +これにより、PNG ファイルを 1 つだけ作成し、それを指す小さな XML ファイルを 2 つ作成するだけで済みます +(次に、XML ファイルの例を示します)。</p> + + +<h4>ドローアブル</h4> + +<p>既存のドローアブルのエイリアスを作成するには、{@code <bitmap>} 要素を使用します。次に例を示します。 +</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<bitmap xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/icon_ca" /> +</pre> + +<p>このファイルを {@code icon.xml} として({@code res/drawable-en-rCA/} などの代替リソース ディレクトリに)保存すると、{@code R.drawable.icon} として参照可能なリソースにコンパイルされますが、実際のところ、これは({@code res/drawable/} に保存されている){@code +R.drawable.icon_ca} リソースのエイリアスです。 + +</p> + + +<h4>レイアウト</h4> + +<p>既存のレイアウトのエイリアスを作成するには、{@code <merge>} にラップされる {@code <include>} 要素を使用します。 +次に例を示します。</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<merge> + <include layout="@layout/main_ltr"/> +</merge> +</pre> + +<p>このファイルを {@code main.xml} として保存すると、{@code R.layout.main} として参照可能なリソースにコンパイルされますが、実際のところ、これは {@code R.layout.main_ltr} リソースのエイリアスです。 + +</p> + + +<h4>文字列とその他の単純な値</h4> + +<p>既存の文字列のエイリアスを作成するには、単に、目的の文字列のリソース ID を新しい文字列の値として使用します。 +次に例を示します。</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="hello">Hello</string> + <string name="hi">@string/hello</string> +</resources> +</pre> + +<p>{@code R.string.hi} リソースは {@code R.string.hello} のエイリアスになりました。</p> + +<p> <a href="{@docRoot}guide/topics/resources/more-resources.html">その他の単純な値</a>も同様に機能します。 +次に色の例を示します。</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<resources> + <color name="yellow">#f00</color> + <color name="highlight">@color/red</color> +</resources> +</pre> + + + + +<h2 id="Compatibility">リソースとの最適な端末の互換性を提供する</h2> + +<p>アプリケーションで複数の端末設定をサポートするには、アプリケーションが使用するそれぞれのタイプのリソースに常にデフォルト リソースを提供することが重要です。 +</p> + +<p>たとえば、アプリケーションが複数の言語をサポートする場合は、<a href="#LocaleQualifier">言語と地域の修飾子</a>を<em>持たない</em> {@code +values/} ディレクトリ(文字列の保存先)を常に用意します。すべての文字列ファイルをすべて言語と地域の修飾子を持つディレクトリに配置してしまうと、自分の文字列がサポートしていない言語に設定された端末でアプリケーションを実行すると、アプリケーションがクラッシュしてしまいます。 + +ただし、デフォルトの {@code values/} リソースを提供しておけば、アプリケーションは適切に実行されます(ユーザーがその言語を理解できない場合でも。—クラッシュは避けられます)。 + +</p> + +<p>同様に、画面の向きに基づいた異なるレイアウト リソースを提供する場合も、いずれかの方向をデフォルトに設定する必要があります。 +たとえば、横向きの {@code +layout-land/} と縦向きの {@code layout-port/} にレイアウト リソースを提供する代わりに、横向きの {@code layout/} と縦向きの {@code layout-port/} のようなリソースをデフォルトとして保存しておきます。 +</p> + +<p>予測しなかった設定でアプリケーションが実行されるだけでなく、新しいバージョンの Android では古いバージョンではサポートされない設定修飾子が追加されることもあるため、デフォルト リソースの提供が重要になります。 + +新しいリソース修飾子を使用するが、古いバージョンの Android とのコードの互換性を保持する場合、古いバージョンの Android でアプリケーションを実行するときにデフォルト リソースが提供されていないと、古いバージョンの Android では新しい修飾子の付いたリソースを使用できないために、アプリケーションがクラッシュします。 + + +たとえば、<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code +minSdkVersion}</a> が 4 に設定されている場合に、<a href="#NightQualifier">ナイトモード</a>(API レベル 8 で追加された {@code night} または {@code notnight})を使用してすべてのドローアブル リソースの修飾子を設定すると、API レベル 4 端末はドローアブル リソースにアクセスできず、クラッシュします。 +この場合、{@code notnight} をデフォルト リソースにする場合、その修飾子を除外することになるため、ドローアブル リソースは {@code drawable/} または {@code drawable-night/} のいずれかになります。 + +</p> + +<p>そこで、端末の最適な互換性を提供するには、アプリケーションを適切に実行するのに必要なリソースに常にデフォルト リソースを提供するようにします。 +次に、設定修飾子を使用して、特定の端末設定向けの代替リソースを作成します。 +</p> + +<p>このルールには次の例外があります。アプリケーションの <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a> が 4 以上の場合、<a href="#DensityQualifier">画像密度</a>修飾子で代替のドローアブル リソースを提供するときには、デフォルトのドローアブル リソースを提供する必要はありません。<em></em> + +デフォルトのドローアブル リソースがない場合でも、Android は代替の画面密度のなかで最適なものを見つけて、必要に応じてビットマップのサイズを変更できます。 + +ただし、すべてのタイプに最適な操作性を提供するには、密度の 3 つのタイプすべてに代替ドローアブルを提供する必要があります。 +</p> + + + +<h2 id="BestMatch">Android が最適なリソースを見つける仕組み</h2> + +<p>代替を提供するリソースを要求すると、現在の端末設定に応じて Android が実行時に使用する代替リソースを選択します。 +Android が代替リソースを選択する方法説明するために、次のドローアブル ディレクトリを想定します。それぞれに同じ画像の異なるバージョンが入っています。 + +</p> + +<pre class="classic no-pretty-print"> +drawable/ +drawable-en/ +drawable-fr-rCA/ +drawable-en-port/ +drawable-en-notouch-12key/ +drawable-port-ldpi/ +drawable-port-notouch-12key/ +</pre> + +<p>さらに、次のような端末設定を想定します。</p> + +<p style="margin-left:1em;"> +ロケール = <code>en-GB</code> <br/> +画面の向き = <code>port</code> <br/> +画面ピクセル密度 = <code>hdpi</code> <br/> +タッチスクリーン タイプ = <code>notouch</code> <br/> +主なテキストの入力方法 = <code>12key</code> +</p> + +<p>端末設定を使用可能な代替リソースに比較して、Android は {@code drawable-en-port} からドローアブルを選択します。 +</p> + +<p>システムは、次のロジックを使用して、使用するリソースを決定します。 +</p> + + +<div class="figure" style="width:371px"> +<img src="{@docRoot}images/resources/res-selection-flowchart.png" alt="" height="471" /> +<p class="img-caption"><strong>図 2.</strong> Android が最適なリソースを見つける仕組みを示したフローチャート。 +</p> +</div> + + +<ol> + <li>端末設定に矛盾するリソース ファイルを排除します。 + <p><code>en-GB</code> ロケールに矛盾するため、<code>drawable-fr-rCA/</code> ディレクトリが排除されます。 +</p> +<pre class="classic no-pretty-print"> +drawable/ +drawable-en/ +<strike>drawable-fr-rCA/</strike> +drawable-en-port/ +drawable-en-notouch-12key/ +drawable-port-ldpi/ +drawable-port-notouch-12key/ +</pre> +<p class="note"><strong>例外:</strong> 画面ピクセル密度は、矛盾により排除されない修飾子の 1 つです。 +それぞれの画面密度はその時点で最適であると判断されたものであるため、端末の画面密度が hdpi の場合でも、<code>drawable-port-ldpi/</code> は排除されません。 + +詳細は、「<a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a>」のドキュメントをご覧ください。 +</p></li> + + <li>リスト(<a href="#table2">表 2</a>)にある(次に)優先される修飾子を選択します(MCC から順に下がっていきます)。 + </li> + <li>この修飾子を含むリソース ディレクトリがあるかどうかを確認します。 </li> + <ul> + <li>ない場合は、ステップ 2 に戻り、次の修飾子を調べます(この例では、言語識別子になるまですべて「いいえ」になります)。 +</li> + <li>「はい」の場合は、ステップ 4 に進みます。</li> + </ul> + </li> + + <li>この修飾子を持たないリソース ディレクトリを排除します。この例では、システムによって言語修飾子を含まないすべてのディレクトリが排除されます。 +</li> +<pre class="classic no-pretty-print"> +<strike>drawable/</strike> +drawable-en/ +drawable-en-port/ +drawable-en-notouch-12key/ +<strike>drawable-port-ldpi/</strike> +<strike>drawable-port-notouch-12key/</strike> +</pre> +<p class="note"><strong>例外:</strong> 対象となる修飾子が画面ピクセル密度の場合、Android は端末の画像密度に最も近いオプションを選択します。一般的に、Android では小さな元画像を拡大するよりも、大きな元画像を縮小する方法が使用されます。 + + +「<a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a>」をご覧ください。 +</p> + </li> + + <li>残るディレクトリが 1 つになるまで、元に戻ってステップ 2、3、4 を繰り返します。このレイでは、次にマッチングするのが画面の向きの修飾子です。そのため、画面の向きを指定しないリソースは排除されます。 + + +<pre class="classic no-pretty-print"> +<strike>drawable-en/</strike> +drawable-en-port/ +<strike>drawable-en-notouch-12key/</strike> +</pre> +<p>{@code drawable-en-port} ディレクトリが残ります。</p> + </li> +</ol> + +<p>この手順は要求した各リソースに対して実行されますが、システムはさらにいくつかの最適化を行います。 +たとえば、端末の設定が判明すると、マッチングしない代替リソースが排除されたりします。 +たとえば、設定言語が英語(「en」)の場合、言語修飾子が英語以外に設定されているリソース ディレクトリはチェック対象のリソースのプールに入ることはありません(言語修飾子のないリソース ディレクトリはそのままプールに入ります)。<em></em> + + +</p> + +<p>画面サイズ修飾子に基づいてリソースを選択する場合、最適なリソースがない場合、システムは現在の画面よりも小さな画面向けのリソースを使用します(たとえば、必要に応じて大きなサイズの画面が通常サイズの画面のリソースを使用します)。 + +ただし、使用できるリソースが現在の画面よりも大きなサイズのものしかない場合は、システムはそれらのリソースを<strong>使用せず</strong>、端末設定にあるその他のリソースがないときは、アプリケーションがクラッシュします(たとえば、すべてのリソースに {@code xlarge} 識別子のタグが付いているが、端末は通常サイズの画面である場合)<em></em> + + + +</p> + +<p class="note"><strong>注:</strong> (<a href="#table2">表 2</a> の)上位にある修飾子の方が、端末に正確に一致する修飾子の数よりも重要になります。<em></em> +たとえば、上のステップ 4 では、<code>drawable-en</code> には一致するパラメータが 1 つしかありませんが(言語)、リストの最後の選択肢には、端末に正確に一致する修飾子が 3 つあります(画面の向き、タッチスクリーン タイプ、入力方法)。 + + +ただし、言語はこれらの他の修飾子よりも優先されるため、<code>drawable-port-notouch-12key</code> は排除されます。 +</p> + +<p>アプリケーションでのリソースの使用方法については、「<a href="accessing-resources.html">リソースへのアクセス</a>」をご覧ください。</p> diff --git a/docs/html-intl/intl/ja/guide/topics/resources/runtime-changes.jd b/docs/html-intl/intl/ja/guide/topics/resources/runtime-changes.jd new file mode 100644 index 000000000000..9bce95aee115 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/resources/runtime-changes.jd @@ -0,0 +1,281 @@ +page.title=実行時の変更の処理 +page.tags=アクティビティ,ライフサイクル +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + + <h2>本書の内容</h2> + <ol> + <li><a href="#RetainingAnObject">構成の変更中にオブジェクトを保持する</a></li> + <li><a href="#HandlingTheChange">構成の変更を自分で処理する</a> + </ol> + + <h2>関連ドキュメント</h2> + <ol> + <li><a href="providing-resources.html">リソースの提供</a></li> + <li><a href="accessing-resources.html">リソースへのアクセス</a></li> + <li><a href="http://android-developers.blogspot.com/2009/02/faster-screen-orientation-change.html">Faster + Screen Orientation Change</a></li> + </ol> +</div> +</div> + +<p>端末の構成の中には、実行時に変化するものがあります(画面の向き、キーボードの可用性、言語など)。 +そのような変更が発生すると、Android は実行中の {@link android.app.Activity} を再起動します({@link android.app.Activity#onDestroy()} が呼び出され、その後に{@link +android.app.Activity#onCreate(Bundle) onCreate()} が呼び出されます)。 + +再起動の動作は、新しい端末構成に一致する代替リソースを使用してアプリケーションを自動的にリロードすることで、アプリケーションを新しい構成に適応させることを目的としています。 + +</p> + +<p>再起動を適切に処理するには、アクティビティが通常の<a href="{@docRoot}guide/components/activities.html#Lifecycle">アクティビティのライフサイクル</a>を通じて事前の状態を格納することが重要です。その場合、アプリケーションの状態に関するデータを保存できるように、Android はアクティビティを破棄する前に {@link android.app.Activity#onSaveInstanceState(Bundle) onSaveInstanceState()} を呼び出します。 + + + +その後、{@link android.app.Activity#onCreate(Bundle) onCreate()} か {@link +android.app.Activity#onRestoreInstanceState(Bundle) onRestoreInstanceState()} の際に状態を格納できます。 +</p> + +<p>アプリケーション自体がそのままの状態で再起動することをテストするには、アプリケーションでさまざまなタスクを実行中に、構成の変更(画面の向きの変更など)を呼び出す必要があります。 + +構成の変更を処理したり、ユーザーが電話を着信し、アプリケーション プロセスが破棄されるほど時間が経過してからアプリケーションに戻ったりするような場合には、ユーザーデータや状態を失うことなくいつでもアプリケーションを再起動できるようにする必要があります。 + + +アクティビティの状態を格納する方法については、「<a href="{@docRoot}guide/components/activities.html#Lifecycle">アクティビティのライフサイクル</a>」をご覧ください。</p> + +<p>ただし、場合によっては、アプリケーションを再起動すると、大量のデータの復元にコストがかかり、操作性が悪くなることがあります。 +そのような場合、次の 2 つの方法で処理できます。 +</p> + +<ol type="a"> + <li><a href="#RetainingAnObject">構成の変更中にオブジェクトを保持する</a> + <p>構成の変更時にアクティビティを再起動できますが、ステートフル オブジェクトがアクティビティの新しいインスタンスに移動します。 +</p> + + </li> + <li><a href="#HandlingTheChange">構成の変更を自分で処理する</a> + <p>特定の構成変更の際に、システムがアクティビティを再起動しないようにしますが、必要に応じてアクティビティをアップデートできるように、構成が変更された場合には、コールバックを受け取ります。 + +</p> + </li> +</ol> + + +<h2 id="RetainingAnObject">構成の変更中にオブジェクトを保持する</h2> + +<p>アクティビティの再起動で大量のデータの復元、ネットワーク接続の再構築、他の負荷のかかる操作の実行が必要になる場合、構成変更のために完全な再起動を実行すると、操作性が悪くなってしまうことがあります。 + +さらに、システムの {@link +android.app.Activity#onSaveInstanceState(Bundle) onSaveInstanceState()} コールバックによって保存される {@link android.os.Bundle} を使用して、アクティビティの状態を完全に復元できない場合もあります。—大きなオブジェクト(ビットマップなど)を扱うためのものではなく、内部のデータをシリアル化してから逆シリアル化を行うため、多くのメモリを消費することになり、構成の変更に時間がかかってしまいます。 + + +そのような場合、構成の変更によるアクティビティの再起動の際に、{@link +android.app.Fragment} を保持することで、再初期化の負担を軽減できます。 +このフラグメントには、保持しておきたいステートフル オブジェクトへの参照を含めることができます。 +</p> + +<p>構成変更により Android システムがアクティビティをシャットダウンするとき、保持するためのマークを設定しておくと、アクティビティのフラグメントが破棄されません。 +ステートフル オブジェクトを保持するために、アクティビティにこのようなフラグメントを追加しておくことができます。 +</p> + +<p>実行時の構成変更の際に、フラグメントにステートフル オブジェクトを保持するには:</p> + +<ol> + <li>{@link android.app.Fragment} クラスを拡張し、ステートフル オブジェクトへの参照を宣言します。 +</li> + <li>フラグメントを作成するときに、{@link android.app.Fragment#setRetainInstance(boolean)} を呼び出します。 + </li> + <li>フラグメントをアクティビティに追加します。</li> + <li>アクティビティの再起動時にフラグメントを取得するには、{@link android.app.FragmentManager} を使用します。 +</li> +</ol> + +<p>次は、フラグメントの定義の例です。</p> + +<pre> +public class RetainedFragment extends Fragment { + + // data object we want to retain + private MyDataObject data; + + // this method is only called once for this fragment + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // retain this fragment + setRetainInstance(true); + } + + public void setData(MyDataObject data) { + this.data = data; + } + + public MyDataObject getData() { + return data; + } +} +</pre> + +<p class="caution"><strong>警告:</strong> オブジェクトの格納が可能な間は、{@link +android.graphics.drawable.Drawable}、{@link android.widget.Adapter}、{@link android.view.View}、さらには {@link android.content.Context} に関連付けられているその他のオブジェクトのように、{@link android.app.Activity} に結び付いたオブジェクトを渡さないようにしてください。 + +オブジェクトを渡すと、元のアクティビティ インスタンスのビューやリソースがすべて漏えいしてしまいます +(リソースが漏えいすると、アプリケーションはリソースを保持しているがガーベジコレクションを実行できず、大量のメモリが失われてしまうことがあります)。 + +</p> + +<p>次に、{@link android.app.FragmentManager} を使用して、フラグメントをアクティビティに追加します。実行時に構成を変更する際にアクティビティを再び起動すると、フラグメントからデータ オブジェクトを取得できます。 + +次は、アクティビティの定義の例です。</p> + +<pre> +public class MyActivity extends Activity { + + private RetainedFragment dataFragment; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + + // find the retained fragment on activity restarts + FragmentManager fm = getFragmentManager(); + dataFragment = (DataFragment) fm.findFragmentByTag(“data”); + + // create the fragment and data the first time + if (dataFragment == null) { + // add the fragment + dataFragment = new DataFragment(); + fm.beginTransaction().add(dataFragment, “data”).commit(); + // load the data from the web + dataFragment.setData(loadMyData()); + } + + // the data is available in dataFragment.getData() + ... + } + + @Override + public void onDestroy() { + super.onDestroy(); + // store the data in the fragment + dataFragment.setData(collectMyLoadedData()); + } +} +</pre> + +<p>この例では、{@link android.app.Activity#onCreate(Bundle) onCreate()} がフラグメントを追加するか、フラグメントへの参照を復元します。さらに、{@link android.app.Activity#onCreate(Bundle) onCreate()} がステートフル オブジェクトをフラグメント インスタンスの内部に格納し、{@link android.app.Activity#onDestroy() onDestroy()} が保持しているフラグメント インスタンス内部のステートフル オブジェクトを更新します。 + + + +</p> + + + + + +<h2 id="HandlingTheChange">構成の変更を自分で処理する</h2> + +<p>アプリケーションに特定の構成の変更の際にリソースを更新する必要がなく、パフォーマンスの制限によりアクティビティの再起動を回避する必要がある場合は、構成の変更をアクティビティ自身が処理することを宣言します。そうすることで、システムによってアクティビティが再起動されなくなります。 +<em></em> + +</p> + +<p class="note"><strong>注:</strong> 構成の変更を自分で処理すると、変更がシステムによって自動的に適用されることがないため、代替リソースの使用が非常に難しくなります。 + +この手法は、構成の変更による再起動を回避する際の最後の手段として検討する手法です。ほとんどの場合、アプリケーションでの使用は推奨されません。 +</p> + +<p>アクティビティで構成の変更を処理することを宣言するには、マニフェスト ファイルの該当する <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> 要素を編集し、処理する構成を表す値とともに <a href="{@docRoot}guide/topics/manifest/activity-element.html#config">{@code +android:configChanges}</a> 属性を配置します。 + +使用可能な値は、<a href="{@docRoot}guide/topics/manifest/activity-element.html#config">{@code +android:configChanges}</a> 属性のドキュメントに一覧が記載されています(一般的には、画面の向きを変更した場合の再起動を回避するには {@code "orientation"} の値を、キーボードの可用性を変更した場合の再起動を回避するには {@code "keyboardHidden"} の値を使用します)。 + +パイプ記号の {@code |} 文字を使用して区切ることで、属性内に複数の構成値を宣言できます。 +</p> + +<p>たとえば、次のマニフェスト コードでは、画面の向きとキーボードの可用性の変更の両方を処理するアクティビティを宣言しています。 +</p> + +<pre> +<activity android:name=".MyActivity" + android:configChanges="orientation|keyboardHidden" + android:label="@string/app_name"> +</pre> + +<p>これで、これらのいずれかの構成が変更された場合でも、{@code MyActivity} が再起動することはなくなりました。代わりに、{@code MyActivity} が {@link +android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()} への呼び出しを取得します。 +このメソッドには、新しい端末構成を指定する {@link android.content.res.Configuration} オブジェクトが渡されます。 + +{@link android.content.res.Configuration} のフィールドを読み込むことで新しい構成を判断し、インターフェースに使用するリソースを更新して適切に変更できます。 + +このメソッドが呼び出されると、アクティビティの {@link android.content.res.Resources} オブジェクトが更新され、新しい構成に基づいたリソースを返します。それにより、システムがアクティビティを再起動しなくても、UI の要素を簡単にリセットできます。 + + +</p> + +<p class="caution"><strong>警告:</strong> Android 3.2(API レベル 13)以降では、端末の画面の向きを縦から横に切り替えると、<strong>「画面サイズ」も変更されます</strong>。 + +そのため、API レベル 13 以降で開発を行う場合(<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a> 属性と <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a> 属性により宣言)、画面の向きによる実行時の再起動を回避するには、{@code "screenSize"} 値と一緒に {@code +"orientation"} 値を使用する必要があります。 + +つまり、{@code +android:configChanges="orientation|screenSize"} を宣言する必要があります。ただし、アプリケーションのターゲットが API レベル 12 以前の場合は、常にアクティビティ自身がこの構成の変更を処理します(Android 3.2 以降の端末で実行している場合でも、この構成の変更によりアクティビティが再起動されることはありません)。 + +</p> + +<p>たとえば、次の {@link +android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()} の実装により現在の端末の画面の向きがチェックされます。 +</p> + +<pre> +@Override +public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + // Checks the orientation of the screen + if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { + Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show(); + } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){ + Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show(); + } +} +</pre> + +<p>{@link android.content.res.Configuration} オブジェクトは、変更された構成を除く、現在のすべての構成を表します。 +ほとんどの場合、構成の変更内容を正確に把握する必要はなく、代替の構成を提供するすべてのリソースを処理中の構成に割り当て直します。 + +たとえば、現在は {@link +android.content.res.Resources} オブジェクトが更新されたため、任意の {@link android.widget.ImageView} を {@link android.widget.ImageView#setImageResource(int) +setImageResource()} でリセットでき、新しい構成には最適なリソースが使用されます(「<a href="providing-resources.html#AlternateResources">リソースの提供</a>」をご覧ください)。 + +</p> + +<p>{@link +android.content.res.Configuration} フィールドの値は、{@link android.content.res.Configuration} クラスの特定の定数に一致する整数であることにご注意ください。 +それぞれのフィールドで使用する定数に関するドキュメントについては、{@link +android.content.res.Configuration} リファレンスの該当するフィールドをご覧ください。 +</p> + +<p class="note"><strong>メモ:</strong> 構成の変更をアクティビティで処理することを宣言すると、代替を提供するすべての要素をリセットする操作が必要になります。 +画面の向きの変更を処理するアクティビティを宣言しており、縦向きと横向きで切り替わる画像がある場合、{@link +android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()} の際にそれぞれの要素に各リソースを割り当て直す必要があります。 + +</p> + +<p>これらの構成の変更に基づいてアプリケーションを更新する必要がない場合は、代わりに <em></em>{@link +android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()} を実装できません。 +このような場合、構成の変更前に使用していたすべてのリソースがそのまま使用され、アクティビティの再起動を回避した状態となります。 + +ただし、アプリケーションはいつでもシャットダウンして以前のままの状態で再起動できる状態にしておく必要があるため、通常のアクティビティのライフサイクルでは、状態を保持しない手段としてこの手法を使用しないようにします。 + +それは、アプリケーションの再起動を回避できない他の構成の変更があるだけでなく、ユーザーがアプリケーションを離れ、ユーザーがアプリケーションに戻る前に破棄されてしまうようなイベントを処理する必要があるためです。 + + +</p> + +<p>アクティビティで処理できる構成の変更についての詳細は、<a href="{@docRoot}guide/topics/manifest/activity-element.html#config">{@code +android:configChanges}</a> のドキュメントと{@link android.content.res.Configuration} クラスをご覧ください。 +</p> diff --git a/docs/html-intl/intl/ja/guide/topics/ui/controls.jd b/docs/html-intl/intl/ja/guide/topics/ui/controls.jd new file mode 100644 index 000000000000..0bc2063764bb --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/ui/controls.jd @@ -0,0 +1,90 @@ +page.title=入力コントロール +parent.title=ユーザー インターフェース +parent.link=index.html +@jd:body + +<div class="figure" style="margin:0"> + <img src="{@docRoot}images/ui/ui-controls.png" alt="" style="margin:0" /> +</div> + +<p>入力コントロールは、アプリのユーザー インターフェースのインタラクティブなコンポーネントです。Android では、ボタン、テキスト フィールド、シークバー、チェックボックス、ズームボタン、トグルボタンなど UI で使用できるさまざまなコントロールが提供されています。 + +</p> + +<p>UI に入力コントロールを追加することは、<a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML レイアウト</a>に XML 要素を追加するのと同じくらい簡単です。テキスト フィールドとボタンを含むレイアウトの例を次に示します。 +</p> + +<pre style="clear:right"> +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="horizontal"> + <EditText android:id="@+id/edit_message" + android:layout_weight="1" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:hint="@string/edit_message" /> + <Button android:id="@+id/button_send" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/button_send" + android:onClick="sendMessage" /> +</LinearLayout> +</pre> + +<p>各入力コントロールでは、特定の一連の入力イベントがサポートされているため、ユーザーがテキストを入力したり、ボタンをタップしたりするときなどに、イベントを処理できます。 +</p> + + +<h2 id="CommonControls">コモン コントロール</h2> +<p>アプリで使用できるコモン コントロールには、次のようなものがあります。それぞれの使い方の詳細については、各リンクをご覧ください。 +</p> + +<p class="note"><strong>注:</strong> Android では、ここにリストされている以外にもいくつかコントロールが提供されています。 +他のコントロールについては、{@link android.widget} パッケージをご確認ください。アプリで、特定の種類の入力コントロールを必要とする場合、独自の <a href="{@docRoot}guide/topics/ui/custom-components.html">カスタム コンポーネント</a> をビルドできます。 +</p> + +<table> + <tr> + <th scope="col">コントロール タイプ</th> + <th scope="col">説明</th> + <th scope="col">関連クラス</th> + </tr> + <tr> + <td><a href="controls/button.html">ボタン</a></td> + <td>ユーザーがアクションを実行するために、押したり、クリックしたりできるプッシュボタン。</td> + <td>{@link android.widget.Button Button} </td> + </tr> + <tr> + <td><a href="controls/text.html">テキスト フィールド</a></td> + <td>編集できるテキスト フィールド。<code>AutoCompleteTextView</code> ウィジェットを使って、オートコンプリート候補を表示するテキスト入力ウィジェットを作成できます。</td> + <td>{@link android.widget.EditText EditText}、{@link android.widget.AutoCompleteTextView}</td> + </tr> + <tr> + <td><a href="controls/checkbox.html">チェックボックス</a></td> + <td>ユーザーが切り替えることができる、オン、オフスイッチ。相互に排他的ではない選択可能なオプションのグループをユーザーに表示するときは、チェックボックスを使ってください。</td> + <td>{@link android.widget.CheckBox CheckBox} </td> + </tr> + <tr> + <td><a href="controls/radiobutton.html">ラジオボタン</a></td> + <td>グループで選択できるオプションは 1 つのみであることを除き、チェックボックスと同様です。</td> + <td>{@link android.widget.RadioGroup RadioGroup} + <br>{@link android.widget.RadioButton RadioButton} </td> + </tr> + <tr> + <td><a href="controls/togglebutton.html" style="white-space:nowrap">トグルボタン</a></td> + <td>ライト インジケーター付きの、オン、オフボタン。</td> + <td>{@link android.widget.ToggleButton ToggleButton} </td> + </tr> + <tr> + <td><a href="controls/spinner.html">スピナー</a></td> + <td>ユーザーが一連の値から 1 つを選択できるドロップダウン リスト。</td> + <td>{@link android.widget.Spinner Spinner} </td> + </tr> + <tr> + <td><a href="controls/pickers.html">ピッカー</a></td> + <td>上下のボタンを使うか、スワイプして、1 つの値を選択するためのダイアログ。日付(月、日、年)の値を入力するには <code>DatePicker</code>code> ウィジェットを使い、時刻(時間、分、午前または午後)の値を入力するには <code>TimePicker</code> ウィジェットを使います。これにより、ユーザーのロケールが自動的に書式設定されます。</td> + <td>{@link android.widget.DatePicker}、{@link android.widget.TimePicker}</td> + </tr> +</table> diff --git a/docs/html-intl/intl/ja/guide/topics/ui/declaring-layout.jd b/docs/html-intl/intl/ja/guide/topics/ui/declaring-layout.jd new file mode 100644 index 000000000000..b0e9c03111fe --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/ui/declaring-layout.jd @@ -0,0 +1,492 @@ +page.title=レイアウト +page.tags=view,viewgroup +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + <h2>本書の内容</h2> +<ol> + <li><a href="#write">XML の記述</a></li> + <li><a href="#load">XML リソースの読み込み</a></li> + <li><a href="#attributes">属性</a> + <ol> + <li><a href="#id">ID</a></li> + <li><a href="#layout-params">レイアウト パラメータ</a></li> + </ol> + </li> + <li><a href="#Position">レイアウトの位置</a></li> + <li><a href="#SizePaddingMargins">サイズ、パディング、マージン</a></li> + <li><a href="#CommonLayouts">共通レイアウト</a></li> + <li><a href="#AdapterViews">アダプタを使ったレイアウトをビルドする</a> + <ol> + <li><a href="#FillingTheLayout">データを使ったアダプタビューを書き込む</a></li> + <li><a href="#HandlingUserSelections">クリック イベントを処理する</a></li> + </ol> + </li> +</ol> + + <h2>キークラス</h2> + <ol> + <li>{@link android.view.View}</li> + <li>{@link android.view.ViewGroup}</li> + <li>{@link android.view.ViewGroup.LayoutParams}</li> + </ol> + + <h2>関連ドキュメント</h2> + <ol> + <li><a href="{@docRoot}training/basics/firstapp/building-ui.html">簡単なユーザー インターフェースをビルドする</a> +</li> </div> +</div> + +<p>レイアウトでは、<a href="{@docRoot}guide/components/activities.html">アクティビティ</a>や<a href="{@docRoot}guide/topics/appwidgets/index.html">アプリ ウィジェット</a>の UI のような、ユーザー インターフェースの視覚的構造が定義されます。次の 2 つの方法でレイアウトを宣言できます。 +</p> +<ul> +<li><strong>XML で UI 要素を宣言する</strong>。Android では、ウィジェットやレイアウトなどの View クラスとサブクラスに対応する単純な XML ボキャブラリが提供されます。 +</li> +<li><strong>実行時にレイアウト要素のインスタンスを作成する</strong>。アプリケーションで View と ViewGroup オブジェクトを作成できます。また、プログラムを使ってプロパティを操作することもできます。 + </li> +</ul> + +<p>Android フレームワークでは、アプリケーション UI の宣言と管理に、これらのいずれかのメソッドまたは両方のメソッドを柔軟に使うことができます。たとえば、レイアウトに表示されるスクリーン要素やそのプロパティを含む、アプリケーションのデフォルト レイアウトを XML で宣言できます。スクリーン オブジェクトの状態を変更するコードをアプリケーション内で追加できます(実行時の XML での宣言を含む)。 </p> + +<div class="sidebox-wrapper"> +<div class="sidebox"> + <ul> + <li><a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin for Eclipse</a> では、XML ファイルを開いて [<strong>レイアウト</strong>] タブを選択すると、XML のレイアウト プレビューが提供されます。 + +</li> + <li>レイアウトのデバッグに、<a href="{@docRoot}tools/debugging/debugging-ui.html#hierarchyViewer">Hierarchy Viewer</a> ツールを使うこともできます。このツールでは、レイアウト プロパティ値の表示、パディングやマージンのインジケーターを使ったワイヤーフレームの描画、エミュレータや端末でデバッグする間のレンダリングされた全画面表示が提供されます。 + + + +</li> + <li><a href="{@docRoot}tools/debugging/debugging-ui.html#layoutopt">layoutopt</a> ツールを使うと、効率性の低下やその他の問題について、レイアウトや階層を素早く解析できます。 +</li> +</div> +</div> + +<p>XML で UI を宣言する利点は、動作を制御するコードとアプリケーションの表示をうまく切り離すことができる点です。UI の記述は、アプリケーション コード外にあるため、ソースコードの変更や再コンパイルをすることなく、記述を修正したり改良したりできます。たとえば、異なる画面の向き、端末の画面サイズ、言語に対して XML レイアウトを作成できます。XML でレイアウトを宣言すると、UI の構造を簡単に視覚化できるため、問題のデバッグも簡単です。そのため、本書では XML でレイアウトを宣言する方法を中心に説明しています。実行時に View オブジェクトのインスタンスを作成することに関心がある場合は、{@link android.view.ViewGroup} と {@link android.view.View} クラス参照をご覧ください。 + +</p> + +<p>通常、UI 要素を宣言する XML ボキャブラリは、クラスとメソッドの構造と命名に厳密に従っており、要素名はクラス名に、属性名はメソッドに対応しています。実際、ほとんどの場合、直接的に対応しているため、クラスメソッドに対応する XML 属性を推測したり、与えられた XML 要素に対応するクラスを推測したりできます。ただし、すべてのボキャブラリが同一とは限りません。場合によっては、命名が若干異なります。たとえば、EditText 要素には、<code>EditText.setText()</code> に対応する <code>text</code> 属性があります。 + + </p> + +<p class="note"><strong>ヒント:</strong> 異なるレイアウト タイプの詳細については、<a href="{@docRoot}guide/topics/ui/layout-objects.html">共通レイアウト オブジェクト</a>をご覧ください。 +また、<a href="{@docRoot}resources/tutorials/views/index.html">Hello Views</a> のチュートリアル ガイドには、さまざまなレイアウトのビルドに関するチュートリアルがあります。 +</p> + +<h2 id="write">XML の記述</h2> + +<p>Android の XML ボキャブラリを使って、HTML でウェブページを作成するのと同じ方法で(ネストした一連の要素を使って)、UI レイアウトとそれに含まれる画面要素を素早く設計できます。 </p> + +<p>各レイアウト ファイルには、必ず 1 つのルート要素が含まれていて、そのルート要素は View または ViewGroup オブジェクトでなくてはなりません。ルート要素を定義すれば、追加のレイアウト オブジェクトやウィジェットを子の要素として追加して、レイアウトを定義するビュー階層を少しずつビルドできます。{@link android.widget.TextView} と {@link android.widget.Button} を保持するために、縦方向の {@link android.widget.LinearLayout} を使用する XML レイアウトの例を次に示します。 +</p> +<pre> +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" > + <TextView android:id="@+id/text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Hello, I am a TextView" /> + <Button android:id="@+id/button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Hello, I am a Button" /> +</LinearLayout> +</pre> + +<p>XML でレイアウトを宣言した後、そのファイルを Android プロジェクトの <code>res/layout/</code> ディレクトリ内で <code>.xml</code> 拡張子を付けて保存して、正しくコンパイルされるようにします。 + </p> + +<p>レイアウト XML ファイルの構文の詳細については、「<a href="{@docRoot}guide/topics/resources/layout-resource.html">Layout Resources</a>」のドキュメントをご覧ください。</p> + +<h2 id="load">XML リソースの読み込み</h2> + +<p>アプリケーションをコンパイルすると、各 XML レイアウト ファイルは {@link android.view.View} リソースにコンパイルされます。 +{@link android.app.Activity#onCreate(android.os.Bundle) Activity.onCreate()} コールバックの実装で、アプリケーション コードからレイアウト リソースを読み込んでください。これを行うには、<code>{@link android.app.Activity#setContentView(int) setContentView()}</code> を呼び出し、<code>R.layout.<em>layout_file_name</em></code> の形式でレイアウト リソースへの参照を渡します。たとえば、XML レイアウトが <code>main_layout.xml</code> として保存される場合、次のようにしてアクティビティに読み込みます。 + + + + + +</p> +<pre> +public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main_layout); +} +</pre> + +<p>アクティビティの <code>onCreate()</code> コールバック メソッドは、アクティビティが起動されるときに、Android フレームワークによって呼び出されます(ライフサイクルに関する説明については、「<a href="{@docRoot}guide/components/activities.html#Lifecycle">アクティビティ</a>」のドキュメントをご覧ください)。 + + +</p> + + +<h2 id="attributes">属性</h2> + +<p>すべての View と ViewGroup オブジェクトでは、独自のさまざまな XML 属性がサポートされています。一部の属性は、View オブジェクト特有のものですが(たとえば TextView では <code>textSize</code> 属性がサポートされています)、これらの属性はこのクラスを拡張可能な View オブジェクトによっても継承されます。一部は、ルート View クラスから継承されるため、すべての View オブジェクトに共通します(<code>id</code> 属性のような)。 + + + +その他の属性は「レイアウト パラメータ」として考慮され、オブジェクトの親である ViewGroup オブジェクトとして定義された、View オブジェクトの特定のレイアウト方向を記述する属性となります。 + +</p> + +<h3 id="id">ID</h3> + +<p>ツリー内で View を一意に識別するために、すべての View オブジェクトには、それに関連付けられた整数の ID があることがあります。アプリケーションがコンパイルされると、この ID は整数として参照されますが、一般的にその ID は <code>id</code> 属性で文字列としてレイアウト XML ファイルに割り当てられます。これは、すべての View オブジェクトに共通の XML 属性で({@link android.view.View} クラスで定義)、非常に頻繁に使用されます。XML タグ内の ID の構文を次に示します。 + + + + +</p> +<pre>android:id="@+id/my_button"</pre> + +<p>文字列の先頭にあるアットマーク(@)は、その XML パーサーが ID の残りの文字列をパースして展開し、それを ID リソースとして識別する必要があることを示します。 +プラス記号(+)は、それが新しいリソース名で、作成してリソースに追加する(<code>R.java</code> ファイル内で)必要があることを意味しています。 +Android フレームワークによって提供されるその他のさまざまな ID リソースがあります。 +Android リソース ID を参照するときは、プラス記号を使う必要はありませんが、次のように <code>android</code> パッケージ名前空間を追加する必要があります。 +</p> +<pre>android:id="@android:id/empty"</pre> +<p><code>android</code> パッケージ名前空間付きの場合、ローカルのリソースクラスからではなく <code>android.R</code> リソースクラスから ID を参照するようになります。 +</p> + +<p>ビューを作成してアプリケーションからそれを参照するには、次のような共通のパターンがあります。</p> +<ol> + <li>レイアウト ファイルでビューとウィジェットを定義して、一意の ID を割り当てる。 +<pre> +<Button android:id="@+id/my_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/my_button_text"/> +</pre> + </li> + <li>次に、View オブジェクトのインスタンスを作成し、それを次のようにレイアウトから取得する(通常は、<code>{@link android.app.Activity#onCreate(Bundle) onCreate()}</code> メソッド内で)。 + +<pre> +Button myButton = (Button) findViewById(R.id.my_button); +</pre> + </li> +</ol> +<p>View オブジェクトの ID を定義することは、{@link android.widget.RelativeLayout} を作成するときに重要になります。相対レイアウトでは、兄弟ビューは一意の ID で参照される別の兄弟ビューに相対するレイアウトを定義できます。 + +</p> +<p>ツリー全体で ID が一意である必要はありませんが、探しているツリーの一部では、一意である必要があります。ほとんどの場合、それはツリー全体になりますが、可能な時に完全に一意になるようにすることが最善です。 + +</p> + + +<h3 id="layout-params">レイアウト パラメータ</h3> + +<p><code>layout_<em>something</em></code> という名前の XML レイアウト属性では、含まれている ViewGroup に適した View に対するレイアウト パラメータが定義されます。 +</p> + +<p>すべての ViewGroup クラスでは、{@link +android.view.ViewGroup.LayoutParams} を拡張するネストされたクラスが実装されます。このサブクラスには、各子ビューのサイズと位置を ViewGroup に合うように定義するプロパティ タイプが含まれています。 + +図 1 にあるように、親 ViewGroup によって、子 ViewGroup を含む、各子ビューのレイアウト パラメータが定義されます。 +</p> + +<img src="{@docRoot}images/layoutparams.png" alt="" /> +<p class="img-caption"><strong>図 1.</strong> 各ビューに関連付けられたレイアウトのパラメータを含むビュー階層の視覚化。 +</p> + +<p>すべての LayoutParams サブクラスには、設定値に独自の構文があります。 +それぞれの子の要素では、その親に適した LayoutParams が定義される必要がありますが、自分の子に対して異なる LayoutParams を定義することもできます。 + </p> + +<p>すべての ViewGroup には、幅と高さ(<code>layout_width</code> と <code>layout_height</code>)が含まれていて、各ビューでそれが定義されている必要があります。 +多くの LayoutParams には、省略可能なマージンと境界線も含まれています。 + <p> + +<p>必要になる頻度は少ない可能性はありますが、幅と高さを正確なサイズで指定することもできます。 +ほとんどの場合は、次の定数のいずれかを使って幅や高さを設定します。 + </p> + +<ul> + <li><var>wrap_content</var> では、ビューがそのコンテンツに必要な寸法に合わせられます。 +</li> + <li><var>match_parent</var> (API レベル 8 以前は <var>fill_parent</var> )では、ビューが親 ViewGroup で許容される最大サイズで表示されます。 +</li> +</ul> + +<p>通常、ピクセルなどの絶対単位でレイアウトの幅と高さを指定することは推奨されません。 + +密度非依存ピクセル単位(<var>dp</var>)、 <var>wrap_content</var>、 +<var>match_parent</var>などの相対測定を使う方が賢明です。そうすることで、さまざまな端末の画面サイズでアプリケーションが正しく表示されるようになります。使用可能な測定タイプは、「<a href="{@docRoot}guide/topics/resources/available-resources.html#dimension">使用可能なリソース</a>」のドキュメントで定義されています。 + + + +</p> + + +<h2 id="Position">レイアウトの位置</h2> + <p> + ビューの形状は、矩形です。ビューには、<em>左</em>と<em>上</em>の座標ペアで表される位置と、幅と高さで表される 2 次元があります。 + +位置と寸法の単位はピクセルです。 + + </p> + + <p> + {@link android.view.View#getLeft()} と {@link android.view.View#getTop()} メソッドを呼び出してビューの位置を取得できます。 +前者では、左またはビューを表す矩形の X 座標が返されます。 +後者では、上またはビューを表す矩形の Y 座標が返されます。 +これらのメソッドでは、両方とも親に相対するビューの位置が返されます。 +たとえば、<code>getLeft()</code> で 20 が返される場合、そのビューはその直属の親の左端から右に 20 ピクセルの位置にあることを意味します。 + + + </p> + + <p> + 他にも、{@link android.view.View#getRight()} や {@link android.view.View#getBottom()} といった不要な計算を回避するさまざまな便利なメソッドが提供されています。 + + これらのメソッドでは、ビューを表す矩形の右端と下端の座標が返されます。 +たとえば、{@link android.view.View#getRight()} を呼び出すことは、<code>getLeft() + getWidth()</code> の計算と同様です。 + + </p> + + +<h2 id="SizePaddingMargins">サイズ、パディング、マージン</h2> + <p> + ビューのサイズは、幅と高さで示します。実際に、ビューには幅と高さ 2 つの値がペアとして保持されています。 + + </p> + + <p> + 最初のペアは、<em>測定された幅</em>と<em>測定された高さ</em>と呼ばれます。 +これらの寸法で、その親内でのビューの大きさが定義されます。 +測定された寸法は、{@link android.view.View#getMeasuredWidth()} と {@link android.view.View#getMeasuredHeight()} を呼び出して取得できます。 + + + </p> + + <p> + 2 番目のペアは、単に<em>幅</em>と<em>高さ</em>と呼ばれたり、<em>描画する幅</em>と<em>描画する高さ</em>と呼ばれたりします。 +これらの寸法は、描画時とレイアウト後に、画面上のビューの実サイズを定義するものです。 + +これらの値は、測定された幅や高さと異なる値にすることもできますが、必須ではありません。 +幅と高さは、{@link android.view.View#getWidth()} と {@link android.view.View#getHeight()} を呼び出して取得できます。 + + </p> + + <p> + その寸法を測るために、ビューではパディングも考慮されます。パディングは、ビューの上下左右に対し、ピクセルで記述されます。 + + パディングを使って、特定のピクセル値でビュー コンテンツのオフセットを指定できます。 +たとえば、左側のパディングが 2 の場合は、左端から 2 ピクセル右にビューのコンテンツが寄せられます。 +パディングは {@link android.view.View#setPadding(int, int, int, int)} メソッドを使って設定でき、{@link android.view.View#getPaddingLeft()}、{@link android.view.View#getPaddingTop()}、{@link android.view.View#getPaddingRight()}、{@link android.view.View#getPaddingBottom()} を呼び出してクエリできます。 + + + + </p> + + <p> + ビューではパディングを定義できますが、マージンについてはサポートされていません。 +ただし、ViewGroup ではそのようなサポートが提供されています。詳細については、{@link android.view.ViewGroup} と {@link android.view.ViewGroup.MarginLayoutParams} をご覧ください。 + + + </p> + + <p>寸法の詳細については、<a href="{@docRoot}guide/topics/resources/more-resources.html#Dimension">寸法の値</a>をご覧ください。 + + </p> + + + + + + +<style type="text/css"> +div.layout { + float:left; + width:200px; + margin:0 0 20px 20px; +} +div.layout.first { + margin-left:0; + clear:left; +} +</style> + + + + +<h2 id="CommonLayouts">共通レイアウト</h2> + +<p>{@link android.view.ViewGroup} クラスの各サブクラスでは、ビュー内でネストするビューを表示する一意の方法が提供されます。 +Android プラットフォームにビルドされる共通のレイアウト タイプの一部を以下に示します。 +</p> + +<p class="note"><strong>注:</strong> 別のレイアウト内で 1 つ以上のレイアウトをネストして UI を設計できますが、レイアウトの階層はできる限り浅くしておくようにしてください。 + +ネストが浅いレイアウトの場合、レイアウトの描画がより速くなります。深いビュー階層より、ワイドなビュー階層の方がより良いと言えます。 +</p> + +<!-- +<h2 id="framelayout">FrameLayout</h2> +<p>{@link android.widget.FrameLayout FrameLayout} is the simplest type of layout +object. It's basically a blank space on your screen that you can +later fill with a single object — for example, a picture that you'll swap in and out. +All child elements of the FrameLayout are pinned to the top left corner of the screen; you cannot +specify a different location for a child view. Subsequent child views will simply be drawn over +previous ones, +partially or totally obscuring them (unless the newer object is transparent). +</p> +--> + + +<div class="layout first"> + <h4><a href="layout/linear.html">線形レイアウト</a></h4> + <a href="layout/linear.html"><img src="{@docRoot}images/ui/linearlayout-small.png" alt="" /></a> + <p>子を横方向または縦方向の 1 行にまとめるレイアウト。ウィンドウの長さが画面の長さを超える場合は、スクロールバーが作成されます。 +</p> +</div> + +<div class="layout"> + <h4><a href="layout/relative.html">相対レイアウト</a></h4> + <a href="layout/relative.html"><img src="{@docRoot}images/ui/relativelayout-small.png" alt="" /></a> + <p>たとえば子 A を子 B の左になど、それぞれの子オブジェクトの位置を相対して指定したり、親の上に揃えてなど、親に相対して指定したりできます。 +</p> +</div> + +<div class="layout"> + <h4><a href="{@docRoot}guide/webapps/webview.html">ウェブビュー</a></h4> + <a href="{@docRoot}guide/webapps/webview.html"><img src="{@docRoot}images/ui/webview-small.png" alt="" /></a> + <p>ウェブページを表示します。</p> +</div> + + + + +<h2 id="AdapterViews" style="clear:left">アダプタを使ったレイアウトをビルドする</h2> + +<p>レイアウトのコンテンツが動的または事前設定されていないとき、{@link android.widget.AdapterView} のサブクラスのレイアウトを使って、実行時にビューでレイアウトを設定できます。 +{@link android.widget.AdapterView} クラスのサブクラスでは、{@link android.widget.Adapter} を使ってそのレイアウトにデータがバインドされます。 + +{@link android.widget.Adapter} はデータソースと {@link android.widget.AdapterView} レイアウト間の仲介として動作します。{@link android.widget.Adapter} によって、配列やデータベース クエリのようなソースからデータが取得され、各エントリが {@link android.widget.AdapterView} レイアウトに追加できるビューに変換されます。 + + +</p> + +<p>アダプタでサポートされている共通レイアウトには次が含まれます。</p> + +<div class="layout first"> + <h4><a href="layout/listview.html">リストビュー</a></h4> + <a href="layout/listview.html"><img src="{@docRoot}images/ui/listview-small.png" alt="" /></a> + <p>スクロール可能な 1 列のリストが表示されます。</p> +</div> + +<div class="layout"> + <h4><a href="layout/gridview.html">グリッドビュー</a></h4> + <a href="layout/gridview.html"><img src="{@docRoot}images/ui/gridview-small.png" alt="" /></a> + <p>スクロール可能な列と行のグリッドが表示されます。</p> +</div> + + + +<h3 id="FillingTheLayout" style="clear:left">データを使ったアダプタビューを書き込む</h3> + +<p>{@link android.widget.AdapterView} インスタンスを {@link android.widget.Adapter} にバインドして、{@link android.widget.ListView} や {@link android.widget.GridView} などの {@link android.widget.AdapterView} を入力できます。外部ソースのデータが取得され、各データエントリを表す {@link +android.view.View} が作成されます。 + +</p> + +<p>Android ではさまざまな種類のデータの取得と {@link android.widget.AdapterView} のビューのビルドに役立つ {@link android.widget.Adapter} のサブクラスがいくつか提供されます。 +最も一般的なアダプタは次の 2 つです。 +</p> + +<dl> + <dt>{@link android.widget.ArrayAdapter}</dt> + <dd>データソースが配列の場合に、このアダプタを使います。デフォルトでは、{@link +android.widget.ArrayAdapter} によって各アイテムで {@link +java.lang.Object#toString()} が呼び出され、そのコンテンツが {@link +android.widget.TextView} に配置されることで、各配列アイテムのビューが作成されます。 + <p>たとえば、{@link +android.widget.ListView} に表示する文字列の配列がある場合、コンストラクタを使って新しい {@link android.widget.ArrayAdapter} を初期化して、各文字列と文字列配列のレイアウトを指定します。 +</p> +<pre> +ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, + android.R.layout.simple_list_item_1, myStringArray); +</pre> +<p>このコンストラクタの引数を次に示します。</p> +<ul> + <li>アプリの {@link android.content.Context}</li> + <li>配列の各文字列に対して {@link android.widget.TextView} を含むレイアウト</li> + <li>文字列配列</li> +</ul> +<p>次に、{@link android.widget.ListView} で {@link android.widget.ListView#setAdapter setAdapter()} を呼び出します。 +</p> +<pre> +ListView listView = (ListView) findViewById(R.id.listview); +listView.setAdapter(adapter); +</pre> + + <p>各アイテムの概観をカスタマイズするには、自分の配列内のオブジェクトに {@link +java.lang.Object#toString()} メソッドをオーバーライドします。または、たとえば各配列アイテムに {@link android.widget.ImageView} が必要な場合など、{@link android.widget.TextView} 以外の各アイテムの表示を作成するには、{@link +android.widget.ArrayAdapter} クラスを拡張し、{@link android.widget.ArrayAdapter#getView +getView()} をオーバーライドして、各アイテムに必要なビュータイプが返されるようにします。 + +</p> + +</dd> + + <dt>{@link android.widget.SimpleCursorAdapter}</dt> + <dd>{@link android.database.Cursor} から取得されたデータの場合は、このアダプタを使います。{@link android.widget.SimpleCursorAdapter} を使う場合は、{@link android.database.Cursor} で各行に使うレイアウトを指定して、{@link android.database.Cursor} のどの列をレイアウトのビューに挿入するのかを指定してください。 + + +たとえば、人の名前と電話番号のリストを作成する場合は、それぞれの人の行と、その名前と番号の列を含む {@link +android.database.Cursor} を返すクエリを実行します。 + +次に、それぞれの結果に対して {@link +android.database.Cursor} のどの列をレイアウトに含めるかを指定する文字列配列と、各列が配置されるべき対応するビューを指定する整数配列を作成します。 +</p> +<pre> +String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME, + ContactsContract.CommonDataKinds.Phone.NUMBER}; +int[] toViews = {R.id.display_name, R.id.phone_number}; +</pre> +<p>{@link android.widget.SimpleCursorAdapter} のインスタンスを作成するとき、各結果に使うレイアウト、結果を含む {@link android.database.Cursor}、次の 2 つの配列を渡します。 +</p> +<pre> +SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, + R.layout.person_name_and_number, cursor, fromColumns, toViews, 0); +ListView listView = getListView(); +listView.setAdapter(adapter); +</pre> +<p>次に、{@link android.widget.SimpleCursorAdapter} によって、対応する {@code toViews} ビューに各 {@code +fromColumns} アイテムを挿入して提供されたレイアウトを使って {@link android.database.Cursor} で各行のビューが作成されます。 +</p>.</dd> +</dl> + + +<p>アプリケーションのライフサイクル中に、アダプタによって読み取られる基礎となるデータを変更する場合は、{@link android.widget.ArrayAdapter#notifyDataSetChanged()} を呼び出してください。 +これによって、データが変更されたアタッチされたビューが通知され、それ自体を更新する必要があることが通知されます。 +</p> + + + +<h3 id="HandlingUserSelections">クリック イベントを処理する</h3> + +<p>{@link android.widget.AdapterView.OnItemClickListener} インターフェースを実装して {@link android.widget.AdapterView} の各アイテムでのクリック イベントに応答できます。 +次に例を示します。</p> + +<pre> +// Create a message handling object as an anonymous class. +private OnItemClickListener mMessageClickedHandler = new OnItemClickListener() { + public void onItemClick(AdapterView parent, View v, int position, long id) { + // Do something in response to the click + } +}; + +listView.setOnItemClickListener(mMessageClickedHandler); +</pre> + + + diff --git a/docs/html-intl/intl/ja/guide/topics/ui/dialogs.jd b/docs/html-intl/intl/ja/guide/topics/ui/dialogs.jd new file mode 100644 index 000000000000..358fc304f60a --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/ui/dialogs.jd @@ -0,0 +1,798 @@ +page.title=ダイアログ +page.tags=alertdialog,dialogfragment + +@jd:body + + + +<div id="qv-wrapper"> + <div id="qv"> + <h2>本書の内容</h2> +<ol> + <li><a href="#DialogFragment">Dialog Fragment を作成する</a></li> + <li><a href="#AlertDialog">アラート ダイアログをビルドする</a> + <ol> + <li><a href="#AddingButtons">ボタンを追加する</a></li> + <li><a href="#AddingAList">リストを追加する</a></li> + <li><a href="#CustomLayout">カスタム レイアウトを作成する</a></li> + </ol> + </li> + <li><a href="#PassingEvents">ダイアログのホストにイベントを渡す</a></li> + <li><a href="#ShowingADialog">ダイアログを表示する</a></li> + <li><a href="#FullscreenDialog">全画面でまたは埋め込まれたフラグメントとしてダイアログを表示する</a> + <ol> + <li><a href="#ActivityAsDialog">大画面でアクティビティをダイアログとして表示する</a></li> + </ol> + </li> + <li><a href="#DismissingADialog">ダイアログを閉じる</a></li> +</ol> + + <h2>キークラス</h2> + <ol> + <li>{@link android.app.DialogFragment}</li> + <li>{@link android.app.AlertDialog}</li> + </ol> + + <h2>関連ドキュメント</h2> + <ol> + <li><a href="{@docRoot}design/building-blocks/dialogs.html">ダイアログ デザインのガイド</a></li> + <li><a href="{@docRoot}guide/topics/ui/controls/pickers.html">ピッカー</a>(日付ダイアログと時刻ダイアログ)</li> + </ol> + </div> +</div> + +<p>ダイアログは、ユーザーによる意思決定や追加情報の入力用に表示される小さなウィンドウです。 +ダイアログは全画面に表示されることはなく、通常はユーザーが処理を続ける前にアクションを起こす必要があるモーダル イベントに使用されます。 +</p> + +<div class="note design"> +<p><strong>ダイアログ デザイン</strong></p> + <p>ダイアログをデザインする方法について(言語に対する推奨を含む)は、<a href="{@docRoot}design/building-blocks/dialogs.html">ダイアログ</a> デザインのガイドをお読みください。 +</p> +</div> + +<img src="{@docRoot}images/ui/dialogs.png" /> + +<p>{@link android.app.Dialog} クラスは、ダイアログの基本クラスですが、{@link android.app.Dialog} ディレクトリのインスタンスを作成することは避けてください。代わりに、次のいずれかのサブクラスを使用します。 + +</p> +<dl> + <dt>{@link android.app.AlertDialog}</dt> + <dd>タイトル、最大 3 つのボタン、選択可能なアイテムやカスタム レイアウトのリストを表示できるダイアログ。 +</dd> + <dt>{@link android.app.DatePickerDialog} または {@link android.app.TimePickerDialog}</dt> + <dd>ユーザーが日付または時刻を選択できるようにあらかじめ定義された UI を含むダイアログ。</dd> +</dl> + +<div class="sidebox"> +<h2>ProgressDialog を使用しない</h2> +<p>Android には、進捗バーを含むダイアログを表示する {@link android.app.ProgressDialog} という別のダイアログ クラスがあります。 +ただし、読み込み中または不確定な進捗状況を表示する必要がある場合は、<a href="{@docRoot}design/building-blocks/progress.html">Progress & Activity</a> のデザイン ガイドラインに従って、レイアウトで {@link android.widget.ProgressBar} を使用してください。 + + +</p> +</div> + +<p>これらのクラスでは、ダイアログのスタイルと構造が定義されますが、ダイアログのコンテナとして {@link android.support.v4.app.DialogFragment} を使用してください。{@link android.support.v4.app.DialogFragment} クラスでは、{@link android.app.Dialog} オブジェクトでメソッドを呼び出す代わりに、ダイアログの作成と表示の管理に必要なすべてのコントロールが提供されます。 + + + +</p> + +<p>{@link android.support.v4.app.DialogFragment} を使ってダイアログを管理すると、ライフサイクル イベント([<em>戻る</em>] ボタンを押したときや画面を回転したときなど)が正しく処理されます。 + +{@link +android.support.v4.app.DialogFragment} クラスを使用すると、従来の {@link +android.support.v4.app.Fragment} のように、大きな UI で埋め込み可能なコンポーネントとしてダイアログの UI を再利用することもできます(ダイアログ UI を大小の画面で異なって表示させる場合など)。 + +</p> + +<p>このガイドの次のセクションでは、{@link android.app.AlertDialog} オブジェクトと組み合わせて {@link +android.support.v4.app.DialogFragment} を使用する方法について説明します。 +日付や時刻ピッカーを作成する場合は、「<a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>」のガイドをご覧ください。 +</p> + +<p class="note"><strong>注:</strong> {@link android.app.DialogFragment} クラスは 元々 Android 3.0(API レベル 11)で追加されたため、このドキュメントでは<a href="{@docRoot}tools/support-library/index.html">サポート ライブラリ</a>と一緒に提供される {@link +android.support.v4.app.DialogFragment} クラスの使用方法について説明します。 + +アプリにこのライブラリを追加すると、Android 1.6 以降を実行する端末で、{@link android.support.v4.app.DialogFragment} とその他のさまざまな API を使うことができます。 + +アプリの最小バージョンで API レベル 11 以降がサポートされている場合、{@link +android.app.DialogFragment} のフレームワーク バージョンを使用できますが、このドキュメントのリンクはサポート ライブラリ API 向けであることにご注意ください。 + +サポート ライブラリを使用するときは、<code>android.app.DialogFragment</code> <em>ではなく</em>、<code>android.support.v4.app.DialogFragment</code> クラス をインポートしてください。 + +</p> + + +<h2 id="DialogFragment">Dialog Fragment を作成する</h2> + +<p>{@link android.support.v4.app.DialogFragment} を拡張して {@link android.support.v4.app.DialogFragment#onCreateDialog +onCreateDialog()} コールバック メソッドで {@link android.app.AlertDialog} を作成することで、さまざまなダイアログ デザイン(カスタム レイアウトや<a href="{@docRoot}design/building-blocks/dialogs.html">ダイアログ</a>のデザインガイドで説明されているものを含む)を実現できます。 + + + +</p> + +<p>{@link android.support.v4.app.DialogFragment} で管理される基本的な {@link android.app.AlertDialog} を次に示します。 +</p> + +<pre> +public class FireMissilesDialogFragment extends DialogFragment { + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + // Use the Builder class for convenient dialog construction + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setMessage(R.string.dialog_fire_missiles) + .setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // FIRE ZE MISSILES! + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // User cancelled the dialog + } + }); + // Create the AlertDialog object and return it + return builder.create(); + } +} +</pre> + +<div class="figure" style="width:290px;margin:0 0 0 20px"> +<img src="{@docRoot}images/ui/dialog_buttons.png" alt="" /> +<p class="img-caption"><strong>図 1</strong> +メッセージと 2 つのアクション ボタンを含むダイアログ</p> +</div> + +<p>このクラスのインスタンスを作成してオブジェクトで {@link +android.support.v4.app.DialogFragment#show show()} を呼び出すと、図 1 のようなダイアログが表示されます。 +</p> + +<p>次のセクションでは、{@link android.app.AlertDialog.Builder} API を使ったダイアログの作成について詳細を説明します。 +</p> + +<p>ダイアログの複雑さに応じて、{@link android.support.v4.app.DialogFragment} ですべての基本的な<a href="{@docRoot}guide/components/fragments.html#Lifecycle">フラグメントのライフサイクル メソッド</a>を含む、他のさまざまなコールバック メソッドを実装できます。 + + + + + + + +<h2 id="AlertDialog">アラート ダイアログをビルドする</h2> + + +<p>{@link android.app.AlertDialog} クラスを使って、さまざまなダイアログ デザインをビルドできます。ほとんどの場合、必要なダイアログ クラスはこれだけです。図 2 のように、アラート ダイアログには 3 つの領域があります。 + +</p> + +<div class="figure" style="width:311px;margin-top:0"> +<img src="{@docRoot}images/ui/dialogs_regions.png" alt="" style="margin-bottom:0" /> +<p class="img-caption"><strong>図 2.</strong> ダイアログのレイアウト。</p> +</div> + +<ol> +<li><b>タイトル</b> + <p>この領域は省略可能で、コンテンツ エリアが詳細メッセージ、リスト、カスタム レイアウトで占有されている場合にのみ使う必要があります。 +単純なメッセージや質問(図 1 にあるダイアログなど)を記述する場合は、タイトルは必要ありません。 +</li> +<li><b>コンテンツ エリア</b> + <p>メッセージ、リスト、その他のカスタム レイアウトを表示できます。</p></li> +<li><b>アクション ボタン</b> + <p>1 つのダイアログ内に置くアクション ボタンは、3 つ以内にする必要があります。</p></li> +</ol> + +<p>{@link android.app.AlertDialog.Builder} クラスでは、カスタム レイアウトなど、これらの種類のコンテンツを含む {@link android.app.AlertDialog} を作成できます。 + +</p> + +<p>{@link android.app.AlertDialog} をビルドするには: </p> + +<pre> +<b>// 1. Instantiate an {@link android.app.AlertDialog.Builder} with its constructor</b> +AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + +<b>// 2. Chain together various setter methods to set the dialog characteristics</b> +builder.setMessage(R.string.dialog_message) + .setTitle(R.string.dialog_title); + +<b>// 3. Get the {@link android.app.AlertDialog} from {@link android.app.AlertDialog.Builder#create()}</b> +AlertDialog dialog = builder.create(); +</pre> + +<p>次のトピックでは、{@link android.app.AlertDialog.Builder} クラスを使ってさまざまなダイアログの属性を定義する方法を示します。 +</p> + + + + +<h3 id="AddingButtons">ボタンを追加する</h3> + +<p>図 2 のようなアクション ボタンを追加するには、{@link android.app.AlertDialog.Builder#setPositiveButton setPositiveButton()} と {@link android.app.AlertDialog.Builder#setNegativeButton setNegativeButton()} メソッドを呼び出します。 + +</p> + +<pre style="clear:right"> +AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); +// Add the buttons +builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // User clicked OK button + } + }); +builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // User cancelled the dialog + } + }); +// Set other dialog properties +... + +// Create the AlertDialog +AlertDialog dialog = builder.create(); +</pre> + +<p><code>set...Button()</code> メソッドには、ボタンのタイトル(<a href="{@docRoot}guide/topics/resources/string-resource.html">文字列リソースで指定</a>)と、ユーザーがボタンを押したときに実行するアクションを定義する {@link android.content.DialogInterface.OnClickListener} が必要です。 + + +</p> + +<p>追加できるアクション ボタンは、次の 3 つです。</p> +<dl> + <dt>Positive</dt> + <dd>アクションを受け入れて続ける場合に使います(「OK」アクション)。</dd> + <dt>Negative</dt> + <dd>アクションをキャンセルする場合に使います。</dd> + <dt>Neutral</dt> + <dd>ユーザーがアクションを続けたくない可能性があり、キャンセルしたいとは限らない場合に使います。 +ポジティブ ボタンとネガティブ ボタンの間に表示されます。 +たとえば、「後で通知する」のようなアクションの場合です。</dd> +</dl> + +<p>各ボタンタイプのいずれか 1 つのみを {@link +android.app.AlertDialog} に追加できます。つまり、2 つ以上の「ポジティブ」ボタンを置くことはできません。</p> + + + +<div class="figure" style="width:290px;margin:0 0 0 40px"> +<img src="{@docRoot}images/ui/dialog_list.png" alt="" /> +<p class="img-caption"><strong>図 3</strong> +タイトルとリストを含むダイアログ</p> +</div> + +<h3 id="AddingAList">リストを追加する</h3> + +<p>{@link android.app.AlertDialog} API で使用できるリストは次の 3 種類です。</p> +<ul> +<li>従来の排他的選択リスト</li> +<li>固定の排他的選択リスト(ラジオボタン)</li> +<li>固定の複数選択リスト(チェックボックス)</li> +</ul> + +<p>図 3 のように、排他的選択リストを作成するには、{@link android.app.AlertDialog.Builder#setItems setItems()} メソッドを使います。 +</p> + +<pre style="clear:right"> +@Override +public Dialog onCreateDialog(Bundle savedInstanceState) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setTitle(R.string.pick_color) + .setItems(R.array.colors_array, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + // The 'which' argument contains the index position + // of the selected item + } + }); + return builder.create(); +} +</pre> + +<p>リストは、ダイアログのコンテンツ エリアに表示されるため、ダイアログにはメッセージとリストの両方は表示できません。{@link android.app.AlertDialog.Builder#setTitle setTitle()} でダイアログのタイトルを設定してください。 + +リストのアイテムを指定するには、{@link +android.app.AlertDialog.Builder#setItems setItems()} を呼び出して配列を渡します。{@link +android.app.AlertDialog.Builder#setAdapter setAdapter()} を使ってリストを指定することもできます。 + +こうすることで、{@link android.widget.ListAdapter} を使って、データベースからなど、ダイナミック データを含むリストを返すことができます。 +</p> + +<p>{@link android.widget.ListAdapter} を使ってリストを返すことを選択する場合は、必ず {@link android.support.v4.content.Loader} を使ってコンテンツが非同期で読み込まれるようにします。 + +この詳細については、「<a href="{@docRoot}guide/topics/ui/declaring-layout.html#AdapterViews">Building Layouts with an Adapter</a>」と「<a href="{@docRoot}guide/components/loaders.html">ローダ</a>」のガイドをご覧ください。 + + +</p> + +<p class="note"><strong>注:</strong> デフォルトでは、次の固定選択リストのいずれかを使っていない場合、リストアイテムをタップするとダイアログが閉じられます。 +</p> + +<div class="figure" style="width:290px;margin:-30px 0 0 40px"> +<img src="{@docRoot}images/ui/dialog_checkboxes.png" /> +<p class="img-caption"><strong>図 4.</strong>複数選択アイテムのリスト。 +</p> +</div> + + +<h4 id="Checkboxes">固定の複数選択または排他的選択リストを追加する</h4> + +<p>複数選択アイテム(チェックボックス)または排他的選択アイテム(ラジオボタン)のリストを追加するには、{@link android.app.AlertDialog.Builder#setMultiChoiceItems(Cursor,String,String, +DialogInterface.OnMultiChoiceClickListener) setMultiChoiceItems()} または {@link android.app.AlertDialog.Builder#setSingleChoiceItems(int,int,DialogInterface.OnClickListener) +setSingleChoiceItems()} メソッドをそれぞれ使用します。 + + +</p> + +<p>{@link java.util.ArrayList} で選択されたアイテムを保存する、図 4 にあるような複数選択リストを作成する方法を次に示します。 + +</p> + +<pre style="clear:right"> +@Override +public Dialog onCreateDialog(Bundle savedInstanceState) { + mSelectedItems = new ArrayList(); // Where we track the selected items + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + // Set the dialog title + builder.setTitle(R.string.pick_toppings) + // Specify the list array, the items to be selected by default (null for none), + // and the listener through which to receive callbacks when items are selected + .setMultiChoiceItems(R.array.toppings, null, + new DialogInterface.OnMultiChoiceClickListener() { + @Override + public void onClick(DialogInterface dialog, int which, + boolean isChecked) { + if (isChecked) { + // If the user checked the item, add it to the selected items + mSelectedItems.add(which); + } else if (mSelectedItems.contains(which)) { + // Else, if the item is already in the array, remove it + mSelectedItems.remove(Integer.valueOf(which)); + } + } + }) + // Set the action buttons + .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + // User clicked OK, so save the mSelectedItems results somewhere + // or return them to the component that opened the dialog + ... + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + ... + } + }); + + return builder.create(); +} +</pre> + +<p>従来のリストとラジオボタンを含むリストでは、「排他的選択」アクションが提供されますが、ユーザーの選択を固定させたい場合は、{@link +android.app.AlertDialog.Builder#setSingleChoiceItems(int,int,DialogInterface.OnClickListener) +setSingleChoiceItems()} を使用してください。つまり、ダイアログを後でもう一度開く場合は、ユーザーの現在の選択を表示し、ラジオボタンを含むリストを作成します。 + + +</p> + + + + + +<h3 id="CustomLayout">カスタム レイアウトを作成する</h3> + +<div class="figure" style="width:290px;margin:-30px 0 0 40px"> +<img src="{@docRoot}images/ui/dialog_custom.png" alt="" /> +<p class="img-caption"><strong>図 5.</strong> カスタム ダイアログのレイアウト。</p> +</div> + +<p>ダイアログでカスタム レイアウトが必要な場合は、レイアウトを作成し、{@link +android.app.AlertDialog.Builder} オブジェクトで {@link +android.app.AlertDialog.Builder#setView setView()} を呼び出して {@link android.app.AlertDialog} にそのレイアウトを追加します。 +</p> + +<p>デフォルトでは、カスタム レイアウトは、ダイアログ ウィンドウ全体に表示されますが、{@link android.app.AlertDialog.Builder} メソッドを使ってボタンとタイトルを追加できます。 +</p> + +<p>以下は、図 5 にあるダイアログのレイアウト ファイルです。</p> + +<p style="clear:right" class="code-caption">res/layout/dialog_signin.xml</p> +<pre> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + <ImageView + android:src="@drawable/header_logo" + android:layout_width="match_parent" + android:layout_height="64dp" + android:scaleType="center" + android:background="#FFFFBB33" + android:contentDescription="@string/app_name" /> + <EditText + android:id="@+id/username" + android:inputType="textEmailAddress" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:layout_marginLeft="4dp" + android:layout_marginRight="4dp" + android:layout_marginBottom="4dp" + android:hint="@string/username" /> + <EditText + android:id="@+id/password" + android:inputType="textPassword" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="4dp" + android:layout_marginLeft="4dp" + android:layout_marginRight="4dp" + android:layout_marginBottom="16dp" + android:fontFamily="sans-serif" + android:hint="@string/password"/> +</LinearLayout> +</pre> + +<p class="note"><strong>ヒント:</strong> デフォルトでは、{@code "textPassword"} 入力タイプを使うために、{@link android.widget.EditText} 要素を設定すると、フォント ファミリーが monospace に設定されるため、フォント ファミリーを {@code "sans-serif"} に変えて、両方のテキスト フィールドで同じフォント スタイルが使用されるようにしてください。 + + +</p> + +<p>{@link android.support.v4.app.DialogFragment} でレイアウトをインフレートするには、{@link android.app.Activity#getLayoutInflater()} で {@link android.view.LayoutInflater} を取得して {@link android.view.LayoutInflater#inflate inflate()} を呼び出します。最初のパラメータは、レイアウト リソース ID で、2 番目のパラメータはレイアウトの親ビューです。その後、{@link android.app.AlertDialog#setView setView()} を呼び出してダイアログのレイアウトを配置できます。 + + + + + +</p> + +<pre> +@Override +public Dialog onCreateDialog(Bundle savedInstanceState) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + // Get the layout inflater + LayoutInflater inflater = getActivity().getLayoutInflater(); + + // Inflate and set the layout for the dialog + // Pass null as the parent view because its going in the dialog layout + builder.setView(inflater.inflate(R.layout.dialog_signin, null)) + // Add action buttons + .setPositiveButton(R.string.signin, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + // sign in the user ... + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + LoginDialogFragment.this.getDialog().cancel(); + } + }); + return builder.create(); +} +</pre> + +<div class="note"> +<p><strong>ヒント:</strong> カスタム ダイアログが必要な場合は、{@link android.app.Dialog} API を使う代わりに、{@link android.app.Activity} をダイアログとして表示できます。 + +アクティビティを作り、<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code +<activity>}</a> マニフェスト要素でそのテーマを {@link android.R.style#Theme_Holo_Dialog Theme.Holo.Dialog} に設定します。 + +</p> + +<pre> +<activity android:theme="@android:style/Theme.Holo.Dialog" > +</pre> +<p>これだけです。これで、アクティビティは全画面でなく、ダイアログ ウィンドウに表示されるようになります。</p> +</div> + + + +<h2 id="PassingEvents">ダイアログのホストにイベントを渡す</h2> + +<p>ユーザーがダイアログのアクション ボタンのいずれかをタップするか、そのリストからアイテムを選択すると、{@link android.support.v4.app.DialogFragment} によって必要なアクションが実行される場合がありますが、ダイアログを開くアクティビティやフラグメントにイベントを配信したい場合もよくあります。 + + +これを行うには、クリック イベントの各タイプのメソッドでインターフェースを定義します。次に、ダイアログからアクション イベントを受け取るホスト コンポーネントでインターフェースを実装します。 + +</p> + +<p>ホスト アクティビティにイベントを配信するインターフェースを定義する {@link android.support.v4.app.DialogFragment} を次に示します。 +</p> + +<pre> +public class NoticeDialogFragment extends DialogFragment { + + /* The activity that creates an instance of this dialog fragment must + * implement this interface in order to receive event callbacks. + * Each method passes the DialogFragment in case the host needs to query it. */ + public interface NoticeDialogListener { + public void onDialogPositiveClick(DialogFragment dialog); + public void onDialogNegativeClick(DialogFragment dialog); + } + + // Use this instance of the interface to deliver action events + NoticeDialogListener mListener; + + // Override the Fragment.onAttach() method to instantiate the NoticeDialogListener + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + // Verify that the host activity implements the callback interface + try { + // Instantiate the NoticeDialogListener so we can send events to the host + mListener = (NoticeDialogListener) activity; + } catch (ClassCastException e) { + // The activity doesn't implement the interface, throw exception + throw new ClassCastException(activity.toString() + + " must implement NoticeDialogListener"); + } + } + ... +} +</pre> + +<p>ダイアログをホスティングするアクティビティによって、ダイアログ フラグメントのコンストラクタを使ってダイアログのインスタンスが作成され、{@code NoticeDialogListener} インターフェースの実装によってダイアログのイベントが受信されます。 + +</p> + +<pre> +public class MainActivity extends FragmentActivity + implements NoticeDialogFragment.NoticeDialogListener{ + ... + + public void showNoticeDialog() { + // Create an instance of the dialog fragment and show it + DialogFragment dialog = new NoticeDialogFragment(); + dialog.show(getSupportFragmentManager(), "NoticeDialogFragment"); + } + + // The dialog fragment receives a reference to this Activity through the + // Fragment.onAttach() callback, which it uses to call the following methods + // defined by the NoticeDialogFragment.NoticeDialogListener interface + @Override + public void onDialogPositiveClick(DialogFragment dialog) { + // User touched the dialog's positive button + ... + } + + @Override + public void onDialogNegativeClick(DialogFragment dialog) { + // User touched the dialog's negative button + ... + } +} +</pre> + +<p>ホスト アクティビティによって、上記の {@link android.support.v4.app.Fragment#onAttach onAttach()} コールバック メソッドで適用される {@code NoticeDialogListener} が実装されるため、ダイアログ フラグメントではインターフェース コールバック メソッドを使ってアクティビティにクリック イベントを配信できます。 + + +</p> + +<pre> +public class NoticeDialogFragment extends DialogFragment { + ... + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + // Build the dialog and set up the button click handlers + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setMessage(R.string.dialog_fire_missiles) + .setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // Send the positive button event back to the host activity + mListener.onDialogPositiveClick(NoticeDialogFragment.this); + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // Send the negative button event back to the host activity + mListener.onDialogNegativeClick(NoticeDialogFragment.this); + } + }); + return builder.create(); + } +} +</pre> + + + +<h2 id="ShowingADialog">ダイアログを表示する</h2> + +<p>ダイアログを表示する場合、{@link +android.support.v4.app.DialogFragment} のインスタンスを作成して {@link android.support.v4.app.DialogFragment#show +show()} を呼び出し、{@link android.support.v4.app.FragmentManager} とダイアログ フラグメントのタグ名を渡します。 +</p> + +<p>{@link android.support.v4.app.FragmentActivity} から {@link android.support.v4.app.FragmentActivity#getSupportFragmentManager()} を、または {@link +android.support.v4.app.Fragment} から {@link +android.support.v4.app.Fragment#getFragmentManager()} を呼び出して {@link android.support.v4.app.FragmentManager} を取得できます。 + +次に例を示します。</p> + +<pre> +public void confirmFireMissiles() { + DialogFragment newFragment = new FireMissilesDialogFragment(); + newFragment.show(getSupportFragmentManager(), "missiles"); +} +</pre> + +<p>2 番目の引数 {@code "missiles"} は、固有のタグ名で、システムはこれを使って必要な時にフラグメントの状態を保存して復元します。 +そのタグを使って、{@link android.support.v4.app.FragmentManager#findFragmentByTag +findFragmentByTag()} を呼び出してフラグメントを操作することもできます。 +</p> + + + + +<h2 id="FullscreenDialog">全画面でまたは埋め込まれたフラグメントとしてダイアログを表示する</h2> + +<p>場合によっては、UI の一部をダイアログとして表示させ、それ以外の場合には、たとえば端末の画面の大小に応じて、全画面や埋め込まれたフラグメントとして表示させるよう UI を設計できます。 + +{@link android.support.v4.app.DialogFragment} クラスは、埋め込み可能な {@link +android.support.v4.app.Fragment} として動作できるため、この柔軟性を実現できます。 +</p> + +<p>ただし、この場合は、{@link android.app.AlertDialog.Builder AlertDialog.Builder} やその他の {@link android.app.Dialog} オブジェクトを使ってダイアログをビルドできません。 +{@link android.support.v4.app.DialogFragment} を埋め込み可能にする場合、レイアウトでダイアログの UI を定義し、{@link android.support.v4.app.DialogFragment#onCreateView +onCreateView()} コールバックでレイアウトを読み込んでください。 + + +</p> + +<p>ダイアログまたは埋め込み可能なフラグメントのいずれかとして(<code>purchase_items.xml</code> という名前のレイアウトを使って)表示できる {@link android.support.v4.app.DialogFragment} の例を次に示します。 +</p> + +<pre> +public class CustomDialogFragment extends DialogFragment { + /** The system calls this to get the DialogFragment's layout, regardless + of whether it's being displayed as a dialog or an embedded fragment. */ + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout to use as dialog or embedded fragment + return inflater.inflate(R.layout.purchase_items, container, false); + } + + /** The system calls this only when creating the layout in a dialog. */ + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + // The only reason you might override this method when using onCreateView() is + // to modify any dialog characteristics. For example, the dialog includes a + // title by default, but your custom layout might not need it. So here you can + // remove the dialog title, but you must call the superclass to get the Dialog. + Dialog dialog = super.onCreateDialog(savedInstanceState); + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + return dialog; + } +} +</pre> + +<p>画面サイズに基づいて、フラグメントをダイアログとしてまたは全画面の UI として表示するかどうかを決めるコードの一例も示します。 +</p> + +<pre> +public void showDialog() { + FragmentManager fragmentManager = getSupportFragmentManager(); + CustomDialogFragment newFragment = new CustomDialogFragment(); + + if (mIsLargeLayout) { + // The device is using a large layout, so show the fragment as a dialog + newFragment.show(fragmentManager, "dialog"); + } else { + // The device is smaller, so show the fragment fullscreen + FragmentTransaction transaction = fragmentManager.beginTransaction(); + // For a little polish, specify a transition animation + transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); + // To make it fullscreen, use the 'content' root view as the container + // for the fragment, which is always the root view for the activity + transaction.add(android.R.id.content, newFragment) + .addToBackStack(null).commit(); + } +} +</pre> + +<p>フラグメントのトランザクション実行の詳細については、「<a href="{@docRoot}guide/components/fragments.html">フラグメント</a>」のガイドをご覧ください。 +</p> + +<p>この例では、<code>mIsLargeLayout</code> ブール値によって、現在の端末でアプリの大きなレイアウト デザインを使う(その結果、全画面でなく、このフラグメントをダイアログとして表示する)かどうかが指定されます。 + +この種のブール値を設定する最良の方法は、異なる画面サイズに対して<a href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">別のリソース値</a>で<a href="{@docRoot}guide/topics/resources/more-resources.html#Bool">ブールリソース値</a>を宣言することです。 + +次に、異なる画面サイズのブールリソースを 2 種類示します。 +</p> + +<p class="code-caption">res/values/bools.xml</p> +<pre> +<!-- Default boolean values --> +<resources> + <bool name="large_layout">false</bool> +</resources> +</pre> + +<p class="code-caption">res/values-large/bools.xml</p> +<pre> +<!-- Large screen boolean values --> +<resources> + <bool name="large_layout">true</bool> +</resources> +</pre> + +<p>アクティビティの {@link android.app.Activity#onCreate onCreate()} メソッド中に、{@code mIsLargeLayout} 値を初期化できます。 +</p> + +<pre> +boolean mIsLargeLayout; + +@Override +public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + mIsLargeLayout = getResources().getBoolean(R.bool.large_layout); +} +</pre> + + + +<h3 id="ActivityAsDialog">大画面でアクティビティをダイアログとして表示する</h3> + +<p>小画面のときにダイアログを全画面の UI として表示するのではなく、大画面のときに {@link android.app.Activity} をダイアログとして表示することで、同じ結果を得ることができます。 + +どちらの方法を選択するかはアプリのデザインによって異なりますが、アプリが小画面で設計されていて、存在期間が短いアクティビティをダイアログとして示すことでタブレットでの使用感を改善するときには、ほとんどの場合、アクティビティをダイアログとして表示する方法が役立ちます。 + + +</p> + +<p>大画面のときにのみ、アクティビティをダイアログとして表示するには、{@link android.R.style#Theme_Holo_DialogWhenLarge Theme.Holo.DialogWhenLarge} テーマを <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code +<activity>}</a> マニフェスト要素に適用します。 + +</p> + +<pre> +<activity android:theme="@android:style/Theme.Holo.DialogWhenLarge" > +</pre> + +<p>テーマを使ったアクティビティのスタイル指定についての詳細は、「<a href="{@docRoot}guide/topics/ui/themes.html">Styles and Themes</a>」をご覧ください。</p> + + + +<h2 id="DismissingADialog">ダイアログを閉じる</h2> + +<p>{@link android.app.AlertDialog.Builder} で作成したアクション ボタンのいずれかがタップされると、システムはダイアログを閉じます。 +</p> + +<p>また、リストでラジオボタンやチェックボックスが使われている場合を除き、ダイアログ リストでアイテムがタップされると、ダイアログが閉じます。 +それ以外の場合は、{@link +android.support.v4.app.DialogFragment} で {@link android.support.v4.app.DialogFragment#dismiss()} を呼び出してダイアログを手動で閉じることができます。 +</p> + +<p>ダイアログが閉じるときに、特定のアクションを実行する必要がある場合は、{@link +android.support.v4.app.DialogFragment} で {@link +android.support.v4.app.DialogFragment#onDismiss onDismiss()} メソッドを実装できます。 +</p> + +<p>ダイアログを<em>キャンセル</em>することもできます。これは、ユーザーがタスクを完了せずに、明示的にダイアログを離れたことを示す特別なイベントです。 +ユーザーが [<em>戻る</em>] ボタンを押す、ダイアログ領域外の画面をタップする、または開発者が {@link +android.app.Dialog} で明示的に {@link android.app.Dialog#cancel()} を呼び出す(ダイアログの [キャンセル] ボタンに応じてなど)場合に実行されます。 + +</p> + +<p>上記の例のように、{@link +android.support.v4.app.DialogFragment} クラスで {@link android.support.v4.app.DialogFragment#onCancel onCancel()} を実装してキャンセル イベントに応答できます。 +</p> + +<p class="note"><strong>注:</strong> システムによって、{@link android.support.v4.app.DialogFragment#onCancel onCancel()} コールバックを呼び出す各イベントで {@link android.support.v4.app.DialogFragment#onDismiss onDismiss()} が呼び出されます。 + +ただし、{@link android.app.Dialog#dismiss Dialog.dismiss()} や {@link +android.support.v4.app.DialogFragment#dismiss DialogFragment.dismiss()} を呼び出す場合、システムによって {@link android.support.v4.app.DialogFragment#onDismiss onDismiss()} が呼び出されますが、{@link android.support.v4.app.DialogFragment#onCancel onCancel()} は<em>呼び出されません</em>。 + + +通常は、ユーザーがダイアログの<em>ポジティブ</em>ボタンを押すときに、{@link android.support.v4.app.DialogFragment#dismiss dismiss()} を呼び出して、ビューからダイアログが削除されるようにしてください。 + +</p> + + diff --git a/docs/html-intl/intl/ja/guide/topics/ui/menus.jd b/docs/html-intl/intl/ja/guide/topics/ui/menus.jd new file mode 100644 index 000000000000..7d8090e7a0ad --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/ui/menus.jd @@ -0,0 +1,1031 @@ +page.title=メニュー +parent.title=ユーザー インターフェース +parent.link=index.html +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + <h2>本書の内容</h2> +<ol> + <li><a href="#xml">XML でのメニューの定義</a></li> + <li><a href="#options-menu">オプション メニューの作成</a> + <ol> + <li><a href="#RespondingOptionsMenu">クリック イベントを処理する</a></li> + <li><a href="#ChangingTheMenu">実行時におけるメニュー アイテムの変更</a></li> + </ol> + </li> + <li><a href="#context-menu">コンテキスト メニューの作成</a> + <ol> + <li><a href="#FloatingContextMenu">フローティング コンテキスト メニューの作成</a></li> + <li><a href="#CAB">コンテキスト アクション モードの使用</a></li> + </ol> + </li> + <li><a href="#PopupMenu">ポップアップ メニューの作成</a> + <ol> + <li><a href="#PopupEvents">クリック イベントを処理する</a></li> + </ol> + </li> + <li><a href="#groups">メニュー グループの作成</a> + <ol> + <li><a href="#checkable">オンにできるメニュー アイテムの使用</a></li> + </ol> + </li> + <li><a href="#intents">インテントに基づくメニュー アイテムの追加</a> + <ol> + <li><a href="#AllowingToAdd">アクティビティを他のメニューに追加できるようにする</a></li> + </ol> + </li> +</ol> + + <h2>キークラス</h2> + <ol> + <li>{@link android.view.Menu}</li> + <li>{@link android.view.MenuItem}</li> + <li>{@link android.view.ContextMenu}</li> + <li>{@link android.view.ActionMode}</li> + </ol> + + <h2>関連ドキュメント</h2> + <ol> + <li><a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a></li> + <li><a href="{@docRoot}guide/topics/resources/menu-resource.html">Menu Resource</a></li> + <li><a href="http://android-developers.blogspot.com/2012/01/say-goodbye-to-menu-button.html">Goodbye to the Menu Button</a> +</li> + </ol> +</div> +</div> + +<p>メニューは、さまざまなタイプのアプリケーションで共通するユーザー インターフェースです。使い慣れた一貫した操作感を提供するには、{@link android.view.Menu} API を使ってアクティビティでユーザーのアクションとその他のオプションを表示する必要があります。 + +</p> + +<p>Android 3.0(API レベル 11)からは、Android 搭載端末では専用の <em>Menu</em> ボタンを表示する必要はなくなりました。 +この変更により、Android アプリでは従来の 6 アイテムのメニューパネルの依存関係から離れて、共通のユーザー アクションを表示するアクションバーを提供する必要があります。 + +</p> + +<p>一部のメニュー アイテムのデザインと操作感は変わりましたが、一連のアクションとオプションを定義する意味論は、引き続き {@link android.view.Menu} API に基づきます。 +このガイドでは、すべてのバージョンの Android で表示されるメニューやアクションの基本的な 3 タイプを作成する方法について説明します。 + +</p> + +<dl> + <dt><strong>オプション メニューとアクションバー</strong></dt> + <dd><a href="#options-menu">オプション メニュー</a>は、アクティビティの主なメニュー アイテムのコレクションです。 +ここには、「検索」、「メールの作成」、「設定」のような、アプリにグローバルな影響があるアクションを配置する必要があります。 + + <p>Android 2.3 以前のバージョン向けに開発している場合は、ユーザーは <em>Menu</em> ボタンを押してオプション メニューパネルを表示できます。 +</p> + <p>Android 3.0 以降の場合、オプション メニューのアイテムは、画面上のアクション アイテムとオーバーフロー オプションの組み合わせで<a href="{@docRoot}guide/topics/ui/actionbar.html">アクションバー</a>に表示されます。 +Android 3.0 からは、<em>Menu</em> ボタンが廃止されたため(一部の端末にはこのボタンがありません)、アクションバーを使ってアクションや他のオプションにアクセスできるよう移行する必要があります。 + + +</p> + <p><a href="#options-menu">オプション メニューの作成</a>のセクションをご覧ください。</p> + </dd> + + <dt><strong>コンテキスト メニューとコンテキスト アクション モード</strong></dt> + + <dd>コンテキスト メニューは、ユーザーが要素を長押しクリックするときに表示される<a href="#FloatingContextMenu">フローティング メニュー</a>です。 +ここでは、選択したコンテンツやコンテキスト フレームに影響するアクションが提供されます。 + + <p>Android 3.0 以降向けに開発している場合は、<a href="#CAB">コンテキスト アクション モード</a>を使って選択されたコンテンツでのアクションを有効にする必要があります。このモードでは、画面最上部にあるバーで選択されたコンテンツに影響するアクション アイテムが表示され、ユーザーは複数のアイテムを選択できます。 + +</p> + <p><a href="#context-menu">コンテキスト メニューの作成</a>のセクションをご覧ください。</p> +</dd> + + <dt><strong>ポップアップ メニュー</strong></dt> + <dd>ポップアップ メニューでは、メニューを呼び出すビューに固定された縦方向のリストでアイテムが表示されます。 +特定のコンテンツに関連するアクションの概要を表示したり、コマンドの 2 番目の部分のオプションを表示したりする場合に適しています。 +ポップアップ メニューのアクションは対応するコンテンツに直接影響を<strong>与えない</strong>ようにしてください(そのためにコンテキスト アクションがあります)。 + +ポップアップ メニューは、アクティビティのコンテンツ領域に関連する拡張されたアクション用です。 + + <p><a href="#PopupMenu">ポップアップ メニューの作成</a>のセクションをご覧ください。</p> +</dd> +</dl> + + + +<h2 id="xml">XML でのメニューの定義</h2> + +<p>Android では、すべてのメニュータイプに、メニュー アイテムを定義するための標準の XML 形式が提供されます。 +アクティビティのコードでメニューをビルドするのではなく、メニューとそのすべてのアイテムを XML <a href="{@docRoot}guide/topics/resources/menu-resource.html">メニュー リソース</a>で定義してください。 +その際、アクティビティやフラグメントでメニュー リソースをインフレートできます({@link android.view.Menu} オブジェクトとして読み込む)。 + +</p> + +<p>メニュー リソースを使うことは、次のような理由で優れた方法と言えます。</p> +<ul> + <li>XML でメニュー構造の視覚化が簡単になる。</li> + <li>メニューのコンテンツを、アプリケーションの振る舞いコードと区別する。</li> + <li>別のプラットフォーム バージョン、画面サイズ、その他の構成用に、<a href="{@docRoot}guide/topics/resources/index.html">アプリリソース</a> フレームワークを活用して、代替のメニュー構成を作ることができる。 +</li> +</ul> + +<p>メニューを定義するには、プロジェクトの <code>res/menu/</code> ディレクトリ内で XML ファイルを作成し、次の要素を含むメニューをビルドします。 +</p> +<dl> + <dt><code><menu></code></dt> + <dd>メニュー アイテムのコンテナである {@link android.view.Menu} を定義します。<code><menu></code> 要素は、ファイルのルートノードである必要があります。また、1 つ以上の <code><item></code> と <code><group></code> 要素を持つことができます。 + +</dd> + + <dt><code><item></code></dt> + <dd>メニューで 1 つのアイテムを表示する {@link android.view.MenuItem} を作成します。この要素には、サブメニューを作成するために、ネストされた <code><menu></code> 要素を含めることができます。 +</dd> + + <dt><code><group></code></dt> + <dd>省略可能な {@code <item>} 要素の非表示コンテナ。メニュー アイテムでアクティブ状態や可視性のようなプロパティを共有できるよう、メニュー アイテムを分類できます。 +詳細については、<a href="#groups">メニュー グループの作成</a>のセクションをご覧ください。 +</dd> +</dl> + + +<p><code>game_menu.xml</code> という名前のメニュー例を次に示します。</p> +<pre> +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/new_game" + android:icon="@drawable/ic_new_game" + android:title="@string/new_game" + android:showAsAction="ifRoom"/> + <item android:id="@+id/help" + android:icon="@drawable/ic_help" + android:title="@string/help" /> +</menu> +</pre> + +<p><code><item></code> 要素では、アイテムの概観と動作を定義するために使用できるいくつかの属性がサポートされています。 +上記メニューのアイテムには、次の属性が含まれます。</p> + +<dl> + <dt>{@code android:id}</dt> + <dd>ユーザーがアイテムを選択するときに、アプリケーションがそのアイテムを認識できるようにする、アイテム固有のリソース ID。 +</dd> + <dt>{@code android:icon}</dt> + <dd>アイテムのアイコンとして使用するための、ドローアブルへの参照。</dd> + <dt>{@code android:title}</dt> + <dd>アイテムのタイトルとして使用するための、文字列への参照。</dd> + <dt>{@code android:showAsAction}</dt> + <dd>このアイテムが<a href="{@docRoot}guide/topics/ui/actionbar.html">アクションバー</a>のアクション アイテムとして、いつ、どのように表示される必要があるかを指定。</dd> +</dl> + +<p>これらの属性は使用する必要のある最も重要なものですが、他にもさまざまな属性があります。サポートされているすべての属性については、「<a href="{@docRoot}guide/topics/resources/menu-resource.html">Menu Resource</a>」のドキュメントをご覧ください。 +</p> + +<p>サブメニューを除くすべてのメニューで、{@code <item>} の子として {@code <menu>} 要素を追加すると、アイテムにサブメニューを追加できます。 +PC アプリケーションのメニューバー(ファイル、編集、表示など)にあるアイテムのように、アプリケーションにトピックで分類できる多くの機能がある場合は、サブメニューが役立ちます。 + +次に例を示します。</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/file" + android:title="@string/file" > + <!-- "file" submenu --> + <menu> + <item android:id="@+id/create_new" + android:title="@string/create_new" /> + <item android:id="@+id/open" + android:title="@string/open" /> + </menu> + </item> +</menu> +</pre> + +<p>アクティビティでメニューを使うには、{@link android.view.MenuInflater#inflate(int,Menu) +MenuInflater.inflate()} を使って、メニュー リソースをインフレートする(XML リソースをプログラム可能なオブジェクトに変換する)必要があります。 +次のセクションでは、各メニュー アイテムのメニューをインフレートする方法を説明します。 +</p> + + + +<h2 id="options-menu">オプション メニューの作成</h2> + +<div class="figure" style="width:200px;margin:0"> + <img src="{@docRoot}images/options_menu.png" height="333" alt="" /> + <p class="img-caption"><strong>図 1.</strong> Android 2.3 のブラウザでのオプション メニュー。 +</p> +</div> + +<p>オプション メニューでは、「検索」、「メールの作成」、「設定」のような、現在のアクティビティ コンテキストに関連するアクションとその他のオプションを含める必要があります。 +</p> + +<p>オプション メニューのアイテムが画面上のどこに表示されるかは、開発対象のアプリケーションのバージョンによって異なります。 +</p> + +<ul> + <li><strong>Android 2.3.x(API レベル 10)以前</strong> 向けにアプリケーションを開発した場合、ユーザーが <em>Menu</em> ボタンを押すときに、図 1 のように、オプション メニューのコンテンツが画面下部に表示されます。 + +開いて最初に表示される部分は、最大 6 つのメニュー アイテムで構成されるアイコン メニューです。 + +7 つ以上のメニュー アイテムが含まれている場合、Android では 6 番目以降のアイテムがオーバーフロー メニューに配置されます。それらのアイテムは、<em>もっと見る</em> を選択して開くことができます。 + +</li> + + <li><strong>Android 3.0(API レベル 11)以降</strong>向けにアプリケーションを開発した場合、オプション メニューのアイテムは<a href="{@docRoot}guide/topics/ui/actionbar.html">アクションバー</a>に表示されます。 +デフォルトでは、システムによってアクション オーバーフローにすべてのアイテムが配置され、ユーザーはアクションバー右端にあるアクション オーバーフロー アイコンを使ってそのアイテムを表示できます。端末に <em>Menu</em> ボタンがある場合はそのボタンを押して表示できます。 + +重要なアクションにすみやかにアクセスできるようにするには、対応する {@code <item>} 要素に {@code android:showAsAction="ifRoom"} を追加して、いくつかのアイテムをアクションバーに表示させるようプロモートできます(図 2を参照)。 + + + + <p>アクション アイテムと他のアクションバーの動作の詳細については、「<a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>」のガイドをご覧ください。 </p> +<p class="note"><strong>注:</strong> Android 3.0 以降向けに開発して<em>いない</em>場合でも、同様の効果のために、自分のアクションバー レイアウトをビルドできます。 +アクションバー付きで以前のバージョンの Android をサポートする方法の一例については、<a href="{@docRoot}resources/samples/ActionBarCompat/index.html">アクションバーの互換性</a>のサンプルをご覧ください。 + +</p> +</li> +</ul> + +<img src="{@docRoot}images/ui/actionbar.png" alt="" /> +<p class="img-caption"><strong>図 2.</strong> ナビゲーション タブ、カメラ アクション アイテム、アクション オーバーフロー ボタンが表示されている <a href="{@docRoot}resources/samples/HoneycombGallery/index.html">Honeycomb Gallery</a> アプリのアクションバー。 +</p> + +<p>{@link android.app.Activity} サブクラスや {@link android.app.Fragment} サブクラスのいずれかからオプション メニューのアイテムを宣言できます。 +アクティビティとフラグメントの両方でオプション メニューのアイテムを宣言する場合、それらは UI に統合されます。まず、アクティビティのアイテムが表示され、次にアクティビティに各フラグメントが追加される順序で各フラグメントのアイテムが表示されます。 + + +必要に応じて、移動する必要のある各 {@code <item>} で {@code android:orderInCategory} 属性を使ってメニュー アイテムの順序を並べ替えることができます。 +</p> + +<p>アクティビティのオプション メニューを指定するには、{@link +android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} をオーバーライドします(フラグメントは独自の {@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()} コールバックを提供)。 +このメソッドでは、メニュー リソース(<a href="#xml">XML で定義</a>)をコールバックで提供される {@link +android.view.Menu} にインフレートできます。 +次に例を示します。</p> + +<pre> +@Override +public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = {@link android.app.Activity#getMenuInflater()}; + inflater.inflate(R.menu.game_menu, menu); + return true; +} +</pre> + +<p>{@link android.view.Menu#add(int,int,int,int) +add()} を使ってメニュー アイテムを追加し、{@link android.view.MenuItem} API でそのプロパティを修正するために、{@link android.view.Menu#findItem findItem()} でアイテムを取得することもできます。 +</p> + +<p>Android 2.3.x 以前向けにアプリケーションを開発した場合、システムは {@link +android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} を呼び出し、ユーザーが初めてそのメニューを開いたときにオプション メニューが作成されます。 +Android 3.0 以降向けに開発した場合、アクティビティの開始時にシステムが {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} を呼び出し、アクションバーにアイテムが表示されるようにします。 + +</p> + + + +<h3 id="RespondingOptionsMenu">クリック イベントを処理する</h3> + +<p>ユーザーがオプション メニューからアイテムを選択すると(アクションバーのアクション アイテムを含む)、アクティビティの {@link android.app.Activity#onOptionsItemSelected(MenuItem) +onOptionsItemSelected()} メソッドが呼び出されます。 +このメソッドでは、選択された {@link android.view.MenuItem} が渡されます。{@link android.view.MenuItem#getItemId()} を呼び出してアイテムを識別できます。これにより、メニュー アイテムに対して一意の ID が返されます(メニュー リソースで {@code android:id} 属性を定義するか、{@link android.view.Menu#add(int,int,int,int) add()} メソッドに指定された整数で)。 + + +この ID を既知のメニュー アイテムと突き合わせて適切なアクションを実行できます。 +次に例を示します。</p> + +<pre> +@Override +public boolean onOptionsItemSelected(MenuItem item) { + // Handle item selection + switch (item.getItemId()) { + case R.id.new_game: + newGame(); + return true; + case R.id.help: + showHelp(); + return true; + default: + return super.onOptionsItemSelected(item); + } +} +</pre> + +<p>メニュー アイテムを正常に処理する場合、{@code true} を返します。メニュー アイテムを処理しない場合は、{@link +android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} のスーパークラスの実装を呼び出す必要があります(デフォルトの実装では fause が返されます)。 + +</p> + +<p>アクティビティにフラグメントが含まれる場合は、システムはまずアクティビティに対して {@link +android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} を呼び出し、次に {@code true} が返されるまで、またはすべてのフラグメントが呼び出されるまで、各フラグメントが追加された順序で、各フラグメントに対して呼び出します。 + +</p> + +<p class="note"><strong>ヒント:</strong> Android 3.0 では、{@code android:onClick} 属性を使って、メニュー アイテムのクリックでの動作を XML で定義できます。 +その属性値は、メニューを使ってアクティビティによって定義されるメソッド名である必要があります。 +そのメソッドは、パブリックであり、1 つの {@link android.view.MenuItem} パラメータを使用できる必要があります。システムがこのメソッドを呼び出すと、選択したメニュー アイテムが渡されます。 + +詳細と例については、「<a href="{@docRoot}guide/topics/resources/menu-resource.html">Menu Resource</a>」のドキュメントをご覧ください。</p> + +<p class="note"><strong>ヒント:</strong> アプリケーションに複数のアクティビティが含まれていて、その一部で同じオプション メニューが提供されている場合、{@link android.app.Activity#onCreateOptionsMenu(Menu) +onCreateOptionsMenu()} と {@link android.app.Activity#onOptionsItemSelected(MenuItem) +onOptionsItemSelected()} メソッドのみを実装するアクティビティを作成することを検討します。 + +その後、同じオプション メニューを共有する必要のある各アクティビティのこのクラスを拡張します。 +この方法で、メニューの動作を継承するメニュー アクションとそれぞれの子クラスを処理するためのコードを 1 セットで管理できます。子孫アクティビティの 1 つにメニュー アイテムを追加する場合は、そのアクティビティの {@link android.app.Activity#onCreateOptionsMenu(Menu) +onCreateOptionsMenu()} をオーバーライドします。 + + +元のメニュー アイテムが作成されるように、{@code super.onCreateOptionsMenu(menu)} を呼び出し、{@link +android.view.Menu#add(int,int,int,int) menu.add()} で新しいメニュー アイテムを追加します。 +各メニュー アイテムのスーパークラスの行動をオーバーライドすることもできます。 +</p> + + +<h3 id="ChangingTheMenu">実行時におけるメニュー アイテムの変更</h3> + +<p>システムが {@link android.app.Activity#onCreateOptionsMenu(Menu) +onCreateOptionsMenu()} を呼び出した後、入力する {@link android.view.Menu} のインスタンスは残り、何らかの理由でメニューが無効にならない限り、{@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} をもう一度呼び出すことはありません。 + +ただし、初期のメニュー状態を作成し、アクティビティのライフサイクル中に変更しないという目的の場合に限って、{@link +android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} を使用する必要があります。 +</p> + +<p>アクティビティのライフサイクル中に発生するイベントに基づいてオプション メニューを変更する場合は、{@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()} メソッドでそれを実行できます。 + +このメソッドは、現在存在している {@link android.view.Menu} オブジェクトを渡し、それを編集(アイテムの追加、削除、無効化など)できるようにします。 + +(フラグメントでも {@link +android.app.Fragment#onPrepareOptionsMenu onPrepareOptionsMenu()} コールバックが提供されます)。</p> + +<p>Android 2.3.x 以前では、ユーザーが <em>Menu</em> ボタンを押してオプション メニューを開くたびに、システムによって {@link +android.app.Activity#onPrepareOptionsMenu(Menu) +onPrepareOptionsMenu()} が呼び出されます。 +</p> + +<p>Android 3.0 以降では、メニュー アイテムがアクションバーに表示されるときに、オプション メニューが常に開かれるとみなされます。 +イベントが発生し、メニューをアップデートするときは、{@link android.app.Activity#invalidateOptionsMenu invalidateOptionsMenu()} を呼び出して、システムが {@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()} を呼び出すようリクエストする必要があります。 + +</p> + +<p class="note"><strong>注:</strong> 現在フォーカスされている {@link android.view.View} に基づいてオプション メニューでアイテムを変更しないでください。 + +タッチモードの場合(ユーザーがトラックボールやリモコンの矢印ボタンを使うとき)、ビューはフォーカスを取得できないため、オプション メニューのアイテム変更のベースとしてフォーカスを使用しないでください。 + +{@link +android.view.View} に状況依存のメニュー アイテムを提供する場合は、<a href="#context-menu">コンテキスト メニュー</a>を使います。</p> + + + + +<h2 id="context-menu">コンテキスト メニューの作成</h2> + +<div class="figure" style="width:420px;margin-top:-1em"> + <img src="{@docRoot}images/ui/menu-context.png" alt="" /> + <p class="img-caption"><strong>図 3.</strong> フローティング コンテキスト メニュー(左)とコンテキスト アクションバー(右)のスクリーンショット +</p> +</div> + +<p>コンテキスト メニューでは、UI の特定のアイテムやコンテキスト フレームに影響するアクションが提供されます。どのビューでもコンテキスト メニューを提供できますが、ほとんどの場合は、{@link +android.widget.ListView}、{@link android.widget.GridView}、各アイテムでユーザーが直接実行できるその他のビュー コレクションのアイテムに使用されます。 + +</p> + +<p>コンテキスト アクションを提供するには次の 2 つの方法があります。</p> +<ul> + <li><a href="#FloatingContextMenu">フローティング コンテキスト メニュー</a>で。メニューは、ユーザーが長押しクリックする(押したままにする)と、コンテキスト メニューのサポートを宣言するビュー上で、メニュー アイテムのフローティング リストとして表示されます。 + +ユーザーは、一度に 1 つのアイテムでコンテキスト アクションを実行できます。 +</li> + + <li><a href="#CAB">コンテキスト アクション モード</a>で。このモードは、選択されたアイテムに影響するアクション アイテムと一緒に画面最上部に<em>コンテキスト アクションバー</em>を表示する {@link android.view.ActionMode} のシステム実装です。 + +このモードがアクティブなとき、ユーザーは一度に複数のアイテムでアクションを実行できます(アプリで許可されている場合)。 +</li> +</ul> + +<p class="note"><strong>注:</strong> コンテキスト アクション モードは、Android 3.0(API レベル 11)以降で使用可能で、使用可能な場合にコンテキスト アクションを表示するのに適した方法です。 + +アプリで 3.0 以前のバージョンをサポートする場合、その端末ではフローティング コンテキスト メニューを使う必要があります。 +</p> + + +<h3 id="FloatingContextMenu">フローティング コンテキスト メニューの作成</h3> + +<p>フローティング コンテキスト メニューを提供するには: </p> +<ol> + <li>{@link android.app.Activity#registerForContextMenu(View) registerForContextMenu()} を呼び出し、{@link android.view.View} を渡して、コンテキスト メニューに関連付ける必要のある {@link android.view.View} を登録します。 + + + <p>アクティビティで {@link android.widget.ListView} や {@link android.widget.GridView} が使用され、各アイテムに同じコンテキスト メニューを提供する場合、{@link android.widget.ListView} や {@link android.widget.GridView} を {@link +android.app.Activity#registerForContextMenu(View) registerForContextMenu()} に渡してコンテキスト メニューにすべてのアイテムを登録します。 + +</p> +</li> + + <li>{@link android.app.Activity} や {@link android.app.Fragment} に {@link +android.view.View.OnCreateContextMenuListener#onCreateContextMenu onCreateContextMenu()} メソッドを実装します。 + + <p>登録されたビューが長押しクリック イベントを受け取ると、システムは {@link +android.view.View.OnCreateContextMenuListener#onCreateContextMenu onCreateContextMenu()} メソッドを呼び出します。 +通常、ここでメニュー リソースをインフレートして、メニュー アイテムを定義します。次に例を示します。 +</p> +<pre> +@Override +public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.context_menu, menu); +} +</pre> + +<p>{@link android.view.MenuInflater} では、<a href="{@docRoot}guide/topics/resources/menu-resource.html">メニュー リソース</a>からコンテキスト メニューをインフレートできます。そのコールバック メソッド パラメータには、ユーザーが選択した {@link android.view.View} と選択されたアイテムに関する追加情報を提供する {@link android.view.ContextMenu.ContextMenuInfo} オブジェクトが含まれます。 + + +アクティビティに、それぞれ別のコンテキスト メニューを提供する複数のビューがある場合、これらのパラメータを使ってインフレートするコンテキスト メニューを決定できます。 + +</p> +</li> + +<li>{@link android.app.Activity#onContextItemSelected(MenuItem) +onContextItemSelected()} を実装します。 + <p>ユーザーがメニュー アイテムを選択すると、システムによってこのメソッドが呼び出され、適切なアクションを実行できるようになります。 +次に例を示します。</p> + +<pre> +@Override +public boolean onContextItemSelected(MenuItem item) { + AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); + switch (item.getItemId()) { + case R.id.edit: + editNote(info.id); + return true; + case R.id.delete: + deleteNote(info.id); + return true; + default: + return super.onContextItemSelected(item); + } +} +</pre> + +<p>{@link android.view.MenuItem#getItemId()} メソッドは、選択されたメニュー アイテムの ID を照会します。<a href="#xml">XML でメニューを定義する</a>のセクションで説明されているように、{@code +android:id} 属性を使って XML で各メニュー アイテムを割り当てる必要があります。 + +</p> + +<p>メニュー アイテムを正常に処理する場合、{@code true} を返します。メニュー アイテムを処理しない場合は、スーパークラスの実装にメニュー アイテムを渡す必要があります。 +アクティビティにフラグメントが含まれる場合、そのアクティビティは最初にこのコールバックを受け取ります。 +未処理のときにスーパークラスを呼び出すと、システムは {@code true} や {@code false} が返されるまで、各フラグメントのそれぞれのコールバック メソッドに 1 つずつ、各フラグメントが追加された順序でイベントを渡します。 + +{@link android.app.Activity} と {@code android.app.Fragment} のデフォルトの実装では {@code +false} が返されるため、未処理のときは常にスーパークラスを呼び出す必要があります。 +</p> +</li> +</ol> + + +<h3 id="CAB">コンテキスト アクション モードの使用</h3> + +<p>コンテキスト アクション モードは、{@link android.view.ActionMode} のシステム実装で、ユーザーによるコンテキスト アクション実行のための操作に焦点が置かれています。 +ユーザーがアイテムを選択してこのモードを有効にすると、画面の最上部に<em>コンテキスト アクションバー</em>が表示され、現在選択中のアイテムで実行できるアクションが表示されます。 + +このモードが有効な間は、ユーザーは複数のアイテムを選択したり(許可されている場合)、アイテムを選択解除したり、アクティビティ内を移動し続けたり(許可されている範囲内で)することができます。 + +ユーザーがすべてのアイテムの選択を解除したり、Back ボタンをしたり、またはバーの左端で <em>Done</em> アクションを選択したりすると、このアクション モードは無効になり、コンテキスト アクションバーは表示されなくなります。 + +</p> + +<p class="note"><strong>注:</strong> コンテキスト アクションバーを<a href="{@docRoot}guide/topics/ui/actionbar.html">アクションバー</a>と関連付ける必要はありません。 +コンテキスト アクションバーが、視覚的にアクションバーの位置にかかる場合でも、個別に操作できます。 + +</p> + +<p>Android 3.0(API レベル 11)以降向けに開発中の場合、通常は<a href="#FloatingContextMenu">フローティング コンテキスト メニュー</a>ではなく、コンテキスト アクション モードを使ってコンテキスト アクションを表示します。 +</p> + +<p>コンテキスト アクションを提供するビューでは、通常は次の 2 つのイベントのいずれかまたは両方で、コンテキスト アクションを呼び出す必要があります。 +</p> +<ul> + <li>ユーザーがビューで長押しクリックする。</li> + <li>ユーザーがチェックボックスまたは同様の UI コンポーネントをビュー内で選択する。</li> +</ul> + +<p>アプリケーションがどのようにコンテキスト アクション モードを呼び出して各アクションの動作を定義するかは、デザインによって異なります。 +基本的に次の 2 つのデザインがあります。</p> +<ul> + <li>個別の任意のビューでのコンテキスト アクション用。</li> + <li>{@link +android.widget.ListView} または {@link android.widget.GridView} のアイテム グループでのバッチ コンテキスト アクション用(ユーザーが複数のアイテムを選択し、そのすべてにアクションを実行できるようにする)。 +</li> +</ul> + +<p>次のセクションでは、各シナリオに必要な設定について説明します。</p> + + +<h4 id="CABforViews">個別のビューに対してコンテキスト アクション モードを有効にする</h4> + +<p>ユーザーが特定のビューを選択するときにのみ、コンテキスト アクション モードを呼び出すには、次のことを行う必要があります。 +</p> +<ol> + <li>{@link android.view.ActionMode.Callback} インターフェースを実装します。このコールバック メソッドでは、コンテキスト アクションバーに対してアクションを指定して、アクション アイテムでのイベント クリックに応答し、アクション モードのその他のライフサイクル イベントを処理できます。 + +</li> + <li>ユーザーがビューを長押しクリックしたときなど、バーを表示するときに、{@link android.app.Activity#startActionMode startActionMode()} を呼び出します。 +</li> +</ol> + +<p>次に例を示します。</p> + +<ol> + <li>{@link android.view.ActionMode.Callback ActionMode.Callback} インターフェースを実装します。 +<pre> +private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() { + + // Called when the action mode is created; startActionMode() was called + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + // Inflate a menu resource providing context menu items + MenuInflater inflater = mode.getMenuInflater(); + inflater.inflate(R.menu.context_menu, menu); + return true; + } + + // Called each time the action mode is shown. Always called after onCreateActionMode, but + // may be called multiple times if the mode is invalidated. + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return false; // Return false if nothing is done + } + + // Called when the user selects a contextual menu item + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_share: + shareCurrentItem(); + mode.finish(); // Action picked, so close the CAB + return true; + default: + return false; + } + } + + // Called when the user exits the action mode + @Override + public void onDestroyActionMode(ActionMode mode) { + mActionMode = null; + } +}; +</pre> + +<p>これらのイベント コールバックは、これらのそれぞれもイベントに関連する {@link +android.view.ActionMode} オブジェクトを渡すこと以外は、<a href="#options-menu">オプション メニュー</a>のコールバックとほぼ同じです。{@link +android.view.ActionMode} API を使って、{@link android.view.ActionMode#setTitle setTitle()} と {@link +android.view.ActionMode#setSubtitle setSubtitle()}(選択されているアイテム数を表示するのに役立つ)でタイトルとサブタイトルを変更するなど、CAB にさまざまな変更を行うことができます。 + +</p> + +<p>また、上記のサンプルでは、アクション モードが破棄されるときに {@code mActionMode} 変数が null に設定されます。 +次のステップでは、それがどのように初期化され、アクティビティやフラグメントでどのようにメンバー変数を保存するのが役立つかについて説明します。 +</p> +</li> + + <li>{@link android.app.Activity#startActionMode startActionMode()} を呼び出して、{@link +android.view.View} で長押しクリックに応答するときなど、適切な時にコンテキスト アクション モードを有効にします。 +</p> + +<pre> +someView.setOnLongClickListener(new View.OnLongClickListener() { + // Called when the user long-clicks on someView + public boolean onLongClick(View view) { + if (mActionMode != null) { + return false; + } + + // Start the CAB using the ActionMode.Callback defined above + mActionMode = getActivity().startActionMode(mActionModeCallback); + view.setSelected(true); + return true; + } +}); +</pre> + +<p>{@link android.app.Activity#startActionMode startActionMode()} を呼び出すと、システムは作成された {@link android.view.ActionMode} を返します。 +メンバー変数でこれを保存すると、その他のイベントに応じてコンテキスト アクションバーを変更できます。 +上記の例では、{@link android.view.ActionMode} を使って、{@link android.view.ActionMode} インスタンスがアクティブな状態である場合に、アクション モードを開始する前にメンバーが null であるかどうかを確認して、そのインスタンスが再作成されないようにしています。 + + +</p> +</li> +</ol> + + + +<h4 id="CABforListView">バッチ コンテキスト アクションを ListView または GridView で有効にする</h4> + +<p>{@link android.widget.ListView} や {@link +android.widget.GridView}(または {@link android.widget.AbsListView} の別の拡張)にアイテムのコレクションがあり、ユーザーがバッチ アクションを実行できるようにする場合は、次のことを行う必要があります。 +</p> + +<ul> + <li>{@link android.widget.AbsListView.MultiChoiceModeListener} インターフェースを実装して、{@link android.widget.AbsListView#setMultiChoiceModeListener +setMultiChoiceModeListener()} で ViewGroup にそれを設定する。 +リスナのコールバック メソッドでは、コンテキスト アクションバーに対してアクションを指定して、アクション アイテムでのイベント クリックに応答し、{@link android.view.ActionMode.Callback} インターフェースから継承されるその他のコールバックを処理できます。 + +</li> + + <li>{@link +android.widget.AbsListView#CHOICE_MODE_MULTIPLE_MODAL} 引数で {@link android.widget.AbsListView#setChoiceMode setChoiceMode()} を呼び出す。</li> +</ul> + +<p>次に例を示します。</p> + +<pre> +ListView listView = getListView(); +listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); +listView.setMultiChoiceModeListener(new MultiChoiceModeListener() { + + @Override + public void onItemCheckedStateChanged(ActionMode mode, int position, + long id, boolean checked) { + // Here you can do something when items are selected/de-selected, + // such as update the title in the CAB + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + // Respond to clicks on the actions in the CAB + switch (item.getItemId()) { + case R.id.menu_delete: + deleteSelectedItems(); + mode.finish(); // Action picked, so close the CAB + return true; + default: + return false; + } + } + + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + // Inflate the menu for the CAB + MenuInflater inflater = mode.getMenuInflater(); + inflater.inflate(R.menu.context, menu); + return true; + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + // Here you can make any necessary updates to the activity when + // the CAB is removed. By default, selected items are deselected/unchecked. + } + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + // Here you can perform updates to the CAB due to + // an {@link android.view.ActionMode#invalidate} request + return false; + } +}); +</pre> + +<p>これだけです。これで、ユーザーが長押しクリックでアイテムを選択すると、システムは {@link +android.widget.AbsListView.MultiChoiceModeListener#onCreateActionMode onCreateActionMode()} メソッドを呼び出して、特定のアクションでコンテキスト アクションバーを表示するようになります。 +コンテキスト アクションバーが表示されている間は、追加のアイテムを選択できます。 +</p> + +<p>コンテキスト アクションによって一般的なアクション アイテムが提供されるとき、ユーザーが長押しクリックの動作に気付かない可能性があることを考慮して、アイテムを選択できるようにチェックボックスや同様の UI 要素を追加したい場合もあります。 + +ユーザーがチェックボックスをオンにするとき、{@link android.widget.AbsListView#setItemChecked setItemChecked()} でオンにされた状態にそれぞれのリストアイテムを設定して、コンテキスト アクション モードを呼び出すことができます。 + +</p> + + + + +<h2 id="PopupMenu">ポップアップ メニューの作成</h2> + +<div class="figure" style="width:220px"> +<img src="{@docRoot}images/ui/popupmenu.png" alt="" /> +<p><strong>図 4.</strong>右上のオーバーフローボタンに固定された Gmail アプリのポップアップ メニュー。 +</p> +</div> + +<p>{@link android.widget.PopupMenu} は {@link android.view.View} に固定されるモーダル メニューです。スペースがある場合にはアンカービューの下に、スペースがない場合はビューの上に表示されます。 +次の場合に役立ちます。</p> +<ul> + <li>特定のコンテンツに<em>関連する</em>アクションにオーバーフロー スタイルのメニューを提供する(図 4 にある Gmail のメールヘッダーなど)。 + + <p class="note"><strong>注:</strong> これは、通常は選択したコンテンツに<em>影響する</em>アクション用であるコンテキスト メニューとは異なります。 +選択したコンテンツに影響するアクションには、<a href="#CAB">コンテキスト アクション モード</a>や<a href="#FloatingContextMenu">フローティング コンテキスト メニュー</a>を使います。 +</p></li> + <li>コマンド センテンスの 2 番目の部分を提供する(別の「追加」オプションを含むポップアップ メニューを生成する「追加」とマークされたボタンなど)。 +</li> + <li>固定選択を保持しない {@link android.widget.Spinner} のようなドロップダウンを提供する。 +</li> +</ul> + + +<p class="note"><strong>注:</strong> {@link android.widget.PopupMenu} は API レベル 11 以降で使用できます。 +</p> + +<p><a href="#xml">XML でメニューを定義する</a>場合の、ポップアップ メニューの表示方法について、次に示します。</p> +<ol> + <li>そのコンストラクタを使って {@link android.widget.PopupMenu} のインスタンスを作成します。これにより、メニューが固定される必要のある、現在のアプリケーションの {@link android.content.Context} と {@link android.view.View} が取得されます。 + +</li> + <li>{@link android.view.MenuInflater} を使って、{@link +android.widget.PopupMenu#getMenu() PopupMenu.getMenu()} によって返される {@link +android.view.Menu} オブジェクトにメニュー リソースをインフレートします。API レベル 14 以降では、代わりに {@link android.widget.PopupMenu#inflate PopupMenu.inflate()} を使うことができます。 +</li> + <li>{@link android.widget.PopupMenu#show() PopupMenu.show()} を呼び出します。</li> +</ol> + +<p>ポップアップ メニューを表示する {@link android.R.attr#onClick android:onClick} 属性を含むボタンの一例を以下に示します。 +</p> + +<pre> +<ImageButton + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/ic_overflow_holo_dark" + android:contentDescription="@string/descr_overflow_button" + android:onClick="showPopup" /> +</pre> + +<p>アクティビティでは、次のようにポップアップ メニューが表示されます。</p> + +<pre> +public void showPopup(View v) { + PopupMenu popup = new PopupMenu(this, v); + MenuInflater inflater = popup.getMenuInflater(); + inflater.inflate(R.menu.actions, popup.getMenu()); + popup.show(); +} +</pre> + +<p>API レベル 14 以降では、{@link +android.widget.PopupMenu#inflate PopupMenu.inflate()} でメニューをインフレートする 2 行を組み合わせることができます。</p> + +<p>ユーザーがアイテムを選択するか、メニュー領域外をタップすると、メニューが閉じます。 +{@link +android.widget.PopupMenu.OnDismissListener} を使って dismiss イベントをリッスンできます。</p> + +<h3 id="PopupEvents">クリック イベントを処理する</h3> + +<p>ユーザーがアイテム メニューを選択するときにアクションを実行するには、{@link +android.widget.PopupMenu.OnMenuItemClickListener} インターフェースを実装し、{@link android.widget.PopupMenu#setOnMenuItemClickListener +setOnMenuItemclickListener()} を呼び出して {@link +android.widget.PopupMenu} でそれを登録する必要があります。 +ユーザーがアイテムを選択すると、インターフェースで {@link +android.widget.PopupMenu.OnMenuItemClickListener#onMenuItemClick onMenuItemClick()} コールバックが呼び出されます。 +</p> + +<p>次に例を示します。</p> + +<pre> +public void showMenu(View v) { + PopupMenu popup = new PopupMenu(this, v); + + // This activity implements OnMenuItemClickListener + popup.setOnMenuItemClickListener(this); + popup.inflate(R.menu.actions); + popup.show(); +} + +@Override +public boolean onMenuItemClick(MenuItem item) { + switch (item.getItemId()) { + case R.id.archive: + archive(item); + return true; + case R.id.delete: + delete(item); + return true; + default: + return false; + } +} +</pre> + + +<h2 id="groups">メニュー グループの作成</h2> + +<p>メニュー グループは、特定の特徴を共有するメニュー アイテムのコレクションです。グループを使って次のことを実行できます。 +</p> +<ul> + <li>{@link android.view.Menu#setGroupVisible(int,boolean) +setGroupVisible()} ですべてのアイテムを表示または非表示にする</li> + <li>{@link android.view.Menu#setGroupEnabled(int,boolean) +setGroupEnabled()} ですべてのアイテムを有効または無効にする</li> + <li>{@link +android.view.Menu#setGroupCheckable(int,boolean,boolean) setGroupCheckable()} ですべてのアイテムをオンにできるかどうかを指定する</li> +</ul> + +<p>メニュー リソースの {@code <group>} 要素内で {@code <item>} 要素をネストするか、{@link +android.view.Menu#add(int,int,int,int) add()} メソッドでグループ ID を指定して、グループを作成できます。 +</p> + +<p>グループを含むメニュー リソースの一例を次に示します。</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/menu_save" + android:icon="@drawable/menu_save" + android:title="@string/menu_save" /> + <!-- menu group --> + <group android:id="@+id/group_delete"> + <item android:id="@+id/menu_archive" + android:title="@string/menu_archive" /> + <item android:id="@+id/menu_delete" + android:title="@string/menu_delete" /> + </group> +</menu> +</pre> + +<p>グループ内のアイテムは、最初のアイテムと同じレベルで表示されます(メニューの 3 つのアイテムすべてが兄弟)。 +ただし、グループ ID を参照するか、上記のメソッドを使って、グループ内の 2 つのアイテムの特徴を変更できます。 +システムが、グループ化されたアイテムを分けることもありません。 +たとえば、各アイテムに {@code +android:showAsAction="ifRoom"} を宣言する場合、その両方がアクションバーまたはアクション オーバーフローに表示されます。 +</p> + + +<h3 id="checkable">オンにできるメニュー アイテムの使用</h3> + +<div class="figure" style="width:200px"> + <img src="{@docRoot}images/radio_buttons.png" height="333" alt="" /> + <p class="img-caption"><strong>図 5.</strong> オンにできるアイテムを含むサブメニューのスクリーンショット。 +</p> +</div> + +<p>メニューは、オプションのオンとオフを切り替えるインターフェースとして役立ちます。スタンドアロンのオプションにはチェックボックスを、相互に排他的なオプションのグループにはラジオボタンを使います。 + +図 5 に、ラジオボタン付きのオンにできるアイテムを含むサブメニューを示します。 +</p> + +<p class="note"><strong>注:</strong> アイコン メニューのメニュー アイテム(オプション メニューから)ではチェックボックスやラジオボタンを表示できません。 +アイコン メニューのアイテムをオンにできるようにする場合、状態が変わるごとにアイコンやテキストを入れ替えて、オンにされた状態を手動で示す必要があります。 + +</p> + +<p>個々のメニュー アイテムには {@code <item>} 要素の {@code +android:checkable} 属性を、グループ全体には {@code <group>} 要素の {@code android:checkableBehavior} 属性を使って、オンにできる動作を定義できます。 +たとえば、このメニュー グループのすべてのアイテムはラジオボタンでオンにできます。 +</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <group android:checkableBehavior="single"> + <item android:id="@+id/red" + android:title="@string/red" /> + <item android:id="@+id/blue" + android:title="@string/blue" /> + </group> +</menu> +</pre> + +<p>{@code android:checkableBehavior} 属性では、次のいずれかが許容されます。 +<dl> + <dt>{@code single}</dt> + <dd>グループから 1 つのアイテムのみをオンにできる(ラジオボタン)</dd> + <dt>{@code all}</dt> + <dd>すべてのアイテムをオンにできる(チェックボックス)</dd> + <dt>{@code none}</dt> + <dd>どのアイテムもオンにできない</dd> +</dl> + +<p>{@code <item>} 要素の {@code android:checked} 属性を使って、デフォルトのオンにされた状態をアイテムに適用でき、{@link +android.view.MenuItem#setChecked(boolean) setChecked()} メソッドを使ってコード内でそれを変更できます。 +</p> + +<p>オンにできるアイテムが選択されると、システムは {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} のような、それぞれの item-selected コールバック メソッドを呼び出します。 +チェックボックスやラジオボタンによって自動的にその状態が変わることはないため、ここでチェックボックスの状態を設定する必要があります。 + +{@link android.view.MenuItem#isChecked()} で、アイテムの現在の状態(ユーザーが選択する前の状態)を照会できます。その後、{@link android.view.MenuItem#setChecked(boolean) setChecked()} でオンにされた状態を設定します。 + +次に例を示します。</p> + +<pre> +@Override +public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.vibrate: + case R.id.dont_vibrate: + if (item.isChecked()) item.setChecked(false); + else item.setChecked(true); + return true; + default: + return super.onOptionsItemSelected(item); + } +} +</pre> + +<p>この方法でオンにされた状態を設定しない場合には、アイテム(チェックボックスまたはラジオボタン)の表示状態はユーザーがオンにしたときに変更されません。 + +状態を設定すると、アクティビティはアイテムのオンにされた状態を維持して、ユーザーが後でメニューを開いたときに、開発者が設定したオンにされた状態が表示されるようになります。 + +</p> + +<p class="note"><strong>注:</strong> オンにできるメニュー アイテムは、セッション単位ベースのみでの使用を意図したもので、アプリケーションが破棄された後は、保存されません。 + +ユーザー用に保存するアプリケーション設定がある場合は、<a href="{@docRoot}guide/topics/data/data-storage.html#pref">共有のプリファレンス</a>を使ってデータを保存してください。 +</p> + + + +<h2 id="intents">インテントに基づくメニュー アイテムの追加</h2> + +<p>{@link android.content.Intent} を使ってメニュー アイテムでアクティビティが起動されるようにしたい場合もあります(自分のアプリケーションのアクティビティであるか、別のアプリケーションのアクティビティであるかにかかわらず)。 +使用するインテントがわかっていて、インテントを開始する必要のある特定のメニュー アイテムがある場合は、適切な on-item-selected コールバック メソッド({@link +android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} のような)中に、{@link android.app.Activity#startActivity(Intent) startActivity()} でインテントを実行できます。 + + +</p> + +<p>ただし、ユーザーの端末にインテントを処理するアプリケーションが含まれているかどうかが不明な場合、それを呼び出すメニュー アイテムを追加すると、そのインテントによってアクティビティが解決されないためにメニュー アイテムが機能しなくなることがあります。 + + +これを解決するために、Android では、インテントを処理する端末で Android によってアクティビティが検出されるときに、メニュー アイテムがメニューに動的に追加されるようにします。 +</p> + +<p>インテントを受け入れる使用可能なアクティビティに基づいてメニュー アイテムを追加するには: </p> +<ol> + <li>{@link android.content.Intent#CATEGORY_ALTERNATIVE} や {@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} カテゴリでインテントを定義します。その他の要件も必要です。 + +</li> + <li>{@link +android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[]) +Menu.addIntentOptions()} を呼び出します。その際、Android によって、インテントを実行できるアプリケーションが検索され、メニューにそのアプリケーションが追加されます。 +</li> +</ol> + +<p>インテントを満たすアプリケーションがインストールされていない場合、メニュー アイテムは追加されません。 +</p> + +<p class="note"><strong>注:</strong> {@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} は、現在画面で選択されている要素の処理に使われます。 + +このため、{@link +android.app.Activity#onCreateContextMenu(ContextMenu,View,ContextMenuInfo) +onCreateContextMenu()} でメニューを作成するときにのみ、それが使われる必要があります。</p> + +<p>次に例を示します。</p> + +<pre> +@Override +public boolean onCreateOptionsMenu(Menu menu){ + super.onCreateOptionsMenu(menu); + + // Create an Intent that describes the requirements to fulfill, to be included + // in our menu. The offering app must include a category value of Intent.CATEGORY_ALTERNATIVE. + Intent intent = new Intent(null, dataUri); + intent.addCategory(Intent.CATEGORY_ALTERNATIVE); + + // Search and populate the menu with acceptable offering applications. + menu.addIntentOptions( + R.id.intent_group, // Menu group to which new items will be added + 0, // Unique item ID (none) + 0, // Order for the items (none) + this.getComponentName(), // The current activity name + null, // Specific items to place first (none) + intent, // Intent created above that describes our requirements + 0, // Additional flags to control items (none) + null); // Array of MenuItems that correlate to specific items (none) + + return true; +}</pre> + +<p>定義されたインテントに一致するインテント フィルタが提供されていることを見つけた各アクティビティに対して、メニュー アイテムのタイトルにインテント フィルタの <code>android:label</code> の値を、メニュー アイテムのアイコンにアプリケーション アイコンを使って、メニュー アイテムが追加されます。 + +{@link android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[]) +addIntentOptions()} メソッドによって、追加されたメニュー アイテム数が返されます。 +</p> + +<p class="note"><strong>注:</strong> {@link +android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[]) +addIntentOptions()} を呼び出すとき、最初の引数で指定されたメニュー グループによって、すべてのメニュー アイテムがオーバーライドされます。 +</p> + + +<h3 id="AllowingToAdd">アクティビティを他のメニューに追加できるようにする</h3> + +<p>他のアプリケーションにアクティビティのサービスを提供して、アプリケーションを他のメニューに含めることができるようにすることもできます(前述の役割を逆にする)。 +</p> + +<p>他のアプリケーションのメニューに含まれるようにするには、通常どおりインテント フィルタを定義する必要がありますが、インテント フィルタのカテゴリに、{@link android.content.Intent#CATEGORY_ALTERNATIVE} や {@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} 値を含めるようにしてください。 + + +次に例を示します。</p> +<pre> +<intent-filter label="@string/resize_image"> + ... + <category android:name="android.intent.category.ALTERNATIVE" /> + <category android:name="android.intent.category.SELECTED_ALTERNATIVE" /> + ... +</intent-filter> +</pre> + +<p>インテント フィルタの記述の詳細については、「<a href="/guide/components/intents-filters.html">インテントとインテント フィルタ</a>」をご覧ください。 +</p> + +<p>この方法を使ったサンプル アプリケーションについては、<a href="{@docRoot}resources/samples/NotePad/src/com/example/android/notepad/NoteEditor.html">Note Pad</a> のサンプルコードをご覧ください。 + +</p> diff --git a/docs/html-intl/intl/ja/guide/topics/ui/notifiers/notifications.jd b/docs/html-intl/intl/ja/guide/topics/ui/notifiers/notifications.jd new file mode 100644 index 000000000000..f341256a3225 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/ui/notifiers/notifications.jd @@ -0,0 +1,979 @@ +page.title=通知 +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> +<h2>本書の内容</h2> +<ol> + <li><a href="#Design">設計上の考慮事項</a></li> + <li><a href="#CreateNotification">通知を作成する</a> + <ol> + <li><a href="#Required">必須通知コンテンツ</a></li> + <li><a href="#Optional">省略可能な通知コンテンツと設定</a></li> + <li><a href="#Actions">通知アクション</a></li> + <li><a href="#Priority">通知の優先度</a></li> + <li><a href="#SimpleNotification">簡単な通知を作成する</a></li> + <li><a href="#ApplyStyle">通知に拡張レイアウトを適用する</a></li> + <li><a href="#Compatibility">互換性を確保する</a></li> + </ol> + </li> + <li><a href="#Managing">通知を管理する</a> + <ol> + <li><a href="#Updating">通知を更新する</a></li> + <li><a href="#Removing">通知を削除する</a></li> + </ol> + </li> + <li><a href="#NotificationResponse">アクティビティの開始時にナビゲーションを維持する</a> + <ol> + <li><a href="#DirectEntry">通常のアクティビティの PendingIntent を設定する</a></li> + <li><a href="#ExtendedNotification">特殊なアクティビティの PendingIntent を設定する</a></li> + </ol> + </li> + <li><a href="#Progress">通知に進捗状況を表示する</a> + <ol> + <li><a href="#FixedProgress">範囲固定の進捗インジケーターを表示する</a></li> + <li><a href="#ActivityIndicator">進行中アクティビティ インジケーターを表示する</a></li> + </ol> + </li> + <li><a href="#metadata">通知メタデータ</a></li> + <li><a href="#Heads-up">ヘッドアップ通知</a></li> + <li><a href="#lockscreenNotification">ロック画面通知</a></li> + <ol> + <li><a href="#visibility">可視性を設定する</a></li> + <li><a href="#controllingMedia">ロック画面でのメディア再生をコントロールする</a></li> + </ol> + <li><a href="#CustomNotification">カスタム通知レイアウト</a></li> +</ol> + + <h2>キークラス</h2> + <ol> + <li>{@link android.app.NotificationManager}</li> + <li>{@link android.support.v4.app.NotificationCompat}</li> + </ol> + <h2>ビデオ</h2> + <ol> + <li> + <a href="http://www.youtube.com/watch?v=Yc8YrVc47TI&feature=player_detailpage#t=1672s">Notifications in 4.1</a> + + </li> + </ol> +<h2>関連ドキュメント</h2> +<ol> + <li> + <a href="{@docRoot}design/patterns/notifications.html">Android Design: Notifications</a> + </li> +</ol> +</div> +</div> +<p> + 通知は、アプリケーションの通常の UI 以外で、ユーザーに表示できるメッセージです。システムが通知を発行通知すると、通知はまず<strong>通知エリア</strong>にアイコンで表示されます。 + +通知の詳細を確認するには、ユーザーが<strong>通知ドロワー</strong>を開く必要があります。 +ドロワー通知エリアと通知ドロワーはどちらも、システムによって制御されているエリアであり、ユーザーはいつでも見ることができます。 + +</p> +<img id="figure1" src="{@docRoot}images/ui/notifications/notification_area.png" height="" alt="" /> +<p class="img-caption"> + <strong>図 1.</strong> 通知エリアの通知。 +</p> +<img id="figure2" src="{@docRoot}images/ui/notifications/notification_drawer.png" width="280px" alt="" /> +<p class="img-caption"> + <strong>図 2.</strong> 通知ドロワーの通知。 +</p> + +<p class="note"><strong>注:</strong> 別途記載がある場合を除き、このガイドでは、バージョン 4 の <a href="{@docRoot}tools/support-library/index.html">サポート ライブラリ</a>の {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} クラスについて記述しています。クラス {@link android.app.Notification.Builder Notification.Builder} は、Android 3.0(API レベル 11)で追加されました。 + + + +</p> + +<h2 id="Design">設計上の考慮事項</h2> + +<p>通知は、Android ユーザー インターフェースの重要なパーツであり、独自の設計ガイドラインが設けられています。Android 5.0 (API レベル 21)で導入されたマテリアル デザインの変更は特に重要です。詳細については、「<a href="{@docRoot}training/material/index.html">マテリアル デザイン</a>」をご覧ください。 + + +通知とその操作の設計方法については、<a href="{@docRoot}design/patterns/notifications.html">通知</a>設計ガイドをご覧ください。 +</p> + +<h2 id="CreateNotification">通知を作成する</h2> + +<p>通知のための UI 情報とアクションを、{@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} オブジェクトに指定します。通知自体を作成するには、{@link android.support.v4.app.NotificationCompat.Builder#build NotificationCompat.Builder.build()} を呼び出します。これにより、指定された UI 情報とアクションを含む {@link android.app.Notification} オブジェクトが返されます。 + + + +通知を発行するには、{@link android.app.NotificationManager#notify NotificationManager.notify()} を呼び出して、この {@link android.app.Notification} オブジェクトをシステムに渡します。 + +</p> + +<h3 id="Required">必須通知コンテンツ</h3> +<p> + {@link android.app.Notification} オブジェクトの<em>必須</em>コンテンツは次のとおりです。 +</p> +<ul> + <li> + 小さなアイコン。{@link android.support.v4.app.NotificationCompat.Builder#setSmallIcon setSmallIcon()} で設定します。 + + </li> + <li> + タイトル。{@link android.support.v4.app.NotificationCompat.Builder#setContentTitle setContentTitle()} で設定します。 + + </li> + <li> + 詳細テキスト。{@link android.support.v4.app.NotificationCompat.Builder#setContentText setContentText()} で設定します。 + + </li> +</ul> +<h3 id="Optional">省略可能な通知コンテンツと設定</h3> +<p> + 上記以外のすべての通知設定とコンテンツは省略可能です。省略可能な通知設定とコンテンツについては、{@link android.support.v4.app.NotificationCompat.Builder} のリファレンスをご覧ください。 + +</p> +<!-- ------------------------------------------------------------------------------------------ --> +<h3 id="Actions">通知アクション</h3> +<p> + 通知アクションは省略可能ですが、通知には、少なくとも 1 つのアクションを追加する必要があります。 + アクションは、ユーザーが通知からアプリケーションの {@link android.app.Activity} に直接移動することを可能にします。ユーザーは、移動先で、イベントを確認したりさらに作業を行ったりすることができます。 + + +</p> +<p> + 1 つの通知が複数のアクションを提供することもあります。そのため、ユーザーが通知をクリックした時にトリガーされるアクションを必ず定義してください。通常、このアクションは、アプリケーション内で {@link android.app.Activity} を開きます。 + +また、アラームのスヌーズやテキスト メッセージへの即時返信などの追加のアクションを実行するボタンを、通知に追加することもできます。この機能は、Android 4.1 から利用できるようになりました。 + +追加のアクション ボタンを使用する場合、それらのボタンの機能をアプリの {@link android.app.Activity} で利用できるようにする必要があります。詳細については、<a href="#Compatibility">互換性の確保</a>についてのセクションをご覧ください。 + + +</p> +<p> + {@link android.app.Notification} 内部では、アクションは、アプリケーションで {@link android.app.Activity} を開始する {@link android.content.Intent} が含まれる {@link android.app.PendingIntent} によって定義されます。 + + +{@link android.app.PendingIntent} を操作と関連付けるには、{@link android.support.v4.app.NotificationCompat.Builder} の該当するメソッドを呼び出します。 + +たとえば、ユーザーが通知ドロワーで通知のテキストをクリックしたときに {@link android.app.Activity} を開始する場合、{@link android.support.v4.app.NotificationCompat.Builder#setContentIntent setContentIntent()} を呼び出して {@link android.app.PendingIntent} を追加します。 + + + +</p> +<p> + ユーザーが通知をクリックしたときに {@link android.app.Activity} を開始することは、最も一般的なアクション シナリオです。 +ユーザーが通知を閉じた場合に {@link android.app.Activity} を開始することもできます。 +Android 4.1 以降では、アクション ボタンから {@link android.app.Activity} を開始できます。 +詳細については、{@link android.support.v4.app.NotificationCompat.Builder} のリファレンスをご覧ください。 + +</p> +<!-- ------------------------------------------------------------------------------------------ --> +<h3 id="Priority">通知の優先度</h3> +<p> + 必要に応じて、通知の優先度を設定できます。通知の優先度は、通知の表示方法についての端末 UI へのヒントの役割を果たします。 + + 通知の優先度を設定するには、{@link android.support.v4.app.NotificationCompat.Builder#setPriority(int) otificationCompat.Builder.setPriority()} を呼び出し、{@link android.support.v4.app.NotificationCompat} 優先度定数の 1 つを渡します。 + + +優先度レベルには、{@link android.support.v4.app.NotificationCompat#PRIORITY_MIN} (-2)から {@link android.support.v4.app.NotificationCompat#PRIORITY_MAX} (2)までの 5 段階あります。優先度レベルが設定されていない場合、優先度はデフォルト値の {@link android.support.v4.app.NotificationCompat#PRIORITY_DEFAULT} (0)になります。 + + + + + +</p> +<p> 適切な優先順位の設定方法については、<a href="{@docRoot}design/patterns/notifications.html">通知</a>設計ガイドの「Correctly set and manage notification priority」をご覧ください。 + + +</p> +<!-- ------------------------------------------------------------------------------------------ --> +<h3 id="SimpleNotification">簡単な通知を作成する</h3> +<p> + 次のスニペットでは、ユーザーに通知がクリックされたときに起動するアクティビティを指定する簡単な通知を作成しています。 +このコードでは {@link android.support.v4.app.TaskStackBuilder} オブジェクトを作成し、そのオブジェクトを使用して、アクションのための {@link android.app.PendingIntent} を作成していることにご注意ください。 + +詳細は、<a href="#NotificationResponse">アクティビティの開始時のナビゲーションの維持</a>セクションで説明しています。 + + +</p> +<pre> +NotificationCompat.Builder mBuilder = + new NotificationCompat.Builder(this) + .setSmallIcon(R.drawable.notification_icon) + .setContentTitle("My notification") + .setContentText("Hello World!"); +// Creates an explicit intent for an Activity in your app +Intent resultIntent = new Intent(this, ResultActivity.class); + +// The stack builder object will contain an artificial back stack for the +// started Activity. +// This ensures that navigating backward from the Activity leads out of +// your application to the Home screen. +TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); +// Adds the back stack for the Intent (but not the Intent itself) +stackBuilder.addParentStack(ResultActivity.class); +// Adds the Intent that starts the Activity to the top of the stack +stackBuilder.addNextIntent(resultIntent); +PendingIntent resultPendingIntent = + stackBuilder.getPendingIntent( + 0, + PendingIntent.FLAG_UPDATE_CURRENT + ); +mBuilder.setContentIntent(resultPendingIntent); +NotificationManager mNotificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); +// mId allows you to update the notification later on. +mNotificationManager.notify(mId, mBuilder.build()); +</pre> +<p>これで、ユーザーに通知が行われました。</p> +<!-- ------------------------------------------------------------------------------------------ --> +<h3 id="ApplyStyle">通知に拡張レイアウトを適用する</h3> +<p> + 通知を拡張ビューに表示するには、まず {@link android.support.v4.app.NotificationCompat.Builder} オブジェクトを任意の標準ビュー オプションで作成します。 + +次に、{@link android.support.v4.app.NotificationCompat.Builder#setStyle Builder.setStyle()} を拡張レイアウト オブジェクトを引数に指定して呼び出します。 + +</p> +<p> + 通知の拡張機能は、Android 4.1 より前のバージョンでは利用できないことにご注意ください。Android 4.1 とそれ以前のプラットフォームでの通知の処理方法については、<a href="#Compatibility">互換性の確保</a>についてのセクションをご覧ください。 + + +</p> +<p> + たとえば、次のコード スニペットでは、先ほどのスニペットで作成した通知を変更して、拡張レイアウトを使用するようにしています。 + +</p> +<pre> +NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this) + .setSmallIcon(R.drawable.notification_icon) + .setContentTitle("Event tracker") + .setContentText("Events received") +NotificationCompat.InboxStyle inboxStyle = + new NotificationCompat.InboxStyle(); +String[] events = new String[6]; +// Sets a title for the Inbox in expanded layout +inboxStyle.setBigContentTitle("Event tracker details:"); +... +// Moves events into the expanded layout +for (int i=0; i < events.length; i++) { + + inboxStyle.addLine(events[i]); +} +// Moves the expanded layout object into the notification object. +mBuilder.setStyle(inBoxStyle); +... +// Issue the notification here. +</pre> + +<h3 id="Compatibility">互換性を確保する</h3> + +<p> + 通知機能をセットするメソッドはサポート ライブラリのクラス {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} に登録されていますが、特定のバージョンですべての通知機能が利用できるわけではありません。 + + + たとえば、アクション ボタンは拡張通知の機能ですが、拡張通知自体が Android 4.1 以上でしか利用できないため、Android 4.1 以上でのみ表示されます。 + + +</p> +<p> + 可能な限り互換性を確保するには、{@link android.support.v4.app.NotificationCompat NotificationCompat} とそのサブクラス、特に {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} を使用して通知を作成します。 + + +さらに、通知の実装時に次の処理を行ってください。 +</p> +<ol> + <li> + ユーザーが利用しているバージョンにかかわらず、通知機能のすべてをすべてのユーザーに提供します。 +それには、アプリの {@link android.app.Activity} からすべての機能が利用できるようにする必要があります。このために、新しい {@link android.app.Activity} を追加した方がよい場合もあります。 + + + <p> + たとえば、{@link android.support.v4.app.NotificationCompat.Builder#addAction addAction()} を使用してメディア再生の開始と停止を行うコントロールを提供する場合、まずこのコントロールをアプリの {@link android.app.Activity} に実装します。 + + + + </p> + </li> + <li> + ユーザーが通知をクリックしたときにその {@link android.app.Activity} が起動するようにして、すべてのユーザーがその機能にアクセスできるようにします。 +それには、{@link android.app.Activity} のための {@link android.app.PendingIntent} を作成する必要があります。 + +{@link android.support.v4.app.NotificationCompat.Builder#setContentIntent setContentIntent()} を呼び出し、{@link android.app.PendingIntent} を通知に追加してください。 + + + </li> + <li> + 利用したい拡張通知機能を通知に追加します。追加した機能は、ユーザーが通知をクリックしたときに開始する {@link android.app.Activity} でも利用できることにご注意ください。 + + + </li> +</ol> + + +<!-- ------------------------------------------------------------------------------------------ --> +<!-- ------------------------------------------------------------------------------------------ --> +<h2 id="Managing">通知を管理する</h2> +<p> + 同じタイプのイベントのために通知を複数回発行する場合、そのたびに新しい通知を作成することは避ける必要があります。 +新しい通知を作成する代わりに、以前の通知を更新して一部の値を変更することやいくつかの値を追加することを検討してください。 + +</p> +<p> + たとえば、Gmail は新しいメールが届いたことを、未読メッセージの数を増やし通知に各メールの概要を追加することで、ユーザーに通知します。 +これは、通知の「スタッキング」と呼ばれています。詳細については、<a href="{@docRoot}design/patterns/notifications.html">通知</a>設計ガイドをご覧ください。 + + +</p> +<p class="note"> + <strong>注:</strong> この Gmail 機能には、「受信トレイ」の拡張レイアウトが必要です。これは、Android 4.1 以降で利用可能な拡張通知機能の 1 つです。 + +</p> +<p> + 次のセクションでは、通知の更新方法と通知の削除方法を説明します。 +</p> +<h3 id="Updating">通知を更新する</h3> +<p> + 後で更新できるように通知をセットアップするには、{@link android.app.NotificationManager#notify(int, android.app.Notification) NotificationManager.notify()} を呼び出し、通知 ID を指定して通知を発行します。 + + 発行後に通知を更新するには、{@link android.support.v4.app.NotificationCompat.Builder} オブジェクトを更新または作成し、そのオブジェクトから {@link android.app.Notification} オブジェクトをビルドし、以前使用した ID と同じ ID で {@link android.app.Notification} を発行します。 + + +以前の通知がそのまま表示されている場合は、{@link android.app.Notification} オブジェクトのコンテンツから、その通知が更新されます。 + +以前の通知が閉じられている場合は、代わりに新しい通知が作成されます。 + +</p> +<p> + 次のスニペットでは、発生したイベントの数を反映するために通知が更新されています。 +このスニペットは通知をスタックし、概要を表示します。 +</p> +<pre> +mNotificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); +// Sets an ID for the notification, so it can be updated +int notifyID = 1; +mNotifyBuilder = new NotificationCompat.Builder(this) + .setContentTitle("New Message") + .setContentText("You've received new messages.") + .setSmallIcon(R.drawable.ic_notify_status) +numMessages = 0; +// Start of a loop that processes data and then notifies the user +... + mNotifyBuilder.setContentText(currentText) + .setNumber(++numMessages); + // Because the ID remains unchanged, the existing notification is + // updated. + mNotificationManager.notify( + notifyID, + mNotifyBuilder.build()); +... +</pre> + +<!-- ------------------------------------------------------------------------------------------ --> +<h3 id="Removing">通知を削除する</h3> +<p> + 次のいずれかが発生するまで、通知は表示され続けます。 +</p> +<ul> + <li> + ユーザーが通知を個別に閉じるか、[Clear All] を使用して通知をすべて閉じる(通知を削除することができる場合)。 + + </li> + <li> + 作成時に {@link android.support.v4.app.NotificationCompat.Builder#setAutoCancel setAutoCancel()} の呼び出しが行われた通知を、ユーザーがクリックする。 + + + </li> + <li> + 特定の通知 ID を指定して {@link android.app.NotificationManager#cancel(int) cancel()} を呼び出す(このメソッドは、実行中の処理に関する通知も削除します)。 + + </li> + <li> + {@link android.app.NotificationManager#cancelAll() cancelAll()} を呼び出す(このメソッドは、それまでに発行したすべての通知を削除します)。 + + </li> +</ul> +<!-- ------------------------------------------------------------------------------------------ --> +<!-- ------------------------------------------------------------------------------------------ --> +<h2 id="NotificationResponse">アクティビティの開始時にナビゲーションを維持する</h2> +<p> + 通知から {@link android.app.Activity} を開始する場合、ユーザーが期待するナビゲーション操作を変えないようにする必要があります。 +たとえば、 <i>[戻る]</i> がクリックされた場合、アプリケーションの標準的なワークフローでは、ホーム画面に戻る必要があります。また、 + <i>[最近使ったアプリ]</i> がクリックされた場合、{@link android.app.Activity} を別のタスクとして表示する必要があります。 +このナビゲーション操作を変えないようにするには、新たなタスクで {@link android.app.Activity} を開始する必要があります。 +{@link android.app.PendingIntent} を設定して新たなタスクを生成する方法は、開始する {@link android.app.Activity} の性質によって異なります。 + +通常は、次の 2 つの場合があります。 +</p> +<dl> + <dt> + 通常のアクティビティ + </dt> + <dd> + アプリケーションの標準的なワークフローの一部である {@link android.app.Activity} を開始します。 +この場合、{@link android.app.PendingIntent} を設定して新たなタスクを開始し、{@link android.app.PendingIntent} にバックスタックを提供します。これにより、アプリケーションの標準的な + + <i>「戻る」</i> 動作を再現します。 + <p> + Gmail アプリからの通知は、このタイプのアクティビティの一例です。1 つの電子メール メッセージの通知をクリックすると、メッセージそれ自体が表示されます。 +[<b>戻る</b>] をタップすると、通知から移動してきたのでなくホーム画面から Gmail に移動してきたかのように、Gmail からホーム画面に戻ります。 + + + </p> + <p> + これは、通知のタップ時に使用していたアプリケーションに関係なく発生します。 +たとえば、Gmail でメッセージを作成しているときに、1 つのメールの通知をクリックすると、すぐにそのメールに移動します。 +その場合、 <i>[戻る]</i> + をタップすると、作成中のメッセージに戻るのではなく、受信トレイ、ホーム画面の順に移動します。 + + </p> + </dd> + <dt> + 特殊なアクティビティ + </dt> + <dd> + ユーザーは、この {@link android.app.Activity} を、通知から開始した場合のみ見ることができます。 + ある意味では、通知自体に表示するのは難しい情報を提供することで、この {@link android.app.Activity} が通知を拡張しているということができます。 +このタイプのアクティビティでは、{@link android.app.PendingIntent} を設定して新たなタスクを開始します。 +ただし、開始した {@link android.app.Activity} はアプリケーションのアクティビティ フローには含まれていないので、バックスタックを作成する必要はありません。 + +たとえば、 <i>[戻る]</i> をクリックすると、ユーザーはホーム画面に移動します。 + + </dd> +</dl> +<!-- ------------------------------------------------------------------------------------------ --> +<h3 id="DirectEntry">通常のアクティビティの PendingIntent を設定する</h3> +<p> + ダイレクト エントリの {@link android.app.Activity} を開始する {@link android.app.PendingIntent} を設定するには、次の手順に従います。 + +</p> +<ol> + <li> + マニフェストに、アプリケーションの {@link android.app.Activity} の階層を定義します。 + <ol style="list-style-type: lower-alpha;"> + <li> + Android 4.0.3 以前へのサポートを追加します。これには、<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data></a></code> 要素を <code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> の子として追加して、開始する {@link android.app.Activity} の親を指定します。 + + + + + <p> + この要素に、<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#nm">android:name</a>="android.support.PARENT_ACTIVITY"</code> を設定します。 + + <code><parent_activity_name></code> が親 <code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> 要素の <code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#nm">android:name</a></code> の値の場合は、<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#val">android:value</a>="<parent_activity_name>"</code> を設定します。 + + + + + +例については、以下の XML をご覧ください。 + </p> + </li> + <li> + また、Android 4.1 以降のサポートを追加します。これには、開始する {@link android.app.Activity} の <code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> 要素に、<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#parent">android:parentActivityName</a></code> 属性を追加します。 + + + + + </li> + </ol> + <p> + 最終的な XML は、次のようになります。 + </p> +<pre> +<activity + android:name=".MainActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> +</activity> +<activity + android:name=".ResultActivity" + android:parentActivityName=".MainActivity"> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value=".MainActivity"/> +</activity> +</pre> + </li> + <li> + {@link android.app.Activity} を開始する {@link android.content.Intent} に基づくバックスタックを作成します。 + + <ol style="list-style-type: lower-alpha;"> + <li> + {@link android.app.Activity} を開始する {@link android.content.Intent} を作成します。 + </li> + <li> + {@link android.app.TaskStackBuilder#create TaskStackBuilder.create()} を呼び出して、スタック ビルダーを作成します。 + + </li> + <li> + {@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()} を呼び出し、バックスタックをスタック ビルダーに追加します。 + + マニフェストに定義した階層のそれぞれの {@link android.app.Activity} ごとに、バックスタックに、{@link android.app.Activity} を開始する {@link android.content.Intent} が含まれます。 + +このメソッドは、新たなタスクでスタックを開始するためのフラグも追加します。 + + <p class="note"> + <strong>注:</strong> {@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()} の引数は開始した {@link android.app.Activity} への参照ですが、このメソッドの呼び出しによって、{@link android.app.Activity} を開始する {@link android.content.Intent} が追加されることはありません。 + + + +追加は、次の d. で行われます。 + </p> + </li> + <li> + {@link android.support.v4.app.TaskStackBuilder#addNextIntent addNextIntent()} を呼び出して、通知から {@link android.app.Activity} を開始する {@link android.content.Intent} を追加します。 + + + a. で作成した {@link android.content.Intent} を、引数として {@link android.support.v4.app.TaskStackBuilder#addNextIntent addNextIntent()} に渡します。 + + + </li> + <li> + 必要に応じて、{@link android.support.v4.app.TaskStackBuilder#editIntentAt TaskStackBuilder.editIntentAt()} を呼び出し、スタック上の {@link android.content.Intent} オブジェクトに引数を追加します。 + +これは、場合によっては、ターゲット {@link android.app.Activity} に、ユーザーが + + <i>[戻る]</i> を使って移動したときに、適切なデータが表示されるようにするために必要です。 + </li> + <li> + {@link android.support.v4.app.TaskStackBuilder#getPendingIntent getPendingIntent()} を呼び出し、このバックスタックのための {@link android.app.PendingIntent} を取得します。 + + この {@link android.app.PendingIntent} は、{@link android.support.v4.app.NotificationCompat.Builder#setContentIntent setContentIntent()} の引数として使用できます。 + + + </li> + </ol> + </li> +</ol> +<p> + 次のコード スニペットでは、上記の処理を行っています。 +</p> +<pre> +... +Intent resultIntent = new Intent(this, ResultActivity.class); +TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); +// Adds the back stack +stackBuilder.addParentStack(ResultActivity.class); +// Adds the Intent to the top of the stack +stackBuilder.addNextIntent(resultIntent); +// Gets a PendingIntent containing the entire back stack +PendingIntent resultPendingIntent = + stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); +... +NotificationCompat.Builder builder = new NotificationCompat.Builder(this); +builder.setContentIntent(resultPendingIntent); +NotificationManager mNotificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); +mNotificationManager.notify(id, builder.build()); +</pre> +<!-- ------------------------------------------------------------------------------------------ --> +<h3 id="ExtendedNotification">特殊なアクティビティの PendingIntent を設定する</h3> +<p> + 次のセクションでは、特殊なアクティビティのための {@link android.app.PendingIntent} の設定方法を説明します。 + +</p> +<p> + 特殊な {@link android.app.Activity} はバックスタックを必要としません。そのため、マニフェストにその {@link android.app.Activity} の階層を定義する必要はありません。また、バックスタックを作成するために {@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()} を呼び出す必要もありません。 + + + +代わりに、マニフェストを利用して {@link android.app.Activity} のタスク オプションを設定し、{@link android.app.PendingIntent#getActivity getActivity()} を呼び出して {@link android.app.PendingIntent} を作成します。 + + +</p> +<ol> + <li> + マニフェストで、{@link android.app.Activity} の <code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> 要素に、次の属性を追加します。 + + + <dl> + <dt> +<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#nm">android:name</a>="<i>activityclass</i>"</code> + </dt> + <dd> + アクティビティの完全修飾クラス名。 + </dd> + <dt> +<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">android:taskAffinity</a>=""</code> + </dt> + <dd> + コードにセットした {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_NEW_TASK} フラグと組み合わせて、{@link android.app.Activity} がアプリケーションのデフォルトのタスクに入ることがないようにします。 + + +アプリケーションのアフィニティがデフォルトのままの既存タスクは影響を受けません。 + + </dd> + <dt> +<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#exclude">android:excludeFromRecents</a>="true"</code> + </dt> + <dd> + 新しいタスクを、 <i>[最近使ったアプリ]</i> から除外し、ユーザーが新しいタスクに間違って戻ることがないようにします。 + + </dd> + </dl> + <p> + 次のスニペットは、この要素を示しています。 + </p> +<pre> +<activity + android:name=".ResultActivity" +... + android:launchMode="singleTask" + android:taskAffinity="" + android:excludeFromRecents="true"> +</activity> +... +</pre> + </li> + <li> + 通知をビルドし発行します。 + <ol style="list-style-type: lower-alpha;"> + <li> + {@link android.app.Activity} を開始する {@link android.content.Intent} を作成します。 + + </li> + <li> + フラグ {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_NEW_TASK} と {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TASK FLAG_ACTIVITY_CLEAR_TASK} を指定して {@link android.content.Intent#setFlags setFlags()} を呼び出し、{@link android.app.Activity} を新しい空のタスクで開始するように設定します。 + + + + + </li> + <li> + {@link android.content.Intent} に、必要に応じてオプションを設定します。 + </li> + <li> + {@link android.app.PendingIntent#getActivity getActivity()} を呼び出し、{@link android.content.Intent} から {@link android.app.PendingIntent} を作成します。 + + この {@link android.app.PendingIntent} は、{@link android.support.v4.app.NotificationCompat.Builder#setContentIntent setContentIntent()} の引数として使用できます。 + + + </li> + </ol> + <p> + 次のコード スニペットでは、上記の処理を行っています。 + </p> +<pre> +// Instantiate a Builder object. +NotificationCompat.Builder builder = new NotificationCompat.Builder(this); +// Creates an Intent for the Activity +Intent notifyIntent = + new Intent(this, ResultActivity.class); +// Sets the Activity to start in a new, empty task +notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_CLEAR_TASK); +// Creates the PendingIntent +PendingIntent notifyPendingIntent = + PendingIntent.getActivity( + this, + 0, + notifyIntent, + PendingIntent.FLAG_UPDATE_CURRENT +); + +// Puts the PendingIntent into the notification builder +builder.setContentIntent(notifyPendingIntent); +// Notifications are issued by sending them to the +// NotificationManager system service. +NotificationManager mNotificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); +// Builds an anonymous Notification object from the builder, and +// passes it to the NotificationManager +mNotificationManager.notify(id, builder.build()); +</pre> + </li> +</ol> +<!-- ------------------------------------------------------------------------------------------ --> +<!-- ------------------------------------------------------------------------------------------ --> +<h2 id="Progress">通知に進捗状況を表示する</h2> +<p> + 通知には、進行中の処理の状況をユーザーに示すアニメーション表示の進捗インジケーターを表示できます。 +その処理にどれくらいの時間がかかるかと、ある時点でその処理がどれだけ完了しているかを見積もることができる場合、「確定(determinate)」タイプのインジケーター(プログレスバー)を使用します。 + +処理にかかる時間を見積もることができない場合は、「不確定(indeterminate)」タイプのインジケーター(アクティビティ インジケーター)を使用します。 + +</p> +<p> + 進捗インジケーターは、{@link android.widget.ProgressBar} クラスのプラットフォーム実装で表示されます。 + +</p> +<p> + Android 4.0 以降のプラットフォーム上で進捗インジケーターを使用するには、{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()} を呼び出します。 +それ以前のバージョンでは、{@link android.widget.ProgressBar} ビューを含むカスタム通知レイアウトを作成する必要があります。 + + +</p> +<p> + 次のセクションでは、{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()} を使用して、通知に進捗状況を表示する方法を説明します。 + +</p> +<!-- ------------------------------------------------------------------------------------------ --> +<h3 id="FixedProgress">範囲固定の進捗インジケーターを表示する</h3> +<p> + 確定プログレスバーを表示するには、{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(max, progress, false)} を呼び出して通知にバーを追加してから、その通知を発行します。 + +処理の進行に合わせて、<code>progress</code> の値を増やし、通知を更新します。 +処理の最後には、<code>progress</code> が <code>max</code> と等しくなります。 +{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()} を呼び出す一般的な方法は、<code>max</code> に 100 を設定して、処理の「進捗度」の値である <code>progress</code> の値を増やすことです。 + + + +</p> +<p> + 処理の完了時には、プログレスバーを表示したままにすることも、削除することもできます。いずれの場合でも、通知のテキストを更新して、処理が完了したことを示すことを忘れないでください。 + + プログレスバーを削除するには、{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, false)} を呼び出します。 + +次に例を示します。 +</p> +<pre> +... +mNotifyManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); +mBuilder = new NotificationCompat.Builder(this); +mBuilder.setContentTitle("Picture Download") + .setContentText("Download in progress") + .setSmallIcon(R.drawable.ic_notification); +// Start a lengthy operation in a background thread +new Thread( + new Runnable() { + @Override + public void run() { + int incr; + // Do the "lengthy" operation 20 times + for (incr = 0; incr <= 100; incr+=5) { + // Sets the progress indicator to a max value, the + // current completion percentage, and "determinate" + // state + mBuilder.setProgress(100, incr, false); + // Displays the progress bar for the first time. + mNotifyManager.notify(0, mBuilder.build()); + // Sleeps the thread, simulating an operation + // that takes time + try { + // Sleep for 5 seconds + Thread.sleep(5*1000); + } catch (InterruptedException e) { + Log.d(TAG, "sleep failure"); + } + } + // When the loop is finished, updates the notification + mBuilder.setContentText("Download complete") + // Removes the progress bar + .setProgress(0,0,false); + mNotifyManager.notify(ID, mBuilder.build()); + } + } +// Starts the thread by calling the run() method in its Runnable +).start(); +</pre> + +<!-- ------------------------------------------------------------------------------------------ --> +<h3 id="ActivityIndicator">進行中アクティビティ インジケーターを表示する</h3> +<p> + 不確定アクティビティ インジケーターを表示するには、{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, true)}(最初の 2 つの引数は無視されます)を使用して通知に追加し、通知を発行します。 + +このインジケーターの外見は、アニメーションが常時表示されていること以外はプログレスバーと同じです。 + +</p> +<p> + 処理の開始時に通知を発行します。通知を変更するまで、アニメーションは表示され続けます。 +処理が完了したら、{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, false)} を呼び出し、次に通知を更新してアクティビティ インジケーターを削除します。 + + + この操作を行わないと、処理が完了してもアニメーションが表示され続けることになります。また、通知のテキストを更新して、処理が完了したことを示すことを忘れないでください。 + +</p> +<p> + アクティビティ インジケーターの仕組みについては、上記のスニペットをご覧ください。次のコード行を探します。 +</p> +<pre> +// Sets the progress indicator to a max value, the current completion +// percentage, and "determinate" state +mBuilder.setProgress(100, incr, false); +// Issues the notification +mNotifyManager.notify(0, mBuilder.build()); +</pre> +<p> + 見つけたコードを次のコードに置き換えます。 +</p> +<pre> + // Sets an activity indicator for an operation of indeterminate length +mBuilder.setProgress(0, 0, true); +// Issues the notification +mNotifyManager.notify(0, mBuilder.build()); +</pre> + +<h2 id="metadata">通知メタデータ</h2> + +<p>通知は、次の {@link android.support.v4.app.NotificationCompat.Builder} メソッドを使用して割り当てるメタデータによって、ソートされることがあります。 +</p> + +<ul> + <li>{@link android.support.v4.app.NotificationCompat.Builder#setCategory(java.lang.String) setCategory()} は、端末が優先モードの場合のアプリ通知の処理方法を設定します(たとえば、通知が着信、インスタント メッセージ、アラームを知らせる場合など)。 + +</li> + <li>{@link android.support.v4.app.NotificationCompat.Builder#setPriority(int) setPriority()} は優先度フィールドに {@code PRIORITY_MAX} または {@code PRIORITY_HIGH} が設定されている通知が、音声または振動を発する通知の場合、小さなフローティング ウィンドウに表示されるようにします。 + +</li> + <li>{@link android.support.v4.app.NotificationCompat.Builder#addPerson(java.lang.String) addPerson()} を使用すると、通知に人物のリストを追加できます。 +アプリは、このリストを利用して、システムに合図を送り、特定の人達からの通知をグループ化したり、それらの人達からの通知を重要度が高い通知としてランク付けしたりします。 + +</li> +</ul> + +<div class="figure" style="width:230px"> + <img src="{@docRoot}images/ui/notifications/heads-up.png" alt="" width="" height="" id="figure3" /> + <p class="img-caption"> + <strong>図 3.</strong> ヘッドアップ通知を表示する全画面アクティビティ + </p> +</div> + +<h2 id="Heads-up">ヘッドアップ通知</h2> + +<p>Android 5.0(API レベル 21)では、端末がアクティブな場合(端末がロックされておらず、画面がオンになっている場合)に、小さなフローティング ウィンドウ(<em>ヘッドアップ通知</em>とも呼ばれます)に通知を表示することができます。 + +これらの通知は、ヘッドアップ通知がアクション ボタンも表示すること以外は、通知をコンパクトにしたものと同じように表示されます。 + +使用中のアプリから移動しなくても、ユーザーは、ヘッドアップ通知に反応したりヘッドアップ通知を閉じたりすることができます。 +</p> + +<p>ヘッドアップ通知のトリガーとなる条件には、たとえば以下のようなものがあります。</p> + +<ul> + <li>ユーザーのアクティビティが全画面モードであること(アプリが {@link android.app.Notification#fullScreenIntent} を使用していること)、または +</li> + <li>その通知が高い優先度を持ち、着信音または振動を使用していること +</li> +</ul> + +<h2 id="lockscreenNotification">ロック画面通知</h2> + +<p>Android 5.0(API レベル 21)では、通知をロック画面に表示できるようになりました。 +アプリは、この機能を利用してメディア再生コントロールやその他の一般的なアクションを提供できます。 +ユーザーは設定でロック画面に通知を表示するかどうか選ぶことができます。また、開発者も、アプリからの通知をロック画面に表示するかどうか指定できます。 +</p> + +<h3 id="visibility">可視性を設定する</h3> + +<p>アプリでは、保護されたロック画面に表示される通知の表示の詳細レベルをコントロールできます。 +{@link android.support.v4.app.NotificationCompat.Builder#setVisibility(int) setVisibility()} を呼び出し、次の値のいずれかを指定してください。 +</p> + +<ul> + <li>{@link android.support.v4.app.NotificationCompat#VISIBILITY_PUBLIC} では、通知のフルコンテンツが表示されます。 +</li> + <li>{@link android.support.v4.app.NotificationCompat#VISIBILITY_SECRET} では、ロック画面に、通知のいずれの部分も表示しません。 +</li> + <li>{@link android.support.v4.app.NotificationCompat#VISIBILITY_PRIVATE} では、通知のアイコンやコンテンツのタイトルなどの基本的な情報を表示しますが、通知のフルコンテンツは表示されません。 +</li> +</ul> + +<p>{@link android.support.v4.app.NotificationCompat#VISIBILITY_PRIVATE} を設定すると、特定の内容を非表示にした代替バージョンの通知コンテンツを提供できます。 +たとえば、SMS アプリで <em>3 件の新しいテキスト メッセージがある</em>ことを示す通知を表示する場合に、メッセージ コンテンツと送信者を非表示にできます。 + +この代替通知を提供するには、{@link android.support.v4.app.NotificationCompat.Builder} を使用してまず置換用の通知を作成し、 +プライベート通知オブジェクトを作成したら、その置換用の通知をプライベート通知オブジェクトに {@link android.support.v4.app.NotificationCompat.Builder#setPublicVersion(android.app.Notification) setPublicVersion()} メソッドを使用してアタッチしてください。 + + +</p> + +<h3 id="controllingMedia">ロック画面でのメディア再生をコントロールする</h3> + +<p>Android 5.0(API レベル 21)では、{@link android.media.RemoteControlClient} を使用したメディア コントロールは、ロック画面に表示されません。このクラスは廃止済みです。 +代わりに、{@link android.app.Notification.MediaStyle} テンプレートと {@link android.app.Notification.Builder#addAction(android.app.Notification.Action) addAction()} メソッドを使用します。このメソッドは、アクションをクリックできるアイコンに変換します。 + + +</p> + +<p class="note"><strong>注:</strong> このテンプレートと {@link android.app.Notification.Builder#addAction(android.app.Notification.Action) addAction()} メソッドはサポート ライブラリには含まれません。そのため、これらの機能は Android 5.0 以降でのみ動作します。 + +</p> + +<p>Android 5.0 でロック画面にメディア再生コントロールを表示するには、可視性を上記の{@link android.support.v4.app.NotificationCompat#VISIBILITY_PUBLIC} に設定します。 +その後、次のサンプルコードに従って、アクションを追加し {@link android.app.Notification.MediaStyle} テンプレートを設定します。 + +</p> + +<pre> +Notification notification = new Notification.Builder(context) + // Show controls on lock screen even when user hides sensitive content. + .setVisibility(Notification.VISIBILITY_PUBLIC) + .setSmallIcon(R.drawable.ic_stat_player) + // Add media control buttons that invoke intents in your media service + .addAction(R.drawable.ic_prev, "Previous", prevPendingIntent) // #0 + .addAction(R.drawable.ic_pause, "Pause", pausePendingIntent) // #1 + .addAction(R.drawable.ic_next, "Next", nextPendingIntent) // #2 + // Apply the media style template + .setStyle(new Notification.MediaStyle() + .setShowActionsInCompactView(1 /* #1: pause button */) + .setMediaSession(mMediaSession.getSessionToken()) + .setContentTitle("Wonderful music") + .setContentText("My Awesome Band") + .setLargeIcon(albumArtBitmap) + .build(); +</pre> + +<p class="note"><strong>注:</strong> {@link android.media.RemoteControlClient} の廃止は、他の点でもメディアのコントロールに影響を与えています。 +新しい API でのメディア セッションの管理と再生のコントロールの詳細については、<a href="{@docRoot}about/versions/android-5.0.html#MediaPlaybackControl">メディア再生コントロール</a>をご覧ください。 + +</p> + + +<!-- ------------------------------------------------------------------------------------------ --> +<h2 id="CustomNotification">カスタム通知レイアウト</h2> +<p> + 通知フレームワークでは、カスタム通知レイアウトを定義することができます。カスタム通知レイアウトは、{@link android.widget.RemoteViews} オブジェクトに通知の外観を定義します。 + + カスタム レイアウトの通知は通常の通知と似ていますが、XML レイアウト ファイルに定義された {@link android.widget.RemoteViews} が使用されています。 + +</p> +<p> + カスタム通知レイアウトで使用できる高さは、通知ビューによって異なります。標準ビュー レイアウトでは 64 dp までで、拡張ビュー レイアウトでは 256 dp までです。 + +</p> +<p> + カスタム通知レイアウトを定義するには、まず、XML レイアウト ファイルをインフレートする {@link android.widget.RemoteViews} オブジェクトのインスタンスを作成します。 +次に、{@link android.support.v4.app.NotificationCompat.Builder#setContentTitle setContentTitle()} などのメソッドを呼び出す代わりに、{@link android.support.v4.app.NotificationCompat.Builder#setContent setContent()} を呼び出します。 + + +コンテンツの詳細をカスタム通知に設定するには、{@link android.widget.RemoteViews} のメソッドを使用してビューの子の値を設定します。 + + +</p> +<ol> + <li> + 別ファイルに通知の XML レイアウトを作成します。ファイル名はどのような名前でもかまいませんが、拡張子は必ず <code>.xml</code> にします。 + + </li> + <li> + アプリで、{@link android.widget.RemoteViews} メソッドを使用して、通知のアイコンとテキストを定義します。 +{@link android.support.v4.app.NotificationCompat.Builder#setContent setContent()} を呼び出して、この {@link android.widget.RemoteViews} オブジェクトを {@link android.support.v4.app.NotificationCompat.Builder} にセットします。 + +{@link android.widget.RemoteViews} オブジェクトに背景 {@link android.graphics.drawable.Drawable} を設定することは避けてください。文字が読めなくなる場合があります。 + + + </li> +</ol> +<p> + {@link android.widget.RemoteViews} クラスには、通知のレイアウトに {@link android.widget.Chronometer} や {@link android.widget.ProgressBar} を簡単に追加できるメソッドも含まれています。 + +通知のカスタム レイアウトの作成についての詳細は、{@link android.widget.RemoteViews} のリファレンスをご覧ください。 + +</p> +<p class="caution"> + <strong>警告:</strong> カスタム通知レイアウトを使用する場合、そのカスタム通知レイアウトがさまざまな画面の向きと解像度で適切に表示されるかどうか、十分に注意してください。 +すべてのビュー レイアウトでさまざまな画面の向きと解像度への対応に注意する必要がありますが、通知ドロワーのスペースが限られているため、通知では特に注意する必要があります。 + +カスタム レイアウトは複雑にし過ぎないようにしてください。また、必ずさまざまな構成でテストするようにしてください。 + +</p> +<!-- ------------------------------------------------------------------------------------------ --> +<h4>カスタム通知のテキストにスタイル リソースを使用する</h4> +<p> + カスタム通知のテキストには、必ずスタイル リソースを使用してください。通知の背景色は端末やバージョンによって異なりますが、スタイル リソースを使用することで、この問題に対処できます。 + +Android 2.3 以降では、標準の通知レイアウトのテキストのスタイルは、システムによって定義されています。 +Android 2.3 以降を対象とするアプリケーションで同じスタイルを使用する場合は、表示される背景でテキストを読むことができるかご確認ください。 + +</p> diff --git a/docs/html-intl/intl/ja/guide/topics/ui/overview.jd b/docs/html-intl/intl/ja/guide/topics/ui/overview.jd new file mode 100644 index 000000000000..08d93560cb4e --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/ui/overview.jd @@ -0,0 +1,71 @@ +page.title=UI の概要 +@jd:body + + +<p>Android アプリのすべてのユーザー インターフェース エレメントは、{@link android.view.View} と {@link android.view.ViewGroup} オブジェクトを使ってビルドされています。 +{@link android.view.View} は、ユーザーが相互操作できる、画面上で何かを描画するオブジェクトです。 +{@link android.view.ViewGroup} は、インターフェースのレイアウトを定義するために、その他の {@link android.view.View}(と {@link android.view.ViewGroup})オブジェクトを保持するオブジェクトです。 + +</p> + +<p>Android では、共通の入力コントロール(ボタンやテキスト フィールドなど)とさまざまなレイアウトモデル(線形レイアウトや相対レイアウトなど)を提供する {@link android.view.View} と {@link android.view.ViewGroup} サブクラスの両方が提供されています。 + +</p> + + +<h2 id="Layout">ユーザー インターフェースのレイアウト</h2> + +<p>アプリの各コンポーネントのユーザー インターフェースは、図 1 のように、{@link +android.view.View} と {@link android.view.ViewGroup} オブジェクトの階層を使って定義されます。各ビューグループは、子ビューをまとめる非表示のコンテナであり、子ビューは UI の一部を描画する入力コントロールまたはその他のウィジェットです。この階層ツリーは、必要に応じて単純にまたは複雑にすることができますが、パフォーマンスの点では単純な階層ツリーが最適です。 + + + +</p> + +<img src="{@docRoot}images/viewgroup.png" alt="" /> +<p class="img-caption"><strong>図 1.</strong> UI レイアウトを定義するビュー階層の図。 +</p> + +<p>レイアウトを宣言するには、コードで {@link android.view.View} オブジェクトのインスタンスを作成してツリーのビルドを始めることができますが、レイアウトを定義する最も簡単で効率的な方法は XML ファイルを使用することです。XML では HTML のように、人が見える構造でレイアウトが提供されます。 + +</p> + +<p>ビューの XML 要素名は、それが表す Android クラスによって決まります。<code><TextView></code> 要素は UI で {@link android.widget.TextView} ウィジェットを、<code><LinearLayout></code> 要素は {@link android.widget.LinearLayout} ビューグループを作成します。 + + + </p> + +<p>たとえば、テキストビューとボタンを含む単純な縦レイアウトは次のようになります。</p> +<pre> +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" > + <TextView android:id="@+id/text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="I am a TextView" /> + <Button android:id="@+id/button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="I am a Button" /> +</LinearLayout> +</pre> + +<p>アプリでレイアウト リソースを読み込むとき、Android はレイアウトの各ノードを初期化して、他の動作の定義、オブジェクト状態の照会、レイアウトの変更をするのに使用できるランタイム オブジェクトにします。 + +</p> + +<p>UI レイアウト作成のガイドについては、<a href="declaring-layout.html">XML レイアウト</a>をご覧ください。 + + + +<h2 id="UIComponents">ユーザー インターフェース コンポーネント</h2> + +<p>{@link android.view.View} と {@link android.view.ViewGroup} オブジェクトを使用してすべての UI をビルドする必要はありません。 +Android では、コンテンツの定義に必要な標準的な UI レイアウトを提供する複数のアプリ コンポーネントが提供されます。 +これらの各 UI コンポーネントには、それぞれのドキュメントで説明されている固有の API(<a href="{@docRoot}guide/topics/ui/actionbar.html">アクションバー</a>、<a href="{@docRoot}guide/topics/ui/dialogs.html">ダイアログ</a>、<a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">状態通知</a>など)があります。 +</p> + + diff --git a/docs/html-intl/intl/ja/guide/topics/ui/settings.jd b/docs/html-intl/intl/ja/guide/topics/ui/settings.jd new file mode 100644 index 000000000000..9e6bb9d04169 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/ui/settings.jd @@ -0,0 +1,1202 @@ +page.title=設定 +page.tags=preference,preferenceactivity,preferencefragment + +@jd:body + + +<div id="qv-wrapper"> +<div id="qv"> + +<h2>本書の内容</h2> +<ol> + <li><a href="#Overview">概要</a> + <ol> + <li><a href="#SettingTypes">プリファレンス</a></li> + </ol> + </li> + <li><a href="#DefiningPrefs">XML にプリファレンスを定義する</a> + <ol> + <li><a href="#Groups">設定グループを作成する</a></li> + <li><a href="#Intents">インテントを使用する</a></li> + </ol> + </li> + <li><a href="#Activity">プリファレンス アクティビティを作成する</a></li> + <li><a href="#Fragment">プリファレンス フラグメントを使用する</a></li> + <li><a href="#Defaults">デフォルト値を設定する</a></li> + <li><a href="#PreferenceHeaders">プリファレンス ヘッダーを使用する</a> + <ol> + <li><a href="#CreateHeaders">ヘッダー ファイルを作成する</a></li> + <li><a href="#DisplayHeaders">ヘッダーを表示する</a></li> + <li><a href="#BackCompatHeaders">旧バージョンでプリファレンス ヘッダーをサポートする</a></li> + </ol> + </li> + <li><a href="#ReadingPrefs">プリファレンスを読み込む</a> + <ol> + <li><a href="#Listening">プリファレンスの変化をリッスンする</a></li> + </ol> + </li> + <li><a href="#NetworkUsage">ネットワークの使用を管理する</a></li> + <li><a href="#Custom">カスタム プリファレンスを作成する</a> + <ol> + <li><a href="#CustomSelected">ユーザー インターフェースを指定する</a></li> + <li><a href="#CustomSave">設定の値を保存する</a></li> + <li><a href="#CustomInitialize">現在の値を初期化する</a></li> + <li><a href="#CustomDefault">デフォルト値を提供する</a></li> + <li><a href="#CustomSaveState">プリファレンスの状態を保存し復元する</a></li> + </ol> + </li> +</ol> + +<h2>キークラス</h2> +<ol> + <li>{@link android.preference.Preference}</li> + <li>{@link android.preference.PreferenceActivity}</li> + <li>{@link android.preference.PreferenceFragment}</li> +</ol> + + +<h2>関連ドキュメント</h2> +<ol> + <li><a href="{@docRoot}design/patterns/settings.html">Settings design guide</a></li> +</ol> +</div> +</div> + + + + +<p>多くの場合、アプリケーションには、ユーザーがアプリの機能や動作を変更できる設定が含まれています。たとえば、一部のアプリでは、通知を有効にするかどうかや、アプリケーションがクラウドとデータを同期する頻度を、ユーザーが指定できます。 + +</p> + +<p>アプリに設定機能を提供するには、Android の {@link android.preference.Preference} API を使用して、他の Android アプリ(システム設定を含む)の操作と整合性のあるインターフェースを構築する必要があります。 + +このドキュメントでは、{@link android.preference.Preference} API を使用して、アプリの設定機能を構築する方法について説明します。 +</p> + +<div class="note design"> +<p><strong>設定の設計</strong></p> + <p>設定の設計方法については、<a href="{@docRoot}design/patterns/settings.html">設定</a>のデザインガイドをご覧ください。</p> +</div> + + +<img src="{@docRoot}images/ui/settings/settings.png" alt="" width="435" /> +<p class="img-caption"><strong>図 1.</strong> Android SMS アプリの設定のスクリーンショット +{@link android.preference.Preference} で定義されたアイテムを選択すると、設定を変更するためのインターフェースが開きます。 +</p> + + + + +<h2 id="Overview">概要</h2> + +<p>設定は、{@link android.view.View} オブジェクトを使用してユーザー インターフェースを作成する方法ではなく、XML ファイルで宣言された {@link android.preference.Preference} クラスの各種のサブクラスを使用する方法で作成されます。 + +</p> + +<p>1 つの {@link android.preference.Preference} オブジェクトが、1 つの設定の構成要素になります。 +各 {@link android.preference.Preference} はアイテムとしてリストに表示され、ユーザーが設定を変更するための適切な UI を提供します。 +たとえば、{@link android.preference.CheckBoxPreference} はチェックボックスを表示するリストアイテムを作成し、{@link android.preference.ListPreference} は、選択リスト付きのダイアログを開くアイテムを作成します。 + +</p> + +<p>追加した各 {@link android.preference.Preference} は、アプリの設定のためのデフォルトの {@link android.content.SharedPreferences} ファイルに設定を保存するためにシステムが使用する対応するキーと値のペアを持ちます。 + +ユーザーが設定を変更する場合、システムが {@link android.content.SharedPreferences} ファイルの対応する値を更新します。 +関連する {@link android.content.SharedPreferences} ファイルを直接操作することが必要なのは、ユーザーの設定に基づいてアプリの動作を決定するために値を読み込むことが必要な場合のみです。 + +</p> + +<p>各設定の {@link android.content.SharedPreferences} に保存される値のデータ型は、次のいずれかにすることができます。 +</p> + +<ul> + <li>Boolean</li> + <li>Float</li> + <li>Int</li> + <li>Long</li> + <li>String</li> + <li>String {@link java.util.Set}</li> +</ul> + +<p>アプリの設定の UI は {@link android.view.View} オブジェクトではなく {@link android.preference.Preference} で作成されているため、リストの設定を表示するには、専用の {@link android.app.Activity} サブクラスまたは {@link android.app.Fragment} サブクラスを使用する必要があります。 + + +</p> + +<ul> + <li>アプリが 3.0 よりも前のバージョンの Android(API レベル 10 以下)をサポートしている場合は、{@link android.preference.PreferenceActivity} クラスを継承してアクティビティを作成する必要があります。 +</li> + <li>Android 3.0 以降では、代わりに、アプリの設定を表示する {@link android.preference.PreferenceFragment} をホストする従来の {@link android.app.Activity} を使用します。ただし、設定のグループが複数ある場合は、{@link android.preference.PreferenceActivity} を使用して大きな画面用の 2 ペイン レイアウトを作成することもできます。 + + +</li> +</ul> + +<p>{@link android.preference.PreferenceActivity} と {@link android.preference.PreferenceFragment} のインスタンスの設定方法は、<a href="#Activity">プリファレンス アクティビティを作成する</a>と<a href="#Fragment">プリファレンス フラグメントを使用する</a>セクションをご覧ください。 + +</p> + + +<h3 id="SettingTypes">プリファレンス</h3> + +<p>アプリの各設定は、{@link android.preference.Preference} クラスの個々のサブクラスに相当します。 +各サブクラスには、設定のタイトルやデフォルト値などを指定できる一連の核となるプロパティが含まれています。 +また、各サブクラスは、専用のプロパティとユーザー インターフェースを提供しています。 +たとえば、図 1. は、SMS アプリの設定のスクリーンショットです。 +設定画面の各リスト アイテムは、それぞれ異なる {@link android.preference.Preference} オブジェクトに基づいています。 +</p> + +<p>以下は、最も一般的なプリファレンスの一部です。</p> + +<dl> + <dt>{@link android.preference.CheckBoxPreference}</dt> + <dd>有効または無効にする設定のチェックボックス付きのアイテムを表示します。保存される値は、Boolean です(オンの場合、<code>true</code>)。 +</dd> + + <dt>{@link android.preference.ListPreference}</dt> + <dd>ラジオボタンのリスト付きのダイアログを開きます。保存される値は、サポートされるデータ型(上記参照)であればどのデータ型にもできます。 +</dd> + + <dt>{@link android.preference.EditTextPreference}</dt> + <dd>{@link android.widget.EditText} ウィジェット付きのダイアログを開きます。保存される値は、{@link java.lang.String} です。 +</dd> +</dl> + +<p>その他のサブクラスと対応するプロパティについては、{@link android.preference.Preference} クラスをご覧ください。 +</p> + +<p>もちろん、組み込みのクラスがすべてのニーズを満たすわけではなく、アプリケーションがより特殊な機能を必要とする可能性もあります。 +たとえば、プラットフォームは、現時点では、数字や日付を選択するための {@link android.preference.Preference} クラスを提供していません。 +そのため、独自の {@link android.preference.Preference} サブクラスを定義することが必要になる場合もあります。 +詳細については、<a href="#Custom">カスタム プリファレンスを作成する</a>セクションをご覧ください。</p> + + + +<h2 id="DefiningPrefs">XML にプリファレンスを定義する</h2> + +<p>実行時に新しい {@link android.preference.Preference} オブジェクトのインスタンスを作成することもできますが、{@link android.preference.Preference} オブジェクトの階層で XML に設定のリストを定義する必要があります。 + +XML ファイルは更新が容易な簡単に読むことができる構造を持つため XML ファイルを使用して設定のコレクションを定義することをお勧めします。 +また、アプリの設定は通常、事前設定されていますが、設定のコレクションを実行時に変更することもできます。 +</p> + +<p>各 {@link android.preference.Preference} サブクラスは、{@code <CheckBoxPreference>} などのクラス名と一致する XML 要素で定義できます。 +</p> + +<p>この XML ファイルは、{@code res/xml/} ディレクトリに保存する必要があります。この XML ファイルには好きな名前を付けることができますが、一般的には、{@code preferences.xml} という名前が使用されています。 +階層の分岐(この分岐がそれ自身の設定のリストを開きます)が {@link android.preference.PreferenceScreen} のネストされたインスタンスを使用して宣言されているため、必要なファイルは通常 1 ファイルのみです。 + +</p> + +<p class="note"><strong>注:</strong> 複数ペイン レイアウトの設定を作成する場合は、フラグメントごとに別々の XML ファイルが必要です。 +</p> + +<p>XML ファイルのルートノードは、{@link android.preference.PreferenceScreen <PreferenceScreen>} 要素にする必要があります。 +この要素内に、各 {@link android.preference.Preference} を追加します。 +{@link android.preference.PreferenceScreen <PreferenceScreen>} 要素内に追加したそれぞれの子は、設定のリストで 1 つのアイテムとして表示されます。 + +</p> + +<p>次に例を示します。</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> + <CheckBoxPreference + android:key="pref_sync" + android:title="@string/pref_sync" + android:summary="@string/pref_sync_summ" + android:defaultValue="true" /> + <ListPreference + android:dependency="pref_sync" + android:key="pref_syncConnectionType" + android:title="@string/pref_syncConnectionType" + android:dialogTitle="@string/pref_syncConnectionType" + android:entries="@array/pref_syncConnectionTypes_entries" + android:entryValues="@array/pref_syncConnectionTypes_values" + android:defaultValue="@string/pref_syncConnectionTypes_default" /> +</PreferenceScreen> +</pre> + +<p>この例には、{@link android.preference.CheckBoxPreference} と {@link android.preference.ListPreference} が含まれています。 +どちらのアイテムにも次の 3 つの属性が含まれています。</p> + +<dl> + <dt>{@code android:key}</dt> + <dd>この属性は、データ値を保持するプリファレンスで必要です。設定の値を {@link android.content.SharedPreferences} に保存するときにシステムが使用する一意のキー(文字列)を指定します。 + + + <p>プリファレンスが {@link android.preference.PreferenceCategory} または{@link android.preference.PreferenceScreen} の場合、またはプリファレンスが {@link android.content.Intent} の呼び出しを指定している場合(<a href="#Intents">{@code <intent>}</a> 要素を使用)、または {@link android.app.Fragment} の表示を指定している場合(<a href="{@docRoot}reference/android/preference/Preference.html#attr_android:fragment">{@code android:fragment}</a> 属性を使用)のみ、インスタンスでこの属性は<em>必要ありません</em>。 + + +</p> + </dd> + <dt>{@code android:title}</dt> + <dd>この属性は、ユーザーに表示される設定の名前です。</dd> + <dt>{@code android:defaultValue}</dt> + <dd>この属性は、システムが {@link android.content.SharedPreferences} ファイルに設定する必要がある初期値を指定します。 +すべての設定のデフォルト値を指定する必要があります。 +</dd> +</dl> + +<p>その他のサポートされている属性については、{@link android.preference.Preference}(と対応するサブクラス)のドキュメントをご覧ください。 +</p> + + +<div class="figure" style="width:300px"> + <img src="{@docRoot}images/ui/settings/settings-titles.png" alt="" /> + <p class="img-caption"><strong>図 2.</strong> カテゴリを設定しタイトルを付ける + <br/><b>1.</b>カテゴリは、{@link android.preference.PreferenceCategory <PreferenceCategory>} 要素で指定します。 + <br/><b>2.</b>タイトルは、{@code android:title} 属性で指定します。 +</p> +</div> + + +<p>設定のリストが 10 アイテムを超える場合は、タイトルを追加して設定のグループを定義するか、それらのグループを別の画面に表示することをお勧めします。 + +詳細については、次のセクションで説明します。</p> + + +<h3 id="Groups">設定グループを作成する</h3> + +<p>10 以上の設定のリストがある場合、ユーザーが目を通して把握し処理することが難しくなる場合があります。 +この問題を解決するには、設定の一部またはすべてをグループに分割し、1 つの長いリストを複数の短いリストに変えます。 + +関連設定のグループは、次の 2 つの方法のいずれかで表示できます。</p> + +<ul> + <li><a href="#Titles">タイトルを使用する</a></li> + <li><a href="#Subscreens">サブ画面を使用する</a></li> +</ul> + +<p>これらのグループ化方法の 1 つまたは両方を利用して、アプリの設定を整理できます。使用する方法と設定の分割方法を決定する際は、Android Design の<a href="{@docRoot}design/patterns/settings.html">Settings</a> ガイドのガイドラインに従ってください。 + +</p> + + +<h4 id="Titles">タイトルを使用する</h4> + +<p>設定のグループの間に見出しを入れる場合(図 2. 参照)、{@link android.preference.Preference} オブジェクトをグループごとに 1 つの {@link android.preference.PreferenceCategory} 内にセットしてください。 + +</p> + +<p>次に例を示します。</p> + +<pre> +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> + <PreferenceCategory + android:title="@string/pref_sms_storage_title" + android:key="pref_key_storage_settings"> + <CheckBoxPreference + android:key="pref_key_auto_delete" + android:summary="@string/pref_summary_auto_delete" + android:title="@string/pref_title_auto_delete" + android:defaultValue="false"... /> + <Preference + android:key="pref_key_sms_delete_limit" + android:dependency="pref_key_auto_delete" + android:summary="@string/pref_summary_delete_limit" + android:title="@string/pref_title_sms_delete"... /> + <Preference + android:key="pref_key_mms_delete_limit" + android:dependency="pref_key_auto_delete" + android:summary="@string/pref_summary_delete_limit" + android:title="@string/pref_title_mms_delete" ... /> + </PreferenceCategory> + ... +</PreferenceScreen> +</pre> + + +<h4 id="Subscreens">サブ画面を使用する</h4> + +<p>設定のグループをサブ画面に配置する場合(図 3. 参照)、{@link android.preference.Preference} オブジェクトのグループを {@link android.preference.PreferenceScreen} 内にセットしてください。 + +</p> + +<img src="{@docRoot}images/ui/settings/settings-subscreen.png" alt="" /> +<p class="img-caption"><strong>図 3.</strong> 子画面を設定する。{@code <PreferenceScreen>} は、選択されると、ネストされた設定を表示するための個別のリストを開くアイテムを作成します。 + +</p> + +<p>次に例を示します。</p> + +<pre> +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- opens a subscreen of settings --> + <PreferenceScreen + android:key="button_voicemail_category_key" + android:title="@string/voicemail" + android:persistent="false"> + <ListPreference + android:key="button_voicemail_provider_key" + android:title="@string/voicemail_provider" ... /> + <!-- opens another nested subscreen --> + <PreferenceScreen + android:key="button_voicemail_setting_key" + android:title="@string/voicemail_settings" + android:persistent="false"> + ... + </PreferenceScreen> + <RingtonePreference + android:key="button_voicemail_ringtone_key" + android:title="@string/voicemail_ringtone_title" + android:ringtoneType="notification" ... /> + ... + </PreferenceScreen> + ... +</PreferenceScreen> +</pre> + + +<h3 id="Intents">インテントを使用する</h3> + +<p>設定画面ではなく、ウェブページを表示するためのウェブブラウザなどの別のアクティビティを開くプリファレンス アイテムが必要になることもあります。 +ユーザーがプリファレンス アイテムを選択したときに {@link android.content.Intent} が呼び出されるようにするには、対応する {@code <Preference>} 要素の子として {@code <intent>} 要素を追加します。 + +</p> + +<p>たとえば、次の方法で、プリファレンス アイテムを使用してウェブページを開くことができます。</p> + +<pre> +<Preference android:title="@string/prefs_web_page" > + <intent android:action="android.intent.action.VIEW" + android:data="http://www.example.com" /> +</Preference> +</pre> + +<p>次の属性を使用して、明示的なインテントと黙示的なインテントの両方を作成できます。</p> + +<dl> + <dt>{@code android:action}</dt> + <dd>{@link android.content.Intent#setAction setAction()} メソッドで割り当てるアクション。 +</dd> + <dt>{@code android:data}</dt> + <dd>{@link android.content.Intent#setData setData()} メソッドで割り当てるデータ。</dd> + <dt>{@code android:mimeType}</dt> + <dd>{@link android.content.Intent#setType setType()} メソッドで割り当てる MIME タイプ。 +</dd> + <dt>{@code android:targetClass}</dt> + <dd>{@link android.content.Intent#setComponent setComponent()} メソッドでのコンポーネント名のクラス部分。 +</dd> + <dt>{@code android:targetPackage}</dt> + <dd>{@link android.content.Intent#setComponent setComponent()} メソッドでのコンポーネント名のパッケージ部分。 +</dd> +</dl> + + + +<h2 id="Activity">プリファレンス アクティビティを作成する</h2> + +<p>アクティビティに設定を表示するには、{@link android.preference.PreferenceActivity} クラスを継承します。 +このクラスは、{@link android.preference.Preference} オブジェクトの階層に基づいて設定のリストを表示する従来の {@link android.app.Activity} クラスを継承したものです。 + +{@link android.preference.PreferenceActivity} は、ユーザーが変更を行ったときに、各 {@link android.preference.Preference} に対応する設定を自動的に保存します。 + +</p> + +<p class="note"><strong>注:</strong> Android 3.0 以降向けにアプリケーションを開発する場合は、代わりに {@link android.preference.PreferenceFragment} を使用する必要があります。 +<a href="#Fragment">プリファレンス フラグメントの使用</a>についての詳細は、次のセグメントをご覧ください。 +</p> + +<p>注意する必要があるのは、{@link android.preference.PreferenceActivity#onCreate onCreate()} のコールバック時に、ビューのレイアウトをロードしてはならないことを忘れないでください。 +代わりに {@link android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} を呼び出し、XML ファイルで宣言済みのプリファレンスをアクティビティに追加する必要があります。 + +以下は、{@link android.preference.PreferenceActivity} を機能させるために最小限必要なコードです。 +</p> + +<pre> +public class SettingsActivity extends PreferenceActivity { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.preferences); + } +} +</pre> + +<p>ユーザーがプリファレンスを変更するとすぐに、ユーザーの設定のチェックが必要なときに他のアプリケーション コンポーネントが読み取ることができるデフォルトの {@link android.content.SharedPreferences} ファイルにシステムによって変更が保存されるため、実際一部のアプリではこのコードで十分です。 + +ただし、多くのアプリでは、プリファレンスに発生する変化をリッスンするために、もう少し多くのコードが必要になります。{@link android.content.SharedPreferences} ファイルの変更のリッスンについての詳細は、<a href="#ReadingPrefs">プリファレンスの読み取り</a>についてのセクションをご覧ください。 + + +</p> + + + + +<h2 id="Fragment">プリファレンス フラグメントを使用する</h2> + +<p>Android 3.0(API レベル 11)以降向けに開発を行っている場合は、{@link android.preference.PreferenceFragment} を使用して {@link android.preference.Preference} オブジェクトのリストを表示する必要があります。 + +{@link android.preference.PreferenceFragment} はどのアクティビティにでも追加できます — {@link android.preference.PreferenceActivity} を使用する必要はありません。 +</p> + +<p>作成するアクティビティの種類にかかわらず、<a href="{@docRoot}guide/components/fragments.html">フラグメント</a>を使用すると、アクティビティを単体で使用する場合と比べて、柔軟なアーキテクチャを持つアプリケーションを作成できます。 + +そのため、可能な限り {@link android.preference.PreferenceActivity} ではなく、{@link android.preference.PreferenceFragment} を使用して設定の表示を管理することをお勧めします。 + +</p> + +<p>{@link android.preference.PreferenceFragment} の実装は、{@link android.preference.PreferenceFragment#onCreate onCreate()} メソッドを {@link android.preference.PreferenceFragment#addPreferencesFromResource addPreferencesFromResource()} を使用してプリファレンス ファイルをロードするように定義するだけと簡単です。 + + +次に例を示します。</p> + +<pre> +public static class SettingsFragment extends PreferenceFragment { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Load the preferences from an XML resource + addPreferencesFromResource(R.xml.preferences); + } + ... +} +</pre> + +<p>他の {@link android.app.Fragment} と同様に、このフラグメントは {@link android.app.Activity} に追加できます。 +次に例を示します。</p> + +<pre> +public class SettingsActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Display the fragment as the main content. + getFragmentManager().beginTransaction() + .replace(android.R.id.content, new SettingsFragment()) + .commit(); + } +} +</pre> + +<p class="note"><strong>注:</strong> {@link android.preference.PreferenceFragment} は、独自の {@link android.content.Context} オブジェクトを持ちません。 +{@link android.content.Context} オブジェクトが必要な場合は、{@link android.app.Fragment#getActivity()} を呼び出すことができます。 +ただし、{@link android.app.Fragment#getActivity()} はフラグメントがアクティビティにアタッチされている場合にのみ呼び出すようにしてください。 +フラグメントがまだアタッチされていない場合や、ライフサイクルの終了時にデタッチされた場合は、{@link android.app.Fragment#getActivity()} は null を返します。 + +</p> + + +<h2 id="Defaults">デフォルト値を設定する</h2> + +<p>作成するプリファレンスは、多くの場合、アプリケーションにとって重要ないくつかの動作を定義します。そのため、ユーザーが最初にプリケーションを開いたときに、各 {@link android.preference.Preference} のデフォルト値で、関連する {@link android.content.SharedPreferences} ファイルを初期化する必要があります。 + + +</p> + +<p>まず、{@code android:defaultValue} 属性を使用して、XML ファイルの各 {@link android.preference.Preference} オブジェクトにデフォルト値を指定してください。 + +指定する値は、対応する {@link android.preference.Preference} オブジェクトで使用できるデータ型であればどのようなデータ型でもかまいません。 +次に例を示します。 +</p> + +<pre> +<!-- default value is a boolean --> +<CheckBoxPreference + android:defaultValue="true" + ... /> + +<!-- default value is a string --> +<ListPreference + android:defaultValue="@string/pref_syncConnectionTypes_default" + ... /> +</pre> + +<p>次に、アプリケーションのメイン アクティビティ、およびユーザーがアプリケーションを最初に開いたときに表示されるその他のアクティビティの {@link android.app.Activity#onCreate onCreate()} メソッドから、{@link android.preference.PreferenceManager#setDefaultValues setDefaultValues()} を呼び出します。 + + +</p> + +<pre> +PreferenceManager.setDefaultValues(this, R.xml.advanced_preferences, false); +</pre> + +<p>{@link android.app.Activity#onCreate onCreate()} 時に、このメソッドを呼び出すと、アプリケーションがデフォルト設定で適切に初期化されます。アプリケーションには、動作(セルラー ネットワーク上でデータをダウンロードするかどうかなど)を決定するために、デフォルト設定を読み込むことが必要な場合があります。 + + +</p> + +<p>このメソッドは次の 3 つの引数を取ります。</p> +<ul> + <li>アプリケーションの {@link android.content.Context}。</li> + <li>デフォルト値を設定するプリファレンス XML ファイルのリソース ID。</li> + <li>デフォルト値を複数回設定すべきかどうかを示すブール値。 +<p><code>false</code> の場合、デフォルト値は過去にこのメソッドが 1 度も呼ばれたことがない場合(または、デフォルト値の共有プリファレンス ファイルの{@link android.preference.PreferenceManager#KEY_HAS_SET_DEFAULT_VALUES} が false の場合)のみ設定されます。 + +</p></li> +</ul> + +<p>この 3 番目の引数を <code>false</code> に設定している限り、アクティビティが開始するたびに、ユーザーが保存したプリファレンスをデフォルト値にリセットして上書きすることなく、安全にこのメソッドを呼び出すことができます。 + +この引数を <code>true</code> に設定した場合は、以前の値がすべてデフォルト値で上書きされます。 +</p> + + + +<h2 id="PreferenceHeaders">プリファレンス ヘッダーを使用する</h2> + +<p>まれに、最初の画面が<a href="#Subscreens">サブ画面</a>のリストのみを表示するように設定を設計した方がよい場合もあります(図 4. と図. 5 のシステム設定アプリなど)。 + +このような設計を Android 3.0 以降で開発する場合、ネストした {@link android.preference.PreferenceScreen} 要素でサブ画面を作成するのではなく、Android 3.0 の新しい「ヘッダー」機能を使用する必要があります。 + +</p> + +<p>ヘッダーを使用して設定を作成するには、次の準備が必要です。</p> +<ol> + <li>設定をグループごとに {@link android.preference.PreferenceFragment} の別々のインスタンスに分けます。 +この場合、設定のグループごとに、個別の XML ファイルが必要になります。 +</li> + <li>各設定グループをリストアップし対応する設定のリストを含むのがどのフラグメントかを宣言する XML ヘッダー ファイルを作成します。 +</li> + <li>{@link android.preference.PreferenceActivity} クラスを継承し、設定をホストします。</li> + <li>{@link android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} コールバックを実装して、ヘッダー ファイルを指定します。 + +</li> +</ol> + +<p>この設計を使用する大きなメリットは、大きな画面で実行する場合に、{@link android.preference.PreferenceActivity} によって自動的に図. 4 の 2 ペイン レイアウトで表示されることです。 +</p> + +<p>アプリケーションが 3.0 より前のバージョンの Android をサポートしている場合でも、3.0 より前の端末で従来の多画面階層をサポートしながら、{@link android.preference.PreferenceFragment} を使用して 3.0 以降の端末で 2 ペイン表示を行うことができます(詳細については、<a href="#BackCompatHeaders">旧バージョンでのプリファレンス ヘッダーのサポート</a>についてのセクションをご覧ください)。 + + + +</p> + +<img src="{@docRoot}images/ui/settings/settings-headers-tablet.png" alt="" /> +<p class="img-caption"><strong>図 4.</strong>ヘッダー付きの 2 ペイン レイアウト。 <br/><b>1.</b>ヘッダーは、XML ヘッダー ファイルで定義します。 + <br/><b>2.</b>設定の各グループは、XML ヘッダー ファイルの {@code <header>} 要素で指定された {@link android.preference.PreferenceFragment} ファイルで定義します。 + +</p> + +<img src="{@docRoot}images/ui/settings/settings-headers-handset.png" alt="" /> +<p class="img-caption"><strong>図 5.</strong> ヘッダーが設定されたモバイル端末。アイテムが選択されると、対応する {@link android.preference.PreferenceFragment} がヘッダーを置き換えます。 + +</p> + + +<h3 id="CreateHeaders" style="clear:left">ヘッダー ファイルを作成する</h3> + +<p>ヘッダーのリストの設定の各グループは、ルート {@code <preference-headers>} 要素内の単独の {@code <header>} 要素によって指定されます。 +次に例を示します。</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> + <header + android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentOne" + android:title="@string/prefs_category_one" + android:summary="@string/prefs_summ_category_one" /> + <header + android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentTwo" + android:title="@string/prefs_category_two" + android:summary="@string/prefs_summ_category_two" > + <!-- key/value pairs can be included as arguments for the fragment. --> + <extra android:name="someKey" android:value="someHeaderValue" /> + </header> +</preference-headers> +</pre> + +<p>{@code android:fragment} 属性を使用して、各ヘッダーは、ユーザーがヘッダーを選択したときに開く {@link android.preference.PreferenceFragment} のインスタンスを宣言します。 +</p> + +<p>{@code <extras>} 要素を使用すると、キーと値のペアを {@link android.os.Bundle} のフラグメントに渡すことができます。 +{@link android.app.Fragment#getArguments()} を呼び出すことで、フラグメントは引数を取得できます。 +さまざまな理由でフラグメントに引数を渡す場合がありますが、各グループの {@link android.preference.PreferenceFragment} の同じサブクラスを再利用し、引数を使用してフラグメントがロードするプリファレンス XML ファイルを指定することは、効果的な引数の使い方の 1 つです。 + + +</p> + +<p>たとえば、次のフラグメントは、各ヘッダーが {@code "settings"} キーを使用して {@code <extra>} 引数を定義している場合、複数の設定グループで再利用できます。 +</p> + +<pre> +public static class SettingsFragment extends PreferenceFragment { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + String settings = getArguments().getString("settings"); + if ("notifications".equals(settings)) { + addPreferencesFromResource(R.xml.settings_wifi); + } else if ("sync".equals(settings)) { + addPreferencesFromResource(R.xml.settings_sync); + } + } +} +</pre> + + + +<h3 id="DisplayHeaders">ヘッダーを表示する</h3> + +<p>プリファレンス ヘッダーを表示するには、{@link android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} コールバックメソッドを実装し、{@link android.preference.PreferenceActivity#loadHeadersFromResource loadHeadersFromResource()} を呼び出す必要があります。 + + +次に例を示します。</p> + +<pre> +public class SettingsActivity extends PreferenceActivity { + @Override + public void onBuildHeaders(List<Header> target) { + loadHeadersFromResource(R.xml.preference_headers, target); + } +} +</pre> + +<p>ユーザーがヘッダーのリストからアイテムを選択した場合、システムが対応する {@link android.preference.PreferenceFragment} を開きます。 +</p> + +<p class="note"><strong>注:</strong> プリファレンス ヘッダーを使用する場合、アクティビティで必要なタスクはヘッダーのロードのみであるため、{@link android.preference.PreferenceActivity} のサブクラスが {@link android.preference.PreferenceActivity#onCreate onCreate()} メソッドを実装する必要はありません。 + + +</p> + + +<h3 id="BackCompatHeaders">旧バージョンでプリファレンス ヘッダーをサポートする</h3> + +<p>アプリケーションが Android 3.0 よりも前のバージョンをサポートしている場合でも、3.0 以降で実行するときに、ヘッダーを使用して 2 ペイン レイアウトを提供できます。 +必要なことは、3.0 よりも前のバージョンの Android で使用するために、ヘッダー アイテムのように動作する基本的な {@link android.preference.Preference <Preference>} 要素を使用する追加のプリファレンス XML ファイルを作成することだけです。 + + +</p> + +<p>新しい {@link android.preference.PreferenceScreen} を開く代わりに、各 {@link android.preference.Preference <Preference>} 要素が、ロードするプリファレンス XML ファイルが指定されている {@link android.preference.PreferenceActivity} に {@link android.content.Intent} を送ります。 + + +</p> + +<p>たとえば、以下は Android 3.0 以降で使用されるプリファレンス ヘッダーの XML ファイル({@code res/xml/preference_headers.xml})です。 +</p> + +<pre> +<preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> + <header + android:fragment="com.example.prefs.SettingsFragmentOne" + android:title="@string/prefs_category_one" + android:summary="@string/prefs_summ_category_one" /> + <header + android:fragment="com.example.prefs.SettingsFragmentTwo" + android:title="@string/prefs_category_two" + android:summary="@string/prefs_summ_category_two" /> +</preference-headers> +</pre> + +<p>また、以下は Android 3.0 よりも前のバージョンに同じヘッダーを提供するプリファレンス ファイル({@code res/xml/preference_headers_legacy.xml})です。 +</p> + +<pre> +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> + <Preference + android:title="@string/prefs_category_one" + android:summary="@string/prefs_summ_category_one" > + <intent + android:targetPackage="com.example.prefs" + android:targetClass="com.example.prefs.SettingsActivity" + android:action="com.example.prefs.PREFS_ONE" /> + </Preference> + <Preference + android:title="@string/prefs_category_two" + android:summary="@string/prefs_summ_category_two" > + <intent + android:targetPackage="com.example.prefs" + android:targetClass="com.example.prefs.SettingsActivity" + android:action="com.example.prefs.PREFS_TWO" /> + </Preference> +</PreferenceScreen> +</pre> + +<p>{@code <preference-headers>} のサポートは Android 3.0 で追加されたため、Android 3.0 以降で実行されている場合のみ、システムは {@link android.preference.PreferenceActivity} の {@link android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} を呼び出します。 + +「レガシー」ヘッダー ファイル({@code preference_headers_legacy.xml})をロードするには、Android のバージョンを確認し、Android 3.0({@link android.os.Build.VERSION_CODES#HONEYCOMB})よりも前のバージョンの場合、{@link android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} を呼び出す必要があります。 + + + + +次に例を示します。</p> + +<pre> +@Override +public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ... + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + // Load the legacy preferences headers + addPreferencesFromResource(R.xml.preference_headers_legacy); + } +} + +// Called only on Honeycomb and later +@Override +public void onBuildHeaders(List<Header> target) { + loadHeadersFromResource(R.xml.preference_headers, target); +} +</pre> + +<p>残りの手順は、アクティビティに渡される {@link android.content.Intent} を処理して、ロードするプリファレンス ファイルを指定するだけです。 +それには、インテントのアクションを取得し、プリファレンス XML の {@code <intent>} タグで使用した既知のアクション文字列と比較します。 +</p> + +<pre> +final static String ACTION_PREFS_ONE = "com.example.prefs.PREFS_ONE"; +... + +@Override +public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + String action = getIntent().getAction(); + if (action != null && action.equals(ACTION_PREFS_ONE)) { + addPreferencesFromResource(R.xml.preferences); + } + ... + + else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + // Load the legacy preferences headers + addPreferencesFromResource(R.xml.preference_headers_legacy); + } +} +</pre> + +<p>{@link android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} の連続呼び出しは、すべてのプリファレンスを 1 つのリストにスタックすることに注意してください。そのため、else if ステートメントを使用して条件を適切に記述して、1 度のみ呼び出されるようにしてください。 + + +</p> + + + + + +<h2 id="ReadingPrefs">プリファレンスを読み込む</h2> + +<p>デフォルトでは、アプリのプリファレンスは、静的メソッド {@link android.preference.PreferenceManager#getDefaultSharedPreferences PreferenceManager.getDefaultSharedPreferences()} を呼び出すとアプリケーション内のどこからでもアクセス可能なファイルに保存されます。 + + +このメソッドは、{@link android.preference.PreferenceActivity} で使用される {@link android.preference.Preference} オブジェクトに関連するすべてのキーと値のペアを含む {@link android.content.SharedPreferences} を返します。 + + +</p> + +<p>たとえば、次の方法で、アプリケーションのその他のアクティビティからプリファレンスの値の 1 つを読み込むことができます。 +</p> + +<pre> +SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); +String syncConnPref = sharedPref.getString(SettingsActivity.KEY_PREF_SYNC_CONN, ""); +</pre> + + + +<h3 id="Listening">プリファレンスの変化をリッスンする</h3> + +<p>さまざまな理由で、ユーザーがプリファレンスを変更してすぐに通知を受け取ることが必要になることがあります。 +プリファレンスの 1 つに変化が発生したときにコールバックを受け取るには、 {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener SharedPreference.OnSharedPreferenceChangeListener} インターフェースを実装し、{@link android.content.SharedPreferences#registerOnSharedPreferenceChangeListener registerOnSharedPreferenceChangeListener()} を呼び出して {@link android.content.SharedPreferences} オブジェクトにリスナを登録します。 + + + + +</p> + +<p>このインターフェースには、コールバック メソッドが {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener#onSharedPreferenceChanged onSharedPreferenceChanged()} 1 つのみしか含まれておらず、アクティビティの一部として簡単に実装できます。 + + +次に例を示します。</p> + +<pre> +public class SettingsActivity extends PreferenceActivity + implements OnSharedPreferenceChangeListener { + public static final String KEY_PREF_SYNC_CONN = "pref_syncConnectionType"; + ... + + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, + String key) { + if (key.equals(KEY_PREF_SYNC_CONN)) { + Preference connectionPref = findPreference(key); + // Set summary to be the user-description for the selected value + connectionPref.setSummary(sharedPreferences.getString(key, "")); + } + } +} +</pre> + +<p>この例では、メソッドが、変更された設定が、既知のプリファレンス キーの設定かどうかチェックしています。メソッドは {@link android.preference.PreferenceActivity#findPreference findPreference()} を呼び出して、変更された {@link android.preference.Preference} オブジェクトを取得しています。これにより、メソッドは、ユーザー選択の説明として表示されるアイテムの概要を変更できます。 + + +つまり、その設定が {@link android.preference.ListPreference} またはその他の複数選択可の設定の場合、設定が変更されたときに {@link android.preference.Preference#setSummary setSummary()} を呼び出して現在のステータス(図 5. のスリープ設定など)を表示する必要があります。 + + +</p> + +<p class="note"><strong>注:</strong> Android Design の <a href="{@docRoot}design/patterns/settings.html">Settings</a> に説明されているように、ユーザーがプリファレンスを変更するごとに、{@link android.preference.ListPreference} の概要を更新して最新の設定を表示することをお勧めします。 + +</p> + +<p>アクティビティでの適切なライフサイクル管理のために、{@link android.app.Activity#onResume} と {@link android.app.Activity#onPause} のそれぞれのコールバック時に、{@link android.content.SharedPreferences.OnSharedPreferenceChangeListener} の登録と登録解除を行うことをお勧めします。 + +</p> + +<pre> +@Override +protected void onResume() { + super.onResume(); + getPreferenceScreen().getSharedPreferences() + .registerOnSharedPreferenceChangeListener(this); +} + +@Override +protected void onPause() { + super.onPause(); + getPreferenceScreen().getSharedPreferences() + .unregisterOnSharedPreferenceChangeListener(this); +} +</pre> + +<p class="caution"><strong>警告:</strong> {@link android.content.SharedPreferences#registerOnSharedPreferenceChangeListener registerOnSharedPreferenceChangeListener()} を呼び出す場合、現時点では、プリファレンス マネージャーにはリスナへの強い参照を格納できません。 + + +リスナへの強い参照を格納しない場合は、リスナがガベージ コレクションの影響を受けやすくなります。 +リスナが必要な間存在し続けるオブジェクトのインスタンス データ内に、リスナへの参照を保持することをお勧めします。 + +</p> + +<p>たとえば、以下のコードでは、呼び出し元は、リスナへの参照を保持していません。 +結果として、リスナはガベージ コレクションの影響を受けることになり、その後のいずれかの時点でエラーになります。 +</p> + +<pre> +prefs.registerOnSharedPreferenceChangeListener( + // Bad! The listener is subject to garbage collection! + new SharedPreferences.OnSharedPreferenceChangeListener() { + public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { + // listener implementation + } +}); +</pre> + +<p>そのため、リスナが必要な間存在し続けるオブジェクトのインスタンス データ フィールドに、リスナへの参照を格納してください。 +</p> + +<pre> +SharedPreferences.OnSharedPreferenceChangeListener listener = + new SharedPreferences.OnSharedPreferenceChangeListener() { + public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { + // listener implementation + } +}; +prefs.registerOnSharedPreferenceChangeListener(listener); +</pre> + +<h2 id="NetworkUsage">ネットワークの使用を管理する</h2> + + +<p>Android 4.0 以降では、フォアグラウンドとバックグラウンドでのアプリケーションのネットワーク データの使用量を、システムの設定アプリケーションでユーザーが確認できます。 +また、ユーザーは、個々のアプリのバックグラウンド データの使用を無効にできます。 +アプリのバックグラウンドからのデータへのアクセスをユーザーが無効にすることを防ぐには、データ接続を効率的に使用することと、アプリケーションの設定でアプリのデータの利用方法をユーザーが調整できるようにすることが必要です。 + +<p> + +<p>たとえば、データを同期する頻度や、Wi-Fi 上でのみアップロードやダウンロードを実行するようにするかどうか、ローミング時にデータを使用するかどうかなどを、ユーザーが設定できるようにすることができます。 +これらをユーザーが管理できる場合、システム設定に設定した限度にデータ使用量が近づいたときに、データへのアプリのアクセスをユーザーが無効にする可能性は減少します。ユーザーはアプリのアクセスを無効にする代わりに、アプリのデータの使用量を厳密に管理できます。 + + +</p> + +<p>アプリのデータ使用を管理するために {@link android.preference.PreferenceActivity} に必要なプリファレンスを追加したら、マニフェスト ファイルに {@link android.content.Intent#ACTION_MANAGE_NETWORK_USAGE} のインテント フィルタを追加する必要があります。 + +次に例を示します。</p> + +<pre> +<activity android:name="SettingsActivity" ... > + <intent-filter> + <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> +</activity> +</pre> + +<p>このインテント フィルタは、これがアプリケーションのデータ使用をコントロールしているアクティビティであるとシステムに示します。 +これにより、ユーザーがシステム設定アプリからアプリのデータ使用量を調べるときに、[<em>View application settings</em>] ボタンを使用できるようになります。このボタンを押すと、{@link android.preference.PreferenceActivity} が開始し、アプリのデータ使用量を調整できるようになります。 + + +</p> + + + + + + + +<h2 id="Custom">カスタム プリファレンスを作成する</h2> + +<p>Android フレームワークには、異なる設定タイプの UI を作成できるさまざまな {@link android.preference.Preference} サブクラスが含まれています。ただし、番号ピッカーや日付ピッカーなど、組み込みソリューションがない場合に必要な設定が存在する可能性もあります。 + + +このような場合、{@link android.preference.Preference} クラスまたは他のサブクラスの 1 つを継承して、カスタム プリファレンスを作成する必要があります。 +</p> + +<p>{@link android.preference.Preference} クラスを継承する場合、次のことが必要です。 +</p> + +<ul> + <li>ユーザーがその設定を選択したときに表示されるユーザー インターフェースを指定する。</li> + <li>適切なタイミングで設定の値を保存する。</li> + <li>{@link android.preference.Preference} が表示されるときに、現在の値(またはデフォルト値)で初期化する。 +</li> + <li>システムによってリクエストされた場合にデフォルト値を提供する。</li> + <li>{@link android.preference.Preference} が独自の UI(ダイアログなど)を提供している場合、状態を保存し復元してライフサイクルの変化を処理する(ユーザーが画面を回転させた場合など)。 +</li> +</ul> + +<p>以下の各セクションでは、上記の各事項を実現する方法を説明します。</p> + + + +<h3 id="CustomSelected">ユーザー インターフェースを指定する</h3> + + <p>{@link android.preference.Preference} クラスを直接継承する場合、{@link android.preference.Preference#onClick()} を実装して、ユーザーがアイテムを選択したときに発生するアクションを定義する必要があります。 + +ただし、大部分のカスタム設定では、手順が簡単な {@link android.preference.DialogPreference} を継承してダイアログを表示する方法が利用されています。 +{@link android.preference.DialogPreference} を継承する場合、クラス コンストラクタで {@link android.preference.DialogPreference#setDialogLayoutResource setDialogLayoutResourcs()} を呼び出してダイアログのレイアウトを指定する必要があります。 + + +</p> + + <p>たとえば、以下のカスタム {@link android.preference.DialogPreference} のコンストラクタでは、レイアウトを宣言しデフォルトのポジティブとネガティブのダイアログ ボタンのテキストを指定しています。 + +</p> + +<pre> +public class NumberPickerPreference extends DialogPreference { + public NumberPickerPreference(Context context, AttributeSet attrs) { + super(context, attrs); + + setDialogLayoutResource(R.layout.numberpicker_dialog); + setPositiveButtonText(android.R.string.ok); + setNegativeButtonText(android.R.string.cancel); + + setDialogIcon(null); + } + ... +} +</pre> + + + +<h3 id="CustomSave">設定の値を保存する</h3> + +<p>設定の値が整数の場合、またはブール値を保存する{@link android.preference.Preference#persistBoolean persistBoolean()} の場合、{@link android.preference.Preference#persistInt persistInt()} など、{@link android.preference.Preference} クラスの {@code persist*()} メソッドのいずれかを呼び出すことで、設定の値をいつでも保存できます。 + + +</p> + +<p class="note"><strong>注:</strong> 各 {@link android.preference.Preference} には、1 つのデータ型のデータのみ保存できます。そのため、カスタム {@link android.preference.Preference} で使用されているデータ型に対応する {@code persist*()} メソッドを使用する必要があります。 + +</p> + +<p>設定をいつ保存したらよいかは、継承する {@link android.preference.Preference} クラスによって異なります。 +{@link android.preference.DialogPreference} を継承する場合、ポジティブな結果でダイアログが閉じられたとき(ユーザーが [OK] ボタンを選択したとき)のみ、値を保存する必要があります。 + +</p> + +<p>{@link android.preference.DialogPreference} が閉じられたときには、システムが {@link android.preference.DialogPreference#onDialogClosed onDialogClosed()} メソッドを呼び出します。 +このメソッドには、ユーザーの結果が「Positive」かどうかを指定するブール値の引数が含まれています — この値が <code>true</code> の場合はユーザーがポジティブ ボタンを選択しているということであり、新しい値を保存する必要があります。 + +次に例を示します。 +</p> + +<pre> +@Override +protected void onDialogClosed(boolean positiveResult) { + // When the user selects "OK", persist the new value + if (positiveResult) { + persistInt(mNewValue); + } +} +</pre> + +<p>この例では、<code>mNewValue</code> は、設定の現在の値を保持するクラスの 1 つです。 +{@link android.preference.Preference#persistInt persistInt()} を呼び出すと、値が {@link android.content.SharedPreferences} ファイルに保存されます(この {@link android.preference.Preference} の XML ファイルに指定されたキーを自動的に使用して保存されます)。 + +</p> + + +<h3 id="CustomInitialize">現在の値を初期化する</h3> + +<p>システムは {@link android.preference.Preference} を画面に追加すると、{@link android.preference.Preference#onSetInitialValue onSetInitialValue()} を呼び出し、その設定用に保存されている値がある場合は通知します。 + +保存されている値がない場合、この呼び出しによりデフォルト値が設定されます。 +</p> + +<p>この {@link android.preference.Preference#onSetInitialValue onSetInitialValue()} メソッドは、ブール値の <code>restorePersistedValue</code> を、その設定用に値が保存済みかどうか示すために渡します。 + +<code>true</code> の場合、{@link android.preference.Preference} クラスの {@code getPersisted*()} メソッド(整数用の {@link android.preference.Preference#getPersistedInt getPersistedInt()} など)のいずれかを呼び出して保存されている値を取得する必要があります。 + + +通常は保存されている値を取得するのは、UI を更新して以前保存した値を反映させるためです。 + +</p> + +<p><code>restorePersistedValue</code> が <code>false</code> の場合、2 番目の引数で渡されたデフォルト値を使用する必要があります。 +</p> + +<pre> +@Override +protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) { + if (restorePersistedValue) { + // Restore existing state + mCurrentValue = this.getPersistedInt(DEFAULT_VALUE); + } else { + // Set default state from the XML attribute + mCurrentValue = (Integer) defaultValue; + persistInt(mCurrentValue); + } +} +</pre> + +<p>各 {@code getPersisted*()} メソッドは、値が保存されていない場合またはキーが存在しない場合に使用するデフォルト値を指定する引数を取ります。 +上記の例では、{@link android.preference.Preference#getPersistedInt getPersistedInt()} が保存されている値を返すことができない場合に備えて、ローカル定数がデフォルト値を指定するために使用されています。 + +</p> + +<p class="caution"><strong>警告:</strong> <code>defaultValue</code> は、<code>restorePersistedValue</code> が <code>true</code> の場合、常に null になるため、{@code getPersisted*()} メソッドでデフォルト値として使用<strong>できません</strong>。 + +</p> + + +<h3 id="CustomDefault">デフォルト値を提供する</h3> + +<p>{@link android.preference.Preference} クラスのインスタンスがデフォルト値を指定している場合({@code android:defaultValue} 属性を使用)、システムは、オブジェクトのインスタンスを作成するときに {@link android.preference.Preference#onGetDefaultValue onGetDefaultValue()} を呼び出してデフォルト値を取得します。 + + +システムでデフォルト値を {@link android.content.SharedPreferences} に保存するには、このメソッドを実装する必要があります。 + +次に例を示します。</p> + +<pre> +@Override +protected Object onGetDefaultValue(TypedArray a, int index) { + return a.getInteger(index, DEFAULT_VALUE); +} +</pre> + +<p>このメソッドは、属性の配列と取得する必要がある {@code android:defaultValue} のインデックス位置を提供しており、これらはデフォルト値を保存するために必要な情報のすべてです。 +属性からデフォルト値を抽出するためにこのメソッドの実装が必要なのは、デフォルト値が定義されていないときのために属性のローカル デフォルト値を指定する必要があるためです。 + +</p> + + + +<h3 id="CustomSaveState">プリファレンスの状態を保存し復元する</h3> + +<p>レイアウトの {@link android.view.View} と同じく、{@link android.preference.Preference} サブクラスは、アクティビティやフラグメントが再開される場合(ユーザーが画面を回転させた場合など)に状態の保存と復元を担当します。 + +{@link android.preference.Preference} クラスの状態を適切に保存し復元するには、ライフサイクル コールバック メソッドの {@link android.preference.Preference#onSaveInstanceState onSaveInstanceState()} と {@link android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()} を実装する必要があります。 + + + +</p> + +<p>{@link android.preference.Preference} の状態は、{@link android.os.Parcelable} インターフェースを実装するオブジェクトによって定義されます。 +Android フレームワークでは、このようなオブジェクトである{@link android.preference.Preference.BaseSavedState} クラスが状態オブジェクトを定義するための起点として提供されています。 + +</p> + +<p>{@link android.preference.Preference} クラスが状態を保存する方法を定義するには、{@link android.preference.Preference.BaseSavedState} クラスを継承する必要があります。 +いくつかのメソッドをオーバーライドして {@link android.preference.Preference.BaseSavedState#CREATOR} オブジェクトを定義してください。 + +</p> + +<p>大部分のアプリでは、次の実装をコピーして、{@link android.preference.Preference} サブクラスが整数以外のデータ型のデータを保存している場合は、{@code value} を処理している行を変更するだけで使用できます。 + +</p> + +<pre> +private static class SavedState extends BaseSavedState { + // Member that holds the setting's value + // Change this data type to match the type saved by your Preference + int value; + + public SavedState(Parcelable superState) { + super(superState); + } + + public SavedState(Parcel source) { + super(source); + // Get the current preference's value + value = source.readInt(); // Change this to read the appropriate data type + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + // Write the preference's value + dest.writeInt(value); // Change this to write the appropriate data type + } + + // Standard creator object using an instance of this class + public static final Parcelable.Creator<SavedState> CREATOR = + new Parcelable.Creator<SavedState>() { + + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; +} +</pre> + +<p>{@link android.preference.Preference.BaseSavedState} の上記の実装をアプリに追加(通常、{@link android.preference.Preference} サブクラスのサブクラスとして追加)するとともに、{@link android.preference.Preference} サブクラスの {@link android.preference.Preference#onSaveInstanceState onSaveInstanceState()} と {@link android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()} を実装する必要があります。 + + + + +</p> + +<p>次に例を示します。</p> + +<pre> +@Override +protected Parcelable onSaveInstanceState() { + final Parcelable superState = super.onSaveInstanceState(); + // Check whether this Preference is persistent (continually saved) + if (isPersistent()) { + // No need to save instance state since it's persistent, + // use superclass state + return superState; + } + + // Create instance of custom BaseSavedState + final SavedState myState = new SavedState(superState); + // Set the state's value with the class member that holds current + // setting value + myState.value = mNewValue; + return myState; +} + +@Override +protected void onRestoreInstanceState(Parcelable state) { + // Check whether we saved the state in onSaveInstanceState + if (state == null || !state.getClass().equals(SavedState.class)) { + // Didn't save the state, so call superclass + super.onRestoreInstanceState(state); + return; + } + + // Cast state to custom BaseSavedState and pass to superclass + SavedState myState = (SavedState) state; + super.onRestoreInstanceState(myState.getSuperState()); + + // Set this Preference's widget to reflect the restored state + mNumberPicker.setValue(myState.value); +} +</pre> + diff --git a/docs/html-intl/intl/ja/guide/topics/ui/ui-events.jd b/docs/html-intl/intl/ja/guide/topics/ui/ui-events.jd new file mode 100644 index 000000000000..1cff3f62d022 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/ui/ui-events.jd @@ -0,0 +1,291 @@ +page.title=入力イベント +parent.title=ユーザー インターフェース +parent.link=index.html +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + <h2>本書の内容</h2> + <ol> + <li><a href="#EventListeners">イベントリスナ</a></li> + <li><a href="#EventHandlers">イベント ハンドラ</a></li> + <li><a href="#TouchMode">タッチモード</a></li> + <li><a href="#HandlingFocus">フォーカスの処理</a></li> + </ol> + +</div> +</div> + +<p>Android では、アプリケーションでのユーザーの操作からイベントをインターセプトする方法が複数用意されていますが、ユーザー インターフェース内のイベントをインターセプトする場合は、ユーザーが操作する個々の View オブジェクトからイベントを取得することになります。 + +View クラスは、このための手段を提供しています。</p> + +<p>レイアウトを構成するために使用する各種の View クラスには、UI イベントの処理に役に立ついくつかのパブリック コールバック メソッドが含まれています。 +これらのパブリック コールバック メソッドは、オブジェクトで対応するアクションが発生したときに Android フレームワークによって呼び出されます。 +たとえば、ビュー(ボタンなど)がタップされたときには、そのオブジェクト上で <code>onTouchEvent()</code> メソッドが呼び出されます。 +このようなイベントをインターセプトするには、クラスを継承しメソッドをオーバーライドする必要があります。 +ただし、このようなイベントを処理するたびに View オブジェクトを継承することは、実用的とは言えません。 +そのため、View クラスには、簡単に定義できるコールバックを持つネストされたインターフェースのコレクションも含まれています。 +これらのインターフェースは、<a href="#EventListeners">イベントリスナ</a>と呼ばれ、UI へのユーザーの操作を取得するために使用されます。 +</p> + +<p>通常は、イベントリスナを使用して、ユーザーの操作をリッスンすることになりますが、カスタム コンポーネントを作成するために View クラスを継承する場合や、 +処理を工夫するために {@link android.widget.Button} クラスを継承することもできます。 + +その場合は、クラスの<a href="#EventHandlers">イベント ハンドラ</a>を使用して、クラスにデフォルトのイベント動作を定義できます。 +</p> + + +<h2 id="EventListeners">イベントリスナ</h2> + +<p>イベントリスナは、コールバック メソッド 1 つを含む {@link android.view.View} クラスのインターフェースです。 +以下のメソッドは、イベントリスナが登録されているビューが UI アイテムへのユーザーの操作によってトリガーされたときに、Android フレームワークによって呼び出されます。 +</p> + +<p>イベントリスナ インターフェースに含まれているのは、以下のコールバック メソッドです。</p> + +<dl> + <dt><code>onClick()</code></dt> + <dd>{@link android.view.View.OnClickListener} のメソッド。ユーザーがアイテムをタップしたとき(タッチモードの場合)、またはナビゲーション キーまたはトラックボールでアイテムにフォーカスを合わせ、適切な「エンター」キーまたはトラックボールを押したときに、呼び出されます。 + + +</dd> + <dt><code>onLongClick()</code></dt> + <dd>{@link android.view.View.OnLongClickListener} のメソッド。ユーザーがアイテムをタップしてホールドしたとき(タッチモードの場合)、またはナビゲーション キーまたはトラックボールでアイテムにフォーカスを合わせ、適切な「エンター」キーまたはトラックボールを長押し(1 秒間)したときに、呼び出されます。 + + +</dd> + <dt><code>onFocusChange()</code></dt> + <dd>{@link android.view.View.OnFocusChangeListener} のメソッド。ナビゲーション キーやトラックボールを使用してユーザーがアイテムに移動してきたときまたはアイテムから離れるときに、呼び出されます。 +</dd> + <dt><code>onKey()</code></dt> + <dd>{@link android.view.View.OnKeyListener} のメソッド。ユーザーがアイテムにフォーカスを合わせて端末のハードウェア キーを押したとき、または離したときに、呼び出されます。 +</dd> + <dt><code>onTouch()</code></dt> + <dd>{@link android.view.View.OnTouchListener} のメソッド。画面(アイテムの境界線内)での押す、離す、移動操作などのタップイベントと認定されるアクションをユーザーが実行した場合に呼び出されます。 + +</dd> + <dt><code>onCreateContextMenu()</code></dt> + <dd>{@link android.view.View.OnCreateContextMenuListener} のメソッド。コンテキスト メニュー(「長押しクリック」し続けると作成されます)の作成中に呼び出されます。 +コンテキスト メニューについての詳細は、「<a href="{@docRoot}guide/topics/ui/menus.html#context-menu">メニュー</a>」のデベロッパー ガイドをご覧ください。 + +</dd> +</dl> + +<p>これらのメソッドは、それぞれのインターフェースにおける唯一のメソッドです。これらのいずれかのメソッドを定義しイベントを処理するには、ネストされたインターフェースをアクティビティに実装するか、ネストされたインターフェースを匿名クラスとして定義します。次に、その実装のインスタンスを対応する <code>View.set...Listener()</code> メソッドに渡します。 + + +(例: <code>{@link android.view.View#setOnClickListener(View.OnClickListener) setOnClickListener()}</code> を呼び出し、{@link android.view.View.OnClickListener OnClickListener} の実装を渡します)。 + +</p> + +<p>次の例は、ボタンへの on-click リスナの登録方法を示しています。 </p> + +<pre> +// Create an anonymous implementation of OnClickListener +private OnClickListener mCorkyListener = new OnClickListener() { + public void onClick(View v) { + // do something when the button is clicked + } +}; + +protected void onCreate(Bundle savedValues) { + ... + // Capture our button from layout + Button button = (Button)findViewById(R.id.corky); + // Register the onClick listener with the implementation above + button.setOnClickListener(mCorkyListener); + ... +} +</pre> + +<p>OnClickListener をアクティビティの一部として実装すると、余分なクラスのロードとオブジェクトの割り当てを避けることができます。 +次に例を示します。</p> +<pre> +public class ExampleActivity extends Activity implements OnClickListener { + protected void onCreate(Bundle savedValues) { + ... + Button button = (Button)findViewById(R.id.corky); + button.setOnClickListener(this); + } + + // Implement the OnClickListener callback + public void onClick(View v) { + // do something when the button is clicked + } + ... +} +</pre> + +<p>上の例の <code>onClick()</code> コールバックには戻り値がありませんが、イベントリスナ メソッドの中には、ブール値を返すことが必要なものもあることに注意してください。 +ブール値が示す事柄はイベントによって異なります。 +以下はその例です。</p> +<ul> + <li><code>{@link android.view.View.OnLongClickListener#onLongClick(View) onLongClick()}</code> - イベントを消費済みでこれ以上イベントを引き継ぐべきでないかどうかを示すブール値を返します。 +つまり、イベントが処理済みでイベントの停止が必要なことを示す場合は、<em>true</em> を返します。イベントが未処理の場合や、他の on-click リスナへのイベントの引き継ぎが必要な場合は、<em>false</em> を返します。 + + +</li> + <li><code>{@link android.view.View.OnKeyListener#onKey(View,int,KeyEvent) onKey()}</code> - イベントを消費済みでこれ以上イベントを引き継ぐべきでないかどうかを示すブール値を返します。 + + つまり、イベントが処理済みでイベントの停止が必要なことを示す場合は、<em>true</em> を返します。イベントが未処理の場合や、他の on-key リスナへのイベントの引き継ぎが必要な場合は、<em>false</em> を返します。 + +</li> + <li><code>{@link android.view.View.OnTouchListener#onTouch(View,MotionEvent) onTouch()}</code> - リスナがイベントを消費しているかどうかを示すブール値を返します。 +ここで注意する必要があるのは、このイベントが相互にフォローし合う複数のアクションを含むことがあることです。 +ダウン アクション イベントが受け取られたときに <em>false</em> を返すと、そのイベントを消費しておらず、そのイベントから続けて発生するアクションに関心がないことを示すことになります。 + +そのため、指での操作などのそのイベント内のその他のアクションや操作の最後に発生する アップ アクション イベントで、呼び出されることはなくなります。 +</li> +</ul> + +<p>ハードウェア キー イベントは常に、その時点でフォーカスがあるビューに届けられることに注意してください。ハードウェア・キー・イベントは、ビュー階層の一番上から下に適切な対象に到達するまでディスパッチされます。 +ビュー(またはビューの子)にフォーカスがある場合、イベントが <code>{@link android.view.View#dispatchKeyEvent(KeyEvent) +dispatchKeyEvent()}</code> メソッドを介して伝わっていると判断できます。 +ビューを通じてキーイベントを取得する別の方法としては、<code>{@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()}</code> と <code>{@link android.app.Activity#onKeyUp(int,KeyEvent) onKeyUp()}</code> を使用してアクティビティ内のすべてのイベントを受け取る方法もあります。 + +</p> + +<p>また、アプリケーションのテキスト入力について検討する際は、多くの端末にソフトウェア入力メソッドしかないことに注意してください。 +ソフトウェア入力メソッドでは、キーの利用は必要ありません。音声入力や手書き入力などを利用できるものもあります。入力メソッドがキーボードに似たインターフェースを提供していたとしても、そのインターフェースは通常、<code>{@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()}</code> ファミリーのイベントをトリガー<strong>しません</strong>。 + +アプリケーションの使用をハードウェア キーボード付きの端末に限定するのではない限り、制御するために特定のキーを押すことが必要な UI は作成しないでください。 + +特に、ユーザーのリターンキー押下時に入力を検証するような処理は行わないようにし、代わりに {@link android.view.inputmethod.EditorInfo#IME_ACTION_DONE} などのアクションを使用して入力メソッドにアプリケーションが求める反応を伝えてください。そうすることで、入力メソッドが UI を意味のあるものにします。 + +ソフトウェア入力メソッドの動作を推測し、その推測に基づいて、書式設定済みのテキストをアプリケーションに提供することは避けてください。 +</p> + +<p class="note"><strong>注:</strong> Android では、まずイベント ハンドラが呼び出され、次にクラス定義から適切なデフォルト ハンドラが呼び出されます。 +そのため、これらのイベントリスナから <em>true</em> が返された場合、イベントの他のイベントリスナへの伝播は止まり、ビューのデフォルトのイベント ハンドラへのコールバックもブロックされます。 + +そのため、イベントを終了させたいことが確実な場合のみ、<em>true</em> を返すようにしてください。</p> + + +<h2 id="EventHandlers">イベント ハンドラ</h2> + +<p>ビューからカスタム コンポーネントを作成する場合、デフォルトのイベント ハンドラとして使用される複数のコールバック メソッドを定義できます。イベント ハンドリングに使用される次のような一般的なコールバックの一部については、詳細を<a href="{@docRoot}guide/topics/ui/custom-components.html">カスタム コンポーネント</a>についてのドキュメントでご覧いただけます。 + + + +</p> +<ul> + <li><code>{@link android.view.View#onKeyDown}</code> - 新しいキーイベントの発生時に呼び出されます。</li> + <li><code>{@link android.view.View#onKeyUp}</code> - キー アップ イベントの発生時に呼び出されます。</li> + <li><code>{@link android.view.View#onTrackballEvent}</code> - トラックボール モーション イベントの発生時に呼び出されます。</li> + <li><code>{@link android.view.View#onTouchEvent}</code> - タッチスクリーン モーション イベント発生時に呼び出されます。</li> + <li><code>{@link android.view.View#onFocusChanged}</code> - ビューがフォーカスを取得した場合または失った場合に呼び出されます。</li> +</ul> +<p>View クラスに含まれていないメソッドの中にも、イベントの処理の方法に直接関係するメソッドがいくつかあります。 +そのため、レイアウト内の複雑なイベントを管理する場合は、以下のメソッドの使用を検討してください。 +</p> +<ul> + <li><code>{@link android.app.Activity#dispatchTouchEvent(MotionEvent) + Activity.dispatchTouchEvent(MotionEvent)}</code> - {@link android.app.Activity} が、すべてのタップイベントをウィンドウにディスパッチされる前にインターセプトできるようにします。 +</li> + <li><code>{@link android.view.ViewGroup#onInterceptTouchEvent(MotionEvent) + ViewGroup.onInterceptTouchEvent(MotionEvent)}</code> - {@link android.view.ViewGroup} が、イベントが子ビューにディスパッチされたときにイベントを監視できるようにします。 +</li> + <li><code>{@link android.view.ViewParent#requestDisallowInterceptTouchEvent(boolean) + ViewParent.requestDisallowInterceptTouchEvent(boolean)}</code> - このメソッドを親ビュー上で呼び出すことで、<code>{@link + android.view.ViewGroup#onInterceptTouchEvent(MotionEvent)}</code> による親ビューのタップイベントのインターセプトを許可しないことを示すことができます。 +</li> +</ul> + +<h2 id="TouchMode">タッチモード</h2> +<p> +ユーザーが方向キーまたはトラックボールを使用してユーザー インターフェースを操作する場合、入力を受け付けるアイテムがどのアイテムなのかユーザーが知ることができるようにアクション可能なアイテム(ボタンなど)にフォーカスを与えることが必要になります。 + +ただし、端末にタッチ機能がある場合は、ユーザーはタップでインターフェースの操作を開始するため、アイテムをハイライトすることや、特定のビューにフォーカスを与えることは必要ではなくなりました。 + +そのため、「タッチモード」と名付けられた操作モードが存在します。 + +</p> +<p> +タッチ可能な端末では、ユーザーが画面をタップすると、端末がタッチモードになります。 +端末がタッチモードの場合、テキスト編集ウィジェットなどの {@link android.view.View#isFocusableInTouchMode} が true のビューのみがフォーカス可能であり、ボタンなどのタップ可能なその他のビューは、タップされたときにフォーカスされることはありません。それらのビューは、押されたときに、on-click リスナを起動します。 + + + +</p> +<p> +ユーザーが方向キーを押すか、またはトラックボールをスクロールすると、端末はタッチモードから抜け、ビューがフォーカスを取得します。 +これにより、ユーザーは、画面をタップすることなく、ユーザー インターフェースの操作を再開できます。 + +</p> +<p> +タッチモード状態は、システム全体(すべてのウィンドウとアクティビティ)で維持されます。端末が現在タッチモードかどうか確認するには、{@link android.view.View#isInTouchMode} を呼び出します。 + + +</p> + + +<h2 id="HandlingFocus">フォーカスの処理</h2> + +<p>フレームワークは、ユーザーに入力に応じて、通常のフォーカス移動を処理します。フレームワークが処理するフォーカス移動には、ビューが削除されたり非表示になったり、新しいビューが利用可能になったりしたことによるフォーカスの変化も含まれます。 + +ビューは、<code>{@link android.view.View#isFocusable()}</code> メソッドで、フォーカスが取得可能なことを示します。 +ビューのフォーカスの取得可否を変更するには、<code>{@link android.view.View#setFocusable(boolean) setFocusable()}</code> を呼び出します。 +タッチモードでは、<code>{@link android.view.View#isFocusableInTouchMode()}</code> でビューがフォーカスを取得可能かどうか確認できます。ビューのフォーカスの取得可否は、<code>{@link android.view.View#setFocusableInTouchMode(boolean) setFocusableInTouchMode()}</code> で変更できます。 + + +</p> + +<p>フォーカスの移動は、所定の方向で最も近くにあるアイテムを見つけるアルゴリズムに基づきますが、 +まれに、デフォルトのアルゴリズムが開発者の意図する動作と一致しない場合もあります。 +この場合、レイアウト ファイルの + +<var>nextFocusDown</var>、 <var>nextFocusLeft</var>、 <var>nextFocusRight</var>、 +<var>nextFocusUp</var> の各 XML 属性を明示的にオーバーライドできます。これらの属性のいずれかを、フォーカスの移動<em>元</em>のビューに追加します。 +フォーカスの移動<em>先</em>のビューの ID になる属性の値を定義します。 +次に例を示します。</p> +<pre> +<LinearLayout + android:orientation="vertical" + ... > + <Button android:id="@+id/top" + android:nextFocusUp="@+id/bottom" + ... /> + <Button android:id="@+id/bottom" + android:nextFocusDown="@+id/top" + ... /> +</LinearLayout> +</pre> + +<p>本来、上記の縦方向のレイアウトでは、1 番上のボタンから上に移動しようとしても、2 番目のボタンから下に移動しようしても、どこにもフォーカスが移動しないはずでしたが、上記の処理により、 +1 番上のボタンによって 1 番下のボタンが + <var>nextFocusUp</var> として定義され(逆の場合も同様)、フォーカスが、上から下と下から上に順番に移動するようになります。 +</p> + +<p>UI でビューをフォーカス可能にする場合は(従来は、ビューはフォーカス可能ではありません)、レイアウトの宣言で <code>android:focusable</code> XML 属性をビューに追加し、値を + + <var>true</var> に設定します。また、<code>android:focusableInTouchMode</code> を使用して、タッチモードのときにビューをフォーカス可能にすることもできます。 +</p> +<p>特定のビューへのフォーカスをリクエストするには、<code>{@link android.view.View#requestFocus()}</code> を呼び出します。</p> +<p>フォーカス イベントをリッスンするには(ビューがフォーカスを受け取ったときまたは失ったときに通知を受け取るには)、上記の<a href="#EventListeners">イベントリスナ</a>のセクションの説明に従って <code>{@link android.view.View.OnFocusChangeListener#onFocusChange(View,boolean) onFocusChange()}</code> を使用します。 + +</p> + + + +<!-- +<h2 is="EventCycle">Event Cycle</h2> + <p>The basic cycle of a View is as follows:</p> + <ol> + <li>An event comes in and is dispatched to the appropriate View. The View + handles the event and notifies any listeners.</li> + <li>If, in the course of processing the event, the View's bounds may need + to be changed, the View will call {@link android.view.View#requestLayout()}.</li> + <li>Similarly, if in the course of processing the event the View's appearance + may need to be changed, the View will call {@link android.view.View#invalidate()}.</li> + <li>If either {@link android.view.View#requestLayout()} or {@link android.view.View#invalidate()} were called, + the framework will take care of measuring, laying out, and drawing the tree + as appropriate.</li> + </ol> + + <p class="note"><strong>Note:</strong> The entire View tree is single threaded. You must always be on + the UI thread when calling any method on any View. + If you are doing work on other threads and want to update the state of a View + from that thread, you should use a {@link android.os.Handler}. + </p> +--> |