summaryrefslogtreecommitdiff
path: root/docs/html-intl/intl/zh-tw/guide
diff options
context:
space:
mode:
authorTrevor Johns <trevorjohns@google.com>2016-04-05 19:43:35 -0700
committerTrevor Johns <trevorjohns@google.com>2016-04-05 20:32:07 -0700
commita5060ee80dbb48bd7fc545d2aeeeb657b79893ea (patch)
tree842bb82e198dccade4bfb3ceafcc01f96083cd34 /docs/html-intl/intl/zh-tw/guide
parentebf3261aa6d80ad4ca1df0fd0509961ff7a1914e (diff)
parent9577d31b10aa654d3ba63947e7733945a358395e (diff)
Merge branch 'mnc-mr-docs' into mnc-ub-dev
Large merge to reconnect automerger for docs branch to mainline. Conflicts: docs/html-intl/intl/es/index.jd docs/html-intl/intl/es/preview/download.jd docs/html-intl/intl/es/preview/index.jd docs/html-intl/intl/ja/index.jd docs/html-intl/intl/ja/preview/download.jd docs/html-intl/intl/ja/preview/index.jd docs/html-intl/intl/ko/index.jd docs/html-intl/intl/ko/preview/download.jd docs/html-intl/intl/ko/preview/index.jd docs/html-intl/intl/pt-br/index.jd docs/html-intl/intl/pt-br/preview/download.jd docs/html-intl/intl/pt-br/preview/index.jd docs/html-intl/intl/ru/index.jd docs/html-intl/intl/ru/preview/download.jd docs/html-intl/intl/ru/preview/index.jd docs/html-intl/intl/zh-cn/index.jd docs/html-intl/intl/zh-cn/preview/download.jd docs/html-intl/intl/zh-cn/preview/index.jd docs/html-intl/intl/zh-tw/index.jd docs/html-intl/intl/zh-tw/preview/download.jd docs/html-intl/intl/zh-tw/preview/index.jd docs/html/guide/topics/manifest/compatible-screens-element.jd docs/html/guide/topics/manifest/uses-feature-element.jd docs/html/preview/download.jd docs/html/preview/features/runtime-permissions.jd docs/html/sdk/index.jd docs/html/tools/revisions/studio.jd docs/html/tools/sdk/eclipse-adt.jd docs/html/tools/support-library/features.jd telephony/java/android/telephony/TelephonyManager.java Bug: 28000173 Change-Id: Iacab0481175f1b32e0ac3bab98cde9e994100e94
Diffstat (limited to 'docs/html-intl/intl/zh-tw/guide')
-rw-r--r--docs/html-intl/intl/zh-tw/guide/components/activities.jd756
-rw-r--r--docs/html-intl/intl/zh-tw/guide/components/bound-services.jd658
-rw-r--r--docs/html-intl/intl/zh-tw/guide/components/fragments.jd812
-rw-r--r--docs/html-intl/intl/zh-tw/guide/components/fundamentals.jd480
-rw-r--r--docs/html-intl/intl/zh-tw/guide/components/index.jd57
-rw-r--r--docs/html-intl/intl/zh-tw/guide/components/intents-filters.jd899
-rw-r--r--docs/html-intl/intl/zh-tw/guide/components/loaders.jd494
-rw-r--r--docs/html-intl/intl/zh-tw/guide/components/processes-and-threads.jd411
-rw-r--r--docs/html-intl/intl/zh-tw/guide/components/recents.jd256
-rw-r--r--docs/html-intl/intl/zh-tw/guide/components/services.jd813
-rw-r--r--docs/html-intl/intl/zh-tw/guide/components/tasks-and-back-stack.jd578
-rw-r--r--docs/html-intl/intl/zh-tw/guide/index.jd74
-rw-r--r--docs/html-intl/intl/zh-tw/guide/topics/manifest/manifest-intro.jd517
-rw-r--r--docs/html-intl/intl/zh-tw/guide/topics/providers/calendar-provider.jd1184
-rw-r--r--docs/html-intl/intl/zh-tw/guide/topics/providers/contacts-provider.jd2356
-rw-r--r--docs/html-intl/intl/zh-tw/guide/topics/providers/content-provider-basics.jd1196
-rw-r--r--docs/html-intl/intl/zh-tw/guide/topics/providers/content-provider-creating.jd1214
-rw-r--r--docs/html-intl/intl/zh-tw/guide/topics/providers/content-providers.jd108
-rw-r--r--docs/html-intl/intl/zh-tw/guide/topics/providers/document-provider.jd916
-rw-r--r--docs/html-intl/intl/zh-tw/guide/topics/resources/accessing-resources.jd337
-rw-r--r--docs/html-intl/intl/zh-tw/guide/topics/resources/overview.jd103
-rw-r--r--docs/html-intl/intl/zh-tw/guide/topics/resources/providing-resources.jd1094
-rw-r--r--docs/html-intl/intl/zh-tw/guide/topics/resources/runtime-changes.jd281
-rw-r--r--docs/html-intl/intl/zh-tw/guide/topics/ui/controls.jd90
-rw-r--r--docs/html-intl/intl/zh-tw/guide/topics/ui/declaring-layout.jd492
-rw-r--r--docs/html-intl/intl/zh-tw/guide/topics/ui/dialogs.jd798
-rw-r--r--docs/html-intl/intl/zh-tw/guide/topics/ui/menus.jd1031
-rw-r--r--docs/html-intl/intl/zh-tw/guide/topics/ui/notifiers/notifications.jd979
-rw-r--r--docs/html-intl/intl/zh-tw/guide/topics/ui/overview.jd71
-rw-r--r--docs/html-intl/intl/zh-tw/guide/topics/ui/settings.jd1202
-rw-r--r--docs/html-intl/intl/zh-tw/guide/topics/ui/ui-events.jd291
31 files changed, 20548 insertions, 0 deletions
diff --git a/docs/html-intl/intl/zh-tw/guide/components/activities.jd b/docs/html-intl/intl/zh-tw/guide/components/activities.jd
new file mode 100644
index 000000000000..ea0934964fed
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/guide/components/activities.jd
@@ -0,0 +1,756 @@
+page.title=Activity
+page.tags=Activity,意圖
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>本文件內容</h2>
+<ol>
+ <li><a href="#Creating">建立 Activity</a>
+ <ol>
+ <li><a href="#UI">實作使用者介面</a></li>
+ <li><a href="#Declaring">在宣示說明中宣告 Activity</a></li>
+ </ol>
+ </li>
+ <li><a href="#StartingAnActivity">啟動 Activity</a>
+ <ol>
+ <li><a href="#StartingAnActivityForResult">啟動 Activity 以取得結果</a></li>
+ </ol>
+ </li>
+ <li><a href="#ShuttingDown">關閉 Activity</a></li>
+ <li><a href="#Lifecycle">管理 Activity 生命週期</a>
+ <ol>
+ <li><a href="#ImplementingLifecycleCallbacks">實作生命週期回呼</a></li>
+ <li><a href="#SavingActivityState">儲存 Activity 狀態</a></li>
+ <li><a href="#ConfigurationChanges">處理設定變更</a></li>
+ <li><a href="#CoordinatingActivities">協調 Activity</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} 是提供畫面的應用程式元件,使用者可以與此畫面互動以執行動作,例如撥號、拍照、傳送電子郵件或檢視地圖。
+
+每個 Activity 都會有專屬視窗,用於繪製其使用者介面。視窗一般會佔滿螢幕,但也可能小於螢幕或在其他視窗上方浮動。
+
+</p>
+
+<p> 應用程式通常由多個 Activity 組成,這些 Activity 之間的繫結鬆散。
+一般來說,應用程式中的某個 Activity 會指定為「主要」Activity。使用者第一次啟動應用程式時,會將此 Activity 向使用者顯示。
+然後,每個 Activity 可以啟動另一個 Activity,以執行不同的動作。
+每次啟動新的 Activity 時,之前的 Activity 會停止,但系統將該 Activity 保留在堆疊中(即「返回堆疊」)。
+
+新的 Activity 啟動時會推送至返回堆疊,然後取得使用者焦點。
+返回堆疊遵循基本的「後進先出」堆疊機制,因此,使用者完成目前的 Activity,按下 [返回] 按鈕<em></em>時,目前的 Activity 會從堆疊被推出 (並終止),然後繼續之前的 Activity。
+
+(返回堆疊在<a href="{@docRoot}guide/components/tasks-and-back-stack.html">工作和返回堆疊</a>文件中,有更詳細的說明)。
+
+</p>
+
+<p>Activity 因啟動新的 Activity 而停止時,Activity 的生命週期回呼方法會通知此狀態的變更。由於 Activity 狀態的變更 &mdash; 可能是系統建立、停止、繼續或終止 Activity 時 &mdash; Activity 會收到數個回呼方法,而且每個回呼都提供您執行適合該次狀態變更的特定工作機會。
+
+
+
+
+例如,停止時,您的 Activity 應釋放任何大型物件,例如網路或資料庫連線。
+Activity 繼續時,您可以重新取得必要資源,並繼續之前中斷的動作。
+這些狀態轉換都是 Activity 生命週期的一部分。
+</p>
+
+<p>本文件的其他部分會討論建置和使用 Activity 的基本概念,包括完整討論 Activity 生命週期的運作方式,讓您可以正確地管理各種 Activity 狀態之間的轉換。
+
+</p>
+
+
+
+<h2 id="Creating">建立 Activity</h2>
+
+<p>如要建立 Activity,您必須建立 {@link android.app.Activity} 的子類別 (或它現有的子類別)。
+在您的子類別中,您需要實作回呼方法,當 Activity 在其生命週期的各種狀態之間轉換時,系統可以呼叫此回呼方法。例如,Activity 建立、停止、繼續或終止時。
+
+最重要的兩個回呼方法如下:
+</p>
+
+<dl>
+ <dt>{@link android.app.Activity#onCreate onCreate()}</dt>
+ <dd>您必須實作此方法。系統建立您的 Activity 時會呼叫此方法。
+在您的實作中,應該初始化 Activity 的基本元件。
+
+ 最重要的是,您必須在這裡呼叫 {@link android.app.Activity#setContentView
+ setContentView()},才能定義 Activity 使用者介面的版面配置。</dd>
+ <dt>{@link android.app.Activity#onPause onPause()}</dt>
+ <dd>系統呼叫此方法做為使用者離開您的 Activity 的第一個指標 (但並非一定表示該 Activity 遭到終止)。
+您通常需要透過這個方法提交要在目前的使用者工作階段以外保留的任何變更 (原因在於使用者可能不會返回)。
+
+</dd>
+</dl>
+
+<p>還有一些您應使用的其他生命週期回呼方法,以便提供 Activity 之間流暢的使用者體驗,並處理讓您的 Activity 停止、甚至終止的非預期中斷。
+
+如需所有生命週期回呼方法的相關資訊,請參閱<a href="#Lifecycle">管理 Activity 生命週期</a>。
+</p>
+
+
+
+<h3 id="UI">實作使用者介面</h3>
+
+<p> Activity 的使用者介面是由階層的檢視所提供 &mdash; 衍生自 {@link android.view.View} 類別的物件。
+每個檢視都控制 Activity 視窗內特定的長方形空間,並且可以回應使用者的互動。
+例如,檢視可能是按鈕,使用者觸碰此按鈕時會初始化一個動作。
+</p>
+
+<p>Android 提供許多現成的檢視,您可以用於設計並組織您的版面配置。
+「小工具」是在畫面上提供視覺和互動元素的檢視,例如按鈕、文字欄位、核取方塊或只是一張影像。
+「版面配置」是衍生自 {@link
+android.view.ViewGroup} 的檢視,讓子檢視可具有獨特的版面配置模型,例如線性版面配置、網格版面配置或相對版面配置。
+您也可以製作 {@link android.view.View} 和
+{@link android.view.ViewGroup} 類別 (或現有子類別) 的子類別,以建立您自己的小工具和版面配置,然後套用到您的 Activity 版面配置。
+</p>
+
+<p>使用檢視定義版面配置的最常見方式,是使用 XML 版面配置檔案 (儲存於您的應用程式資源)。
+這樣一來,您可以分別維護使用者介面的設計和定義 Activity 行為的原始程式碼。
+您可以使用 {@link android.app.Activity#setContentView(int) setContentView()} 傳送版面配置的資源 ID,將版面配置設為 Activity 的 UI。
+
+不過,您也可以透過將新的 {@link
+android.view.View} 插入 {@link android.view.ViewGroup},然後藉由將根
+{@link android.view.ViewGroup} 傳送給 {@link android.app.Activity#setContentView(View)
+setContentView()} 來使用該版面配置,以便在您的 Activity 程式碼中建立新的 {@link android.view.View},並且建置視圖層次。
+</p>
+
+<p>如需關於建立使用者介面的詳細資訊,請參閱<a href="{@docRoot}guide/topics/ui/index.html">使用者介面</a>。</p>
+
+
+
+<h3 id="Declaring">在宣示說明中宣告 Activity</h3>
+
+<p>您必須在宣示說明檔案中宣告 Activity,系統才能加以存取。
+如要宣告您的 Activity,請開啟宣示說明檔案,然後新增 <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a> 元素做為 <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application&gt;}</a> 元素的下層物件。
+
+範例:</p>
+
+<pre>
+&lt;manifest ... &gt;
+ &lt;application ... &gt;
+ &lt;activity android:name=".ExampleActivity" /&gt;
+ ...
+ &lt;/application ... &gt;
+ ...
+&lt;/manifest &gt;
+</pre>
+
+<p>您可以包括此元素中的其他屬性 (attribute) 來定義屬性 (property),例如 Activity 的標籤、Activity 的圖示或 Activity UI 的設計風格。<a href="{@docRoot}guide/topics/manifest/activity-element.html#nm">{@code android:name}</a> 屬性 (attribute) 是唯一必須的屬性 &mdash; 它會指定 Activity 的類別名稱。
+
+
+一旦發佈應用程式,您就不得變更此名稱,這是因為這樣做可能會破壞一些功能,例如應用程式捷徑 (閱讀部落格貼文:<a href="http://android-developers.blogspot.com/2011/06/things-that-cannot-change.html">不能變更的事項</a>)。
+
+
+</p>
+
+<p>請參閱 <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a> 元素參考文件,進一步瞭解如何在宣示說明中宣告 Activity。
+</p>
+
+
+<h4>使用意圖篩選器</h4>
+
+<p><a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
+&lt;activity&gt;}</a> 元素也可以指定各種意圖篩選器 &mdash; 使用 <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code
+&lt;intent-filter&gt;}</a> 元素 &mdash; 以便宣告其他應用程式元件啟動它的方式。
+</p>
+
+<p>使用 Android SDK 工具建立新的應用程式時,自動為您建立的
+虛設常式 Activity 會內含意圖篩選器。含意圖篩選器會宣告回應
+「主要」動作的 Activity,並且應放置在「啟動器」類別。意圖篩選器看起來會如下所示:
+</p>
+
+<pre>
+&lt;activity android:name=".ExampleActivity" android:icon="@drawable/app_icon"&gt;
+ &lt;intent-filter&gt;
+ &lt;action android:name="android.intent.action.MAIN" /&gt;
+ &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
+ &lt;/intent-filter&gt;
+&lt;/activity&gt;
+</pre>
+
+<p><a href="{@docRoot}guide/topics/manifest/action-element.html">{@code
+&lt;action&gt;}</a> 元素指出這是應用程式的「主要」進入點。<a href="{@docRoot}guide/topics/manifest/category-element.html">{@code
+&lt;category&gt;}</a> 元素指出此 Activity 應列於系統的應用程式啟動器 (以允許使用者啟動此 Activity)。
+</p>
+
+<p>如果您本來就要讓應用程式獨自運作,不要讓其他應用程式啟動其 Activity,則不需要任何其他意圖篩選器。
+只有一個 Activity 可以有「主要」動作和「啟動器」類別,如同上一個範例所示。
+您不要讓其他應用程式使用的 Activity,則不應使用意圖篩選器,而且您可以使用明確的意圖自行加以啟動 (將於以下小節討論)。
+
+</p>
+
+<p>不過,如果您的 Activity 需要回應從其他應用程式 (和您自己的應用程式) 傳送過來的隱含式意圖,則必須為您的 Activity 定義額外的意圖篩選器。
+
+針對您要回應的意圖類型,您必須包括 <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code
+&lt;intent-filter&gt;}</a>,其中內含
+<a href="{@docRoot}guide/topics/manifest/action-element.html">{@code
+&lt;action&gt;}</a> 元素和 <a href="{@docRoot}guide/topics/manifest/category-element.html">{@code
+&lt;category&gt;}</a> 元素 (選用) 和/或 <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code
+&lt;data&gt;}</a> 元素。這些元素會指定您的 Activity 可以回應哪些類型的意圖。
+</p>
+
+<p>如需關於您的 Activity 如何回應意圖的詳細資訊,請參閱<a href="{@docRoot}guide/components/intents-filters.html">意圖和意圖篩選器</a>。
+</p>
+
+
+
+<h2 id="StartingAnActivity">啟動 Activity</h2>
+
+<p>透過呼叫 {@link android.app.Activity#startActivity
+ startActivity()}、將 {@link android.content.Intent} (描述要啟動的 Activity) 傳給它,您可以啟動另一個 Activity。
+意圖會指出您要啟動的那個 Activity,或描述您要執行的動作類型 (而讓系統為您選取適當的 Activity,甚至可以是來自不同應用程式的 Activity)。
+
+
+意圖也可以攜帶少量的資料給已啟動的 Activity 使用。
+</p>
+
+<p>在您自己的應用程式內運作時,通常只要啟動已知的 Activity。
+ 建立意圖並明確定義您要啟動的 Activity (使用類別名稱),可以達成此目的。
+例如,以下示範 Activity 如何啟動另一個名為 {@code
+SignInActivity} 的 Activity:</p>
+
+<pre>
+Intent intent = new Intent(this, SignInActivity.class);
+startActivity(intent);
+</pre>
+
+<p>不過,您的應用程式也希望可以執行其他動作,例如使用您 Activity 中的資料以傳送電子郵件、文字訊息或狀態更新。
+在此情況下,您的應用程式可能就沒有專屬的 Activity 來執行這類動作。因此,您可以改為運用裝置上其他應用程式提供的 Activity。讓這些 Activity 為您執行所需的動作。
+
+這正是意圖寶貴的地方 &mdash; 您可以建立意圖,在其中描述您要執行的動作,然後系統會從另一個應用程式啟動適當的 Activity。
+
+
+如果有多個 Activity 都可以處理意圖,則使用者可以選取要使用哪個 Activity。
+例如,如果要讓使用者傳送電子郵件訊息,您可以建立下列意圖:
+
+</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} 額外值是一個字串陣列,由應該要寄送電子郵件的電子郵件地址所組成。
+電子郵件應用程式回應此意圖時,它會讀取額外值中提供的字串陣列,並將這些內容放置在編寫電子郵件表單的「收件人」欄位。
+
+在此情況下,電子郵件應用程式的 Activity 會啟動,並且會在使用者完成後,繼續您的 Activity。
+</p>
+
+
+
+
+<h3 id="StartingAnActivityForResult">啟動 Activity 以取得結果</h3>
+
+<p>有時候,您會想要收到由您啟動 Activity 的結果。如要接收結果,請透過呼叫 {@link android.app.Activity#startActivityForResult
+ startActivityForResult()} (而非 {@link android.app.Activity#startActivity
+ startActivity()}) 以啟動 Activity。
+如要接收後續 Activity 的結果,請實作 {@link android.app.Activity#onActivityResult onActivityResult()} 回呼方法。
+
+後續 Activity 完成時,會將 {@link
+android.content.Intent} 中的結果傳回到您的 {@link android.app.Activity#onActivityResult onActivityResult()} 方法。
+</p>
+
+<p>例如,您可能會讓使用者在聯絡人中挑選一位,讓您的 Activity 可以針對該聯絡人的資訊進行一些處理。
+以下示範如何建立這類意圖,並處理結果:
+</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);
+}
+
+&#64;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 &amp;&amp; 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()} 方法中使用的基本邏輯,以便處理 Activity 結果。
+第一個條件會檢查要求是否成功 &mdash; 如果成功,則{@code resultCode} 會是 {@link android.app.Activity#RESULT_OK} &mdash;,以及此結果回應的要求是否為已知的要求 &mdash; 範例中的 {@code requestCode} 符合以 {@link android.app.Activity#startActivityForResult
+startActivityForResult()} 傳送的第二個參數。
+
+
+程式碼在這裡透過查詢 {@link android.content.Intent} ({@code data} 參數) 中傳回的資料,來處理 Activity 結果。
+</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">關閉 Activity</h2>
+
+<p>呼叫 Activity 的 {@link android.app.Activity#finish
+finish()} 方法,可以關閉此 Activity。您也可以呼叫
+{@link android.app.Activity#finishActivity finishActivity()},關閉您之前啟動的個別 Activity。</p>
+
+<p class="note"><strong>注意:</strong>大多數情況,您不應使用這些方法明確地結束 Activity。
+如同下一節所討論的 Activity 生命週期,Android 系統會為您管理 Activity 的生命週期,所以您不需要結束您自己的 Activity。
+
+呼叫這些方法對使用者體驗有負面的影響,只有在您十分確定不希望使用者返回 Activity 的此執行個體時,才加以呼叫。
+
+</p>
+
+
+<h2 id="Lifecycle">管理 Activity 生命週期</h2>
+
+<p>實作回呼方法來管理 Activity 的生命週期,對於開發強大且有彈性的應用程式來說,相當重要。
+
+Activity 的生命週期受到相關其他 Activity、本身的工作以及返回堆疊的直接影響。
+</p>
+
+<p>Activity 基本上有以下三種狀態:</p>
+
+<dl>
+ <dt><i>已繼續</i></dt>
+ <dd>Activity 位於螢幕的前景,具有使用者焦點 (此狀態有時候也稱為「執行中」)。
+</dd>
+
+ <dt><i>已暫停</i></dt>
+ <dd>前景中有其他具備焦點的 Activity,但系統仍然可以看到這個 Activity。也就是說,這個 Activity 上方有另一個,該 Activity 為半透明,或是未覆蓋整個螢幕。
+
+已暫停的 Activity 是完全有效的 ({@link android.app.Activity} 物件會保留在記憶體中、維護所有狀態和成員資訊,以及繼續附加至視窗管理員),但在系統記憶體極低的情況下會遭到終止。
+
+</dd>
+
+ <dt><i>已停止</i></dt>
+ <dd>另一個 Activity 已完全遮蓋原本的 Activity (原本的 Activity 現在位於「背景」)。
+已停止的 Activity 仍然是有效的 ({@link android.app.Activity} 物件會保留在記憶體中、維護所有狀態和成員資訊,但「不會」<em></em>附加至視窗管理員)。
+
+只是使用者不會再看到已停止的 Activity,而且其他地方需要記憶體時,系統會將它終止。
+</dd>
+</dl>
+
+<p>如果 Activity 已暫停或已停止,系統可以透過要求它結束 (呼叫其 {@link android.app.Activity#finish finish()} 方法) 或直接終止其處理程序,將它從記憶體中刪除。
+
+Activity 遭到結束或終止後,再次開啟時,必須全部重新建立。
+</p>
+
+
+
+<h3 id="ImplementingLifecycleCallbacks">實作生命週期回呼</h3>
+
+<p>Activity 在不同的狀態之間轉換時 (如上所述),會透過各種回呼方法進行通知。
+所有的回呼方法都是虛設,請加以覆寫,以便在 Activity 狀態變更時,執行適當的工作。
+下列主要 Activity 包括每個基礎生命週期方法:
+</p>
+
+
+<pre>
+public class ExampleActivity extends Activity {
+ &#64;Override
+ public void {@link android.app.Activity#onCreate onCreate}(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // The activity is being created.
+ }
+ &#64;Override
+ protected void {@link android.app.Activity#onStart onStart()} {
+ super.onStart();
+ // The activity is about to become visible.
+ }
+ &#64;Override
+ protected void {@link android.app.Activity#onResume onResume()} {
+ super.onResume();
+ // The activity has become visible (it is now "resumed").
+ }
+ &#64;Override
+ protected void {@link android.app.Activity#onPause onPause()} {
+ super.onPause();
+ // Another activity is taking focus (this activity is about to be "paused").
+ }
+ &#64;Override
+ protected void {@link android.app.Activity#onStop onStop()} {
+ super.onStop();
+ // The activity is no longer visible (it is now "stopped")
+ }
+ &#64;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>總而言之,這些方法定義了 Activity 的整個生命週期。透過實作這些方法,您可以監視 Activity 生命週期中的三個巢狀迴圈:
+ </p>
+
+<ul>
+<li>Activity 的<b>整個生命週期</b>是介於 {@link
+android.app.Activity#onCreate onCreate()} 呼叫和 {@link
+android.app.Activity#onDestroy} 呼叫之間。您的 Activity 應在 {@link android.app.Activity#onCreate onCreate()} 中設定「全域」狀態 (例如定義版面配置),並且在 {@link android.app.Activity#onDestroy} 中釋放所有剩餘的資源。
+
+例如,如果您的 Activity 有一個執行緒在背景執行,並從網路下載資料,那麼最好可以在 {@link android.app.Activity#onCreate onCreate()} 中建立該執行緒,然後在 {@link
+android.app.Activity#onDestroy} 中將它停止。
+
+</li>
+
+<li><p>Activity 的<b>可見生命週期</b>是介於 {@link
+android.app.Activity#onStart onStart()} 呼叫和 {@link
+android.app.Activity#onStop onStop()} 呼叫之間。在此期間,使用者可以在螢幕上看到該 Activity,並與之互動。
+例如,啟動新的 Activity,而這個 Activity 不再看得到時,會呼叫 {@link android.app.Activity#onStop onStop()}。
+在這兩個方法之間,您可以維護需要讓使用者看到的資源。
+例如,您可以在{@link
+android.app.Activity#onStart onStart()} 中註冊
+{@link android.content.BroadcastReceiver},以監視影響到 UI 的變更,然後當使用者不再看到您顯示的內容時,在 {@link android.app.Activity#onStop onStop()} 中將它取消註冊。
+
+系統可以在 Activity 的整個生命週期時,多次呼叫 {@link android.app.Activity#onStart onStart()} 和 {@link
+android.app.Activity#onStop onStop()},因為 Activity 對使用者而言會一直在顯示和隱藏之間切換。
+</p></li>
+
+<li><p>Activity 的<b>前景生命週期</b>是介於 {@link
+android.app.Activity#onResume onResume()} 呼叫和 {@link android.app.Activity#onPause
+onPause()} 呼叫之間。在此期間,Activity 會在螢幕上所有其他 Activity 的前面,而且具有使用者輸入焦點。
+Activity 可以經常在前景和背景之間轉換 &mdash; 例如,裝置進入睡眠或顯示對話方塊時,會呼叫 {@link android.app.Activity#onPause onPause()}。
+
+由於此狀態可能會經常轉換,因此這兩個方法中的程式碼應十分精簡,這樣可以避免使用者在轉換時等待。
+</p></li>
+</ul>
+
+<p>圖 1 說明 Activity 在轉換狀態時的可能迴圈和路徑。長方形代表您可以實作的回呼方法,以便 Activity 在轉換狀態時執行操作。
+
+ <p>
+
+<img src="{@docRoot}images/activity_lifecycle.png" alt="" />
+<p class="img-caption"><strong>圖 1.</strong>Activity 生命週期。</p>
+
+<p>表 1 列出相同的生命週期回呼方法,其中詳細描述每個回呼方法,並且指出每個回呼方法在 Activity 整個生命週期中的位置,包括系統是否可以在回呼方法完成後終止 Activity。
+
+
+</p>
+
+<p class="table-caption"><strong>表 1.</strong>Activity 生命週期回呼方法摘要。
+</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>一開始建立 Activity 時呼叫。
+ 您應該在這裡所有的一般靜態設定 &mdash; 建立檢視、將資料繫結至清單等等。
+「套件」物件會傳送給此方法,如果有擷取到狀態,此物件會內含 Activity 的上一個狀態 (請參閱下文的<a href="#actstate">儲存 Activity 狀態</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;">&nbsp;&nbsp;&nbsp;&nbsp;</td>
+ <td colspan="2" align="left"><code>{@link android.app.Activity#onRestart
+onRestart()}</code></td>
+ <td>Activity 已停止後,即將再次啟動之前呼叫。
+
+ <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>Activity 即將要讓使用者看到之前呼叫。
+ <p>如果 Activity 移到前景,後面會接著 {@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;">&nbsp;&nbsp;&nbsp;&nbsp;</td>
+ <td align="left"><code>{@link android.app.Activity#onResume onResume()}</code></td>
+ <td>Activity 即將與使用者開始互動之前呼叫。
+此時,Activity 位於 Activity 堆疊的最上方,接受使用的輸入。
+
+ <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>系統即將開始繼續另一個 Activity 時呼叫。
+認可對永久資料的未儲存變更、停止動畫,以及會使用 CPU 等等資源的其他操作時,一般會使用此方法。
+
+不論此操作會執行什麼動作,都要快速完成,這是因為此方法傳回後,才會繼續下一個 Activity。
+
+ <p>如果 Activity 返回前景,後面會接著 {@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>使用者看不到 Activity 時呼叫。Activity 遭到終止或另一個 Activity (不論是現有 Activity 或新的 Activity) 已經繼續,而且將它覆蓋住,就會發生此情形。
+
+
+ <p>如果 Activity 回來與使用者互動,後面會接著 {@code onRestart()},如果 Activity 離開,後面會接著
+ {@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>在 Activity 終止前呼叫。Activity 會接收到的最後呼叫。
+Activity 正在完成 (有人在 Activity 上呼叫 <code>{@link android.app.Activity#finish
+ finish()}</code>),或系統正在暫時終止 Activity 的這個執行個體以節省空間時,會呼叫此方法。
+
+您可以使用 <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>此欄標示為「完成後是否可終止?」表示系統是否可以「在方法傳回後」隨時終止代管 Activity 的處理程序<em></em>,而不需要執行另一行 Activity 的程式碼。
+
+有三個方法標示為「是」:({@link
+android.app.Activity#onPause
+onPause()}、{@link android.app.Activity#onStop onStop()} 以及 {@link android.app.Activity#onDestroy
+onDestroy()})。由於 {@link android.app.Activity#onPause onPause()} 是這三個方法中的第一個方法,Activity 建立後,{@link android.app.Activity#onPause onPause()} 是一定會呼叫的最後一個方法,之後處理程序才能加以終止<em></em> &mdash; 如果系統必須緊急收回記憶體,可能就不會呼叫 {@link
+android.app.Activity#onStop onStop()} 和 {@link android.app.Activity#onDestroy onDestroy()}。
+
+
+
+因此,您應該使用 {@link android.app.Activity#onPause onPause()} 將極為重要的永久資料 (例如使用者的編輯內容) 寫入儲存空間。
+不過,您應選擇哪些資訊必須在 {@link android.app.Activity#onPause onPause()} 期間加以保留,這是因為此方法中的任何程序遭到封鎖,都無法轉換到下一個 Activity,而且會讓使用者體驗變慢。
+
+
+</p>
+
+<p> 在「是否可終止」<b></b>欄標示為「否」的方法,從呼叫這些方法的那一刻起,會保護代管 Activity 的處理程序不會遭到終止。
+因此,Activity 從 {@link android.app.Activity#onPause onPause()} 傳回到呼叫
+ {@link android.app.Activity#onResume onResume()} 的期間為可終止。
+再次呼叫和傳回
+{@link android.app.Activity#onPause onPause()} 之前,Activity 為不可終止。 </p>
+
+<p class="note"><strong>注意:</strong>表 1 中定義為不是「可終止」的 Activity 仍可遭到系統終止 &mdash; 但只會發生在無技可施的情況下。
+
+Activity 可加以終止的時機,於<a href="{@docRoot}guide/components/processes-and-threads.html">處理和執行緒</a>文件中有更詳細的討論。
+
+</p>
+
+
+<h3 id="SavingActivityState">儲存 Activity 狀態</h3>
+
+<p><a href="#Lifecycle">管理 Activity 生命週期</a>的簡介中提到,當 Activity 暫停或停止時,會保留 Activity 的狀態。
+
+這點是成立的,原因在於當 {@link android.app.Activity} 物件暫停或停止時,它仍然保留在記憶體中 &mdash; 關於它的成員和目前狀態的所有資訊,仍然為有效的。
+
+因此,使用者在 Activity 內所做的任何變更,都會保留下來。所以,當 Activity 返回前景 (當它「繼續」時),那些變更仍然會在原地。
+
+</p>
+
+<p>不過,當系統終止 Activity 以收回記憶體時,{@link
+android.app.Activity} 物件會遭到終止,所以系統就無法將它及其狀態完好無缺地繼續。
+如果使用者瀏覽回 {@link android.app.Activity} 物件,系統必須加以重新建立。
+但是,使用者不會注意到系統已終止該 Activity 並加以重新建立,可能因此期待 Activity 就跟之前的狀態一樣。
+
+如果是這樣,您可以實作額外的回呼方法,以確認 Activity 狀態相關的重要資訊會保留下來。此回呼方法讓您儲存關於 Activity 狀態的資訊:{@link
+android.app.Activity#onSaveInstanceState onSaveInstanceState()}。
+
+</p>
+
+<p>系統會在終止 Activity 之前呼叫 {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()}。
+系統會將 {@link android.os.Bundle} 傳送給此方法,您可以使用 {@link
+android.os.Bundle#putString putString()} 和 {@link
+android.os.Bundle#putInt putInt()} 之類的方法,將 Activity 相關的狀態資訊以名稱-值組的方式儲存。
+
+然後,如果系統終止應用程式處理程序,並且使用者瀏覽回您的 Activity,則系統會重新建立 Activity,然後將 {@link android.os.Bundle} 傳送給 {@link android.app.Activity#onCreate onCreate()} 和 {@link
+android.app.Activity#onRestoreInstanceState onRestoreInstanceState()}。
+
+您可以使用以上其中一種方法,從 {@link android.os.Bundle} 擷取已儲存的狀態,然後還原 Activity 狀態。
+
+如果沒有狀態資訊可供還原,則傳送過來的 {@link
+android.os.Bundle} 為空值 (null) (第一次建立 Activity 時,就是這種情況)。
+</p>
+
+<img src="{@docRoot}images/fundamentals/restore_instance.png" alt="" />
+<p class="img-caption"><strong>圖 2.</strong>Activity 返回使用者焦點,同時具備完整狀態的兩種方式:Activity 遭到終止,然後重新建立,Activity 必須還原之前儲存的狀態;或者Activity 已停止,然後繼續,Activity 狀態維持完整。
+
+
+</p>
+
+<p class="note"><strong>注意:</strong>不保證在您的 Activity 遭到終止之前,一定會呼叫 {@link
+android.app.Activity#onSaveInstanceState onSaveInstanceState()},這是因為有時會發生不需要儲存狀態的情形 (例如,使用者使用「返回」按鈕離開您的 Activity 時<em></em>,原因在於使用者明確地關閉 Activity)。
+
+
+
+如果系統要呼叫 {@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()},有些 Activity 狀態會經由{@link android.app.Activity} 類別的預設實作 {@link
+android.app.Activity#onSaveInstanceState onSaveInstanceState()} 而還原。
+具體來說,預設實作會針對版面配置中的每一個 {@link
+android.view.View} 呼叫對應的 {@link
+android.view.View#onSaveInstanceState onSaveInstanceState()} 方法,這樣可以讓每個檢視提供本身應該要儲存的相關資訊。
+
+在 Android 架構中,幾乎每個小工具都適當地實作此方法,因此 UI 中可見的變更都會自動儲存,並於 Activity 重新建立時加以還原。
+
+例如,{@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()} 方法即可。
+您通常不應停用儲存狀態的功能,不過,如果您想要還原不同的 Activity UI 狀態,則另當別論。
+</p>
+</div>
+</div>
+
+<p>儘管 {@link
+android.app.Activity#onSaveInstanceState onSaveInstanceState()} 的預設實作會儲存 Activity UI 相關的實用資訊,您仍然需要加以覆寫,以儲存額外的資訊,例如,您需要儲存 Activity 生命期間變更的成員值 (此真可能與 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()},您只能用它來記錄 Activity 的短暫狀態 (UI 的狀態) &mdash; 不應該用它儲存永久資料。
+
+而是要在使用者離開 Activity 時,利用 {@link
+android.app.Activity#onPause onPause()} 來儲存永內資料 (例如要儲存到資料庫的資料)。
+</p>
+
+<p>測試應用程式是否能夠還原其狀態的好方式,只要旋轉裝置,改變螢幕方向即可。
+螢幕方向改變時,系統會終止 Activity 並重新建立,以便套用針對新的螢幕設定而提供使用的替代資源。
+
+單單就這一點而言,您的 Activity 在重新建立時可以完整還原,就非常重要了,這是因為使用者操作應用程式時會經常旋轉螢幕。
+
+</p>
+
+
+<h3 id="ConfigurationChanges">處理設定變更</h3>
+
+<p>有些裝置設定可以在執行階段期間進行變更 (例如,螢幕方向、鍵盤可用性和語言)。
+發生這類變更時,Android 會重新建立執行中的 Activity (系統呼叫 {@link android.app.Activity#onDestroy},然後立即呼叫 {@link
+android.app.Activity#onCreate onCreate()})。
+此行為的設計透過自動重新載入應用程式與提供的替代資源 (例如針對不同的螢幕方向和大小的不同版面配置),可協助應用程式適應新的設定。
+
+
+</p>
+
+<p>如果您如上所述正確地設計 Activity,處理由於螢幕方向變更的重新啟動,然後還原 Activity 的狀態,您的應用程式對於 Activity 生命週期中的不可預期事件,會更具有抗性。
+
+</p>
+
+<p>處理這類重新啟動的最佳方式,是使用 {@link
+android.app.Activity#onSaveInstanceState onSaveInstanceState()} 和 {@link
+android.app.Activity#onRestoreInstanceState onRestoreInstanceState()} (或 {@link
+android.app.Activity#onCreate onCreate()}) 儲存並還原 Activity 的狀態,如同上一節所討論。
+</p>
+
+<p>如需關於執行階段發生的設定變更,以及如何加以處理的詳細資訊,請參閱<a href="{@docRoot}guide/topics/resources/runtime-changes.html">處理執行階段變更</a>指南。
+
+</p>
+
+
+
+<h3 id="CoordinatingActivities">協調 Activity</h3>
+
+ <p>Activity 啟動另一個 Activity 時,它們兩者都經歷生命週期轉換。第一個 Activity 暫停並停止 (雖然如果仍然可以在背景看到它,表示它並未真的「停止」),而另一個 Activity 建立起來。
+
+若這些 Activity 共用儲存到磁碟或其他地方的資料,第一個 Activity 在第二個 Activity 已建立之前,不會完全停止,瞭解這件事很重要。然而,啟動第二個 Activity 的處理程序與停止第一個 Activity 的處理程序會重疊。
+
+
+</p>
+
+<p>生命週期回呼的順序定義的很好,尤其是當兩個 Activity 位於相同的處理程序,而其中一個 Activity 啟動另一個 Activity 時。
+Activity A 啟動 Activity B 時所發生的操作順利如下:
+ </p>
+
+<ol>
+<li>Activity A 的 {@link android.app.Activity#onPause onPause()} 方法會執行。</li>
+
+<li>Activity B 按順序執行 {@link android.app.Activity#onCreate onCreate()}、{@link
+android.app.Activity#onStart onStart()} 以及 {@link android.app.Activity#onResume onResume()} 方法。
+(Activity B 現在擁有使用者焦點)。</li>
+
+<li>然後,如果螢幕上已經看不到 Activity A,就會執行 Activity A 的 {@link
+android.app.Activity#onStop onStop()} 方法。</li>
+</ol>
+
+ <p>這一段可預測的生命週期回呼,可以讓您管理 Activity 之間資訊的轉換。
+例如,如果第一個 Activity 停止時,您必須寫入資料庫,讓接下來的 Activity 可以讀取,那麼您應該在 {@link android.app.Activity#onPause onPause()} 期間寫入,而不是在 {@link
+android.app.Activity#onStop onStop()} 期間寫入。
+
+</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/zh-tw/guide/components/bound-services.jd b/docs/html-intl/intl/zh-tw/guide/components/bound-services.jd
new file mode 100644
index 000000000000..da47634b894f
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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">使用 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>繫結服務是主從介面中的伺服器。繫結服務讓元件 (例如 Activity) 可以繫結至服務、傳送要求、接收回應,甚至執行處理程序間通訊 (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()},但有時候需要實作兩者。
+
+例如,此功能對於音樂播放器就很實用,除了可以讓服務無限期執行,也可以提供繫結功能。
+這樣一來,Activity 就可以啟用服務並播放音樂,然後即使使用者離開應用程式後,音樂仍然繼續播放。
+使用者後續回到此應用程式時,Activity 可以繫結至服務,以重新取得播放的控制權。
+</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#onServiceConnected onServiceConnected()} (位於 {@link
+android.content.ServiceConnection}) 以傳遞 {@link android.os.IBinder} (用戶端可以用來與服務溝通)。
+
+
+</p>
+
+<p>多個用戶端可以同時連線至該服務。不過,系統只會在用戶端第一次繫結時,呼叫服務的
+{@link android.app.Service#onBind onBind()} 方法,以擷取 {@link android.os.IBinder}。
+然後,系統會將同一個 {@link android.os.IBinder} 傳遞給其他任何繫結的用戶端,不會再次呼叫 {@link android.app.Service#onBind onBind()}。
+</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} 程式設計介面。用戶端可以使用此介面與服務互動。
+定義介面有三種方式:
+</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} 提供的公用方法。
+
+
+ <p>若您的服務只是您自己應用程式的背景工作者,建議使用此方式。
+除非您的服務是由其他應用程式或跨個別處理程序使用,才不用以此方式建立自己的介面。
+</dd>
+
+ <dt><a href="#Messenger">使用 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} 會將所有要求都排列到單一個執行緒,因此,就不用將服務設計成執行緒安全的形式。
+</p>
+ </dd>
+
+ <dt>使用 AIDL</dt>
+ <dd>AIDL (Android 介面定義語言) 的工作是將物件分解為作業系統瞭解的始類型,然後將這些原始類型在各個處理程序間進行封送,以執行 IPC。先前使用 {@link android.os.Messenger} 的技術,實際上就是以 AIDL 作為底層結構。
+
+
+如上所述,{@link android.os.Messenger} 會在單一執行緒中建立所有用戶端要求的佇列,所以服務一次會接收一個要求。
+不過,如果您要讓服務可以同時處理多個要求,則可以直接使用 AIDL。
+
+在此情況下,您的服務必須具備多執行緒的功能,而且是以執行緒安全的形式建置。
+ <p>如要直接使用 AIDL,您必須建立 {@code .aidl} 檔案,並在其中定義程式設計介面。
+Android SDK 工具會使用此檔案產生一個抽象類別,以便實作介面並處理 IPC。您就可以在服務內加以延伸。
+
+</p>
+ </dd>
+</dl>
+
+ <p class="note"><strong>注意:</strong>大部分應用程式<strong>不應</strong>使用 AIDL 建立繫結服務,若自行建立的話,就需要實作多執行緒功能,可能會導致更複雜的實作。
+
+因此,AIDL 不適用於大部分應用程式,而且本文不會討論如何在您的服務中使用 AIDL。
+如果您確定需要直接使用 AIDL,請參閱 <a href="{@docRoot}guide/components/aidl.html">AIDL</a> 文件。
+
+</p>
+
+
+
+
+<h3 id="Binder">延伸 Binder 類別</h3>
+
+<p>如果您的服務只會在本機應用程式使用,而且不需要跨處理程序運作,則可以實作您自己的 {@link android.os.Binder} 類別,讓用戶端直接存取服務中的公用方法。
+
+</p>
+
+<p class="note"><strong>注意:</strong>用戶端和服務都位於相同應用程式和處理程序時才適用,這也是最常見的情況。
+例如,需要將 Activity 繫結到其專屬服務 (在背景播放音樂)的音樂應用程式,就很適合。
+
+</p>
+
+<p>設定的方式如下:</p>
+<ol>
+ <li>在您的服務中建立 {@link android.os.Binder} 的執行個體,以具備以下其中一種功用:
+ <ul>
+ <li>包含用戶端可以呼叫的公用方法</li>
+ <li>傳回目前的 {@link android.app.Service} 執行個體,其中含有用戶端可以呼叫的公用方法
+</li>
+ <li>傳回由服務所裝載另一個類別的執行個體,而此服務含有用戶端可以呼叫的公用方法
+</li>
+ </ul>
+ <li>從 {@link
+android.app.Service#onBind onBind()} 回呼方法傳回此 {@link android.os.Binder} 的執行個體。</li>
+ <li>在用戶端方面,從 {@link
+android.content.ServiceConnection#onServiceConnected onServiceConnected()} 回呼方法接收 {@link android.os.Binder},然後使用提供的方法呼叫繫結服務。
+</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;
+ }
+ }
+
+ &#64;Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ /** method for clients */
+ public int getRandomNumber() {
+ return mGenerator.nextInt(100);
+ }
+}
+</pre>
+
+<p>{@code LocalBinder} 提供 {@code getService()} 方法,讓用戶端擷取 {@code LocalService} 目前的執行個體。
+這樣可以讓用戶端呼叫服務中的公用方法。
+例如,用戶端可以從服務呼叫 {@code getRandomNumber()}。</p>
+
+<p>當按一下按鈕時,會發生繫結至 {@code LocalService} 並呼叫 {@code getRandomNumber()}的 Activity:
+</p>
+
+<pre>
+public class BindingActivity extends Activity {
+ LocalService mService;
+ boolean mBound = false;
+
+ &#64;Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+ }
+
+ &#64;Override
+ protected void onStart() {
+ super.onStart();
+ // Bind to LocalService
+ Intent intent = new Intent(this, LocalService.class);
+ bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+ }
+
+ &#64;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() {
+
+ &#64;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;
+ }
+
+ &#64;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>上述範例未明確從服務解除繫結,但所有用戶端都應該在適當時間解除繫結 (例如,Activity 暫停時)。
+</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">使用 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} 讓服務一次處理一個呼叫。如果您的服務必須處理多執行緒,則要使用 <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.os.IBinder},服務會從 {@link android.app.Service#onBind onBind()} 傳回給用戶端。
+</li>
+ <li>用戶端使用 {@link android.os.IBinder} 將 {@link android.os.Messenger} (參照服務的 {@link android.os.Handler}) 具現化,用戶端就可以用來將
+{@link android.os.Message} 物件傳送給服務。
+</li>
+ <li>服務會在其 {@link
+android.os.Handler} 中接收每個 {@link android.os.Message} &mdash; 更明確地說,就是在 {@link android.os.Handler#handleMessage
+handleMessage()} 方法中加以接收。</li>
+</ul>
+
+
+<p>這樣一來,用戶端就不需要呼叫服務的任何「方法」。用戶端只要傳遞「訊息」({@link android.os.Message} 物件),服務就會在其 {@link android.os.Handler} 中接收。
+
+</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 {
+ &#64;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.
+ */
+ &#64;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()} 傳送訊息。例如,以下的簡單 Activity 會繫結至服務,然後將 {@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();
+ }
+ }
+
+ &#64;Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+ }
+
+ &#64;Override
+ protected void onStart() {
+ super.onStart();
+ // Bind to the service
+ bindService(new Intent(this, MessengerService.class), mConnection,
+ Context.BIND_AUTO_CREATE);
+ }
+
+ &#64;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.Message} 給服務,其中包括用戶端的 {@link android.os.Messenger} (位於 {@link android.os.Messenger#send send()} 方法的 {@link android.os.Message#replyTo} 參數中)。
+
+
+</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()} 會立即傳回,但「不會」將<em></em> {@link android.os.IBinder} 傳回給用戶端。
+如要接收 {@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>只有 Activity、服務以及內容提供者可以繫結至服務 &mdash; 您<strong>不能</strong>從廣播接收者繫結至服務。
+</p>
+
+<p>因此,如要從用戶端繫結至服務,必須符合下列條件: </p>
+<ol>
+ <li>實作 {@link android.content.ServiceConnection}。
+ <p>實作中必須覆寫兩個回呼方法:</p>
+ <dl>
+ <dt>{@link android.content.ServiceConnection#onServiceConnected onServiceConnected()}</dt>
+ <dd>系統會呼叫此方法來傳遞 {@link android.os.IBinder} (由服務的 {@link android.app.Service#onBind onBind()} 方法所傳回)。
+</dd>
+ <dt>{@link android.content.ServiceConnection#onServiceDisconnected
+onServiceDisconnected()}</dt>
+ <dd>與服務之間的連線突然遺失時 (例如服務當機或遭到終止時),Android 系統會呼收此方法。
+用戶端解除繫結時,「不會」<em></em>呼叫此方法。
+</dd>
+ </dl>
+ </li>
+ <li>呼叫會傳送 {@link
+android.content.ServiceConnection} 實作的 {@link
+android.content.Context#bindService bindService()}。 </li>
+ <li>系統呼叫 {@link android.content.ServiceConnection#onServiceConnected
+onServiceConnected()} 回呼方法時,您就可以使用介面定義的方法,開始呼叫服務。
+</li>
+ <li>如要與服務中斷連線,請呼叫 {@link
+android.content.Context#unbindService unbindService()}。
+ <p>用戶端遭到終結時,會與服務解除繫結。不過,您應該要在與服務完成互動時,或者 Activity 暫停,要讓服務未使用時可以加以關閉的情況下,一定要解除繫結。
+
+(以下將有繫結和解除繫結適當時機的詳細討論)。
+</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>第二個參數是 {@link android.content.ServiceConnection} 物件。</li>
+<li>第三個參數是旗標,用來指出繫結的選項。如果服務尚未存在,通常是使用 {@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>如果您只要在 Activity 可見時與服務互動,則要在 {@link android.app.Activity#onStart onStart()} 時繫結,並於 {@link
+android.app.Activity#onStop onStop()} 時解除繫結。
+</li>
+ <li>如果您希望 Activity 即使在背景中停止時,仍然會接收回應,則可以在 {@link android.app.Activity#onCreate onCreate()} 時繫結,並於{@link android.app.Activity#onDestroy onDestroy()} 時解除繫結。
+
+請注意,這表示您的 Activity 在整個執行期間 (即使是在背景執行也一樣) 都需要使用服務,因此,如果服務位於另一個處理程序,您要增加該處理程序的權重。但系統很可能因而將它終止。
+
+
+</li>
+ </ul>
+ <p class="note"><strong>注意:</strong>Activity 的 {@link android.app.Activity#onResume onResume()} 和 {@link
+android.app.Activity#onPause onPause()} 期間,通常<strong>不要</strong>繫結和解除繫結,因為這些回呼會在每個週期轉換時發生,而且您應該要讓這些轉換期間所發生的處理動作保持在最少狀態。
+
+另外,如果您的應用程式中有多個 Activity 繫結至同一個服務,而這兩個 Activity 之間會進行轉換,則服務會在目前的 Activity 解除繫結(暫停) 時,而下一個 Activity 繫結之前 (繼續時),先終結後再重新建立
+
+
+(此 Activity 轉換如何在 Activity 之間協調其週期的資訊,於 <a href="{@docRoot}guide/components/activities.html#CoordinatingActivities">Activity</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()} 一起啟動的)。
+如果您的服務純粹是繫結服務,就不用管理它的週期&mdash; 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()} 方法時,可以選擇傳回
+{@code true} (如果您希望用戶端下次繫結至服務時,可以接收 {@link android.app.Service#onRebind
+onRebind()} 呼叫,而不是接收 {@link
+android.app.Service#onBind onBind()} 的呼叫)。{@link android.app.Service#onRebind
+onRebind()} 會傳回空值,但用戶端仍然會在其
+{@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/zh-tw/guide/components/fragments.jd b/docs/html-intl/intl/zh-tw/guide/components/fragments.jd
new file mode 100644
index 000000000000..e54769b0c88b
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/guide/components/fragments.jd
@@ -0,0 +1,812 @@
+page.title=片段
+parent.title=Activity
+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">將片段新增到 Activity 中</a></li>
+ </ol>
+ </li>
+ <li><a href="#Managing">管理片段</a></li>
+ <li><a href="#Transactions">進行片段交易</a></li>
+ <li><a href="#CommunicatingWithActivity">與 Activity 通訊</a>
+ <ol>
+ <li><a href="#EventCallbacks">為 Activity 建立事件回呼</a></li>
+ <li><a href="#ActionBar">將項目新增到動作列中</a></li>
+ </ol>
+ </li>
+ <li><a href="#Lifecycle">處理片段生命週期</a>
+ <ol>
+ <li><a href="#CoordinatingWithActivity">調整 Activity 生命週期</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">使用片段建置動態 UI</a></li>
+ <li><a href="{@docRoot}guide/practices/tablets-and-handsets.html">支援平板電腦和手機</a>
+</li>
+ </ol>
+</div>
+</div>
+
+<p>{@link android.app.Fragment} 代表一種行為或
+{@link android.app.Activity} 中的一部分使用者介面。您可以合併單一 Activity 中的多個片段,藉此建置
+多窗格 UI 以及在多個 Activity 中重複使用片段。您可以將片段想成是 Activity 的模組化區段,片段擁有自己的生命週期、接收自己的輸入事件,而且您可以在 Activity 執行時新增或移除片段 (有點像是您可以在不同 Activity 中重複使用的「子 Activity」)。
+
+
+</p>
+
+<p>片段必須一律嵌入 Activity 中,而主要 Activity 的生命週期會直接影響片段的生命週期。
+例如,當 Activity 暫停時,其中的所有片段也會一併暫停;而當 Activity 遭到刪除時,所有片段也會一併刪除。
+不過,當 Activity 執行時 (該 Activity 會處於繼續進行<em></em><a href="{@docRoot}guide/components/activities.html#Lifecycle">生命週期狀態</a>),您可以個別操縱所有片段,例如新增或移除片段。
+
+當您進行片段交易這類操作時,您也可以將片段加到 Activity 所管理的返回堆疊中 &mdash; Activity 中的所有返回堆疊項目均為所發生片段交易的記錄。
+
+
+返回堆疊可讓使用者復原片段交易 (往回瀏覽),只要按下 [返回]<em></em> 按鈕即可。
+</p>
+
+<p>當您將片段新增為 Activity 版面配置的一部分後,片段就會位於 Activity 檢視階層中的 {@link
+android.view.ViewGroup},而且片段會自行定義專屬的版面配置。您可以宣告 Activity 版面配置檔案中的片段,或是在應用程式的程式碼中將片段加到現有的 {@link android.view.ViewGroup} 中,藉此在 Activity 版面配置中將片段插入為 {@code &lt;fragment&gt;} 元素。
+
+
+
+不過,片段未必要成為 Activity 版面配置的一部分;您也可以選擇不透過其 UI,以隱形工作人員的身分使用 Activity 的片段。
+
+</p>
+
+<p>本文說明如何建置應用程式以使用片段,包括片段如何在加到 Activity 返回堆疊時保持自身狀態、如何與 Activity 和 Activity 中的其他片段共用活動、如何製作 Activity 欄等等。
+
+
+</p>
+
+
+<h2 id="Design">設計概念</h2>
+
+<p>我們在 Android 3.0 (API 級別 11) 中導入了片段,主要目的是為了在大型螢幕 (例如平板電腦) 上支援更多動態和彈性 UI 設計。
+由於平板電腦的螢幕比手機大上許多,因此有更多空間可結合及交換 UI 元件。
+
+片段可實現這種介面設計,而不必讓您管理複雜的檢視階層變更。
+將 Activity 的版面配置劃分成片段後,您就可以修改 Activity 在執行階段的外觀,以及保留 Activity 所管理返回堆疊的相關變更。
+
+</p>
+
+<p>例如,某個新聞應用程式可使用單一片段在畫面左側顯示文章清單,並且使用另一個片段在畫面右側顯示某篇文章 &mdash; 這兩個片段是以並排方式出現在某個 Activity 中,而每個片段都有自己的一組生命週期回呼方法,可自行處理其使用者輸入事件。
+
+
+因此,使用者可以在相同 Activity 中選取並閱讀某篇文章 (如圖 1 中的平板電腦版面配置所示),而不必使用不同 Activity 選取及閱讀文章。
+
+</p>
+
+<p>請務必將每個片段設計成模組化和可重複使用的 Activity 元件。這是因為每個片段會根據其生命週期回呼,定義專屬版面配置和行為,而您可將單一片段加到多個 Activity 中,故請將其設計成可重複使用的元件,同時避免直接操縱個別片段。
+
+
+由於模組化片段可讓您針對不同螢幕大小變更片段組合,因此請務必這麼做。
+設計您的應用程式以支援平板電腦和手機時,您可以在不同版面配置設定中重複使用片段,藉此根據可用的螢幕空間提供最佳的使用者體驗。
+
+以手機為例說明,如果相同 Activity 中有多個片段不相符,則只要分割片段即可提供單一面板式的 UI。
+
+</p>
+
+<img src="{@docRoot}images/fundamentals/fragments.png" alt="" />
+<p class="img-caption"><strong>圖 1.</strong>片段所定義的兩個 UI 模組如何針對平板電腦設計合併成單一 Activity、如何針對手機設計分割成個別 Activity。
+
+</p>
+
+<p>例如 &mdash; 延續新聞應用程式範例加以說明 &mdash; 在平板電腦大小的裝置上執行的應用程式可將兩個片段嵌入「Activity A」<em></em>。
+不過,在手機大小的螢幕上,由於螢幕空間不足以容納兩個片段,因此「Activity A」<em></em>只會包含文章清單的片段,而當使用者選取文章後,系統就會啟動內含第二個片段的「Activity B」<em></em>,讓使用者閱讀文章。
+
+
+因此,應用程式可透過重複使用不同片段組合的方式,同時支援平板電腦和手機 (如圖 1 所示)。
+
+</p>
+
+<p>如要進一步瞭解如何使用不同片段組合針對各種螢幕設定設計應用程式,請參閱<a href="{@docRoot}guide/practices/tablets-and-handsets.html">支援平板電腦和手機</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>片段的生命週期 (當其中的 Activity 處於執行狀態時)。
+</p>
+</div>
+
+<p>如要建立片段,您必須建立 {@link android.app.Fragment} 的子類別 (或是其現有的子類別)。
+{@link android.app.Fragment} 類別內含與{@link android.app.Activity} 十分雷同的程式碼。
+該程式碼包括與 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 應用程式改用片段,只要將 Activity 的回呼方法中的程式碼移到片段的個別回呼方法即可。
+
+
+</p>
+
+<p>一般來說,您至少必須實作下列生命週期方法:</p>
+
+<dl>
+ <dt>{@link android.app.Fragment#onCreate onCreate()}</dt>
+ <dd>系統會在建立片段時呼叫這個方法。在實作這個方法時,您必須初始化您想保留的必要片段元件,以便恢復已暫停或停止的片段。
+
+</dd>
+ <dt>{@link android.app.Fragment#onCreateView onCreateView()}</dt>
+ <dd>系統會在片段初次顯示其使用者介面時呼叫這個方法。
+您必須透過這個方法傳回 {@link android.view.View} (片段版面配置的根目錄),才能顯示片段的 UI。
+如果片段並未提供 UI 的話,則可以傳回空值。
+</dd>
+ <dt>{@link android.app.Activity#onPause onPause()}</dt>
+ <dd>系統會在使用者初次離開片段時呼叫這個方法 (即使使用者這麼做未必會刪除片段)。
+您通常需要透過這個方法提交要在目前的使用者工作階段以外保留的任何變更 (原因在於使用者可能不會返回)。
+
+</dd>
+</dl>
+
+<p>大多數應用程式都至少必須針對每個片段實作這三個方法,不過您也必須使用幾個其他回呼方法來控制片段生命週期的各種狀態。
+
+如要進一步瞭解所有回呼方法,請參閱<a href="#Lifecycle">處理片段生命週期</a>。
+</p>
+
+
+<p>以下列出幾個您可能會想擴充的子類別 (基礎 {@link
+android.app.Fragment} 類別除外):</p>
+
+<dl>
+ <dt>{@link android.app.DialogFragment}</dt>
+ <dd>顯示浮動對話方塊。使用這個類別建立對話方塊是使用 {@link android.app.Activity} 類別中的對話方塊協助程式方法的推薦替代方法,這是因為使用此類別可將片段對話方塊納入 Activity 所管理的片段堆疊,讓使用者得已返回已關閉的片段。
+
+
+</dd>
+
+ <dt>{@link android.app.ListFragment}</dt>
+ <dd>顯示配接器 (例如 {@link
+android.widget.SimpleCursorAdapter}) 所管理的項目清單;與 {@link android.app.ListActivity} 方法相似。這個方法可提供數種管理清單檢視畫面的方法,例如可處理點擊事件的 {@link
+android.app.ListFragment#onListItemClick(ListView,View,int,long) onListItemClick()}回呼。
+
+</dd>
+
+ <dt>{@link android.preference.PreferenceFragment}</dt>
+ <dd>列出 {@link android.preference.Preference} 物件的階層;與
+{@link android.preference.PreferenceActivity} 方法相似。為應用程式建立「設定」Activity 時,這個方法就非常實用。
+</dd>
+</dl>
+
+
+<h3 id="UI">新增使用者介面</h3>
+
+<p>片段通常是當作某 Activity 的使用者介面使用,而且可將自身的版面配置提供給 Activity。
+</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.app.Fragment#onCreateView onCreateView()} 的
+{@link android.widget.ListView},因此您不必加以實作。</p>
+
+<p>如要從 {@link
+android.app.Fragment#onCreateView onCreateView()} 傳回版面配置,您可以從 XML 中定義的<a href="{@docRoot}guide/topics/resources/layout-resource.html">l版面配置資源</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 {
+ &#64;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} (來自 Activity 的版面配置),系統會將您的片段版面配置插入其中。
+
+{@code savedInstanceState} 參數是 {@link android.os.Bundle},當片段即將恢復時 (如要進一步瞭解還原狀態,請參閱<a href="#Lifecycle">處理片段生命週期</a>),這個參數就會提供先前的片段執行個體的相關資料。
+
+
+</p>
+
+<p>{@link android.view.LayoutInflater#inflate(int,ViewGroup,boolean) inflate()} 方法採用三種引數:
+</p>
+<ul>
+ <li>您想要擴大的版面配置的資源 ID。</li>
+ <li>要設為擴大過後版面配置的上層檢視的 {@link android.view.ViewGroup}。請務必傳遞 {@code
+container},以便讓系統將版面配置參數套用至擴大過後版面配置的根檢視 (由將做為其目標的父檢視所指定)。
+</li>
+ <li>用於指示系統是否要在擴大期間將擴大過後的版面配置附加到 {@link
+android.view.ViewGroup} (第二個參數) 的布林值 (由於系統已將擴大過後的版面配置插入 {@code
+container},因此布林值應為 false &mdash; 如果您傳送 true,會導致系統在最終版面配置中建立多餘的檢視群組)。
+</li>
+</ul>
+
+<p>您現在已瞭解如何建立可提供版面配置的片段了。接著,請將建立好的片段新增至 Activity。
+</p>
+
+
+
+<h3 id="Adding">將片段新增到 Activity 中</h3>
+
+<p>片段通常會將一部分 UI 嵌入主要 Activity 的整體檢視階層中。
+您有兩種方式可將片段新增到 Activity 版面配置:
+</p>
+
+<ul>
+ <li><b>宣告 Activity 版面配置檔案內含的片段。</b>
+<p>選用這種方式時,您可以將片段視為檢視,為其指定版面配置屬性。
+例如,以下是內含兩個片段的 Activity 版面配置檔案:
+</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"&gt;
+ &lt;fragment android:name="com.example.news.ArticleListFragment"
+ android:id="@+id/list"
+ android:layout_weight="1"
+ android:layout_width="0dp"
+ android:layout_height="match_parent" /&gt;
+ &lt;fragment android:name="com.example.news.ArticleReaderFragment"
+ android:id="@+id/viewer"
+ android:layout_weight="2"
+ android:layout_width="0dp"
+ android:layout_height="match_parent" /&gt;
+&lt;/LinearLayout&gt;
+</pre>
+ <p>{@code &lt;fragment&gt;} 中的 {@code android:name} 屬性可指定系統呼叫版面配置中的 {@link
+android.app.Fragment} 類別。</p>
+
+<p>系統建立這個 Activity 版面配置後,就會呼叫版面配置中指定的任何片段,並為每個片段呼叫 {@link android.app.Fragment#onCreateView onCreateView()} 方法,藉此擷取所有片段的版面配置。
+
+系統會插入片段所傳回的 {@link android.view.View} 來取代 {@code &lt;fragment&gt;} 元素。
+</p>
+
+<div class="note">
+ <p><strong>注意:</strong>您必須為每個片段提供專屬識別碼,以便系統在 Activity 重新開始時復原片段 (您也可以使用此識別碼擷取要交易的片段,例如移除片段)。
+
+您有三種方式可提供片段的 ID:
+</p>
+ <ul>
+ <li>提供內含專屬 ID 的 {@code android:id} 屬性。</li>
+ <li>提供內含不重複字串的 {@code android:tag} 屬性。</li>
+ <li>如果您未提供上述兩項屬性,系統會採用容器檢視的 ID。
+</li>
+ </ul>
+</div>
+ </li>
+
+ <li><b>或者,利用程式將片段新增至現有的 {@link android.view.ViewGroup}。</b>
+<p>只要 Activity 處於執行狀態,您都可以將片段新增至 Activity 版面配置。方法很簡單,只要指定您想在其中加入片段的 {@link
+android.view.ViewGroup} 即可。
+</p>
+ <p>如要在 Activity 中進行片段交易 (例如新增、移除或替換片段),請使用 {@link android.app.FragmentTransaction} 中的 API 進行。
+您可以透過以下方式取得 {@link android.app.Activity} 的 {@link android.app.FragmentTransaction} 執行個體:
+</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 加以指定),而第二個參數則是要新增的引數。
+
+</p>
+ <p>透過
+{@link android.app.FragmentTransaction} 完成變更後,請呼叫 {@link android.app.FragmentTransaction#commit} 以便讓變更生效。
+</p>
+ </li>
+</ul>
+
+
+<h4 id="AddingWithoutUI">新增不顯示 UI 的片段</h4>
+
+<p>上述範例說明如何將片段新增至 Activity,以提供 UI。但事實上,您也可以使用片段為 Activity 提供背景行為,避免顯示額外的 UI。
+
+</p>
+
+<p>如要新增不顯示使 UI 的片段,請使用 {@link
+android.app.FragmentTransaction#add(Fragment,String)} 從 Activity 新增片段 (請提供片段的不重複字串「標記」,而不是檢視 ID)。
+這樣即可新增片段,但由於該片段並未與 Activity 版面配置中的檢視相關聯,因此不會接收 {@link
+android.app.Fragment#onCreateView onCreateView()} 的呼叫。
+如此一來,您就不必實作該方法。</p>
+
+<p>提供片段的字串標記並不是採用非 UI 片段時的必要步驟 &mdash; 您也可以提供沒有 UI 的片段的字串標記 &mdash; 不過,如果片段沒有 UI,則字串標記將成為識別片段的唯一途徑。
+
+如果您想之後再從 Activity 中取得片段,請使用 {@link android.app.FragmentManager#findFragmentByTag
+findFragmentByTag()}。
+</p>
+
+<p>如需使用沒有 UI 的片段做為背景工作者的 Activity 範例,請參閱 SDK 範例中位於以下路徑的 {@code
+FragmentRetainInstance.java} 範例 (可透過 Android SDK Manager 存取)<code>&lt;sdk_root&gt;/APIDemos/app/src/main/java/com/example/android/apis/app/FragmentRetainInstance.java</code>。
+
+</p>
+
+
+
+<h2 id="Managing">管理片段</h2>
+
+<p>如要管理 Activity 中的片段,請使用 {@link android.app.FragmentManager}。如要取得這些片段,請呼叫 Activity 中的 {@link android.app.Activity#getFragmentManager()}。
+</p>
+
+<p>您可透過 {@link android.app.FragmentManager} 執行下列操作:</p>
+
+<ul>
+ <li>使用 {@link
+android.app.FragmentManager#findFragmentById findFragmentById()} (針對在 Activity 版面配置中提供 UI 的片段) 或 {@link android.app.FragmentManager#findFragmentByTag
+findFragmentByTag()} (針對未提供 UI 的片段) 取得 Activity 中的現有片段。
+</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>使用 Activity 中片段的一項實用功能,就是新增、移除、替換片段以及對它們執行其他動作,藉此反映使用者互動。
+您針對 Activity 提交的每組變更稱為交易,而您可以使用 {@link
+android.app.FragmentTransaction} 中的進行這種交易。
+此外,您也可以儲存對 Activity 所管理的返回堆疊進行的交易,讓使用者能夠往回瀏覽片段變更 (如同往回瀏覽 Activity)。
+
+</p>
+
+<p>您可以從 {@link
+android.app.FragmentManager} 中取得如下所示的 {@link android.app.FragmentTransaction}:</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()},就能將該交易套用至 Activity。
+</p>
+</dl>
+
+<p>不過,您可能會為了新增交易至片段交易返回堆疊,先呼叫 {@link
+android.app.FragmentTransaction#addToBackStack addToBackStack()},然後再呼叫 {@link
+android.app.FragmentTransaction#commit()}。
+返回堆疊是由 Activity 所管理,可讓使用者透過按下 [返回]<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 newFragment} 會針對依據 {@code R.id.fragment_container} ID 識別的版面配置容器,
+替換其中的任何現有片段 (如果有的話)。系統會呼叫 {@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()} 之前套用的所有變更都會新增至返回堆疊做為單次交易,在這種情況下,按下 [返回]<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()} 來提交交易,但僅限於 Activity <a href="{@docRoot}guide/components/activities.html#SavingActivityState">儲存其狀態</a>之前 (也就是使用者離開 Activity 之前)。
+如果您在這個時間點之後嘗試提交交易,就會發生例外狀況,
+這是因為狀態會在交易提交後遺失 (如果需要復原 Activity 的話)。
+如果想確保狀態遺失不會造成任何影響,請使用 {@link
+android.app.FragmentTransaction#commitAllowingStateLoss()} 提交交易。</p>
+
+
+
+
+<h2 id="CommunicatingWithActivity">與 Activity 通訊</h2>
+
+<p>雖然 {@link android.app.Fragment} 是實作成不同於
+{@link android.app.Activity} 的物件,而且可在多個 Activity 中使用,特定片段執行個體仍會直接與含有該物件的 Activity 建立關聯。
+</p>
+
+<p>因此,片段可存取內含{@link
+android.app.Fragment#getActivity()} 的 {@link android.app.Activity} 執行個體,以及輕鬆進行在 Activity 版面配置中尋找檢視等工作:
+</p>
+
+<pre>
+View listView = {@link android.app.Fragment#getActivity()}.{@link android.app.Activity#findViewById findViewById}(R.id.list);
+</pre>
+
+<p>相同地,您的 Activity 可利用 {@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">為 Activity 建立事件回呼</h3>
+
+<p>在某些情況下,您可能需要可用來與 Activity 分享事件的片段。如果您需要這種片段,建議您在片段內定義回呼介面,然後要求主要 Activity 實作該片段。
+
+當 Activity 透過介面接收回呼後,即可視需要與版面配置中的其他片段分享這項資訊。
+</p>
+
+<p>例如,假設新聞應用程式的 Activity 中有兩個片段 &mdash; 一個用於顯示文章清單 (片段 A),另一個用於顯示文章 (片段 B) &mdash; 其中的片段 A 必須告知 Activity 使用者選取清單項目的時間點,以便通知片段 B 顯示文章。
+
+在這個範例中,{@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>接著,代管片段的 Activity 會實作 {@code OnArticleSelectedListener} 介面,並且覆寫 {@code onArticleSelected()} 以便將片段 A 的事件告知片段 B。為了確保主要 Activity 可實作該介面,片段 A 的 {@link
+android.app.Fragment#onAttach onAttach()} 回呼方法 (系統將片段新增至 Activity 時會呼叫這種方法) 轉換傳入 {@link android.app.Fragment#onAttach
+onAttach()} 的 {@link android.app.Activity},藉此呼叫 {@code OnArticleSelectedListener} 執行個體:
+
+
+
+
+</p>
+
+<pre>
+public static class FragmentA extends ListFragment {
+ OnArticleSelectedListener mListener;
+ ...
+ &#64;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>如果 Activity 並未實作介面,那麼片段會擲回
+{@link java.lang.ClassCastException}。成功擲回時,{@code mListener} 成員會保留 Activity 所實作
+{@code OnArticleSelectedListener} 的參照資料,以便片段 A 呼叫 {@code OnArticleSelectedListener} 介面定義的方法與 Activity 分享事件。
+
+例如,假設片段 A 是
+{@link android.app.ListFragment} 的延伸,則每當使用者點擊清單項目時,系統就會呼叫片段中的 {@link android.app.ListFragment#onListItemClick
+onListItemClick()},讓該方法呼叫 {@code onArticleSelected()} 以便與 Activity 分享事件:
+
+</p>
+
+<pre>
+public static class FragmentA extends ListFragment {
+ OnArticleSelectedListener mListener;
+ ...
+ &#64;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,可讓 Activity (或其他片段) 用來從應用程式的 {@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()} 來為 Activity 的<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>雖然片段會在使用者選取項目時,針對所有新增的選單項目接收回呼,不過最先在使用者選取選單項目時接收個別回呼的是 Activity。
+
+如果 Activity 在使用者選取項目時所實作的回呼無法處理所選項目,則系統會將該事件傳送到片段的回呼中。
+這種情況會發生在「選項選單」和內容選單。
+</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>Activity 生命週期對片段生命週期造成的影響。
+</p>
+</div>
+
+<p>管理片段生命週期的方式與管理 Activity 生命週期十分雷同。與 Activity 相同,片段有以下三種狀態:
+</p>
+
+<dl>
+ <dt><i>已繼續</i></dt>
+ <dd>系統會在執行中的 Activity 內顯示片段。</dd>
+
+ <dt><i>已暫停</i></dt>
+ <dd>前景中有其他具備焦點的 Activity,但系統仍會顯示含有這個片段的 Activity (前景 Activity 處於半透明狀態,或是未覆蓋整個螢幕)。
+
+</dd>
+
+ <dt><i>已停止</i></dt>
+ <dd>系統不會顯示片段。這可能是因為主要 Activity 已停止,或是加到返回堆疊的片段已從 Activity 中移除。
+已停止的片段仍處於有效狀態 (系統會保留所有狀態和成員資訊),
+但使用者無法看到這類片段,而且當 Activity 遭到刪除時,這些片段也會一併刪除。
+</dd>
+</dl>
+
+<p>與 Activity 相同,您可以使用 {@link
+android.os.Bundle} 保留片段的狀態,以便在 Activity 的處理程序遭到刪除後想重新建立 Activity 時,還原片段狀態。
+您可以在片段的 {@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">Activity</a>。
+
+</p>
+
+<p>Activity 與片段生命週期之間最明顯的差異是,生命週期儲存在個別返回堆疊的方式。
+在預設情況下,Activity 停止後會插入系統所管理的 Activity 堆疊,方便使用者按下 [返回]<em></em> 按鈕來返回該 Activity (如<a href="{@docRoot}guide/components/tasks-and-back-stack.html">工作和返回堆疊</a>所述)。不過,片段只會在您進行移除片段的交易期間,呼叫 {@link
+android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} 來要求系統儲存執行個體時,插入主要 Activity 所管理的返回堆疊。
+
+
+
+
+</p>
+
+<p>在其他情況下,管理片段生命週期的方式與管理 Activity 生命週期十分雷同。
+因此,<a href="{@docRoot}guide/components/activities.html#Lifecycle">管理 Activity 生命週期</a>的做法同樣適用於片段。
+不過,建議您參考相關資源,瞭解 Activity 生命週期對片段生命週期造成的影響。
+</p>
+
+<p class="caution"><strong>注意:</strong>如果您需要 {@link android.app.Fragment} 的
+{@link android.content.Context} 物件,請呼叫 {@link android.app.Fragment#getActivity()}。不過,請務必只在確定片段是附加到 Activity 的情況下,再呼叫 {@link android.app.Fragment#getActivity()}。
+
+如果片段未附加到 Activity,或是片段因超過生命週期而遭到卸除,則 {@link android.app.Fragment#getActivity()} 將傳回空值。
+</p>
+
+
+<h3 id="CoordinatingWithActivity">調整 Activity 生命週期</h3>
+
+<p>內含片段的 Activity 的生命週期會直接影響片段的生命週期,這樣一來,Activity 的每次生命週期回呼會針對每個片段產生相似的回呼。
+
+例如,當 Activity 收到 {@link android.app.Activity#onPause} 後,Activity 中的每個片段都會收到 {@link android.app.Fragment#onPause}。
+</p>
+
+<p>不過,片段有幾個額外的生命週期回呼,可用於處理與 Activity 之間的特殊互動,以執行建置或刪除片段 UI 等動作。以下是這些額外的回呼方法:
+
+</p>
+
+<dl>
+ <dt>{@link android.app.Fragment#onAttach onAttach()}</dt>
+ <dd>當片段與 Activity 建立關聯時,系統就會呼叫這個方法 ({@link
+android.app.Activity} 會傳入與片段相關聯的 Activity)。</dd>
+ <dt>{@link android.app.Fragment#onCreateView onCreateView()}</dt>
+ <dd>系統會呼叫這個方法來建立與片段相關聯的檢視階層。</dd>
+ <dt>{@link android.app.Fragment#onActivityCreated onActivityCreated()}</dt>
+ <dd>當 Activity 的 {@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>當使用者將片段與 Activity 解除關聯時,系統就會呼叫這個方法。</dd>
+</dl>
+
+<p>如圖 3 所述,片段生命週期的流程會受到主要 Activity 的影響。
+您可以透過該圖片瞭解 Activity 的連續狀態如何決定片段要接收的回呼方法。
+例如,當 Activity 收到 {@link
+android.app.Activity#onCreate onCreate()} 回呼後,Activity 中的片段就不會收到
+{@link android.app.Fragment#onActivityCreated onActivityCreated()} 以外的回呼。</p>
+
+<p>Activity 一旦進入已恢復狀態,您便可視需要在 Activity 中新增或移除片段。
+因此,只有處於已恢復狀態的 Activity 會影響片段的生命週期。
+</p>
+
+<p>不過,當 Activity 不再處於已恢復狀態後,Activity 就會再次推送片段的生命週期。
+</p>
+
+
+
+
+<h2 id="Example">範例說明</h2>
+
+<p>以下提供使用兩個片段建立兩個面板的版面配置的 Activity 範例,藉此綜合說明本文所述內容。
+下方 Activity 包含一個用於顯示莎士比亞劇作清單的片段,以及另一個用於在使用者選取清單項目時顯示劇作摘要的片段。
+
+這個 Activity 範例同時示範了如何根據螢幕設定提供不同的片段設定。
+</p>
+
+<p class="note"><strong>注意:</strong>如需這個 Activity 的完整原始碼,請查閱
+<a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.html">{@code
+FragmentLayout.java}</a>。</p>
+
+<p>主要 Activity 會在 {@link
+android.app.Activity#onCreate onCreate()} 時以常見的方式套用版面配置:</p>
+
+{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java main}
+
+<p>Activity 套用的版面配置為 {@code fragment_layout.xml}:</p>
+
+{@sample development/samples/ApiDemos/res/layout-land/fragment_layout.xml layout}
+
+<p>使用這個版面配置可讓系統在 Activity 載入版面配置時,呼叫 {@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}。也就是說,如果裝置採用直向螢幕設定,系統只會顯示劇作名稱清單。
+因此,當使用者在採用這種設定的裝置上點擊清單項目後,應用程式就會啟動新 Activity 來顯示劇作摘要,而不是載入第二個片段。
+
+</p>
+
+<p>接著,請看看片段類別如何達到以上目標。首先是用於顯示莎士比亞劇作名稱清單的 {@code
+TitlesFragment}。這個片段會延伸 {@link
+android.app.ListFragment},並且依據該類別控制大多數的清單檢視工作。</p>
+
+<p>如果您檢查這個程式碼,將會發現使用者點擊清單項目後會觸發兩種行為:視採用的版面配置而定,系統會建立並呈現新的片段,以便在同一 Activity 中顯示詳細資料 (將片段加到 {@link
+android.widget.FrameLayout}),或是啟動新的 Activity (藉此顯示片段)。
+
+</p>
+
+{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java titles}
+
+<p>第二個片段 {@code DetailsFragment} 則會針對
+{@code TitlesFragment} 中,使用者所選清單項目的劇本摘要:</p>
+
+{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java details}
+
+<p>針對 {@code TitlesFragment} 類別發出的回呼,如果使用者點擊清單項目,而且目前的版面配置「並未」<em></em>包含 {@code R.id.details} 檢視 ({@code DetailsFragment} 所屬的檢視),則應用程式會執行 {@code DetailsActivity} Activity 來顯示項目內容。
+
+
+</p>
+
+<p>以下是會在螢幕採用橫向版面設定時,嵌入 {@code DetailsFragment} 以顯示所選劇本摘要的 {@code DetailsActivity}:
+</p>
+
+{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java
+details_activity}
+
+<p>請注意,這個 Activity 會在螢幕採用橫向版面配置的情況下自行結束,因此主要 Activity 會接續顯示 {@code TitlesFragment} 旁的 {@code DetailsFragment}。如果使用者在採用直向版面配置的裝置上執行 {@code DetailsActivity},然後將該裝置旋轉成橫向 (這會重新執行目前的 Activity),就可能會發生這種情況。
+
+
+</p>
+
+
+<p>如需更多使用片段的範例 (以及本範例的原始檔案),請參閱<a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/index.html#Fragment">ApiDemos</a> 所提供的 API Demos 範例應用程式 (可透過 <a href="{@docRoot}resources/samples/get.html">SDK 元件範本</a>下載)。
+
+</p>
+
+
diff --git a/docs/html-intl/intl/zh-tw/guide/components/fundamentals.jd b/docs/html-intl/intl/zh-tw/guide/components/fundamentals.jd
new file mode 100644
index 000000000000..d3b3c2899614
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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 程式語言編寫而成。Android SDK 工具可將您的程式碼 &mdash; 連同任何相關資料和資源檔案 &mdash; 編入 APK (
+ <i>Android 套件,</i>使用 {@code .apk} 後綴字詞的封存檔)。
+APK 檔案包含 Android 應用程式的所有內容,搭載 Android 作業系統的裝置會使用這種檔案來安裝應用程式。
+</p>
+
+<p>Android 應用程式安裝到裝置之後,便可在專屬的安全性沙箱中執行: </p>
+
+<ul>
+ <li>Android 作業系統是一種支援多位使用者的 Linux 系統;在這種系統中,每款應用程式即代表不同的使用者。
+</li>
+
+<li>在預設情況下,系統會為每款應用程式指派一個不重複 Linux 使用者 ID (只有系統可使用這個 ID,應用程式無法取得這項資訊)。
+系統會為應用程式中的所有檔案設定權限,因此只有該應用程式指派的使用者 ID 可存取這些檔案。
+ </li>
+
+<li>所有處理程序都有專屬的虛擬機器 (VM),供系統在獨立環境中執行應用程式的程式碼。
+</li>
+
+<li>在預設情況下,每款應用程式會在專屬的 Linux 處理程序中執行。Android 會在需要執行應用程式的任何元件時啟動處理程序,並且在不必執行應用程式元件,或系統必須復原記憶體供其他應用程式使用時關閉處理程序。
+
+</li>
+</ul>
+
+<p>如此一來,Android 系統就會實作「最低權限原則」<em></em>。換句話說,在預設情況下,所有應用程式只能存取執行工作時所需的元件。
+
+這樣一來,應用程式便無法存取系統的某些部分,藉此建立十分安全的執行環境。
+</p>
+
+<p>不過,應用程式可透過一些方式與其他應用程式分享資料,以及存取系統服務:
+</p>
+
+<ul>
+ <li>兩款應用程式可共用相同的 Linux 使用者 ID,以便存取彼此的檔案。
+為了節省系統資源,共用相同使用者 ID 的應用程式可在相同 Linux 處理程序中執行,以及共用相同的 VM (前提是應用程式必須使用相同的憑證進行簽署)。
+
+</li>
+ <li>應用程式可要求存取裝置資料 (例如使用者的聯絡人資料、簡訊、掛載式儲存空間 (SD 卡)、相機、藍牙等)。
+使用者必須在安裝期間授予所有應用程式權限。
+</li>
+</ul>
+
+<p>本文提供有關 Android 應用程式如何在系統中運作的基本概念,其餘部分則說明以下幾點:
+</p>
+<ul>
+ <li>定義應用程式的核心架構元件。</li>
+ <li>用於宣告應用程式所需元件和裝置功能的宣示說明檔案。
+</li>
+ <li>應用程式的程式碼以外的資源;這些資源可讓您的應用程式針對各種裝置設定最佳化本身的行為。
+</li>
+</ul>
+
+
+
+<h2 id="Components">應用程式元件</h2>
+
+<p>應用程式元件是 Android 應用程式的重要設計模組。每個元件 都是系統進入您應用程式的不同要點。並非所有元件都是使用者的實際進入點;某些元件的定義取決於其他元件,但所有元件都是獨立的個體,扮演著特定角色 &mdash; 換句話說,每個元件都是獨特的設計模組,可協助定義您應用程式的整體行為。
+
+
+
+</p>
+
+<p>應用程式元件可分為 4 種不同類型。每種類型的用途和生命週期均不相同,可定義元件的建立及刪除方式。
+</p>
+
+<p>以下是應用程式元件的 4 種類型:</p>
+
+<dl>
+
+<dt><b>Activity</b></dt>
+
+<dd>單一 <i>Activity</i> 代表顯示使用者介面的一個畫面。例如,電子郵件應用程式可包含一個用於顯示新郵件清單的 Activity、一個用於撰寫郵件的 Activity,以及一個用於閱讀郵件的 Activity。
+
+雖然電子郵件應用程式的 Activity 會共同運作,以提供豐富的使用者體驗,不過每個 Activity 都是不同的個體。
+
+因此,其他應用程式可執行其中任何一項 Activity (如果電子郵件應用程式允許的話)。
+例如,相機應用程式可在電子郵件應用程式中,執行用於撰寫新郵件的 Activity,以便讓使用者分享相片。
+
+
+<p>Activity 是實作成 {@link android.app.Activity} 的子類別;詳情請參閱 <a href="{@docRoot}guide/components/activities.html">Activity</a> 開發人員指南。
+
+</p>
+</dd>
+
+
+<dt><b>服務</b></dt>
+
+<dd>單一 <i>服務</i> 是在背景執行的元件,用於進行長期作業或遠端處理程序工作。
+服務並不會提供使用者介面。
+例如,服務可在使用者位於其他應用程式時在背景撥放音樂,或是透過網路擷取資料,同時允許使用者與 Activity 進行互動。
+
+其他元件 (例如 Activity) 可啟動並讓服務執行,或是繫結至 Activity 以便與其進行互動。
+
+
+<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">內容供應程式</a>開發人員指南。
+</p>
+</dd>
+
+
+<dt><b>廣播接收器</b></dt>
+
+<dd>單一 <i>廣播接收器</i> 是一種元件,可回應整個系統的廣播通知。
+大多數廣播都是由系統所發出 &mdash; 例如,系統會發出廣播來通知使用者螢幕已關閉、電池電量不足,或相片已拍攝完成。此外,應用程式也可發出廣播 &mdash; 例如說發出廣播來通知其他應用程式特定資料已下載到裝置,可供它們使用。
+
+
+雖然廣播接收器無法顯示使用者介面,但它們可<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 系統設計的一項特色是,任何應用程式都可啟動其他應用程式的元件。
+例如,假設您想讓使用者透過裝置相機拍攝相片,您的應用程式可利用其他具備相關功能的應用程式 (如果有的話) 以達到這個目標,這樣您就不必自行建立用於拍攝相片的 Activity。
+
+您不需要納入或連結相機應用程式的程式碼,只要啟動相機應用程式中用於拍攝像片的 Activity 即可。
+
+
+啟動相關 Activity 後,系統就會將相片傳回您的應用程式供您使用。對於使用者而言,相機就宛如是您應用程式的一部分。
+</p>
+
+<p>當系統啟動某個元件後,就會啟動該應用程式的處理程序 (如果該應用程式目前並非處於執行中狀態) 並且呼叫該元件所需的類別。
+例如,假設您的應用程式啟動相機應用程式中用於拍攝相片的 Activity,則該 Activity 會在隸屬於相機應用程式的處理程序中執行,而不是您應用程式的處理程序。因此,與大多數其他系統的應用程式不同,Android 應用程式沒有單一進入點 (例如沒有 {@code main()} 函式)。
+
+
+
+</p>
+
+<p>系統是在個別處理程序 (具備檔案權限,可限制其他應用程式存取) 中執行每款應用程式,因此您的應用程式無法直接啟動其他應用程式的元件,不過 Android 系統可以。
+
+基於這個原因,如要啟動其他應用程式的元件,您必須向指定「意圖」<em></em>的系統發送訊息,以啟動特定元件。
+
+系統隨後會為您啟用所需的元件。</p>
+
+
+<h3 id="ActivatingComponents">啟用元件</h3>
+
+<p>4 種元件類型的其中 3 種 &mdash; Activity、服務和廣播接收器 &mdash; 是透過「意圖」<em></em>這種非同步訊息啟用。意圖會在執行階段將元件與彼此繫結 (您可以意圖想成要求其他元件進行動作的傳令員),不論元件是否屬於您的應用程式。
+
+
+
+</p>
+
+<p>意圖是使用 {@link android.content.Intent} 物件建立而成,該物件可定義訊息來啟用特定元件或特定「類型」<em></em>的元件 &mdash; 意圖可以採取明確或隱含設定。
+
+</p>
+
+<p>針對 Activity 和服務,意圖會定義要執行的動作 (例如「查看」或「傳送」某項目),並且可能會指定執行動作的目標資料 URI (以及通知要啟用的元件)。
+
+例如,意圖可傳達某 Activity 的要求,顯示圖片或開啟網頁。
+在某些情況下,您可以啟動 Activity 來接收結果,此時該 Activity 也會傳回{@link android.content.Intent} 的結果 (例如,您可以發出意圖讓使用者挑選聯絡人資料,並將該資訊傳回給您 &mdash; 傳回意圖會包含指向所選聯絡人的 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()} (如果您想讓 Activity 傳回結果的話) 即可啟動 Activity (或是指派新工作給 Activity)。
+
+</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">Activity</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>宣告應用程式所使用或所需的硬體和軟體,例如相機、藍牙服務或多點觸控螢幕。
+</li>
+ <li>應用程式需要連結的 API 程式庫 (除了 Android 架構 API 以外),例如 <a href="http://code.google.com/android/add-ons/google-apis/maps-overview.html">Google 地圖程式庫</a>。
+
+</li>
+ <li>還有其他工作</li>
+</ul>
+
+
+<h3 id="DeclaringComponents">宣告元件</h3>
+
+<p>宣告說明的主要工作是將應用程式的元件告知系統。例如,宣告說明檔案可用如下方式宣告 Activity:
+ </p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;manifest ... &gt;
+ &lt;application android:icon="@drawable/app_icon.png" ... &gt;
+ &lt;activity android:name="com.example.project.ExampleActivity"
+ android:label="@string/example_label" ... &gt;
+ &lt;/activity&gt;
+ ...
+ &lt;/application&gt;
+&lt;/manifest&gt;</pre>
+
+<p>在 <code><a
+href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>元素中,{@code android:icon} 屬性會指向識別應用程式的圖示資源。
+
+</p>
+
+<p>而在 <code><a
+href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code> 元素中,
+{@code android:name} 屬性會指定 {@link
+android.app.Activity} 子類別的完整類別名稱,{@code android:label} 屬性則會指定要當作 Activity 的使用者可見標籤使用的字串。
+</p>
+
+<p>您必須用以下方式宣告所有應用程式元件:</p>
+<ul>
+ <li><code><a
+href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>:Activity 適用的元素
+</li>
+ <li><code><a
+href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>:服務適用的元素
+</li>
+ <li><code><a
+href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code>:廣播接收器適用的元素
+</li>
+ <li><code><a
+href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>:內容供應程式適用的元素
+</li>
+</ul>
+
+<p>系統看不到您納入來源但未在宣示說明中宣告的 Activity、服務和內容供應程式,因此系統無法執行這些項目。
+不過,您可在宣示說明宣告廣播接收器,或是透過程式碼以動態方式建立廣播接收器 (將廣播接收器建立為
+{@link android.content.BroadcastReceiver} 物件),然後呼叫 {@link android.content.Context#registerReceiver registerReceiver()}
+向系統註冊廣播接收器。
+
+</p>
+
+<p>如要進一步瞭解如何為應用程式建立宣示說明檔案,請參閱 <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml 檔案</a>。
+ </p>
+
+
+
+<h3 id="DeclaringComponentCapabilities">宣告元件功能</h3>
+
+<p>如<a href="#ActivatingComponents">啟用元件</a>所述,您可以使用
+{@link android.content.Intent} 來啟動 Activity、服務和廣播接收器。如要這麼做,請在意圖中明確指定目標元件 (使用元件類別名稱)。
+不過,意圖最大的功能在於「隱含意圖」<em></em>的概念。
+隱含意圖可簡單描述要執行的動作類型 (或是執行動作的資料依據) 以及讓系統在裝置中找出可執行動作的元件,然後加以啟動。
+
+
+如果意圖指出有多個元件可執行動作,則使用者可選取要使用的元件。
+</p>
+
+<p>系統會比對接受到的意圖與裝置上其他應用程式的宣示說明檔案中提供的意圖篩選器,藉此識別可回應意圖的元件。
+<i></i>
+</p>
+
+<p>在應用程式的宣示說明中宣告 Activity 時,您可視需要納入宣告 Activity 功能的意圖篩選器,以便讓 Activity 可回應其他應用程式的意圖。
+
+您可以為元件宣告意圖篩選器,方法是將 <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code
+&lt;intent-filter&gt;}</a> 元素新增為元件宣告元素的子元素。
+</p>
+
+<p>例如,假設您以用於撰寫新郵件的 Activity 建置電子郵件應用程式,您可以下列方式宣告意圖篩選器來回應「傳送」意圖 (藉此傳送新郵件):
+</p>
+<pre>
+&lt;manifest ... >
+ ...
+ &lt;application ... &gt;
+ &lt;activity android:name="com.example.project.ComposeEmailActivity">
+ &lt;intent-filter>
+ &lt;action android:name="android.intent.action.SEND" />
+ &lt;data android:type="*/*" />
+ &lt;category android:name="android.intent.category.DEFAULT" />
+ &lt;/intent-filter>
+ &lt;/activity>
+ &lt;/application&gt;
+&lt;/manifest>
+</pre>
+
+<p>接著,如果其他應用程式透過 {@link
+android.content.Intent#ACTION_SEND} 動作建立了意圖並傳送到 {@link android.app.Activity#startActivity
+startActivity()},系統就可能會啟動您的 Activity 讓使用者撰寫及傳送郵件。
+</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 (<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API 級別</a> 7) 導入的 API,建議您用下列方式在宣示說明檔案中宣告這些需求:
+</p>
+
+<pre>
+&lt;manifest ... >
+ &lt;uses-feature android:name="android.hardware.camera.any"
+ android:required="true" />
+ &lt;uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" />
+ ...
+&lt;/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">裝置相容性</a>。
+
+</p>
+
+
+
+<h2 id="Resources">應用程式資源</h2>
+
+<p>Android 應用程式是以程式碼等其他要素開發而成 &mdash; 例如圖片、音訊檔案以及與應用程式視覺效果相關的其他資源。例如,您必須使用 XML 檔案定義 Activity 使用者介面的動畫、選單、樣式、顏色以及版面配置。
+
+
+使用應用程式資源可協助更新應用程式的各種特性,而不必修改程式碼 &mdash; 或是提供多組替代資源 &mdash; 藉此針對各種裝置設定 (例如不同的語言和螢幕大小) 最佳化您的應用程式。
+
+
+</p>
+
+<p>針對您在 Android 專案中加入的所有資源,SDK 建置工具會定義一個整數 ID,讓您用於從應用程式的程式碼或 XML 中定義的其他資源參照特定資源。
+
+例如,假設您的應用程式含有名為 {@code
+logo.png} 的圖片檔案 (儲存在 {@code res/drawable/} 目錄中),SDK 工具會產生名為 {@code R.drawable.logo} 的資源 ID,讓您用於參照圖片並將其插入使用者介面。
+
+</p>
+
+<p>提供原始碼以外資源的一個重點是針對不同的裝置設定提供替代資源。
+
+例如,您可以在 XML 中定義使用者介面字串,藉此將字串翻譯成其他語言,以及將這些字串儲存成個別檔案。
+接著,視您附加到資源目錄名稱的語言「修飾語」<em></em> (例如代表法文字串值的 {@code res/values-fr/}),以及使用者的語言設定而定,Android 系統會為您的 UI 套用適當的語言字串。
+
+
+</p>
+
+<p>Android 針對替代資源支援各種「修飾語」<em></em>。修飾語是一個簡短字串;您可在資源目錄名稱中加入修飾語,藉此定義應使用這些資源的裝置設定。
+
+例如,您通常需要為 Activity 建立多種版面配置 (視裝置螢幕的方向和大小而定)。
+
+例如,假設裝置螢幕的方向為縱向 (直版),版面配置的按鈕就必須以垂直方向排列;假設裝置螢幕的方向為橫向 (寬版),則版面配置的按鈕就必須以水平方向排列。
+
+如要根據螢幕方向變更版面配置,請建立兩種版面配置,然後為每個版面配置目錄名稱套用適當的修飾語。
+
+如此系統就會根據目前的裝置方向,自動套用適當的版面配置。
+</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 來啟用應用程式元件 (例如 Activity 和服務),以及如何將應用程式元件提供給其他應用程式使用。
+
+</dd>
+ <dt><a href="{@docRoot}guide/components/activities.html">Activity</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">裝置相容性</a></dt>
+ <dd>說明 Android 如何在各種裝置上運作,以及如何針對各個裝置最佳化您的應用程式,或針對不同裝置限制應用程式提供的功能。
+
+</dd>
+ <dt><a href="{@docRoot}guide/topics/security/permissions.html">系統權限</a></dt>
+ <dd>說明 Android 如何運用系統權限規定應用程式必須取得使用者同意才能使用特定 API。
+</dd>
+ </dl>
+</div>
+</div>
+
diff --git a/docs/html-intl/intl/zh-tw/guide/components/index.jd b/docs/html-intl/intl/zh-tw/guide/components/index.jd
new file mode 100644
index 000000000000..f34c7120e8ad
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/guide/components/index.jd
@@ -0,0 +1,57 @@
+page.title=應用程式元件
+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>本文示範如何搭配 v4 支援程式庫 (可針對 Honeycomb 以下版本裝置提供向下相容性支援) 使用 DialogFragments 來顯示簡易的編輯對話方塊,以及透過介面將結果回傳給呼叫「Activity」。</p>
+ </a>
+
+ <a href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">
+ <h4>適用於各種裝置的片段</h4>
+ <p>我們於今日推出的靜態程式庫可列出相同的 Fragments API (以及新的 LoaderManager 和些許其他類別),讓與 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>管理 Activity 生命週期</h4>
+ <p>本課程說明每個「Activity」執行個體都會接收的生命週期重要回呼方法,並且說明如何使用這些方法,讓 Activity 的運作能符合使用者的預期,以及讓 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 和 Action Provider 物件在不同應用程式間傳送及接收內容的常見方法。
+</p>
+ </a>
+ </div>
+
+</div>
diff --git a/docs/html-intl/intl/zh-tw/guide/components/intents-filters.jd b/docs/html-intl/intl/zh-tw/guide/components/intents-filters.jd
new file mode 100644
index 000000000000..d3edac3f817a
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/guide/components/intents-filters.jd
@@ -0,0 +1,899 @@
+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">與其他應用程式互動</a></li>
+<li><a href="{@docRoot}training/sharing/index.html">分享內容</a></li>
+</ol>
+
+</div>
+</div>
+
+
+
+
+<p>{@link android.content.Intent} 是可用來向另一個<a href="{@docRoot}guide/components/fundamentals.html#Components">應用程式元件</a>要求動作的傳訊物件。
+
+雖然意圖有幾種方式可加速元件間的通訊,但共有三種基本使用案例:
+</p>
+
+<ul>
+<li><b>如何啟動 Activity:</b>
+<p>{@link android.app.Activity} 代表應用程式中的單一畫面。您可以將 {@link android.content.Intent} 傳送至 {@link android.content.Context#startActivity startActivity()} 來啟動
+{@link android.app.Activity} 的新執行個體。
+{@link android.content.Intent} 可描述要啟動的 Activity 並攜帶任何必要資料。
+</p>
+
+<p>如果您想要在 Activity 完成時收到結果,
+請呼叫 {@link android.app.Activity#startActivityForResult
+startActivityForResult()}。Activity 的 {@link android.app.Activity#onActivityResult onActivityResult()}回呼中的個別 {@link android.content.Intent} 物件,就是 Activity 收到的結果。
+
+如需詳細資訊,請參閱 <a href="{@docRoot}guide/components/activities.html">Activity</a> 指南。
+</p></li>
+
+<li><b>如何啟動服務:</b>
+<p>{@link android.app.Service} 是可以在背景中執行操作的元件,但沒有使用者介面。
+您可以將 {@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) 或{@link
+android.content.Context#sendStickyBroadcast sendStickyBroadcast()},以向其他應用程式傳送廣播。
+
+
+</p>
+</li>
+</ul>
+
+
+
+
+<h2 id="Types">意圖類型</h2>
+
+<p>意圖類型分為兩種:</p>
+
+<ul>
+<li><b>明確意圖</b>:可依名稱 (完整類別名稱) 指定要啟動的元件。
+一般情況下,您會使用明確意圖啟動您應用程式中的元件,這是因為您知道 Activity 的類別名稱或您想要啟動的服務。
+例如,為回應使用者動作而啟動新的 Activity,或啟動服務以在背景下載檔案。
+
+</li>
+
+<li><b>隱含意圖</b>:不會指定特定元件,而會宣告要執行的一般動作,讓另一個應用程式的元件來處理它。
+例如,如果您想要向使用者顯示地圖上的某個位置,可以使用隱含意圖,要求另一個支援應用程式在地圖上顯示指定的位置。
+
+</li>
+</ul>
+
+<p>當您建立明確意圖以啟動 Activity 或服務時,系統會立即啟動
+{@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>說明如何透過系統傳送隱含意圖以啟動另一個 Activity:<b>[1]</b> Activity A <em></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} 傳送給它來啟動相符的 Activity (Activity B<em></em>)。
+
+
+</p>
+</div>
+
+<p>當您建立隱含意圖時,Android 系統會比較意圖內容和裝置上其他應用程式的<a href="{@docRoot}guide/topics/manifest/manifest-intro.html">宣示說明檔案</a>中宣告的「意圖篩選器」<em></em>,以找出要啟動的適當元件。
+
+如果意圖和意圖篩選器相符,系統會啟動該元件,並將 {@link android.content.Intent} 物件傳送給它。
+如果有多個意圖篩選器符合意圖,系統會顯示對話方塊,供使用者挑選要使用的應用程式。
+</p>
+
+<p>意圖篩選器是應用程式宣示說明檔案中的運算式,可指定元件要接收的意圖類型。
+
+例如,藉由宣告 Activity 的意圖篩選器,可讓其他應用程式使用特定意圖類型直接啟動您的 Activity。
+同樣地,如果您「不」<em></em>為 Activity 宣告任何意圖篩選器,就只能以明確意圖啟動它。
+
+</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>的,因此系統會根據其他意圖資訊來決定哪個元件應接收意圖 (例如動作、資料及類別 &mdash; 如下所述)。
+
+如果您需要啟動應用程式中的特定元件,就應該指定元件名稱。
+</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>就廣播意圖而言,這是指已發生且系統回報的動作。動作大半決定其餘意圖的建構方式 &mdash; 特別是資料與額外資料中包含的項目。
+
+
+
+<p>您可以在應用程式內指定自己的動作以供意圖使用 (或由其他應用程式用來呼叫應用程式中的元件),但您應使用 {@link android.content.Intent} 類別或其他架構類別定義的動作常數。
+
+以下是可啟動 Activity 的一些常見動作:
+</p>
+
+<dl>
+<dt>{@link android.content.Intent#ACTION_VIEW}</dt>
+ <dd>當您有一些資訊可讓 Activity 向使用者顯示時,例如要在圖庫應用程式檢視的相片或要在地圖應用程式檢視的地址,就可以透過 {@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} 類別參考文件。
+其他動作則是在 Android 架構的其他位置完成定義,例如可在系統設定應用程式中開啟特定畫面的動作位在 {@link android.provider.Settings} 中。
+
+</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>URI ({@link android.net.Uri} 物件) 可參考據以執行的資料和/或該資料的 MIME 類型。
+提供的資料類型通常是由意圖的動作控制。例如,如果動作是 {@link android.content.Intent#ACTION_EDIT},資料就應包含欲編輯文件的 URI。
+
+
+
+<p>建立意圖時,除了意圖的 URI 以外,請務必指定資料類型 (其 MIME 類型)。
+
+
+例如,能夠顯示影像的 Activity 可能無法播放音訊檔案,即使有類似的 URI 格式。
+因此,指定資料的 MIME 格式可協助 Android 系統找出最適合接收意圖的元件。
+
+不過 &mdash; 尤其是當資料指出資料位在裝置何處且受
+{@link android.content.ContentProvider} 控制讓系統看見資料 MIME 類型的
+{@code content:} URI 時,有時能夠從 URI 推論出 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 類型,「請勿」<strong></strong>呼叫 {@link android.content.Intent#setData setData()} 和
+{@link android.content.Intent#setType setType()},原因是這兩者會抵銷彼此的值。
+請務必使用 {@link android.content.Intent#setDataAndType setDataAndType()} 來設定 URI 與 MIME 類型。
+
+</p>
+</dd>
+
+<p><dt><b>類別</b></dt>
+<dd>字串當中包含哪種元件應處理意圖的其他相關資訊。
+意圖中可放置的類別描述數目並沒有限制,但大多數意圖都不需要類別。
+以下是一些常見類別:
+
+
+<dl>
+<dt>{@link android.content.Intent#CATEGORY_BROWSABLE}</dt>
+ <dd>目標 Activity 允許自己由網頁瀏覽器啟動,以顯示連結所參照的資料 &mdash; 例如影像或電子郵件訊息。
+
+ </dd>
+<dt>{@link android.content.Intent#CATEGORY_LAUNCHER}</dt>
+ <dd>Activity 是工作的初始 Activity,而且列在系統的應用程式啟動器中。
+
+ </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()}方法來新增額外資料,每種方法都接受兩個參數:索引鍵名稱與值。
+
+
+您也可以使用所有的額外資料建立 {@link android.os.Bundle} 物件,再透過 {@link
+android.content.Intent#putExtras putExtras()} 將 {@link android.content.Intent} 插入 {@link android.os.Bundle}。</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 系統如何啟動 Activity (例如,Activity 屬於哪個
+<a href="{@docRoot}guide/components/tasks-and-back-stack.html">工作</a>) 以及如何處理已啟動的 Activity (例如,它是否屬於最近 Activity 清單)。
+
+
+
+<p>如需詳細資訊,請參閱 {@link android.content.Intent#setFlags setFlags()} 方法。</p>
+</dd>
+
+</dl>
+
+
+
+
+<h3 id="ExampleExplicit">明確意圖範例</h3>
+
+<p>您用來啟動特定應用程式元件的就是明確意圖,例如應用程式中的特定 Activity 或服務。如要建立明確意圖,請定義
+
+{@link android.content.Intent}物件的元件名稱 &mdash; 其他意圖屬性均為選用性質。
+</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>使用者可能會沒有「任何」<em></em>
+應用程式可處理您傳送至 {@link android.content.Context#startActivity
+startActivity()} 的隱含意圖。如果發生這種情況,呼叫會失敗且應用程式將會當機。如要確認 Activity 將可收到意圖,請在
+{@link android.content.Intent} 物件上呼叫 {@link android.content.Intent#resolveActivity
+resolveActivity()}。如果結果不是 null,表示至少有一個應用程式能夠處理該意圖,可以放心呼叫
+
+{@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("text/plain");
+
+// 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}動作和攜帶「純文字」資料的意圖)。
+
+
+如果只有一個應用程式能夠處理,該應用程式會立即開啟並獲派該意圖。
+如果有多個 Activity 接受該意圖,系統會顯示對話方塊,供使用者挑選要使用的應用程式。
+</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>有多個應用程式均回應您的隱含意圖時,使用者可以選擇要使用的應用程式,並將該應用程式當成動作的預設選擇。
+
+如果在執行動作時使用者希望之後都使用同一應用程式 (例如使用者偏好使用某個特定網頁瀏覽器開啟網頁,這項功能就非常實用。
+
+</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 &lt;intent-filter&gt;}</a> 元素,針對您的每個應用程式元件宣告一或多個意圖篩選器。每個意圖篩選器都會根據意圖的動作、資料和類別,指定其接受的意圖類型。
+
+
+
+只有在意圖通過您的其中一個意圖篩選器時,系統才會將隱含意圖傳送至您的應用程式元件。
+</p>
+
+<p class="note"><strong>注意:</strong>不論元件宣告的意圖篩選器為何,明確意圖一律會傳送至其目標。
+</p>
+
+<p>應用程式元件應為其所能執行的各個獨特工作宣告不同的篩選器。例如,圖片庫應用程式中的一個 Activity 可能會有兩個篩選器:一個用於檢視圖片的篩選器,以及另一個用於編輯圖片的篩選器。
+
+當 Activity 啟動時,它會檢查
+{@link android.content.Intent} 並根據
+{@link android.content.Intent} 中的資訊決定如何運作 (例如,是否要檢視編輯器控制項)。</p>
+
+<p>每個意圖篩選器都是由 <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter&gt;}</a> 元素定義在應用程式的宣示說明檔案中,以巢狀方式置於對應的應用程式元件 (例如,<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a> 元素)。
+
+
+在 <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter&gt;}</a> 內,您可以使用以下三個元素當中的一或多個元素,指定要接受的意圖類型:
+
+</p>
+
+<dl>
+<dt><a href="{@docRoot}guide/topics/manifest/action-element.html">{@code &lt;action&gt;}</a></dt>
+ <dd>在 {@code name} 屬性中,宣告接受的意圖動作。值必須是動作的常值字串值,不得為類別常數。
+</dd>
+<dt><a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data&gt;}</a></dt>
+ <dd>使用一或多項屬性指定資料 URI (
+<code>scheme</code>、<code>host</code>、<code>port</code>、
+<code>path</code> 等) 與 MIME 類型的各層面,以宣告接受的資料類型。</dd>
+<dt><a href="{@docRoot}guide/topics/manifest/category-element.html">{@code &lt;category&gt;}</a></dt>
+ <dd>在 {@code name} 屬性中,宣告接受的意圖類別。值必須是動作的常值字串值,不得為類別常數。
+
+
+ <p class="note"><strong>注意:</strong>如要接收隱含意圖,您「必須」<strong></strong>在意圖篩選器中納入 {@link android.content.Intent#CATEGORY_DEFAULT} 類別。
+
+
+{@link android.app.Activity#startActivity startActivity()} 與
+{@link android.app.Activity#startActivityForResult startActivityForResult()} 方法對所有意圖進行處理時,就像已宣告
+{@link android.content.Intent#CATEGORY_DEFAULT} 類別一樣。
+ 如果您未在意圖篩選器中宣告此類別,任何隱含意圖都不會解析為 Activity。
+</p>
+ </dd>
+</dl>
+
+<p>例如,假設資料類型為文字,以下 Activity 宣告的意圖篩選器都可接受
+{@link android.content.Intent#ACTION_SEND} 意圖:</p>
+
+<pre>
+&lt;activity android:name="ShareActivity">
+ &lt;intent-filter>
+ &lt;action android:name="android.intent.action.SEND"/>
+ &lt;category android:name="android.intent.category.DEFAULT"/>
+ &lt;data android:mimeType="text/plain"/>
+ &lt;/intent-filter>
+&lt;/activity>
+</pre>
+
+<p>想要建立包含多個
+<a href="{@docRoot}guide/topics/manifest/action-element.html">{@code &lt;action&gt;}</a>、
+<a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data&gt;}</a> 或
+<a href="{@docRoot}guide/topics/manifest/category-element.html">{@code &lt;category&gt;}</a> 執行個體的篩選器也沒關係。
+如果您這樣做,只需要確定該元件能處理這些篩選器元素的任何組合。
+</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>藉由將意圖與三個元素個別比較,針對篩選器來測試隱含意圖。
+如要傳送至元件,意圖必須通過共三個測試。
+
+如果無一相符,Android 系統就不會將意圖傳送至該元件。不過,由於元件可能會有多個意圖篩選器,未通過其中一個元件篩選器的意圖可能會通過另一個篩選器。
+
+
+如要進一步瞭解系統如何解析意圖,請參閱下文的<a href="#Resolution">意圖解析</a>。</p>
+
+<p class="caution"><strong>注意:</strong>如要避免一時疏忽而執行不同應用程式的
+{@link android.app.Service},請一律使用明確意圖啟動您自己的服務,同時不要宣告服務的意圖篩選器。
+</p>
+
+<p class="note"><strong>注意:</strong>對於所有 Activity,您都必須在宣示說明檔案中宣告意圖篩選器。
+
+不過,廣播接收器的篩選器可以藉由呼叫
+{@link android.content.Context#registerReceiver(BroadcastReceiver, IntentFilter, String,
+Handler) registerReceiver()} 進行動態註冊。您之後可以利用 {@link
+android.content.Context#unregisterReceiver unregisterReceiver()} 來取消註冊接收器。這樣做可在您的應用程式執行時,讓應用程式只能在指定期間內接聽特定廣播。
+
+</p>
+
+
+
+
+
+
+
+<h3 id="ExampleFilters">篩選器範例</h3>
+
+<p>如要進一步瞭解意圖篩選器行為,可以看看社交分享應用程式宣示說明檔案中的以下程式碼片段。
+</p>
+
+<pre>
+&lt;activity android:name="MainActivity">
+ &lt;!-- This activity is the main entry, should appear in app launcher -->
+ &lt;intent-filter>
+ &lt;action android:name="android.intent.action.MAIN" />
+ &lt;category android:name="android.intent.category.LAUNCHER" />
+ &lt;/intent-filter>
+&lt;/activity>
+
+&lt;activity android:name="ShareActivity">
+ &lt;!-- This activity handles "SEND" actions with text data -->
+ &lt;intent-filter&gt;
+ &lt;action android:name="android.intent.action.SEND"/>
+ &lt;category android:name="android.intent.category.DEFAULT"/>
+ &lt;data android:mimeType="text/plain"/>
+ &lt;/intent-filter&gt;
+ &lt;!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data -->
+ &lt;intent-filter&gt;
+ &lt;action android:name="android.intent.action.SEND"/>
+ &lt;action android:name="android.intent.action.SEND_MULTIPLE"/>
+ &lt;category android:name="android.intent.category.DEFAULT"/>
+ &lt;data android:mimeType="application/vnd.google.panorama360+jpg"/>
+ &lt;data android:mimeType="image/*"/>
+ &lt;data android:mimeType="video/*"/>
+ &lt;/intent-filter&gt;
+&lt;/activity&gt;
+</pre>
+
+<p>第一個 Activity {@code MainActivity} 是應用程式的主要進入點 &mdash; 這個 Activity 會在使用者使用啟動器圖示初次啟動應用程式時開啟:
+</p>
+<ul>
+ <li>{@link android.content.Intent#ACTION_MAIN} 動作可指出這是主要進入點且預期沒有任何意圖資料。
+</li>
+ <li>{@link android.content.Intent#CATEGORY_LAUNCHER} 類別可指出此 Activity 的圖示應該放在系統的應用程式啟動器中。
+如果 <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>元素未以 {@code icon} 指定圖示,系統會使用 <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application&gt;}</a> 元素中的圖示。
+
+</li>
+</ul>
+<p>上述兩項必須成對,Activity 才會顯示在應用程式啟動器中。</p>
+
+<p>第二個 Activity {@code ShareActivity} 是用來加速分享文字與媒體內容。
+雖然使用者可能藉由從 {@code MainActivity} 來瀏覽它而進入此 Activity,但它們也能從發出隱含意圖 (符合兩個意圖篩選器之一) 的另一款應用程式直接進入 {@code ShareActivity}。
+
+</p>
+
+<p class="note"><strong>注意:</strong>
+<a href="https://developers.google.com/panorama/android/">{@code
+application/vnd.google.panorama360+jpg}</a> MIME 類型是指定全景相片的特殊資料類型,您可以透過
+<a href="{@docRoot}reference/com/google/android/gms/panorama/package-summary.html">Google 全景</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.PendingIntent#getActivity PendingIntent.getActivity()} 適用於啟動 {@link android.app.Activity} 的 {@link android.content.Intent}。
+</li>
+ <li>{@link android.app.PendingIntent#getService PendingIntent.getService()} 適用於啟動 {@link android.app.Service} 的 {@link android.content.Intent}。
+</li>
+ <li>{@link android.app.PendingIntent#getBroadcast PendingIntent.getBroadcast()} 適用於啟動 {@link android.content.BroadcastReceiver} 的 {@link android.content.Intent}。
+</li>
+</ul>
+
+<p>除非您的應用程式「收到」<em></em>來自其他應用程式的待處理意圖,否則您可能只需要上述建立
+{@link android.app.PendingIntent} 的
+{@link android.app.PendingIntent} 方法。</p>
+
+<p>每個方法會採用目前的應用程式 {@link android.content.Context}、您要包裝的
+{@link android.content.Intent} 以及一或多個指定應如何使用意圖的旗標 (例如該意圖是否能使用多次)。
+</p>
+
+<p>如要進一步瞭解如何使用待處理意圖,請參閱個別使用案例的參考文件,例如<a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">通知</a>以及<a href="{@docRoot}guide/topics/appwidgets/index.html">應用程式小工具</a> API 指南。
+
+</p>
+
+
+
+
+
+
+
+<h2 id="Resolution">意圖解析</h2>
+
+
+<p>當系統收到要啟動 Activity 的隱含意圖時,會根據三個層面來比較意圖與意圖篩選器,以便為該意圖搜尋最適合的 Activity。
+</p>
+
+<ul>
+ <li>意圖動作
+ <li>意圖資料 (URI 與資料類型)
+ <li>意圖類別
+</ul>
+
+<p>下列各節就如何在應用程式宣示說明檔案中宣告意圖篩選器這點,說明如何比對意圖以找出適當的元件。
+</p>
+
+
+<h3 id="ActionTest">動作測試</h3>
+
+<p>如要指定接受的意圖動作,意圖篩選器可以宣告零或多個
+<a href="{@docRoot}guide/topics/manifest/action-element.html">{@code
+&lt;action&gt;}</a> 元素。例如:</p>
+
+<pre>
+&lt;intent-filter&gt;
+ &lt;action android:name="android.intent.action.EDIT" /&gt;
+ &lt;action android:name="android.intent.action.VIEW" /&gt;
+ ...
+&lt;/intent-filter&gt;
+</pre>
+
+<p>如要通過此篩選器,{@link android.content.Intent} 中指定的動作必須與篩選器中列出的其中一個動作相符。
+</p>
+
+<p>如果篩選器未列出任何可供意圖比對的動作,所有意圖都無法通過測試。
+不過,如果 {@link android.content.Intent} 未指定任何動作,它就會通過測試 (只要篩選器至少包含一個動作即可)。
+
+</p>
+
+
+
+<h3 id="CategoryTest">類別測試</h3>
+
+<p>如要指定接受的意圖類別,意圖篩選器可以宣告零或多個
+<a href="{@docRoot}guide/topics/manifest/category-element.html">{@code
+&lt;category&gt;}</a> 元素。例如:</p>
+
+<pre>
+&lt;intent-filter&gt;
+ &lt;category android:name="android.intent.category.DEFAULT" /&gt;
+ &lt;category android:name="android.intent.category.BROWSABLE" /&gt;
+ ...
+&lt;/intent-filter&gt;
+</pre>
+
+<p>{@link android.content.Intent} 中的每個類別都必須與篩選器中的類別相符,意圖才會通過類別測試。
+不需要反向進行 &mdash; 意圖篩選器宣告的類別可以比
+{@link android.content.Intent} 中指定的類別多,而
+{@link android.content.Intent} 仍可通過測試。因此,不論篩選器中宣告的類別為何,未包含類別的意圖一律可通過此測試。
+</p>
+
+<p class="note"><strong>注意:</strong>Android 會將 {@link android.content.Intent#CATEGORY_DEFAULT} 類別自動套用到所有傳送至 {@link
+android.content.Context#startActivity startActivity()} 與 {@link
+android.app.Activity#startActivityForResult startActivityForResult()} 的隱含意圖。因此,如果您希望 Activity 收到隱含意圖,Activity 的意圖篩選器就必須包含
+{@code "android.intent.category.DEFAULT"} 的類別 (如先前的 {@code &lt;intent-filter&gt;} 範例中所示)。
+
+
+
+</p>
+
+
+
+<h3 id="DataTest">資料測試</h3>
+
+<p>如要指定接受的意圖資料,意圖篩選器可以宣告零或多個
+<a href="{@docRoot}guide/topics/manifest/data-element.html">{@code
+&lt;data&gt;}</a> 元素。例如:</p>
+
+<pre>
+&lt;intent-filter&gt;
+ &lt;data android:mimeType="video/mpeg" android:scheme="http" ... /&gt;
+ &lt;data android:mimeType="audio/mpeg" android:scheme="http" ... /&gt;
+ ...
+&lt;/intent-filter&gt;
+</pre>
+
+<p>每個 <code><a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data&gt;</a></code>
+ 元素都能指定 URI 結構與資料類型 (MIME 媒體類型)。URI 的每個部分都有個別的屬性:
+{@code scheme}、{@code host}、{@code port} 和 {@code path}。
+
+</p>
+
+<p style="margin-left: 2em">{@code &lt;scheme&gt;://&lt;host&gt;:&lt;port&gt;/&lt;path&gt;}</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 &lt;data&gt;}</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 與篩選器的 URI 格式相符,而且篩選器同樣未指定 MIME 類型時,包含 URI 但沒有 MIME 類型 (既非明確也無法從 URI 推測得出) 的意圖才會通過測試。
+
+</li>
+
+<li>只有在篩選器列出相同的 MIME 類型且未指定 URI 格式時,包含 MIME 類型但沒有 URI 的意圖才會通過測試。
+</li>
+
+<li>只有在 MIME 類型與篩選器中列出的類型相符時,包含 URI 與 MIME 類型 (明確或可從 URI 推測得出) 的意圖才會通過 MIME 類型部分的測試。
+
+如果它的 URI 與篩選器中的 URI 相符,或如果它有
+{@code content:} 或 {@code file:} URI,而且篩選器未指定 URI 時,就會通過 URI 部分的測試。換句話說,如果它的篩選器「只」<em></em>列出 MIME 類型,就會假設元件支援 {@code content:} 與 {@code file:} 資料。
+
+
+</p></li>
+</ol>
+
+<p>
+最後一項規則 (規則 (d)) 可反映出希望元件能夠從檔案或內容供應程式取得本機資料的期望。
+
+因此,其篩選器可以只列出資料類型,同時不需要明確命名
+{@code content:} 與 {@code file:} 配置。
+此為典型案例。例如,如下所示的 <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data&gt;}</a> 元素可以告訴 Android,元件能夠從內容供應程式取得影像資料並加以顯示:
+
+
+</p>
+
+<pre>
+&lt;intent-filter&gt;
+ &lt;data android:mimeType="image/*" /&gt;
+ ...
+&lt;/intent-filter&gt;</pre>
+
+<p>
+由於大部分可用資料都是由內容供應程式分配,因此指定資料類型但未指定 URI 的篩選器也許會最常見。
+
+</p>
+
+<p>
+另一個常見的設定是含有配置與資料類型的篩選器。例如,如下所示的
+<a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data&gt;}</a>元素可以告訴 Android,元件能夠從網路擷取影片資料以執行動作:
+
+
+</p>
+
+<pre>
+&lt;intent-filter&gt;
+ &lt;data android:scheme="http" android:type="video/*" /&gt;
+ ...
+&lt;/intent-filter&gt;</pre>
+
+
+
+<h3 id="imatch">意圖比對</h3>
+
+<p>和意圖篩選器比對的意圖不只可探尋要啟動的目標元件,還能探尋裝置上元件集合的相關資料。
+
+例如,主畫面應用程式會利用指定
+{@link android.content.Intent#ACTION_MAIN} 動作與
+{@link android.content.Intent#CATEGORY_LAUNCHER} 類別的意圖篩選器來尋找所有 Activity,以填入應用程式啟動器。
+</p>
+
+<p>您的應用程式能以類似的方式使用意圖比對。
+{@link android.content.pm.PackageManager} 有一組 {@code query...()}方法可將接受特定意圖的所有元件傳回,還有一系列類似的
+{@code resolve...()} 方法可決定回應意圖的最佳元件。
+
+例如,
+{@link android.content.pm.PackageManager#queryIntentActivities
+queryIntentActivities()} 會傳回所有 Activity 清單,上述的 Activity 都可以執行當成引數傳送的意圖,以及
+{@link
+android.content.pm.PackageManager#queryIntentServices
+queryIntentServices()} 可傳回類似的服務清單。
+
+這些方法不會啟動元件,只會列出可以回應的元件。類似的方法
+{@link android.content.pm.PackageManager#queryBroadcastReceivers
+queryBroadcastReceivers()} 可用於廣播接收器。
+</p>
+
+
+
+
diff --git a/docs/html-intl/intl/zh-tw/guide/components/loaders.jd b/docs/html-intl/intl/zh-tw/guide/components/loaders.jd
new file mode 100644
index 000000000000..89bfc80744d9
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/guide/components/loaders.jd
@@ -0,0 +1,494 @@
+page.title=載入器
+parent.title=Activity
+parent.link=activities.html
+@jd:body
+<div id="qv-wrapper">
+<div id="qv">
+ <h2>本文件內容</h2>
+ <ol>
+ <li><a href="#summary">載入器 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 導入的載入器可輕鬆在 Activity 或片段中,以非同步方式載入資料。
+載入器的特性如下:</p>
+ <ul>
+ <li>適用於所有 {@link android.app.Activity} 和 {@link
+android.app.Fragment} 。</li>
+ <li>提供以非同步方式載入資料。</li>
+ <li>監視其資料來源,並在內容變更時傳送新的結果。
+</li>
+ <li>可在設定變更後重新建立時,自動重新連接到上次載入器的游標,
+因此不需要重新查詢資料。
+</li>
+ </ul>
+
+<h2 id="summary">載入器 API 摘要</h2>
+
+<p>有多個類別和介面可能與在應用程式中使用載入器有關。
+請參閱下表的摘要說明:</p>
+
+<table>
+ <tr>
+ <th>類別/介面</th>
+ <th>說明</th>
+ </tr>
+ <tr>
+ <td>{@link android.app.LoaderManager}</td>
+ <td>與 {@link android.app.Activity} 或
+{@link android.app.Fragment} 相關聯的抽象類別,可用於管理一或多個 {@link
+android.content.Loader} 執行個體。這可以協助應用程式管理所需執行時間較長的操作與 {@link android.app.Activity} 或 {@link android.app.Fragment} 生命週期搭配使用,這最常與
+{@link android.content.CursorLoader} 搭配使用,不過應用程式能夠撰寫自己的載入器來載入其他類型的資料。
+
+
+
+ <br />
+ <br />
+ 每個 Activity 或片段只能有一個 {@link android.app.LoaderManager},但 {@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} 通訊協定,用來查詢建置於 {@link android.content.AsyncTaskLoader} 的游標,以便在背景執行緒中執行游標查詢,藉此避免封鎖應用程式的 UI。
+
+
+以非同步方式從 {@link
+android.content.ContentProvider} 載入資料,而不是透過片段或 Activity 的 API 來管理查詢,最好的方法就是使用此載入器。
+</td>
+ </tr>
+</table>
+
+<p>上表中的類別和介面就是您將用來在應用程式中實作載入器的基本元件。
+上述元件不需要在您建立載入器時全部使用,但您必須一律參照到 {@link
+android.app.LoaderManager},才能初始化載入器並實作
+{@link android.content.Loader} 類別,例如 {@link
+android.content.CursorLoader}。
+以下各節說明如何在應用程式中使用這些類別和介面。
+</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} 可在 {@link android.app.Activity} 或 {@link android.app.Fragment} 內管理一或多個 {@link
+android.content.Loader} 執行個體。
+每個 Activity 或片段只能有一個 {@link
+android.app.LoaderManager}。</p>
+
+<p>您通常會在 Activity 的 {@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.LoaderCallbacks} 實作,
+{@link android.app.LoaderManager} 會呼叫此實作來回報載入器事件。在本範例中,本機類別會實作 {@link
+android.app.LoaderManager.LoaderCallbacks} 執行個體,以將參照傳送給它自己 ({@code this})。
+
+</li>
+</ul>
+<p>{@link android.app.LoaderManager#initLoader initLoader()} 呼叫可確保載入器已初始化且處於有效狀態。
+可能會有兩種結果:</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">使用 LoaderManager 回呼</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}) 在停止之後,應該會保留它們的資料。
+這可讓應用程式保留其在 Activity 或片段的 {@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>uri<em></em> - 要擷取內容的 URI。 </li>
+ <li>projection<em></em> - 要傳回的欄清單。傳送
+<code>null</code> 將會傳回無效的所有欄。 </li>
+ <li>selection<em></em> - 篩選器會採用 SQL WHERE 子句的格式 (WHERE 本身除外) 宣告要傳回的列。
+傳送
+<code>null</code> 將會傳回指定 URI 的所有列。 </li>
+ <li>selectionArgs<em></em> - 您可能會在選取項目中包含 ?s,而其會由來自 selectionArgs<em></em> 的值按照其出現在選取項目中的順序所取代。
+
+值將會繫結為字串。 </li>
+ <li>sortOrder<em></em> - 如何採用 SQL ORDER BY 子句的格式 (ORDER BY 本身除外) 來排列各列的順序。
+傳遞 <code>null</code> 將會使用預設的排序順序,其可能是無排序順序。
+</li>
+</ul>
+<p>例如:</p>
+<pre>
+ // If non-null, this is the current filter the user has provided.
+String mCurFilter;
+...
+public Loader&lt;Cursor&gt; 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 = &quot;((&quot; + Contacts.DISPLAY_NAME + &quot; NOTNULL) AND (&quot;
+            + Contacts.HAS_PHONE_NUMBER + &quot;=1) AND (&quot;
+            + Contacts.DISPLAY_NAME + &quot; != '' ))&quot;;
+    return new CursorLoader(getActivity(), baseUri,
+            CONTACTS_SUMMARY_PROJECTION, select, null,
+            Contacts.DISPLAY_NAME + &quot; COLLATE LOCALIZED ASC&quot;);
+}</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.widget.SimpleCursorAdapter#swapCursor swapCursor()} 方法,如此才不會關閉舊的
+{@link android.database.Cursor}。例如:</p>
+
+<pre>
+// This is the Adapter being used to display the list's data.<br
+/>SimpleCursorAdapter mAdapter;
+...
+
+public void onLoadFinished(Loader&lt;Cursor&gt; 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&lt;Cursor&gt; 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.app.Fragment} 的完整實作,
+其顯示的 {@link android.widget.ListView} 包含聯絡人內容供應程式的查詢結果。它使用 {@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&lt;Cursor&gt; {
+
+ // 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(&quot;No phone numbers&quot;);
+
+        // 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(&quot;Search&quot;);
+        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(&quot;FragmentComplexList&quot;, &quot;Item clicked: &quot; + 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&lt;Cursor&gt; 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 = &quot;((&quot; + Contacts.DISPLAY_NAME + &quot; NOTNULL) AND (&quot;
+                + Contacts.HAS_PHONE_NUMBER + &quot;=1) AND (&quot;
+                + Contacts.DISPLAY_NAME + &quot; != '' ))&quot;;
+        return new CursorLoader(getActivity(), baseUri,
+                CONTACTS_SUMMARY_PROJECTION, select, null,
+                Contacts.DISPLAY_NAME + &quot; COLLATE LOCALIZED ASC&quot;);
+    }
+
+    public void onLoadFinished(Loader&lt;Cursor&gt; 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&lt;Cursor&gt; 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">取得範例</a>。
+ </p>
+
diff --git a/docs/html-intl/intl/zh-tw/guide/components/processes-and-threads.jd b/docs/html-intl/intl/zh-tw/guide/components/processes-and-threads.jd
new file mode 100644
index 000000000000..74dbb8ebb3f1
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/guide/components/processes-and-threads.jd
@@ -0,0 +1,411 @@
+page.title=處理程序和執行緒
+page.tags=生命週期、背景
+
+@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">處理程序間通訊</a></li>
+</ol>
+
+</div>
+</div>
+
+<p>當應用程式元件啟動且該應用程式未執行任何其他元件時,Android 系統會以執行單一執行緒的方式,為該應用程式啟動新的 Linux 處理程序。
+
+預設會以相同的處理程序和執行緒 (稱為「主要」執行緒) 執行相同應用程式的所有元件。
+如果應用程式元件啟動且已有該應用程式的處理程序存在 (由於應用程式還有另一個元件存在),那麼元件會在該處理程序中啟動,並使用相同的執行緒執行。
+
+不過,您可以安排應用程式中的不同元件以個別處理程序執行,還可以為任何處理程序建立額外的執行緒。
+
+</p>
+
+<p>本文件說明處理程序和執行緒如何在 Android 應用程式中運作。</p>
+
+
+<h2 id="Processes">處理程序</h2>
+
+<p>在預設情況下,系統會以相同的處理程序執行相同應用程式的所有元件,而且大部分應用程式都是如此。
+不過,如果您需要控制特定元件所屬的處理程序,可以在宣示說明檔案中這麼做。
+</p>
+
+<p>每種元件元素 &mdash; <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
+&lt;activity&gt;}</a>、<a href="{@docRoot}guide/topics/manifest/service-element.html">{@code
+&lt;service&gt;}</a>、<a href="{@docRoot}guide/topics/manifest/receiver-element.html">{@code
+&lt;receiver&gt;}</a> 和 <a href="{@docRoot}guide/topics/manifest/provider-element.html">{@code
+&lt;provider&gt;}</a> &mdash; 的宣示說明項目都支援 {@code android:process} 屬性,這項屬性能指定元件應在哪個處理程序執行。
+您可以設定此屬性讓每個元件都以自己的處理程序執行,或只讓當中的部分元件共用同一處理程序。
+您也可以設定
+{@code android:process},讓不同應用程式的元件以相同的處理程序執行,只要這些應用程式分享相同的 Linux 使用者 ID 並以相同的憑證簽署。
+
+</p>
+
+<p><a href="{@docRoot}guide/topics/manifest/application-element.html">{@code
+&lt;application&gt;}</a> 元素也支援 {@code android:process} 屬性,以設定要套用到所有元件的預設值。
+</p>
+
+<p>Android 可能會在記憶體不足且需要其他處理程序更立即為使用者提供服務時,決定關閉處理程序。
+使用已終止的處理程序執行的應用程式元件會因此而終結。
+當再次有工作需要執行時,就會為這些元件再次啟動處理程序。
+</p>
+
+<p>Android 系統會將處理程序對使用者的相對重要性加權,以決定要終止的處理程序。
+例如,相較於代管可見 Activity 的處理程序,系統較容易關閉代管已不在螢幕上顯示的 Activity 的處理程序。
+因此,是否要終止處理程序,取決於以該處理程序執行中的元件狀態。
+如要瞭解用於決定是否終止處理程序的規則,請參閱下文。
+ </p>
+
+
+<h3 id="Lifecycle">處理程序生命週期</h3>
+
+<p>Android 系統會儘可能持續維護處理程序,但最終仍必須移除舊的處理程序,以便回收記憶體供新的或更重要的處理程序使用。
+系統會根據以該處理程序執行的元件和那些元件的狀態,將每個處理程序放入「重要性階層」,藉此決定要保留以及要終止的處理程序。
+
+
+重要性最低的處理程序會最先遭到終止,接著是重要性次低的處理程序,依此類推,視需要收回系統資源。
+
+</p>
+
+<p>重要性階層共有五個層級。下方清單依照重要性的順序列出不同類型的處理程序 (第一個處理程序為「最重要」<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} 已繫結至正在與使用者互動的 Activity。
+</li>
+
+ <li>其代管的 {@link android.app.Service} 正「在前景」執行中 (服務已呼叫 {@link android.app.Service#startForeground startForeground()})。
+
+
+ <li>其代管的 {@link android.app.Service} 正在執行本身的其中一個生命週期回呼 ({@link android.app.Service#onCreate onCreate()}、{@link android.app.Service#onStart onStart()} 或 {@link android.app.Service#onDestroy onDestroy()})。
+
+</li>
+
+ <li>其代管的 {@link android.content.BroadcastReceiver} 正在執行本身的 {@link
+android.content.BroadcastReceiver#onReceive onReceive()} 方法。</li>
+ </ul>
+
+ <p>一般來說,在任何指定時間內只會有幾個前景處理程序存在。只有在記憶體過低而全都無法繼續執行時,才會採取這最後的手段來終止它們。
+在這種情況下,裝置通常已達到記憶體分頁處理狀態,因此必須終止一些前景處理程序,才能讓使用者介面保持回應。
+
+</p></li>
+
+ <li><b>可見處理程序</b>
+ <p>這種處理程序是指沒有任何前景元件的處理程序,但仍會影響使用者在螢幕上看見的內容。
+針對下列任一情況,系統會將處理程序視為可見:
+</p>
+
+ <ul>
+ <li>其代管的 {@link android.app.Activity} 不在前景中,但使用者仍可看見 (已呼叫它的 {@link android.app.Activity#onPause onPause()} 方法)。
+例如,如果前景 Activity 啟動的對話方塊允許在它身後看見先前的 Activity,就會發生這種情況。
+
+</li>
+
+ <li>其代管的 {@link android.app.Service} 已繫結至可見 (或前景) Activity。
+</li>
+ </ul>
+
+ <p>可見處理程序相當重要而且不會遭到終止,除非系統為了讓所有前景處理程序維持執行而必須終止這類處理程序。
+ </p>
+ </li>
+
+ <li><b>服務處理程序</b>
+ <p>這種處理程序是指正在執行已使用 {@link
+android.content.Context#startService startService()} 方法啟動的服務的處理程序;此處理程序不屬於上述兩種較重要的類別。
+雖然服務處理程序是間接繫結至使用者所見內容,但通常會執行使用者重視的工作 (例如,在背景中播放音樂,或下載網路上的資料),因此除非記憶體不足,無法讓所有前景與可見處理程序保持執行,否則系統會讓這類處理程序繼續執行。
+
+
+ </p>
+ </li>
+
+ <li><b>背景處理程序</b>
+ <p>這種處理程序會保留使用者目前看不見的 Activity (已呼叫 Activity 的
+{@link android.app.Activity#onStop onStop()} 方法)。這些處理程序會間接影響使用者體驗,且系統能隨時將其終止,藉此回收記憶體以供前景、可見或服務處理程序使用。
+
+
+通常會有許多背景處理程序處於執行中,因此會將它們放在 LRU (最近最少使用) 清單中,以確保在最後才將包含使用者最近最常見 Activity 的處理程序終止。
+
+如果 Activity 正確實作其生命週期方法並儲存其目前狀態,終止其處理程序不會對使用者體驗造成任何可察覺的影響,原因是當使用者瀏覽回 Activity 時,該 Activity 會還原它的所有可見狀態。
+
+
+如要進一步瞭解如何儲存及還原狀態,請參閱 <a href="{@docRoot}guide/components/activities.html#SavingActivityState">Activity</a>。
+</p>
+ </li>
+
+ <li><b>空白處理程序</b>
+ <p>這種處理程序是指未保留任何使用中應用程式元件的處理程序。讓這類處理程序保持有效的唯一目的是將其用於快取,以改善元件下次執行時所需的啟動時間。
+
+系統通常會終止這些處理程序,以平衡處理程序快取與底層核心快取之間的整體系統資源。
+</p>
+ </li>
+</ol>
+
+
+ <p>Android 會根據在處理程序中目前處於使用中的元件重要性,將處理程序盡量排在最高層級。
+例如,如果處理程序代管一項服務和一個可見 Activity,此處理程序的會排為可見處理程序,而不是服務處理程序。
+</p>
+
+ <p>此外,還可能因為它有其他相依處理程序,而導致處理程序的排名提升:為另一個處理程序提供服務的處理程序,其排名絕不能低於為其提供服務的處理程序。
+
+例如,如果處理程序 A 的內容供應程式為處理程序 B 中的用戶端提供服務,或處理程序 A 中的服務繫結至處理程序 B 中的元件,則系統至少會將處理程序 A 視為和處理程序 B 一樣重要。
+
+</p>
+
+ <p>由於執行服務的處理程序排名會比包含背景 Activity 的處理程序排名高,因此初始化長時間執行操作的 Activity 可能適合啟動該操作的<a href="{@docRoot}guide/components/services.html">服務</a>,而不只是建立工作者執行緒 &mdash; 特別是該操作可能會比 Activity 持久。例如,將圖片上傳至網站 Activity 應該啟動要執行上傳的服務,如果使用者離開 Activity,上傳處理程序也能在背景中繼續進行。如果使用服務,不論 Activity 發生什麼情況,都可保證該操作的優先順序至少會是「服務處理程序」。
+
+
+
+
+
+廣播接收器應該採用服務,而不是只在執行緒中放置時間耗用操作,也是相同的理由。
+</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>」(ANR) 對話方塊。
+
+使用者接著會決定結束您的應用程式,並可能因感到不滿而將其解除安裝。
+</p>
+
+<p>此外,Andoid UI 工具組「並非」<em></em>安全執行緒,因此請勿透過工作者執行緒操縱 UI &mdash; 使用者介面的所有操縱作業都必須從 UI 執行緒來執行。
+
+基於上述原因,Android 的單一執行緒模型只有兩項簡單規則:</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>首先,由於這會建立新的執行緒來處理網路操作,所以看起來似乎可以正常運作。
+不過,它違反單一執行緒模型的第二項規則:「不要從 UI 執行緒以外的位置存取 Android UI 工具組」<em></em>&mdash; 這個範例修改工作者執行緒中的 {@link
+android.widget.ImageView},而不是 UI 執行緒。
+這樣會產生未定義且預期外的行為,不但難以追蹤且耗費時間。
+</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>現在這個實作才是安全執行緒:雖然從不同的執行緒完成網路操作,但卻是從 UI 執行緒操縱 {@link android.widget.ImageView}。
+</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&lt;String, Void, Bitmap&gt; {
+ /** 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#doInBackground doInBackground()} 呼叫 {@link android.os.AsyncTask#publishProgress publishProgress()},以便透過 UI 執行緒執行 {@link
+android.os.AsyncTask#onProgressUpdate onProgressUpdate()}。</li>
+<li>您可以從任何執行緒隨時取消工作</li>
+</ul>
+
+<p class="caution"><strong>注意:</strong>使用工作者執行緒可能會遇到的另一個問題是,由於<a href="{@docRoot}guide/topics/resources/runtime-changes.html">執行階段設定變更</a> (例如使用者變更螢幕方向時) 使您的 Activity 意外重新啟動,而可能會終止您的工作者站執行緒。
+
+請參閱 <a href="http://code.google.com/p/shelves/">Shelves</a> 範例應用程式的原始程式碼,以瞭解如何在遇到其中一種重新啟動情況時保留您的工作,以及如何在 Activity 遭到終止時適當取消該工作。
+
+</p>
+
+
+<h3 id="ThreadSafe">安全執行緒方法</h3>
+
+<p> 在某些情況下,您實作的方法可能是從多個執行緒呼叫,因此務必要撰寫成安全執行緒。
+ </p>
+
+<p>這種情況主要發生在可從遠端呼叫的方法,例如<a href="{@docRoot}guide/components/bound-services.html">已繫結服務</a>中的方法。當在源自執行 {@link android.os.IBinder IBinder} 的相同處理程序中實作 {@link android.os.IBinder} 方法上的呼叫時,該方法是以呼叫端的執行緒執行。
+
+
+
+不過,當呼叫源自另一個處理程序時,會從系統在相同處理程序中當成 {@link android.os.IBinder
+IBinder} (未以處理程序的 UI 執行緒執行) 維護的執行緒集區,以選擇的執行緒來執行該方法。例如,雖然服務的
+{@link android.app.Service#onBind onBind()} 方法可從服務處理程序的 UI 執行緒呼叫,但以 {@link android.app.Service#onBind
+onBind()} 傳回的物件實作的方法會從集區中的執行緒呼叫。
+
+由於服務能有多個用戶端,同時也能有多個集區執行緒採用相同的
+{@link android.os.IBinder IBinder} 方法。因此 {@link android.os.IBinder
+IBinder} 方法必須實作為安全執行緒。</p>
+
+<p> 同樣地,內容供應程式能接收源自其他處理程序的資料要求。
+雖然 {@link android.content.ContentResolver} 與 {@link android.content.ContentProvider}
+類別會隱藏如何管理處理程序間通訊的詳細資料,但回應這些要求的 {@link
+android.content.ContentProvider} 方法 &mdash; {@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()} &mdash; 是在內容供應程式的處理程序中從執行緒集區呼叫,而不是該處理程序的 UI 執行緒。
+由於可能會同時有任意數目的執行緒呼叫這些方法,因此它們也要實作為安全執行緒。
+ </p>
+
+
+<h2 id="IPC">處理程序間通訊</h2>
+
+<p>Android 提供一項使用遠端程序呼叫 (RPC) 進行處理程序間通訊 (IPC) 的機制,RPC 是指 (以另一個處理程序) 從遠端執行由 Activity 或其他應用程式元件呼叫的方法,再加上要傳回給呼叫端的任何結果。
+
+
+這需要將方法呼叫與其資料分解成作業系統能夠瞭解的程度,將它從本機處理程序與位址空間傳輸到遠端處理程序與位址空間,然後再重新組合和重新實作呼叫。
+
+接著,再以相反的方向傳輸傳回值。
+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/zh-tw/guide/components/recents.jd b/docs/html-intl/intl/zh-tw/guide/components/recents.jd
new file mode 100644
index 000000000000..d56c12c0e87b
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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">使用 Activity 屬性來新增工作</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>總覽畫面 (也被稱為最近畫面、最近工作清單,或最近的應用程式) 是系統層級的 UI,可以列出最近存取的 <a href="{@docRoot}guide/components/activities.html">Activity</a> 與<a href="{@docRoot}guide/components/tasks-and-back-stack.html">工作</a>。
+
+使用者可以透過清單導覽並選擇要繼續的工作,或是使用者可以滑動的方式從清單移除工作。
+
+使用 Android 5.0 版本 (API 級別 21),相同 Activity (包含不同文件) 的多個執行個體可以在總覽畫面中顯示為工作。
+例如:對多份 Google 文件,Google 雲端硬碟能讓每份文件都對應一個工作。
+每份文件在總覽畫面中都會顯示為工作。
+</p>
+
+<img src="{@docRoot}images/components/recents.png" alt="" width="284" />
+<p class="img-caption"><strong>圖 1.</strong>總覽畫面會顯示三份 Google 雲端硬碟文件,每份都分別顯示為一項工作。
+</p>
+
+<p>一般而言,您應該允許系統定義如何在總覽畫面中呈現工作與 Activity,而且不需要修改此行為。
+然而,您的應用程式可以決定要如何與在何時於總覽畫面中顯示 Activity。
+
+{@link android.app.ActivityManager.AppTask} 類別讓您可以管理工作,而 {@link android.content.Intent} 類別的 Activity 旗標可以讓您指定何時從總覽畫面新增或移除 Activity。
+
+此外,<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">
+&lt;activity&gt;</a></code> 屬性可以讓您設定宣示說明中的行為。</p>
+
+<h2 id="adding">新增工作到總覽畫面</h2>
+
+<p>使用 {@link android.content.Intent} 類別的旗標可以新增工作,該工作針對何時與如何在總覽畫面中開啟或重新開啟文件,可給予更多控制權。
+當您使用
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>屬性時,您可以選擇永遠在新工作開啟文件或對文件重複使用現有工作。
+
+</p>
+
+<h3 id="flag-new-doc">使用意圖旗標來新增工作</h3>
+
+<p>當您建立 Activity 的新文件時,您可以呼叫
+ {@link android.app.ActivityManager.AppTask} 類別的 {@link android.app.ActivityManager.AppTask#startActivity(android.content.Context, android.content.Intent, android.os.Bundle) startActivity()}方法,傳送啟動 Activity 的意圖至新文件。
+
+如要插入邏輯中斷,讓系統可以將您的 Activity 當作總覽視窗中的新工作,傳送啟動 Activity 的 {@link android.content.Intent}其 {@link android.content.Intent#addFlags(int) addFlags()} 方法中的 {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} 旗標。
+
+
+</p>
+
+<p class="note"><strong>注意:</strong>{@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} 旗標會取代 {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET} 旗標,後者已從 Android 5.0 (API 級別 21) 起失效。
+
+</p>
+
+<p>如果您在建立新文件時設定 {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK} 旗標,則系統永遠會在建立新工作時也在根目錄建立目標 Activity。此設定允許可以在一個以上的工作中開啟相同的文件。
+
+下列程式碼示範主要 Activity 如何處理:
+</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} 旗標一起啟動的 Activity 務必要在宣示說明中設定 {@code android:launchMode="standard"} 屬性值 (預設)。
+
+</p>
+
+<p>當主要 Activity 啟動新的 Activity 時,系統會透過現有工作搜尋其意圖和 Activity 意圖元件名稱及意圖資料相同的 Activity。
+如果找不到工作,或意圖已包含 {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK} 旗標,則會建立新的工作並使用 Activity 做為其根目錄。
+
+如果找到工作,則會將該工作帶到前面並傳送新的意圖到 {@link android.app.Activity#onNewIntent onNewIntent()}。
+新的 Activity 會取得意圖並在總覽視窗中建立新的文件,如下列範例所示:
+
+</p>
+
+<p class="code-caption"><a href="{@docRoot}samples/DocumentCentricApps/index.html">NewDocumentActivity.java
+</a></p>
+<pre>
+&#64;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);
+}
+
+&#64;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">使用 Activity 屬性來新增工作</h3>
+
+<p>Activity 也可以在宣示說明中指定為永遠啟動新工作,這可透過使用<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code> 屬性的 <a href="{@docRoot}guide/topics/manifest/activity-element.html#dlmode">
+{@code android:documentLaunchMode}</a> 達成。
+
+此屬性有四個值,在使用者使用應用程式開啟文件時,會產生下列效果:
+</p>
+
+<dl>
+ <dt>"{@code intoExisting}"</dt>
+ <dd>Activity 會對文件重複使用現有的工作。設定
+{@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} 旗標,但「不」<em></em>設定
+{@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK} 旗標,會與上述<a href="#flag-new-doc">使用意圖旗標來新增工作</a>達到相同效果。
+</dd>
+
+ <dt>"{@code always}"</dt>
+ <dd>Activity 會為文件建立新的工作,就算文件已開始也會建立新的工作。使用此值與設定 {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} 與 {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK} 旗標會達到相同效果。
+
+</dd>
+
+ <dt>"{@code none”}"</dt>
+ <dd>Activity 不會為文件建立新的工作。總覽視窗會將 Activity 當作預設:會顯示應用程式的單一工作,該工作會從使用者最後呼叫的 Activity 繼續。
+
+</dd>
+
+ <dt>"{@code never}"</dt>
+ <dd>Activity 不會為文件建立新的工作。設定此值會覆寫 {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} 與 {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK} 旗標的行為,如果任一個已於意圖中設定,總覽視窗會顯示應用程式的單一工作,該工作會從使用者最後呼叫的 Activity 繼續。
+
+
+
+</dd>
+</dl>
+
+<p class="note"><strong>注意:</strong>如果值不是 {@code none} 與 {@code never},則 Activity 必須使用 {@code launchMode="standard"} 定義。
+如果沒有指定此屬性,則會使用
+{@code documentLaunchMode="none"}。</p>
+
+<h2 id="removing">移除工作</h2>
+
+<p>依照預設,當 Activity 結束時,會自動將文件工作從總覽畫面移除。
+您可以使用 {@link android.app.ActivityManager.AppTask} 類別,搭配 {@link android.content.Intent} 旗標或 <code><a href="{@docRoot}guide/topics/manifest/activity-element.html">
+&lt;activity&gt;</a></code> 屬性,來覆寫此行為。
+</p>
+
+<p>您可以完全從總覽畫面排除工作,設定方式為將
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</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">&lt;activity&gt;</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>在總覽畫面建立新工作的 Activity 中,您可以指定何時移除工作與結束所有相關 Activity,方法為呼叫{@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>如果您要保留總覽畫面中的工作 (就算其 Activity 已結束), 方法為傳送啟動 Activity 的意圖其 {@link android.content.Intent#addFlags(int) addFlags()} 方法中的
+{@link android.content.Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS} 旗標。
+</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">&lt;activity&gt;</a></code> 屬性的 <a href="{@docRoot}guide/topics/manifest/activity-element.html#autoremrecents">
+{@code android:autoRemoveFromRecents}</a> 為 {@code false}。
+對文件 Activity 的預設值為 {@code true},對定期 Activity 的預設值則為 {@code false}。
+如同之前的討論,使用此屬性可以覆寫 {@link android.content.Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS} 旗標。
+</p>
+
+
+
+
+
+
+
diff --git a/docs/html-intl/intl/zh-tw/guide/components/services.jd b/docs/html-intl/intl/zh-tw/guide/components/services.jd
new file mode 100644
index 000000000000..d6a440d88dd6
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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">延伸服務類別</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)。
+例如,服務可能處理網路交易、播放音樂、執行檔案輸入/輸出或與內容供應程式互動,這些都可以從背景執行。
+
+</p>
+
+<p>服務基本上可以採取兩種形式:</p>
+
+<dl>
+ <dt>啟動</dt>
+ <dd>服務「啟動」表示應用程式元件 (例如 Activity) 透過呼叫
+{@link android.content.Context#startService startService()} 來啟動服務。一旦啟動,服務可以無限次數地在背景中執行,就算啟動服務的元件已終結也不會影響。
+通常,已啟動的服務會執行單一操作且不會將結果傳回呼叫端。例如,服務可能會透過網路下載或上傳檔案。
+
+當操作完成時,服務應該會自行終結。
+</dd>
+ <dt>繫結</dt>
+ <dd>服務「繫結」表示應用程式元件透過呼叫 {@link
+android.content.Context#bindService bindService()} 來繫結至服務。已繫結的服務提供主從式介面,讓元件可以與服務互動、傳送要求、取得結果,甚至可以使用處理程序間通訊 (IPC) 來跨程序達到目的。
+
+已繫結的服務伴隨另一個繫結至服務的應用程式元件執行。
+多重元件可以一次繫結至服務,但是當所有元件都取消繫結時,服務就會被終結。
+</dd>
+</dl>
+
+<p>雖然此文件通常分別討論服務的這兩種類別,但您的服務兩種方式都可以執行 &mdash; 可以啟動服務 (無限次數地執行) 也允許繫結。
+這僅與您是否實作兩種回呼方法而定:{@link
+android.app.Service#onStartCommand onStartCommand()} 允許元件啟動服務,而 {@link
+android.app.Service#onBind onBind()} 則允許繫結。
+</p>
+
+<p>不論您的應用程式是否啟動、繫結或兩者都有,任何應用程式元件可以使用服務 (就算來自不同的應用程式),與任何元件可以使用 Activity 的方式相同 &mdash; 使用 {@link android.content.Intent} 啟動服務。
+
+然而,您可以宣告服務為私用、位於宣示說明檔案之中,與封鎖從其他應用程式存取。
+如需更多討論資訊,請詳見<a href="#Declaring">在宣示說明中宣告服務</a>。
+
+</p>
+
+<p class="caution"><strong>注意:</strong>服務會在其託管程序的主執行緒中執行 &mdash; 服務<strong>不會</strong>建立自己的執行緒且<strong>不會</strong>在另外的程序中執行 (除非您另行指定)。
+
+這代表如果您的服務即將從事任何 CPU 密集的作業或封鎖操作 (如播放 MP3 或連線網路),您應該在服務中建立新的執行緒來執行這些工作。
+
+透過使用另外的執行緒,您會降低應用程式不回應 (ANR) 錯誤的風險,且應用程式的主執行緒仍可以專務於使用者與您的 Activity 互動。
+
+</p>
+
+
+<h2 id="Basics">基本概念</h2>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+ <h3>應該使用服務或執行緒?</h3>
+ <p>服務簡單而言就是可以在背景中執行的元件,就算使用者不與您的應用程式互動也不會影響。
+所以,您應該只在需要時才建立服務。
+</p>
+ <p>如果您必須在主執行緒外執行作業,但只有在使用者與您應用程式互動時才需要,則您可能應該建立新的執行緒而非服務。
+例如,如果您想要播放一些音樂,但只在執行您的 Activity 時播放,您可能在
+{@link android.app.Activity#onCreate onCreate()} 中建立執行緒,在 {@link
+android.app.Activity#onStart onStart()} 中開始執行該執行緒,然後在 {@link android.app.Activity#onStop
+onStop()} 中停止。
+也可以考慮使用 {@link android.os.AsyncTask} 或 {@link android.os.HandlerThread},來代替傳統的 {@link java.lang.Thread} 類別。
+如需更多有關執行緒的資訊,請參閱<a href="{@docRoot}guide/components/processes-and-threads.html#Threads">程序與執行緒</a>文件。
+</p>
+ <p>請記得如果您確實使用服務,依照預設會在您應用程式的主執行緒中執行該服務,所以,如果服務執行密集的操作或封鎖操作,則您仍應在服務中建立新的執行緒。
+
+</p>
+</div>
+</div>
+
+<p>如要建立服務,您必須建立 {@link android.app.Service} 的子類別 (或是其現有的子類別之一)。
+在您的實作中,如果可以,您必須覆寫某些回呼方法,這些方法負責處理服務生命週期的關鍵層面,並提供元件繫結至服務的機制。
+
+您應該覆寫的最重要回呼方法為:</p>
+
+<dl>
+ <dt>{@link android.app.Service#onStartCommand onStartCommand()}</dt>
+ <dd>當另一個元件 (如 Activity) 透過呼叫 {@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>當其他元件想要與服務 (如執行 RPC) 繫結時,系統會透過呼叫 {@link android.content.Context#bindService
+bindService()} 來呼叫此方法。
+在您實作此方法時,透過傳回 {@link android.os.IBinder},您必須提供用戶端可用來與服務通訊的介面。
+您必須永遠實作此方法,但如果您不想允許繫結,則您應該傳回 null。
+</dd>
+ <dt>{@link android.app.Service#onCreate()}</dt>
+ <dd>當第一次建立服務時,系統會呼叫此方法來執行一次性的設定程序 (在其呼叫 {@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>只有在記憶體不足且必須復原擁有使用者焦點的 Activity 其系統資源時,Android 系統才會強制停止服務。
+如果服務已繫結至擁有使用者焦點的 Activity,則該服務不太容易被終止,且如果服務被宣告為<a href="#Foreground">在前景中執行</a> (稍後會討論),則該服務幾乎不會被終止。
+否則,如果長時間執行於前景中啟動的服務,則系統會隨時間降低該服務在背景工作清單中的位置,且該服務會很容易被終止 &mdash; 如果已啟動您的服務,則您必須設計讓系統可以完美地處理重新啟動。
+
+
+
+如果系統終止服務,則系統會在可以再度取得資源時立即重新啟動服務 (雖然這也會依據您從 {@link
+android.app.Service#onStartCommand onStartCommand()} 傳回的值而有所不同,稍後會討論)。
+如需更多有關系統何時可能終結服務的資訊,請參閱<a href="{@docRoot}guide/components/processes-and-threads.html">程序與執行緒</a>文件。
+
+</p>
+
+<p>在下列小節,您將看到您如何可以建立每種類型的服務與如何從不同應用程式元件使用。
+</p>
+
+
+
+<h3 id="Declaring">在宣示說明中宣告服務</h3>
+
+<p>就如同 Activity (與其他元件),您必須在您應用程式的宣示說明檔案中宣告所有服務。
+</p>
+
+<p>如要宣告您的服務,可以新增 <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a> 元素為 <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application&gt;}</a>元素的子項。
+
+例如:</p>
+
+<pre>
+&lt;manifest ... &gt;
+ ...
+ &lt;application ... &gt;
+ &lt;service android:name=".ExampleService" /&gt;
+ ...
+ &lt;/application&gt;
+&lt;/manifest&gt;
+</pre>
+
+<p>如需更多有關在宣示說明中宣告您服務的行系資訊,請參閱 <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a> 元素。
+</p>
+
+<p>您還可以在 <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a> 元素中包含其他屬性,用來定義如啟動服務所需權限的屬性,與服務應該執行的程序。
+
+<a href="{@docRoot}guide/topics/manifest/service-element.html#nm">{@code android:name}</a> 屬性是唯一必備的屬性 &mdash; 用來指定服務的類別名稱。
+一旦您發佈應用程式,您就不應該變更此名稱,因為如果這樣做,會由於依賴明確的意圖來啟動或繫結服務 (閱讀部落格貼文、<a href="http://android-developers.blogspot.com/2011/06/things-that-cannot-change.html">不能變更的事項</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>如 Activity 等應用程式元件可以透過呼叫 {@link
+android.content.Context#startService startService()} 與傳送用來指定服務及包含服務所要使用任何資料的
+{@link android.content.Intent},來啟動服務。服務會接收 {@link android.app.Service#onStartCommand
+onStartCommand()} 方法中的此 {@link android.content.Intent}。
+</p>
+
+<p>例如,假設 Activity 需要一些資料到線上資料庫。藉由傳送意圖至 {@link
+android.content.Context#startService startService()},Activity 可以啟動伴隨服務並傳送要儲存的資料。
+服務會接收 {@link
+android.app.Service#onStartCommand onStartCommand()} 中的意圖,連線到網際網路,並執行資料庫交易。
+當操作完成時,服務應該會自行終結。
+</p>
+
+<p class="caution"><strong>注意:</strong>服務會在與應用程式相同的程序中執行,服務會在該程序中被宣告,且依照預設,會位於該應用程式的主執行緒之中。
+所以,在使用者與來自相同應用程式的 Activity 互動時,如果您的服務執行密集的操作或封鎖操作,則該服務將會降低 Activity 的效能。
+
+要避免影響應用程式的效能,您應該在服務之中啟動新的執行緒。
+</p>
+
+<p>傳統上,有兩種類別可以延伸為建立已啟動的服務:</p>
+<dl>
+ <dt>{@link android.app.Service}</dt>
+ <dd>這是所有服務的基本類別。當您延伸此類別時,建立用來執行所有服務工作的新執行緒是非常重要的,因為依照預設,服務會使用您應用程式的主執行緒,這會降低任何您應用程式所執行 Activity 的效能。
+
+
+</dd>
+ <dt>{@link android.app.IntentService}</dt>
+ <dd>這是 {@link android.app.Service} 的子類別,會使用 worker 執行緒來處理所有的啟動要求,一次一個。
+如果您不需要您的服務同時處理多個要求,則這是最佳的選項。
+您唯一要做的就是實作 {@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>建立預設的 worker 執行緒,該執行緒會執行所有傳送至 {@link
+android.app.Service#onStartCommand onStartCommand()} 的意圖,並與您應用程式的主執行緒有所分別。
+</li>
+ <li>建立工作佇列,該佇列會一次傳送一個意圖到您的 {@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#onStartCommand
+onStartCommand()} 其預設實作,然後傳送至您的 {@link
+android.app.IntentService#onHandleIntent onHandleIntent()} 實作。</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.
+ */
+ &#64;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() &lt; 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} 才可以適當處理 worker 執行緒的生命。</p>
+
+<p>例如,{@link android.app.IntentService#onStartCommand onStartCommand()} 必須傳回預設的實作 (這就是意圖如何被傳送至 {@link
+android.app.IntentService#onHandleIntent onHandleIntent()}):
+</p>
+
+<pre>
+&#64;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()},您不需要呼叫超級類別的唯一方法就是 {@link android.app.IntentService#onBind
+onBind()} (但只有在您的服務允許繫結時才需要實作)。
+</p>
+
+<p>在下一節,您會看到在延伸基本 {@link android.app.Service} 類別時,如何實作同類的服務,這需要寫更多程式碼,但是如果您需要同時處理多個啟動要求時,這可能是比較合適的處理方式。
+
+</p>
+
+
+<h3 id="ExtendingService">延伸服務類別</h3>
+
+<p>如同您在前一節看到的,使用 {@link android.app.IntentService} 可讓您已啟動服務的實作變得非常容易。
+然而,如果您要求您的服務執行多重執行緒 (取代透過工作佇列處理啟動要求),則您可以延伸 {@link android.app.Service} 類別來處理每個意圖。
+
+</p>
+
+<p>為了對比之用,下列程式碼範例是 {@link
+android.app.Service} 類別的實作,該類別執行與上述使用 {@link
+android.app.IntentService} 範例相同的工作。也就是,對每個啟動要求,會使用 worker 執行緒來執行工作,且一次只處理一個要求。
+</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);
+ }
+ &#64;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() &lt; 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);
+ }
+ }
+
+ &#64;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);
+ }
+
+ &#64;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;
+ }
+
+ &#64;Override
+ public IBinder onBind(Intent intent) {
+ // We don't provide binding, so return null
+ return null;
+ }
+
+ &#64;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>重新傳送最後的意圖。
+相反地,除非有待決的意圖要啟動服務傳送,否則系統會使用 null 意圖呼叫 {@link android.app.Service#onStartCommand onStartCommand()},如果有待決的意圖要啟動服務,則會傳送那些意圖。
+
+這適用於媒體播放程式 (或類似服務) 這類不執行命令,但可以無次數限制執行與等待工作的服務。
+</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()},從 Activity 或其他應用程式元件來啟動服務。Android 系統會呼叫服務的 {@link
+android.app.Service#onStartCommand onStartCommand()} 方法並傳送 {@link
+android.content.Intent} 給該方法。(絕對不要直接呼叫 {@link android.app.Service#onStartCommand
+onStartCommand()})。</p>
+
+<p>例如,使用明確意圖並搭配 {@link android.content.Context#startService
+startService()},Activity 可以啟動前小節範例中的服務 ({@code
+HelloSevice}):</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()})。
+</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()} 的要求,則在您開始處理啟動要求時,您不應該停止服務,因為您仍可能會收到新的啟動要求 (在第一個要求結束時停止可能會終止第二個要求)。
+
+如要避免發生此問題,您可以使用 {@link android.app.Service#stopSelf(int)} 來確保您停止服務的要求會總是基於最新的啟動要求。
+
+也就是,當您呼叫 {@link
+android.app.Service#stopSelf(int)} 時,會傳送啟動要求的 ID (<code>startId</code> 已傳送至 {@link android.app.Service#onStartCommand onStartCommand()}) 至您相關的停止要求。
+
+然而,如果服務在您可以呼叫 {@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),與來自 Activity 的服務及您應用程式中的其他元件互動時,或是想要揭露您應用程式的特定功能給其他應用程式時,您應該建立已繫結的服務。
+
+</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>快顯通知是一個會出現在目前視窗表面上短暫時間然後消失的訊息,此時狀態列通知會在狀態列提供一個圖示與訊息,使用者可以選擇然後採取行動 (例如啟動 Activity)。
+
+</p>
+
+<p>通常,當已完成某些背景作業(如完成檔案下載) 且使用者現在可以採取行動時,狀態列通知是最佳的方法。
+
+當使用者從擴展的檢視選取通知時,通知可以啟動 Activity (如檢視已下載檔案)。
+</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>例如,播放來自某服務音樂的音樂播放器應該被設為在前景中執行,因為使用者明確意識到這項操作。
+
+狀態列中的通知可能會指出目前播放的歌曲,並允許使用者啟動 Activity 來與音樂播放器互動。
+</p>
+
+<p>如要要求您的服務在前景中執行,可以呼叫 {@link
+android.app.Service#startForeground startForeground()}。此方法有兩個參數:一個整數用來唯一識別通知,以及 {@link
+android.app.Notification} 供狀態列使用。
+例如:</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">建立狀態列通知</a>。
+</p>
+
+
+
+<h2 id="Lifecycle">管理服務的生命週期</h2>
+
+<p>服務的生命週期比 Activity 的生命週期要簡單多了。然而,密切關注如何建立與終結服務就更重要了,因為在使用者沒有意識到的狀況下可在背景中執行服務。
+
+</p>
+
+<p>服務生命週期 &mdash; 從何時建立到何時終結 &mdash; 可以遵循兩種不同的路徑:
+</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>這兩種路徑不是完全獨立的。也就是,您可以繫結至已經使用
+{@link android.content.Context#startService startService()} 啟動的服務。例如,可以啟動背景音樂服務,方法是呼叫 {@link android.content.Context#startService
+startService()} 並搭配可識別要播放音樂的 {@link android.content.Intent}。
+之後,使用者可能會想要透過播放器試試某些控制或取得關於目前歌曲的資訊,可以將 Activity 繫結至服務,方法為呼叫 {@link
+android.content.Context#bindService bindService()}。
+
+就這個的案子而言,除非所有的用戶端都取消繫結,否則 {@link
+android.content.Context#stopService stopService()} 或 {@link android.app.Service#stopSelf
+stopSelf()} 不會實際上停止服務。 </p>
+
+
+<h3 id="LifecycleCallbacks">實作生命週期回呼</h3>
+
+<p>就如同 Activity,服務有您可以實作來監控服務狀態變更與在適合時段執行作業的生命週期回呼方法。
+下列服務會示範每個生命週期方法:
+</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
+
+ &#64;Override
+ public void {@link android.app.Service#onCreate onCreate}() {
+ // The service is being created
+ }
+ &#64;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>;
+ }
+ &#64;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>;
+ }
+ &#64;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>;
+ }
+ &#64;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
+ }
+ &#64;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>不像 Activity 生命週期回呼方法,您「不」<em></em>需要呼叫這些回呼方法的超級類別實作。
+</p>
+
+<img src="{@docRoot}images/service_lifecycle.png" alt="" />
+<p class="img-caption"><strong>圖 2.</strong>服務生命週期。左圖顯示使用 {@link android.content.Context#startService
+startService()} 建立服務的生命週期,右圖顯示使用
+{@link android.content.Context#bindService bindService()} 建立服務的生命週期。
+</p>
+
+<p>透過實作這些方法,您可以監控服務生命週期中的兩個巢狀迴圈: </p>
+
+<ul>
+<li>服務的<strong>整個生命</strong>發生在 {@link
+android.app.Service#onCreate onCreate()} 被呼叫的時間與 {@link
+android.app.Service#onDestroy} 回傳的時間之間。就像 Activity,服務於
+{@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.Intent},也會被分別傳送至 {@link android.content.Context#startService
+startService()} 或 {@link android.content.Context#bindService bindService()}。
+<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()} 回呼)。
+所有,除非服務已繫結至用戶端,系統會在服務停止時終結服務 &mdash; {@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/zh-tw/guide/components/tasks-and-back-stack.jd b/docs/html-intl/intl/zh-tw/guide/components/tasks-and-back-stack.jd
new file mode 100644
index 000000000000..e23301d641bc
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/guide/components/tasks-and-back-stack.jd
@@ -0,0 +1,578 @@
+page.title=工作和返回堆疊
+parent.title=Activity
+parent.link=activities.html
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>本文件內容</h2>
+<ol>
+<li><a href="#ActivityState">儲存 Activity 狀態</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"> Android 的多工作業方式
+</a></li>
+</ol>
+
+<h2>另請參閱</h2>
+<ol>
+ <li><a href="{@docRoot}design/patterns/navigation.html">Android 設計:導覽
+</a></li>
+ <li><a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;} 宣示說明元素
+</a></li>
+ <li><a href="{@docRoot}guide/components/recents.html">總覽畫面</a></li>
+</ol>
+</div>
+</div>
+
+
+<p>一個應用程式通常包含多個 <a href="{@docRoot}guide/components/activities.html">Activity</a>。每個 Activity 應根據使用者可執行的特定動作類型加以設計,且要能啟動其他 Activity。
+
+例如,電子郵件應用程式可能會有一個可顯示新訊息清單的 Activity。
+當使用者選擇一則訊息,會開啟新的 Activity 以檢視該訊息。</p>
+
+<p>Activity 甚至可啟動裝置上其他應用程式的 Activity。例如,如果您的應用程式想要傳送一封電子郵件訊息,您可以定義一個意圖以執行「傳送」動作並包含一些資料,像是電子郵件地址和訊息。
+
+其他應用程式中宣告處理此意圖類型的 Activity 就會開啟。
+在這種情況下,意圖就是要傳送電子郵件,因此電子郵件應用程式會啟動「撰寫」Activity (如果有多個 Activity 支援相同的意圖,則系統會讓使用者選擇要使用的 Activity)。
+
+電子郵件傳送後,您的 Activity 就會繼續,並將電子郵件 Activity 視為您應用程式的一部分。
+雖然 Activity 可能來自不同的應用程式,但 Android 會將兩個 Activity 放在相同的工作中,以維護使用者體驗的流暢性。
+
+<em></em></p>
+
+<p>工作是執行特定工作時,與使用者互動的 Activity 集合。
+Activity 會在堆疊 (返回堆疊<em></em>) 中依照每個 Activity 開啟的順序加以排列。
+</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>裝置主螢幕是大多數工作開始的地方。當使用者輕觸應用程式啟動組件上的某個圖示 (或主螢幕上的捷徑 ) 時,應用程式工作會移到前景。
+
+如果應用程式沒有工作 (最近未使用應用程式),則會建立新的工作,且該應用程式的「主要」Activity 會以堆疊中的根 Activity 形式開啟。
+
+</p>
+
+<p>當目前的 Activity 啟動另一個 Activity 時,會將新的 Activity 推到堆疊的頂端並取得焦點。
+之前的 Activity 會留在堆疊中,但已停止。Activity 停止後,系統會保留其使用者介面的目前狀態。
+當使用者按下 [返回] 按鈕<em></em>,會將目前的 Activity 從堆疊頂端推出 (Activity 已終結),並繼續進行之前的 Activity (還原其 UI 之前的狀態)。
+
+
+堆疊中的 Activity 不會重新整理,只會從堆疊推入和推出 &mdash; 由目前 Activity 啟動時推入堆疊,而當使用者使用 [返回] 按鈕離開時推出堆疊。<em></em>
+
+因此,返回堆疊會以「後進先出」的物件結構進行運作。
+
+圖 1 透過時間軸將此行為視覺化,以時間軸顯示 Activity 間的進度以及每個時間點的目前返回堆疊。
+
+</p>
+
+<img src="{@docRoot}images/fundamentals/diagram_backstack.png" alt="" />
+<p class="img-caption"><strong>圖 1.</strong>顯示工作中每個新 Activity 如何將項目新增到返回堆疊。
+當使用者按下 [返回] 按鈕,目前的 Activity 將會終結,而之前的 Activity 則會繼續進行。<em></em>
+
+</p>
+
+
+<p>如果使用者持續按下 [返回]<em></em>,則會持續推出堆疊中的每個 Activity 以顯示之前的 Activity,直到使用者返回主螢幕 (或到工作開始時執行的 Activity)。
+
+
+當堆疊中的 Activity 全部移除後,工作將不再存在。</p>
+
+<div class="figure" style="width:287px">
+<img src="{@docRoot}images/fundamentals/diagram_multitasking.png" alt="" /> <p
+class="img-caption"><strong>圖 2.</strong>兩個工作:工作 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>單一 Activity 會具現化很多次。</p>
+</div>
+
+<p>工作是一個緊密結合的單位,當使用者開始新的工作時可以移到「背景」,或透過 [首頁] 按鈕前往主螢幕。<em></em>
+在背景時,工作中的所有 Activity 都會停止,但該工作的返回堆疊會保留下來 &mdash; 該工作純粹失去焦點,由另一個工作取而代之,如圖 2 所示。
+
+
+之後,工作可以返回「前景」,讓使用者繼續未完成的工作。
+例如,假設目前的工作 (工作 A) 的堆疊中有三個 Activity &mdash; 兩個位於目前的 Activity 下。
+使用者按下 [首頁] 按鈕,<em></em>然後從應用程式啟動新的應用程式。
+
+當主螢幕出現時,工作 A 會移到背景。
+新的應用程式啟動時,系統會啟動該應用程式的工作 (工作 B),該應用程式會有自己的 Activity 堆疊。
+與該應用程式互動之後,使用者會再次回到首頁,並選取原來啟動工作 A 的應用程式。現在,工作 A 移到了前景 &mdash; 堆疊中的三個 Activity 全部保持不變,而堆疊中最頂端的 Activity 則會繼續進行。
+
+
+
+此時,使用者也能切換回工作 B,前往首頁並選取啟動該工作的應用程式圖示 (或從<a href="{@docRoot}guide/components/recents.html">總覽畫面</a>選取應用程式工作)。這是在 Android 執行多工作業的範例。
+
+
+
+</p>
+
+<p class="note"><strong>注意:</strong>背景可以一次執行多個工作。
+不過,如果使用者同時執行多個背景工作,系統可能會開始終結背景 Activity 以復原記憶體,導致 Activity 狀態遺失。
+請參閱下列有關 <a href="#ActivityState">Activity 狀態</a>的章節。
+</p>
+
+<p>由於返回堆疊中的 Activity 不會重新整理,如果您的應用程式允許使用者從一個以上的 Activity 中啟動特定 Activity,則會建立該 Activity 的新執行個體並推入堆疊 (而不會將 Activity 任何之前的執行個體移到最頂端)。
+
+
+因此,您應用程式中的一個 Activity 可能會具現化很多次 (甚至來自不同的工作),如圖 3 所示。
+也因為這樣,如果使用者使用 [返回] 按鈕瀏覽之前的資訊,Activity 的每個執行個體會依開啟的順序顯示<em></em> (每個會有自己的 UI 狀態)。
+
+
+不過,如果您不希望 Activity 具現化一次以上,則可以修改這個行為。
+如需詳細步驟,請參閱下文的<a href="#ManagingTasks">管理工作</a>。</p>
+
+
+<p>摘要說明 Activity 和工作的預設行為:</p>
+
+<ul>
+ <li>當 Activity A 啟動 Activity B,Activity A 會停止,但系統會保留其狀態(例如捲軸位置和輸入表單的文字)。
+
+如果使用者在 Activity B 按下 [返回] 按鈕,<em></em>Activity A 的狀態會復原並繼續執行。
+</li>
+ <li>當使用者按下 [首頁] 按鈕離開工作,<em></em>目前的 Activity 會停止且其工作會移到背景。
+
+系統會保留工作中所有 Activity 的狀態。如果使用者稍後選取啟動工作的啟動組件圖示繼續執行工作,工作會移到前景並在堆疊頂端繼續執行 Activity。
+
+</li>
+ <li>如果使用者按下 [返回] 按鈕<em></em>,會將目前的 Activity 從堆疊推出並終結。
+
+堆疊中之前的 Activity 會繼續進行。Activity 終結後,系統將不會保留 Activity 的狀態。
+<em></em></li>
+ <li>Activity 可以具現化很多次,即使來自其他工作也一樣。</li>
+</ul>
+
+
+<div class="note design">
+<p><strong>導覽設計</strong></p>
+ <p>如需應用程式導覽如何在 Android 運作的詳細資訊,請參閱 Android 設計的<a href="{@docRoot}design/patterns/navigation.html">導覽</a>指南。</p>
+</div>
+
+
+<h2 id="ActivityState">儲存 Activity 狀態</h2>
+
+<p>如上所述,系統的預設行為會在 Activity 停止時保留 Activity 的狀態。
+如此一來,當使用者瀏覽之前的 Activity 時,其使用者介面的顯示方式將與離開時一樣。
+不過,您可以 &mdash; 也<strong>應該</strong> &mdash; 使用回呼方法主動保留 Activity 的狀態,以防止 Activity 遭到終結且必須重新建立的情況。
+
+</p>
+
+<p>如果系統停止您其中一個 Activity (例如,當新的 Activity 開始或工作移到背景),當系統需要復原系統記憶體時,可能會完全終結該 Activity。
+
+發生這種情況時,與 Activity 狀態相關的資訊都將遺失。如果發生這種情況,系統仍然知道該 Activity 位於返回堆疊中,但是當 Activity 移到堆疊頂端時,系統必須重新建立該 Activity (而不是繼續執行)。
+
+
+如果不想讓使用者的工作遺失,您應該在 Activity 中實作 {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()} 回呼方法,主動保留該工作。
+
+
+</p>
+
+<p>如需儲存 Activity 狀態的詳細資訊,請參閱 <a href="{@docRoot}guide/components/activities.html#SavingActivityState">Activity</a> 文件。
+</p>
+
+
+
+<h2 id="ManagingTasks">管理工作</h2>
+
+<p>如上所述,Android 管理工作和返回堆疊的方式 &mdash; 將連續啟動的所有 Activity 放在相同的工作及「後進先出」堆疊中 &mdash; 對大多數應用程式而言非常好用,而且您不需擔心 Activity 與工作關聯的方式或它們如何存在於返回堆疊中。
+
+
+不過,您也許會想中斷一般的行為。
+您或許會希望應用程式的 Activity 可以在啟動時開始一個新的工作 (而不是放入目前的工作中);或者當您啟動一個 Activity 時,您可能會想使用其現有的執行個體 (而不是在返回堆疊頂端建立新的執行個體);又或者當使用者離開工作時,您想要清除返回堆疊中的所有 Activity,只留下根 Activity。
+
+
+
+</p>
+
+<p>如要執行這些工作及更多工作,您可以使用 <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a> 宣示說明元素中的屬性,以及您傳送到 {@link android.app.Activity#startActivity startActivity()} 之意圖中的旗標。
+
+
+</p>
+
+<p>就這個情況而言,您可以使用的主要 <a href="{@docRoot}guide/topics/manifest/activity-element.html">
+{@code &lt;activity&gt;}</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>在以下各節中,您將瞭解如何使用這些宣示說明屬性和意圖旗標,定義 Activity 與工作關聯的方式以及它們在返回堆疊中的行為。
+</p>
+
+<p>同時,還會分開討論工作與 Activity 如何在總覽畫面表示和進行管理。
+請參閱<a href="{@docRoot}guide/components/recents.html">總覽畫面</a>以取得詳細資訊。
+一般而言,您應該允許系統定義如何在總覽畫面中呈現工作與 Activity,而且不需要修改此行為。
+</p>
+
+<p class="caution"><strong>注意:</strong>大多數應用程式不應中斷 Activity 和工作的預設行為:
+如果您判斷修改 Activity 的預設行為是必要的,請謹慎小心並記得測試啟動期間 Activity 的可用性,以及使用 [返回] 按鈕從其他 Activity 和工作瀏覽到此 Activity 的情況。請記得測試可能會與使用者預期的行為衝突的瀏覽行為。<em></em>
+
+
+</p>
+
+
+<h3 id="TaskLaunchModes">定義啟動模式</h3>
+
+<p>啟動模式可讓您定義 Activity 的新執行個體與目前工作關聯的方式。
+您可用兩種方法定義不同的啟動模式:</p>
+<ul class="nolist">
+ <li><a href="#ManifestForTasks">使用宣示說明檔案</a>
+ <p>當您在宣示說明檔案中宣告 Activity 時,您可以指定 Activity 啟動時該如何與工作關聯。
+</li>
+ <li><a href="#IntentFlagsForTasks">使用意圖旗標</a>
+ <p>當您呼叫 {@link android.app.Activity#startActivity startActivity()} 時,您可以在 {@link android.content.Intent} 包含一個旗標,宣告新 Activity 應如何 (或是否) 與目前的工作關聯。
+
+</p></li>
+</ul>
+
+<p>因此,如果 Activity A 啟動 Activity B,Activity B 可以在其宣示說明中定義它應如何與目前的工作 (如果有) 關聯,而且 Activity A 也能要求 Activity B 應如何與目前的工作關聯。
+
+如果這兩個 Activity 皆定義 Activity B 應如何與工作關聯,相較於 Activity B 的要求 (如宣示說明中所定義),會優先採用 Activity A 的要求 (如意圖中所定義)。
+
+</p>
+
+<p class="note"><strong>注意:</strong>某些宣示說明檔案中提供的啟動模式可能沒有對應的意圖旗標,同樣地,某些意圖旗標提供的啟動模式無法在宣示說明中定義。
+
+</p>
+
+
+<h4 id="ManifestForTasks">使用宣示說明檔案</h4>
+
+<p>當您在宣示說明檔案中宣告 Activity 時,您可以使用 <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a> 元素的 <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code
+launchMode}</a> 屬性,指定 Activity 應如何與工作關聯。
+
+</p>
+
+<p><a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code
+launchMode}</a> 屬性可指定應如何將 Activity 啟動至工作內的指示。
+您可以為
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">launchMode</a></code> 屬性指定四種不同的啟動模式:
+</p>
+
+<dl>
+<dt>{@code "standard"} (預設模式)</dt>
+ <dd>預設。系統在啟動 Activity 的工作中建立新的執行個體,並將意圖路由至該處。
+Activity 可以具現化很多次,每個執行個體可屬於不同的工作,而且一個工作可以有多個執行個體。
+</dd>
+<dt>{@code "singleTop"}</dt>
+ <dd>如果 Activity 的執行個體已經出現在目前工作的頂端,系統會透過呼叫其 {@link
+android.app.Activity#onNewIntent onNewIntent()} 方法,將意圖路由至該執行個體,而不是建立新的 Activity 執行個體。
+
+Activity 可以具現化很多次,每個執行個體可屬於不同的工作,而且一個工作可以有多個執行個體 (但僅限於返回堆疊頂端的 Activity 不是現有的 Activity 執行個體時<em></em>)。
+
+
+ <p>例如,假設工作的返回堆疊包含根 Activity A 及 Activity B、C 及在最頂端的 D (堆疊為 A-B-C-D;D 在最頂端)。
+類型 D Activity 的意圖抵達。
+如果 D 有預設的 {@code "standard"} 啟動模式,則會啟動新的類別執行個體,且堆疊會變成 A-B-C-D-D。不過,如果 D 啟動模式為 {@code "singleTop"},D 的現有執行個體會透過 {@link
+android.app.Activity#onNewIntent onNewIntent()} 接收意圖,這是因為它位於堆疊的最頂端 &mdash; 堆疊會維持 A-B-C-D。不過,如果類型 B Activity 的意圖抵達,則 B 的新執行個體會新增到堆疊中,即使其啟動模式為 {@code "singleTop"} 也是如此。
+
+
+
+</p>
+ <p class="note"><strong>注意:</strong>建立新的 Activity 執行個體之後,使用者可按下 [返回]<em></em> 按鈕,返回之前的 Activity。
+但是,如果處理新意圖的是現有的 Activity 執行個體,則使用者無法按下 [返回]<em></em> 按鈕回到新意圖抵達 {@link android.app.Activity#onNewIntent
+onNewIntent()} 之前的 Activity 狀態。
+
+
+
+</p>
+</dd>
+
+<dt>{@code "singleTask"}</dt>
+ <dd>系統會建立新的工作並在新工作的根目錄將 Activity 具現化。不過,如果 Activity 的執行個體已經出現在其他工作中,系統會透過呼叫其 {@link
+android.app.Activity#onNewIntent onNewIntent()} 方法,將意圖路由至現有的執行個體,而不是建立新的執行個體。
+
+一次只能有一個 Activity 執行個體。
+
+ <p class="note"><strong>注意:</strong>雖然 Activity 是在新工作中啟動,使用者仍可使用 [返回] 按鈕返回之前的 Activity。
+<em></em></p></dd>
+<dt>{@code "singleInstance"}。</dt>
+ <dd>與 {@code "singleTask"} 一樣,差別在於系統不會將任何其他 Activity 啟動至保留執行個體的工作中。
+Activity 一律是其工作的唯一成員;使用此項目啟動的任何 Activity 會在個別的工作中開啟。
+</dd>
+</dl>
+
+
+<p>另外一個例子,Android 瀏覽器應用程式宣告網頁瀏覽器 Activity 應永遠在自己的工作中開啟 &mdash; 透過在 <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a> 元素指定 {@code singleTask} 啟動模式。
+這表示如果您的應用程式發出開啟 Android 瀏覽器的意圖,其 Activity 不會與您的應用程式放在同一個工作中。<em></em>
+
+
+而是會為瀏覽器啟動新的工作,或者如果瀏覽器已經有工作在背景執行,會將該工作帶出來處理新的意圖。
+
+</p>
+
+<p>無論 Activity 在新工作啟動或與啟動該 Activity 之 Activity 的相同工作中啟動,使用者都能使用 [返回] 按鈕返回之前的 Activity。<em></em>
+不過,如果您啟動指定 {@code singleTask} 啟動模式的 Activity,如果該 Activity 的執行個體存在於背景工作中,則該工作會整個移到前景。
+
+此時,返回堆疊現在包含已帶出且位於堆疊頂端之工作的所有 Activity。
+
+圖 4 說明這種類型的情況。</p>
+
+<img src="{@docRoot}images/fundamentals/diagram_backstack_singletask_multiactivity.png" alt="" />
+<p class="img-caption"><strong>圖 4.</strong>顯示含有啟動模式 "singleTask" 的 Activity 如何新增到返回堆疊。
+如果 Activity 已經是背景工作的一部份且有自己的返回堆疊,則整個返回堆疊都會帶出來,位於目前工作的最頂端。
+
+</p>
+
+<p>如要進一步瞭解如何使用宣示說明檔案中的啟動模式,請參閱 <code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code> 元素,其中會有 {@code launchMode} 屬性和可接受值的詳細說明。
+
+
+</p>
+
+<p class="note"><strong>注意:</strong>您使用 <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a> 屬性指定的 Activity 行為可被啟動 Activity 之意圖所含的旗標所覆寫,如下一節所述。
+
+</p>
+
+
+
+<h4 id="#IntentFlagsForTasks">使用意圖旗標</h4>
+
+<p>啟動 Activity 時,您可以在傳送到 {@link
+android.app.Activity#startActivity startActivity()} 的意圖中包含旗標,以修改 Activity 及其工作的預設關聯。
+您可以用來修改預設行為的旗標包括:
+</p>
+
+<p>
+ <dt>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</dt>
+ <dd>在新工作中啟動 Activity。如果工作已為您目前啟動的 Activity 執行,該工作會移到前景並復原至上個狀態,而且 Activity 會在 {@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>如果現在正在啟動的 Activity 是目前的 Activity (位於返回堆疊的頂端),則現有執行個體會收到 {@link android.app.Activity#onNewIntent onNewIntent()} 呼叫,而不會建立新的 Activity 執行個體。
+
+
+ <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>如果正在啟動的 Activity 已在目前的工作中執行,則不會啟動新的 Activity 執行個體,而是會終結位於其上方的所有其他 Activity,且此意圖會透過 {@link android.app.Activity#onNewIntent onNewIntent()} 傳送到繼續執行的 Activity 執行個體 (現在位於頂端)。
+
+
+
+ <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} 搭配使用。
+一起使用時,這些旗標可以找出位於其他工作中的現有 Activity,然後將它放置於可以回應意圖的地方。
+
+ </p>
+ <p class="note"><strong>注意:</strong>如果指定 Activity 的啟動模式為 {@code "standard"},它也會從堆疊中移除,改為啟動新的執行個體處理傳入的意圖。
+
+
+這是因為當啟動模式為 {@code "standard"} 時,一律會為新的意圖建立新的執行個體。
+ </p>
+</dd>
+</dl>
+
+
+
+
+
+<h3 id="Affinities">處理親和性</h3>
+
+<p>親和性<em></em>可指出 Activity 偏好屬於哪個工作。根據預設,相同應用程式的所有 Activity 間互相都有親和性。
+因此,根據預設,相同應用程式的所有 Activity 都偏好位於相同的工作。
+不過,您可以修改 Activity 的預設親和性。
+不同應用程式中定義的 Activity 可以共用親和性,或者相同應用程式中定義的 Activity 可以指派不同的工作親和性。
+
+</p>
+
+<p>您可以使用 <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a> 元素的 <a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">{@code taskAffinity}</a> 屬性修改任何指定 Activity 的親和性。
+
+</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 &lt;manifest&gt;}</a> 元素中宣告的預設封裝名稱不同,因為系統使用該名稱來識別應用程式的預設工作親和性。
+
+
+
+</p>
+
+<p>在兩種情況下會用到親和性:</p>
+<ul>
+ <li>當啟動 Activity 的意圖包含
+{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} 旗標。
+
+
+<p>根據預設,新的 Activity 會啟動至 Activity (名為 {@link android.app.Activity#startActivity startActivity()}) 的工作中。
+系統會將它推入至與呼叫端相同的返回堆疊。
+不過,如果傳送至
+{@link android.app.Activity#startActivity startActivity()} 的意圖包含 {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} 旗標,則系統會找尋不同的工作來放置新的 Activity。
+
+這通常是新工作。
+不過,它不一定要是新工作。如果現有工作中有與新 Activity 相同的親和性,Activity 會啟動至該工作中。
+如果沒有,會開始新的工作。</p>
+
+<p>如果此旗標導致 Activity 開始新的工作,而使用者按 [首頁] 按鈕離開它,必須要有方法可以讓使用者回來瀏覽這個工作。<em></em>
+
+有些實體 (例如,通知管理員) 總是從外部工作開始 Activity,從來不使用自己的工作,因此他們都會將 {@code FLAG_ACTIVITY_NEW_TASK} 放入傳送到
+{@link android.app.Activity#startActivity startActivity()} 的意圖。
+
+如果您的 Activity 可以由外部實體呼叫且可能使用此旗標,記得要提供使用者獨立的方法回到啟動的工作,例如,透過啟動組件圖示 (工作的根 Activity 有一個 {@link android.content.Intent#CATEGORY_LAUNCHER} 意圖篩選器;請參閱下方的<a href="#Starting">開始工作</a>)。
+
+
+
+</p>
+</li>
+
+ <li>當 Activity 的<a href="{@docRoot}guide/topics/manifest/activity-element.html#reparent">
+{@code allowTaskReparenting}</a> 屬性設為 {@code "true"}。
+ <p>在這種情況下,當工作移到前景時,Activity 可以從其啟動的工作移到與其有親和性的工作。
+</p>
+ <p>例如,假設將報告所選城市天氣狀況的 Activity 定義為旅遊應用程式的一部份。
+它與相同應用程式中的其他 Activity 有相同的親和性 (預設的應用程式親和性),而且它允許與此屬性重設父代。
+當您的其中一個 Activity 開始氣象報告程式 Activity,它一開始屬於與您 Activity 相同的工作。
+
+不過,當旅遊應用程式工作移到前景,氣象報告程式 Activity 就會重新指派給該工作,並在其中顯示。
+</p>
+</li>
+</ul>
+
+<p class="note"><strong>提示:</strong>如果從使用者的角度來看 {@code .apk} 檔案包含一個以上的「應用程式」,您可能會想要使用 <a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">{@code taskAffinity}</a> 屬性對與每個「應用程式」關聯的 Activity 指派不同的親和性。
+
+</p>
+
+
+
+<h3 id="Clearing">清除返回堆疊</h3>
+
+<p>如果使用者離開工作一段很長的時間,系統會清除根 Activity 以外所有 Activity 的工作
+。當使用者再次回到工作,只會復原根 Activity。
+系統會有這樣的行為是因為在一段很長的時間後,使用者很可能會放棄他們之前在做的工作,並回到工作開始其他新的工作。
+ </p>
+
+<p>您可以使用下列一些 Activity 屬性來修改這個行為: </p>
+
+<dl>
+<dt><code><a
+href="{@docRoot}guide/topics/manifest/activity-element.html#always">alwaysRetainTaskState</a></code>
+</dt>
+<dd>如果這項屬性在工作的根 Activity 中設為 {@code "true"},則剛描述的預設行為不會發生。
+即使過了很長的一段時間,工作仍然會在堆疊保留所有的 Activity。
+</dd>
+
+<dt><code><a
+href="{@docRoot}guide/topics/manifest/activity-element.html#clear">clearTaskOnLaunch</a></code></dt>
+<dd>如果這項屬性在工作的根 Activity 中設為 {@code "true"},則剛描述的預設行為不會發生。
+即使過了很長的一段時間,工作仍然會在堆疊保留所有的 Activity。
+換句話說,它與
+<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> 相似,但它在單一 Activity 上作業,而不是在整個工作。
+
+它也會導致任何 Activity 離開,包含根 Activity。
+如果設成 {@code "true"},Activity 只會在目前的工作階段留在此工作中。
+如果使用者離開後再回到工作,該工作將不再存在。
+</dd>
+</dl>
+
+
+
+
+<h3 id="Starting">開始工作</h3>
+
+<p>您可以給予 Activity 一個意圖篩選器,將
+{@code "android.intent.action.MAIN"} 設定為指定的動作,
+{@code "android.intent.category.LAUNCHER"} 設定為指定的類別,以便將該 Activity 設定為工作的進入點。
+例如:</p>
+
+<pre>
+&lt;activity ... &gt;
+ &lt;intent-filter ... &gt;
+ &lt;action android:name="android.intent.action.MAIN" /&gt;
+ &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
+ &lt;/intent-filter&gt;
+ ...
+&lt;/activity&gt;
+</pre>
+
+<p>這類意圖篩選器可在應用程式啟動組件顯示 Activity 的圖示和標籤,讓使用者啟動 Activity 並回到 Activity 啟動後任何時間建立的工作。
+
+
+</p>
+
+<p>第二項功能很重要:使用者必須能夠在離開工作後,使用此 Activity 啟動組件回到此工作。
+由於這個原因,兩個將 Activity 標示為一律啟動工作的<a href="#LaunchModes">啟動模式</a> {@code "singleTask"} 和
+{@code "singleInstance"},應只能在 Activity 有 {@link android.content.Intent#ACTION_MAIN} 和 {@link android.content.Intent#CATEGORY_LAUNCHER} 篩選器時才能使用。
+
+
+例如,試想如果缺少篩選器會發生什麼情況:
+意圖會啟動 {@code "singleTask"} Activity、起始新工作,然後使用者會花一些時間在該工作進行作業。
+之後,使用者按下 [首頁]<em></em> 按鈕。
+此工作現在會傳送到背景而且不會顯示。現在,使用者沒有辦法回到工作,這是因為應用程式啟動組件沒有代表此工作的項目。
+</p>
+
+<p>在您不希望使用者返回 Activity 的情況下,將
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code> 元素的
+<a href="{@docRoot}guide/topics/manifest/activity-element.html#finish">{@code finishOnTaskLaunch}</a> 設定為 {@code "true"} (請參閱<a href="#Clearing">清除堆疊</a>)。
+
+</p>
+
+<p>如要進一步瞭解工作和 Activity 在總覽畫面中的顯示及管理方式,請參閱<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/zh-tw/guide/index.jd b/docs/html-intl/intl/zh-tw/guide/index.jd
new file mode 100644
index 000000000000..f7ad966d73fa
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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">應用程式基礎知識</a>。
+</p>
+<p>如果想立即編寫程式碼,請參閱<a href="{@docRoot}training/basics/firstapp/index.html">建立您的第一個應用程式</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 應用程式是由許多不同元件建置而成,應用程式可個別呼叫每個元件。
+例如,「Activity」<em></em>可在單一畫面中顯示使用者介面,而「服務」<em></em>則個別可在背景中執行作業。
+
+</p>
+
+<p>您可以透過某個元件使用「意圖」<em></em>啟動另一個元件。您甚至可以啟動其他應用程式中的元件,例如啟動地圖應用程式的 Activity 來顯示地址。
+這個模型可為單一應用程式提供多個進入點,還能讓任何應用程式針對其他應用程式可能呼叫的動作,以使用者設定的「預設值」運作。
+
+</p>
+
+
+<p><b>瞭解詳情:</b></p>
+<ul class="nolist">
+<li><a href="{@docRoot}guide/components/fundamentals.html">應用程式基礎知識</a>
+<li><a href="{@docRoot}guide/components/intents-filters.html">意圖和意圖篩選器</a>
+<li><a href="{@docRoot}guide/components/activities.html">Activity</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">裝置相容性</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/zh-tw/guide/topics/manifest/manifest-intro.jd b/docs/html-intl/intl/zh-tw/guide/topics/manifest/manifest-intro.jd
new file mode 100644
index 000000000000..5e42e37d91fc
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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>描述應用程式的元件 &mdash; 組成應用程式的 Activity、服務、廣播接收器和內容供應程式。
+
+為實作每個元件的類別命名以及發佈類別的功能 (例如,類別可處理的 {@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>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+
+<a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a>
+
+ <a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/permission-tree-element.html">&lt;permission-tree /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/instrumentation-element.html">&lt;instrumentation /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">&lt;uses-sdk /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html">&lt;uses-configuration /&gt;</a> <!-- ##api level 3## -->
+ <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">&lt;uses-feature /&gt;</a> <!-- ##api level 4## -->
+ <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html">&lt;supports-screens /&gt;</a> <!-- ##api level 4## -->
+ <a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html">&lt;compatible-screens /&gt;</a> <!-- ##api level 9## -->
+ <a href="{@docRoot}guide/topics/manifest/supports-gl-texture-element.html">&lt;supports-gl-texture /&gt;</a> <!-- ##api level 11## -->
+
+ <a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a>
+
+ <a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/action-element.html">&lt;action /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/category-element.html">&lt;category /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;/intent-filter&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;/activity&gt;</a>
+
+ <a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a> . . . <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;/intent-filter&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;/activity-alias&gt;</a>
+
+ <a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a> . . . <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;/intent-filter&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data/&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;/service&gt;</a>
+
+ <a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a> . . . <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;/intent-filter&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;/receiver&gt;</a>
+
+ <a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/path-permission-element.html">&lt;path-permission /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;/provider&gt;</a>
+
+ <a href="{@docRoot}guide/topics/manifest/uses-library-element.html">&lt;uses-library /&gt;</a>
+
+ <a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;/application&gt;</a>
+
+<a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;/manifest&gt;</a>
+</pre>
+
+<p>
+下方按字母順序列出可出現在宣示說明檔案中的所有元素。
+只有這些才是符合資格的元素,您無法新增自己的元素或屬性。
+
+</p>
+
+<p style="margin-left: 2em">
+<code><a href="{@docRoot}guide/topics/manifest/action-element.html">&lt;action&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/category-element.html">&lt;category&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/instrumentation-element.html">&lt;instrumentation&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/permission-tree-element.html">&lt;permission-tree&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/supports-screens-element.html">&lt;supports-screens&gt;</a></code> <!-- ##api level 4## -->
+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html">&lt;uses-configuration&gt;</a></code> <!-- ##api level 3## -->
+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">&lt;uses-feature&gt;</a></code> <!-- ##api level 4## -->
+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-library-element.html">&lt;uses-library&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">&lt;uses-sdk&gt;</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">&lt;manifest&gt;</a></code> 與
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> 是必要元素,務必顯示兩者且這些元素只能出現一次。
+雖然您至少必須顯示當中的一些元素,才能完成有意義的作業,但大部分其他元素可以出現數次或完全不出現。
+
+
+
+
+<p>
+如果可以的話,元素還可以包含其他元素。所有值並非當成元素內的字元資料使用,而是透過屬性設定。
+
+</p>
+
+<p>
+系統通常不會將位於相同層級的元素排序。例如,
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>、
+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code> 和
+<code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code> 元素能以任何順序排列組合。
+(
+<code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a></code> 元素是這項規則的例外狀況:
+由於它是
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code> 的別名,因此必須跟在該元素的後面)。
+
+</p></dd>
+
+<dt><b>屬性</b></dt>
+<dd>形式上而言,所有屬性均為選用性質。不過,您必須為元素指定某些屬性,才能達到其目的。
+請使用本文件當成參考指南。
+真正的選用屬性會提及在缺少規格時要使用的預設值或狀態。
+
+
+<p>除了
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</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">&lt;application&gt;</a></code> 元素) 與其主要元件:Activity (<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>)、服務 (<code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>)、廣播接收器 (<code><a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code>) 以及內容供應程式 (<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</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>&lt;manifest . . . &gt;
+ &lt;application . . . &gt;
+ &lt;service android:name="com.example.project.SecretService" . . . &gt;
+ . . .
+ &lt;/service&gt;
+ . . .
+ &lt;/application&gt;
+&lt;/manifest&gt;</pre>
+
+<p>
+不過,採用速記法時,如果字串的第一個字元是句點,就會將字串附加到應用程式的封裝名稱 (如同由
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code> 元素的
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html#package">package</a></code> 屬性指定)。
+
+
+下列的指派結果會和上述相同:
+</p>
+
+<pre>&lt;manifest package="com.example.project" . . . &gt;
+ &lt;application . . . &gt;
+ &lt;service android:name=".SecretService" . . . &gt;
+ . . .
+ &lt;/service&gt;
+ . . .
+ &lt;/application&gt;
+&lt;/manifest&gt;</pre>
+
+<p>
+啟動元件時,Android 會建立具名子類別的執行個體。如果未指定子類別,就會建立基本類別的執行個體。
+
+</p></dd>
+
+<dt><b>多個值</b></dt>
+<dd>如果可以指定多個值,該元素幾乎會一直重複,而不是在單一元素內列出多個值。
+例如,意圖篩選器能列出數種動作:
+
+
+<pre>&lt;intent-filter . . . &gt;
+ &lt;action android:name="android.intent.action.EDIT" /&gt;
+ &lt;action android:name="android.intent.action.INSERT" /&gt;
+ &lt;action android:name="android.intent.action.DELETE" /&gt;
+ . . .
+&lt;/intent-filter&gt;</pre></dd>
+
+<dt><b>資源值</b></dt>
+<dd>有些屬性的值可以供使用者查看 &mdash; 例如 Activity 的標籤和圖示。
+您必須將這些屬性的值本地化,以便從資源或主題設定這些值。
+資源值是採用下列格式表示:
+</p>
+
+<p style="margin-left: 2em">{@code @[<i>package</i>:]<i>type</i>:<i>name</i>}</p>
+
+<p>
+其中的<i>package</i> 名稱可以省略 (如果資源所在的封裝和應用程式相同的話),
+ <i>type</i> 是指資源類型 &mdash; 例如「字串」或「可繪項目」 &mdash; 而
+ <i>name</i> 則是可識別特定資源的名稱。範例:
+
+</p>
+
+<pre>&lt;activity android:icon="@drawable/smallPic" . . . &gt</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}'表示換行字元,或 '{@code \\uxxxx}' 表示 Unicode 字元。
+
+</dd>
+</dl>
+
+
+<h2 id="filef">檔案功能</h2>
+
+<p>
+下列各節說明如何在宣示說明檔案中反映部分 Android 功能。
+
+</p>
+
+
+<h3 id="ifs">意圖篩選器</h3>
+
+<p>
+應用程式的核心元件 (即應用程式的 Activity、服務和廣播接收器) 是由
+ <i>意圖</i>啟動。意圖是一組資訊組合 ({@link android.content.Intent} 物件),用於說明要採取的動作 &mdash; 包括執行依據的資料、應執行動作的元件類別,以及其他相關的指示。
+
+
+Android 會找出適當的元件來回應意圖、視需要啟動元件的新執行個體,以及將意圖物件傳送給它。
+
+
+
+</p>
+
+<p>
+元件會通知其功能 (元件可回應的意圖類型),而通知途徑是
+ <i>意圖篩選器</i>。由於 Android 系統必須先瞭解元件能夠處理哪些意圖,才能啟動該元件,因此意圖篩選器在宣示說明中會指定為
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</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">&lt;permission&gt;</a></code> 元素含有上述三種屬性,當系統詢問使用者是否將權限授予發出要求的應用程式時,可以將代表權限的圖示、該權限的名稱以及所需的描述全都向使用者顯示。
+
+
+
+
+</p>
+
+<p>
+在各種情況下,元件中設定的圖示和標籤會成為所有容器下層元素的預設
+{@code icon} 與 {@code label} 設定因此,
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> 元素中設定的圖示和標籤會是應用程式各元件的預設圖示和標籤。
+
+同樣地,為元件 (例如
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code> 元素) 設定的圖示和標籤會是元件的
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code> 元素預設值。
+
+
+如果
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> 元素設有一個標籤,但 Activity 與其意圖篩選器並未設定該標籤,系統會將應用程式標籤視為 Activity 和意圖篩選器的標籤。
+
+
+
+</p>
+
+<p>
+每當執行篩選器通告的功能,要向使用者顯示元件時,就會將為意圖篩選器設定的圖示和標籤用來代表元件。
+
+例如,包含
+"{@code android.intent.action.MAIN}" 與
+"{@code android.intent.category.LAUNCHER}" 設定的篩選器會將某 Activity 宣告為啟動應用程式的 Activity,也就是應顯示在應用程式啟動器中的 Activity。
+
+因此,顯示在啟動器中的會是篩選器中設定的圖示和標籤。
+
+</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>
+單一功能最多只能利用一項權限來加以保護。
+</p>
+
+<p>
+如果應用程式需要存取受權限保護的功能,它必須在宣示說明中利用
+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code> 元素來宣告其需要該項權限。
+
+接著,要在裝置上安裝該應用程式時,安裝程式會檢查簽署該應用程式憑證的授權單位 (在某些情況下還會詢問使用者),然後決定是否授予要求的權限。
+
+
+如果授予權限,該應用程式就能夠使用受保護的功能。
+
+如果不授予權限,存取相關功能的嘗試就會失敗,但使用者不會收到任何通知。
+
+</p>
+
+<p>
+應用程式也能利用權限來保護自己的元件 (Activity、服務、廣播接收器和內容供應程式)。
+它能使用 Android 定義的任何權限 (列於
+{@link android.Manifest.permission android.Manifest.permission}) 或其他應用程式宣告的任何權限。
+
+此外,應用程式也能自行定義權限。新的權限是以
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code> 元素宣告。
+
+例如,您可以利用下列權限保護 Activity:
+</p>
+
+<pre>
+&lt;manifest . . . &gt;
+ &lt;permission android:name="com.example.project.DEBIT_ACCT" . . . /&gt;
+ &lt;uses-permission android:name="com.example.project.DEBIT_ACCT" /&gt;
+ . . .
+ &lt;application . . .&gt;
+ &lt;activity android:name="com.example.project.FreneticActivity"
+ android:permission="com.example.project.DEBIT_ACCT"
+ . . . &gt;
+ . . .
+ &lt;/activity&gt;
+ &lt;/application&gt;
+&lt;/manifest&gt;
+</pre>
+
+<p>
+請注意,在本範例中,不只以
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code> 元素宣告 {@code DEBIT_ACCT} 權限,還使用
+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code> 元素來要求使用此權限。
+
+
+即使保護是由應用程式本身強制施行,還是必須要求使用該權限,應用程式的其他元件才能啟動受保護的 Activity。
+
+
+</p>
+
+<p>
+在相同的範例中,如果 {@code permission} 屬性設定為在別處宣告的權限 (例如 {@code android.permission.CALL_EMERGENCY_NUMBERS}),就不必再次使用
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code> 元素來宣告。
+
+
+
+不過,還是必須利用
+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code> 來要求使用。
+</p>
+
+<p>
+
+<code><a href="{@docRoot}guide/topics/manifest/permission-tree-element.html">&lt;permission-tree&gt;</a></code> 元素可為程式碼將定義的一組權限宣告命名空間。
+
+此外,
+<code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></code> 可為一組權限定義標籤 (以
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code> 元素在宣示說明中宣告的權限或在別處宣告的權限)。
+
+它只會影響在向使用者呈現權限時的分組方式。
+
+<code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></code> 元素不會指定各權限所屬的群組,只會指定群組的名稱。
+
+只要將群組名稱指派給
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</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">&lt;uses-library&gt;</a></code> 元素,才能命名各個程式庫。
+(您可以在封裝的說明文件中找到程式庫名稱)。
+
+</p>
diff --git a/docs/html-intl/intl/zh-tw/guide/topics/providers/calendar-provider.jd b/docs/html-intl/intl/zh-tw/guide/topics/providers/calendar-provider.jd
new file mode 100644
index 000000000000..42434e4b30e8
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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">日曆表格</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">活動表格</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">參與者表格</a>
+<ol>
+ <li><a href="#add-attendees">新增參與者</a></li>
+ </ol>
+ </li>
+ <li><a href="#reminders">提醒表格</a>
+<ol>
+ <li><a href="#add-reminders">新增提醒</a></li>
+ </ol>
+ </li>
+ <li><a href="#instances">執行個體表格</a>
+ <ol>
+ <li><a href="#query-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>&lt;class&gt;</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>此表格內含日曆特定的資訊。
+此表格中的每一列包含單一日曆的詳細資訊,例如名稱、色彩、同步資訊等等。
+</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.Events}</td>
+
+ <td>此表格內含活動特定的資訊。
+此表格中的每一列包含單一活動的資訊 &mdash; 例如,活動標題、位置、開始時間、結束時間等等。
+
+活動可以只發生一次或發生多次。參與者、提醒以及延伸屬性儲存於個別的表格。
+它們每一個都有 {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID},會參照「活動」表格中的 {@link android.provider.BaseColumns#_ID}。
+
+</td>
+
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.Instances}</td>
+
+ <td>此表格內含活動每次發生的開始和結束時間。
+此表格的每一列代表單一活動發生。
+單次活動執行個體和活動的對應為 1:1。
+對於週期性活動,則會自動產生多個列,對應到該活動的多次發生。
+</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.Attendees}</td>
+
+ <td>此表格內含活動參與者 (邀請對象) 的資訊。
+每一列代表一個活動的單一邀請對象。
+其中會指出邀請對象類型,以及邀請對象是否出席該活動的回應。
+</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.Reminders}</td>
+
+ <td>此表格內含警示/通知資訊。
+每一列代表一個活動的單一警示。一個活動可以設定多個提醒。
+每個活動的最大數量提醒指定於
+{@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>
+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
+&lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;...&gt;
+ &lt;uses-sdk android:minSdkVersion=&quot;14&quot; /&gt;
+ &lt;uses-permission android:name=&quot;android.permission.READ_CALENDAR&quot; /&gt;
+ &lt;uses-permission android:name=&quot;android.permission.WRITE_CALENDAR&quot; /&gt;
+ ...
+&lt;/manifest&gt;
+</pre>
+
+
+<h2 id="calendar">日曆表格</h2>
+
+<p>{@link android.provider.CalendarContract.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> 在範例的下一個部分,您將建構查詢。選項會指定查詢的條件。
+在此範例中,查詢會尋找日曆中有 <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 的附加 ID
+({@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()}) 或以第一個選擇項目方式提供。
+
+
+選項的開頭應該是 <code>&quot;_id=?&quot;</code>,而且第一個
+<code>selectionArg</code> 應該是日曆的 {@link
+android.provider.BaseColumns#_ID}。
+您也可以透過將 ID 編碼在 URI 中,以執行更新。此範例會使用
+({@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, &quot;Trevor's Calendar&quot;);
+Uri updateUri = ContentUris.withAppendedId(Calendars.CONTENT_URI, calID);
+int rows = getContentResolver().update(updateUri, values, null, null);
+Log.i(DEBUG_TAG, &quot;Rows updated: &quot; + rows);</pre>
+
+<h3 id="insert-calendar">插入日曆</h2>
+
+<p>日曆的設計主要是由同步配接器進行管理,因此您只能以同步配接器的方式插入新日曆。
+在大多數情況下,應用程式只能對日曆進行與外觀相關的變更,例如變更顯示名稱
+。如果應用程式需要建立本機日曆,請以同步配接器的方式插入日曆,方法是使用 {@link android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} 的 {@link android.provider.CalendarContract.SyncColumns#ACCOUNT_TYPE}。
+{@link android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} 是特殊的日曆帳戶類型,它沒有與裝置帳戶關聯。
+
+
+
+
+
+此類型的日曆不會同步至伺服器。如需關於同步配接器的相關討論,請參閱<a href="#sync-adapter">同步配接器</a>。
+</p>
+
+<h2 id="events">活動表格</h2>
+
+<p>{@link android.provider.CalendarContract.Events} 表格包含個人活動的詳細資訊。
+如要新增、更新或刪除活動,應用程式必須在<a href="#manifest">宣示說明檔案</a>中包括 {@link android.Manifest.permission#WRITE_CALENDAR}權限。
+
+</p>
+
+<p>下列「活動」欄可以讓應用程式和同步配接器寫入。
+如需關於支援欄位的完整清單,請參閱 {@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>活動開始的時間,以紀元元年 1 月 1 日零時起算經過的 UTC 毫秒數為單位。 </td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#DTEND}</td>
+ <td>活動結束的時間,以紀元元年 1 月 1 日零時起算經過的 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>&quot;PT1H&quot;</code> 表示活動持續一小時,而值 <code>&quot;P2W&quot;</code> 指出持續 2 週。
+
+
+ </td>
+
+
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#ALL_DAY}</td>
+
+ <td>值 1 表示此活動需要整天,如同當地時區所定義。
+值 0 表示定期活動,會在一天中的任何時間開始和結束。
+</td>
+
+
+ </tr>
+
+
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#RRULE}</td>
+
+ <td>活動的週期規則。例如,<code>&quot;FREQ=WEEKLY;COUNT=10;WKST=SU&quot;</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()}。
+請注意,如果您是透過 {@link
+android.content.Intent#ACTION_INSERT INSERT} 意圖 (如同<a href="#intent-insert">使用意圖插入活動</a> &mdash; 所描述的案例) 插入活動,則不適用此規則,將會提供預設時區。
+
+</li>
+
+ <li>對於非週期性活動,您必須包括 {@link
+android.provider.CalendarContract.EventsColumns#DTEND}。 </li>
+
+
+ <li>對於週期性活動,您必須包括 {@link
+android.provider.CalendarContract.EventsColumns#DURATION},以及 {@link
+android.provider.CalendarContract.EventsColumns#RRULE} 或 {@link
+android.provider.CalendarContract.EventsColumns#RDATE}。請注意,如果您是透過 {@link
+android.content.Intent#ACTION_INSERT INSERT} 意圖 (如同<a href="#intent-insert">使用意圖插入活動</a> &mdash; 所描述的案例) 插入活動,則不適用此規則。您可以使用 {@link
+android.provider.CalendarContract.EventsColumns#RRULE} 搭配 {@link android.provider.CalendarContract.EventsColumns#DTSTART} 和 {@link android.provider.CalendarContract.EventsColumns#DTEND},然後「日曆」應用程式就會自動將它轉換為一段持續時間。
+
+
+</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, &quot;Jazzercise&quot;);
+values.put(Events.DESCRIPTION, &quot;Group workout&quot;);
+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 來執行其他日曆操作 &mdash; 例如,在活動中新增參與者或提醒。
+
+</p>
+
+
+<h3 id="update-event">更新活動</h3>
+
+<p>您的應用程式允許使用者編輯活動時,我們建議您使用 {@link android.content.Intent#ACTION_EDIT EDIT} 意圖編輯活動 (如同<a href="#intent-edit">使用意圖插入活動</a>所述)。不過,如果需要,您也可以直接編輯活動。
+
+
+如要執行活動的更新,您要提供活動的 <code>_ID</code>,可以是 URI 的附加 ID ({@link
+android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()}) 或以第一個選擇項目方式提供。
+
+
+選項的開頭應該是 <code>&quot;_id=?&quot;</code>,而且第一個
+<code>selectionArg</code> 應該是活動的 <code>_ID</code>。
+您也可以使用不含 ID 的選項進行更新。以下是更新活動的範例。
+
+它使用
+{@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, &quot;Kickboxing&quot;);
+updateUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
+int rows = getContentResolver().update(updateUri, values, null, null);
+Log.i(DEBUG_TAG, &quot;Rows updated: &quot; + rows); </pre>
+
+<h3 id="delete-event">刪除活動</h3>
+
+<p>您可以透過活動 URI 的附加 ID {@link
+android.provider.BaseColumns#_ID} 或使用標準選擇方式來刪除活動。
+如果您使用附加 ID,就不能進行選擇。刪除有兩種方式:以應用程式和以同步配接器。
+應用程式刪除會將 <em>deleted</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, &quot;Rows deleted: &quot; + rows);
+</pre>
+
+<h2 id="attendees">參與者表格</h2>
+
+<p>{@link android.provider.CalendarContract.Attendees} 表格的每一列都代表活動的單一參與者或邀請對象。
+呼叫
+{@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>以下是將單一參與者新增至活動的範例。請注意,
+{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} 為必要的:
+</p>
+
+<pre>
+long eventID = 202;
+...
+ContentResolver cr = getContentResolver();
+ContentValues values = new ContentValues();
+values.put(Attendees.ATTENDEE_NAME, &quot;Trevor&quot;);
+values.put(Attendees.ATTENDEE_EMAIL, &quot;trevor@example.com&quot;);
+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">提醒表格</h2>
+
+<p>{@link android.provider.CalendarContract.Reminders} 表格的每一列都代表活動的單一提醒。
+呼叫
+{@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">執行個體表格</h2>
+
+<p>
+{@link android.provider.CalendarContract.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">查詢執行個體表格</h3>
+
+<p>如要查詢「執行個體」表格,您需要在 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>Extra</th>
+ </tr>
+ <tr>
+ <td><br>
+ {@link android.content.Intent#ACTION_VIEW VIEW} <br></td>
+ <td><p><code>content://com.android.calendar/time/&lt;ms_since_epoch&gt;</code></p>
+ 您也可以使用
+{@link android.provider.CalendarContract#CONTENT_URI CalendarContract.CONTENT_URI} 參照 URI。如需使用此意圖的範例,請參閱<a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-view">使用意圖檢視日曆資料</a>。
+
+
+ </td>
+ <td>開啟日曆到 <code>&lt;ms_since_epoch&gt;</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/&lt;event_id&gt;</code></p>
+
+ 您也可以使用
+{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI} 參照 URI。如需使用此意圖的範例,請參閱<a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-view">使用意圖檢視日曆資料</a>。
+
+
+ </td>
+ <td>檢視 <code>&lt;event_id&gt;</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/&lt;event_id&gt;</code></p>
+
+ 您也可以使用
+{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI} 參照 URI。如需使用此意圖的範例,請參閱<a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-edit">使用意圖編輯活動</a>。
+
+
+
+ </td>
+ <td>編輯 <code>&lt;event_id&gt;</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>
+
+ 您也可以使用
+{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI} 參照 URI。如需使用此意圖的範例,請參閱<a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-insert">使用意圖插入活動</a>。
+
+
+ </td>
+
+ <td>建立活動。</td>
+ <td>Extra 列於下表。</td>
+ </tr>
+</table>
+
+<p>下表列出「日曆供應程式」支援的意圖 Extra:
+</p>
+<table>
+ <tr>
+ <th>意圖 Extra</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>活動開始時間,以紀元元年 1 月 1 日零時起算經過的毫秒數為單位。</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME
+CalendarContract.EXTRA_EVENT_END_TIME}</td>
+
+ <td>活動結束時間,以紀元元年 1 月 1 日零時起算經過的毫秒數為單位。</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>它指定 {@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI} 作為 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} 額外欄位,將活動的時間預先填入表單。
+這些時間值必須以自紀元元年 1 月 1 日零時起算經過的 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, &quot;Yoga&quot;)
+ .putExtra(Events.DESCRIPTION, &quot;Group class&quot;)
+ .putExtra(Events.EVENT_LOCATION, &quot;The gym&quot;)
+ .putExtra(Events.AVAILABILITY, Events.AVAILABILITY_BUSY)
+ .putExtra(Intent.EXTRA_EMAIL, &quot;rowan@example.com,trevor@example.com&quot;);
+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, &quot;My New Title&quot;);
+startActivity(intent);</pre>
+
+<h3 id="intent-view">使用意圖檢視日曆資料</h3>
+<p>「日曆供應程式」提供兩種不同的方式來使用 {@link android.content.Intent#ACTION_VIEW VIEW} 意圖:</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(&quot;time&quot;);
+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>同步配接器需要在 URI 中提供 {@link
+android.provider.CalendarContract.SyncColumns#ACCOUNT_NAME} 和 {@link
+android.provider.CalendarContract.SyncColumns#ACCOUNT_TYPE} 作為查詢參數。 </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,&quot;true&quot;)
+ .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/zh-tw/guide/topics/providers/contacts-provider.jd b/docs/html-intl/intl/zh-tw/guide/topics/providers/contacts-provider.jd
new file mode 100644
index 000000000000..b5f888012eed
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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>{@code android.provider.ContactsContract.StreamItems}</li>
+</ol>
+<h2>相關範例</h2>
+<ol>
+ <li>
+ <a href="{@docRoot}resources/samples/ContactManager/index.html">聯絡人管理員
+</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 內容供應程式元件。負責維護三種與人有關的資料類型,每一種類型都會對應到供應程式所提供的表格,如圖 1 所示:
+
+
+</p>
+<img src="{@docRoot}images/providers/contacts_structure.png" alt="" height="364" id="figure1" />
+<p class="img-caption">
+ <strong>圖 1.</strong>聯絡人供應程式表格結構。
+</p>
+<p>
+ 這三個表格通常會以其合約類別的名稱來稱呼。類別會定義內容 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>
+ 原始聯絡人是來自單一帳戶類型和帳戶名稱的人員資料。
+因為聯絡人供應程式允許一個人有多種線上服務做為資料來源,所以聯絡人供應程式可以讓同一個人有多個原始聯絡人。
+
+ 多個原始聯絡人也可以讓使用者,將相同帳戶類型中多個帳戶的人員資料合併。
+
+</p>
+<p>
+ 原始聯絡人的大部分資料不是儲存在
+{@link android.provider.ContactsContract.RawContacts} 表格,而是儲存在 {@link android.provider.ContactsContract.Data} 表格中的一或多個列。
+每個資料列都有一欄
+{@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID Data.RAW_CONTACT_ID},當中包含其上層資料列 {@link android.provider.ContactsContract.RawContacts} 的 {@code android.provider.BaseColumns#_ID RawContacts._ID} 值。
+
+
+</p>
+<h3 id="RawContactsColumns">重要的原始聯絡人欄</h3>
+<p>
+ {@link android.provider.ContactsContract.RawContacts} 表格中的重要欄列於表 1。
+請詳閱表格下方的注意事項:
+</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>。
+一定要將帳戶類型加上您所擁有或控制網域的網域識別碼。
+這樣可以確認您的帳戶類型是唯一的。
+
+ </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} 表格中只有一列這種類型。
+
+ </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 在其裝置上定義了下列三個使用者帳戶:
+
+</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>設定中為這三個帳戶啟用了「同步聯絡人」<em></em>。
+
+</p>
+<p>
+ 假設 Emily Dickinson 開啟瀏覽器視窗,使用
+ <code>emily.dickinson@gmail.com</code>登入 Gmail,開啟[聯絡人] 並新增「Thomas Higginson」。
+接著,她使用
+ <code>emilyd@gmail.com</code>登入 Gmail,並寄送電子郵件給「Thomas Higginson」(系統已自動將他新增為聯絡人)。
+她也在 Twitter 上關注「colonel_tom」(Thomas Higginson 的 Twitter ID)。
+
+</p>
+<p>
+ 聯絡人供應程式建立三個原始聯絡人的方式如下:
+</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>
+ 如前所述,原始聯絡人的資料是儲存在
+ {@link android.provider.ContactsContract.Data} 列,而此列會連結到原始聯絡人的
+ <code>_ID</code> 值。這樣讓原始聯絡人的相同資料類型可以有多個執行個體,例如電子郵件地址或電話號碼。
+例如,如果{@code emilyd@gmail.com} 的 "Thomas Higginson" (Thomas Higginson 的原始聯絡人列,與 Google 帳戶 <code>emilyd@gmail.com</code> 關聯) 的住家電子郵件地址為
+ <code>thigg@gmail.com</code>,而工作電子郵件地址為
+ <code>thomas.higginson@gmail.com</code>,則聯絡人供應程式會儲存這兩個電子郵件地址列,並將兩者連結到原始聯絡人。
+
+
+
+</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>
+ 如果原始聯絡人的此類型資料列出現多次,則
+ {@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>
+ 一般欄有 15 個 (名稱為 <code>DATA1</code> 到
+ <code>DATA15</code>),系統通常會提供這些欄。另外有 4 個一般欄(<code>SYNC1</code> 到 <code>SYNC4</code>) 只能透過同步配接器使用。
+
+不管列中的資料類型為何,一定可以使用一般欄名稱常數。
+
+</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} 類別定義了 {@link android.provider.ContactsContract.Data} 列的類型特定欄名稱常數。此列內含 MIME 類型 {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE
+Email.CONTENT_ITEM_TYPE}。
+
+
+類別含有電子郵件地址欄的常數
+ {@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS}。
+
+ {@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS}的實際值是「data1」。此值與欄的一般名稱相同。
+
+</p>
+<p class="caution">
+ <strong>注意:</strong>如果
+ {@link android.provider.ContactsContract.Data} 表格使用供應程式預先定義 MIME 類型的其中一種,請不要將您自訂的資料新增至此表格。
+假如將您自訂的資料新增至此表格,可能會遺失資料或讓供應程式發生故障。
+例如,您不應該將含有 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>原始聯絡人只有一列此資料。</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.ContactsContract.CommonDataKinds.Photo}</td>
+ <td>原始聯絡人 (與此資料列相關聯) 的主要相片。</td>
+ <td>原始聯絡人只有一列此資料。</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.ContactsContract.CommonDataKinds.Email}</td>
+ <td>原始聯絡人 (與此資料列相關聯) 的電子郵件地址。</td>
+ <td>原始聯絡人可以有多個電子郵件地址。</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.ContactsContract.CommonDataKinds.StructuredPostal}</td>
+ <td>原始聯絡人 (與此資料列相關聯) 的郵寄地址。</td>
+ <td>原始聯絡人可以有多個郵寄地址。</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>
+ 聯絡人供應程式會合併所有帳戶類型和帳戶名稱的原始聯絡人,而成為「聯絡人」<strong></strong>。
+藉此協助使用者顯示及修改針對某個人所收集的所有資料。
+聯絡人供應程式負責建立新的聯絡人列,以及彙總原始聯絡人與現有的聯絡人列。
+應用程式或同步配接器都可以新增聯絡人,而聯絡人列中的某些欄屬於唯讀性質。
+
+</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} 表格也有
+{@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} 欄,此為聯絡人列的「永久」連結。
+因為聯絡人供應程式會自動維護聯絡人,它會變更聯絡人列的 {@code android.provider.BaseColumns#_ID} 值,以回應彙總或同步操作。
+
+即使發生這種情況,與聯絡人的
+{@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} 合併的內容 URI {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI} 仍會指向聯絡人列,因此,您可以使用
+{@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY}
+ 來維護「常用聯絡人」等聯絡人的連結。
+
+此欄有自己的格式,與 {@code android.provider.BaseColumns#_ID} 欄的格式無關。
+
+</p>
+<p>
+ 圖 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>聯絡人、原始聯絡人以及詳細資料表格的關係。
+</p>
+<h2 id="Sources">來自同步配接器的資料</h2>
+<p>
+ 使用者將聯絡人資料直接輸入裝置,但資料也會過「同步配接器」從網路服務流入聯絡人供應程式<strong></strong> (同步配接器會自動將資料在裝置和服務之間傳輸)。
+
+同步配接器受到系統的控制、在背景執行,並且會呼叫 {@link android.content.ContentResolver} 方法來管理資料。
+
+
+</p>
+<p>
+ 在 Android 中,與同步配接器搭配運作的網路服務,是透過帳戶類型加以識別。
+ 每個同步配接器會與一種帳戶類型搭配,但可以支援該類型的多個帳戶名稱。
+帳戶類型和帳戶名稱在<a href="#RawContactsExample">原始聯絡人資料的來源</a>中會有更詳細的說明。
+ 下列定義提供更詳細的資訊,說明帳戶類型和名稱與同步配接器和服務之間的關係。
+
+</p>
+<dl>
+ <dt>
+ 帳戶類型
+ </dt>
+ <dd>
+ 識別使用者儲存資料的服務。在大部分情況下,使用者必須經過服務的驗證。
+例如,Google 聯絡人是一種帳戶類型,由程式碼 <code>google.com</code> 加以識別。
+此值會對應到
+ {@link android.accounts.AccountManager} 所使用的帳戶類型。
+ </dd>
+ <dt>
+ 帳戶名稱
+ </dt>
+ <dd>
+ 識別特定帳戶或帳戶類型的登入。Google 聯絡人帳戶與 Google 帳戶相同,都是使用電子郵件地址做為帳戶名稱。
+
+ 其他服務可能是以單一文字使用者名稱或數值 ID 做為帳戶名稱。
+ </dd>
+</dl>
+<p>
+ 帳戶類型不必是唯一的。使用者可以設定多個 Google 聯絡人帳戶,並將其資料下載至聯絡人供應程式;如果使用者有一組個人帳戶名稱的個人聯絡人,還有另一組工作用的聯絡人,就可能發生此情形。
+
+帳戶名稱通常是唯一的。
+兩者加起來,就可以識別聯絡人供應程式和外部服務之間的特定資料流程。
+
+</p>
+<p>
+ 如果您要將服務的資料傳輸到聯絡人供應程式,則需要編寫您自己的同步配接器。
+如要進一步瞭解同步配接器,請參閱<a href="#SyncAdapters">聯絡人供應程式同步配接器</a>。
+
+</p>
+<p>
+ 圖 4 顯示聯絡人供應程式在人員相關的資料流程中所扮演的角色。
+在標記為「同步配接器」的方塊中,每個配接器都以其帳戶類型做為標籤。
+</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>一或多份表格的讀取權限</dt>
+ <dd>
+ {@link android.Manifest.permission#READ_CONTACTS},在
+ <code>AndroidManifest.xml</code> 的
+ <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">
+ &lt;uses-permission&gt;</a></code> 元素中,以
+ <code>&lt;uses-permission android:name="android.permission.READ_CONTACTS"&gt;</code> 指定。
+ </dd>
+ <dt>一或多份表格的寫入權限</dt>
+ <dd>
+ {@link android.Manifest.permission#WRITE_CONTACTS},在
+<code>AndroidManifest.xml</code> 的
+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">
+ &lt;uses-permission&gt;</a></code> 元素中,以
+<code>&lt;uses-permission android:name="android.permission.WRITE_CONTACTS"&gt;</code> 指定。
+ </dd>
+</dl>
+<p>
+ 這些權限不會延伸到使用者設定檔資料。如要瞭解使用者設定檔及其必要權限,請參閱<a href="#UserProfile">使用者設定檔</a>。
+
+
+</p>
+<p>
+ 請記住,使用者的聯絡人資料是個人的敏感資訊。使用者很關心隱私權相關的問題,因此不希望應用程式收集使用者本身或其聯絡人的相關資訊。
+
+ 如果沒有明確說明為何需要存取使用者的聯絡人資料,使用者可能會給您的應用程式低評分,或直接拒絕安裝。
+
+</p>
+<h2 id="UserProfile">使用者設定檔</h2>
+<p>
+ {@link android.provider.ContactsContract.Contacts} 表格中有一列內含裝置使用者的設定檔資料,
+此資料描述裝置的 <code>user</code>,而不是其中一位使用者的聯絡人。
+針對使用設定檔的每個系統,設定檔聯絡人列會連結到原始聯絡人列。
+
+ 每個設定檔原始聯絡人列可以有多個資料列。{@link android.provider.ContactsContract.Profile} 類別中提供存取使用者設定檔的常數。
+
+</p>
+<p>
+ 存取使用者設定檔需要特殊權限。除了
+{@link android.Manifest.permission#READ_CONTACTS} 和
+{@link android.Manifest.permission#WRITE_CONTACTS} 的讀取和寫入權限以外,存取使用者設定檔還分別需要 {@code android.Manifest.permission#READ_PROFILE} 讀取權限和
+{@code android.Manifest.permission#WRITE_PROFILE} 寫入權限。
+
+
+</p>
+<p>
+ 請務必將使用者的設定檔視為敏感資訊。
+{@code 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>如果您擷取了多個聯絡人列,而想要判斷其中之一是否為使用者設定檔,請測試該列的
+{@link android.provider.ContactsContract.ContactsColumns#IS_USER_PROFILE} 欄。
+如果聯絡人為使用者設定檔,此欄會設為「1」。
+
+</p>
+<h2 id="ContactsProviderMetadata">聯絡人供應程式中繼資料</h2>
+<p>
+ 聯絡人供應程式管理的資料可以追蹤存放庫中聯絡人資料的
+狀態。存放庫相關的中繼資料儲存在不同的位置,包括
+「原始聯絡人」、「資料」以及「聯絡人」表格列,
+{@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>
+ 修改原始聯絡人或資料表格的同步配接器一律會將字串{@link android.provider.ContactsContract#CALLER_IS_SYNCADAPTER} 附加到其使用的內容 URI,
+
+藉此防止供應程式將列標記為已變更 (dirty)。
+ 否則,同步配接器修改會顯示為本機修改,因而傳送到伺服器,儘管伺服器才是修改的來源。
+
+ </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>
+ 唯一:帳戶的每個原始聯絡人都必須有自己的來源 ID。如果沒有強制執行此條件,則聯絡人應用程式會發生問題。
+
+ 請注意,同一個帳戶「類型」<em></em>的兩個原始聯絡人可能會有相同的來源 ID。
+例如,{@code emily.dickinson@gmail.com} 帳戶的原始聯絡人「Thomas Higginson」與
+ {@code emilyd@gmail.com} 帳戶的原始聯絡人「Thomas Higginson」的來源 ID相同。
+
+
+ </li>
+ <li>
+ 穩定:來源 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」:應用程式 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} 表格中的一或多個
+{@link android.provider.ContactsContract.CommonDataKinds.GroupMembership} 列所指出)。
+
+
+ 在 {@link android.provider.ContactsContract.Settings} 表格列中為帳戶類型和帳戶設定此旗標,可以強制讓不屬於任何群組的聯絡人成為可見的。
+
+ 此旗標的其中一個用途是,顯示伺服器中不屬於任何群組的聯絡人。
+ </td>
+ </tr>
+ <tr>
+ <td>
+ 「1」:針對此帳戶和帳戶類型,應用程式 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} 列的
+所有 {@link android.provider.ContactsContract.RawContacts} 列,或單一
+{@link android.provider.ContactsContract.RawContacts} 列的所有
+{@link android.provider.ContactsContract.CommonDataKinds.Email} 列。
+為了協助此操作,聯絡人供應程式提供<strong>實體</strong>建構,其運作方式就像是資料庫結合各個表格一樣。
+
+
+</p>
+<p>
+ 實體就像是一份表格,由上層表格及其下層表格中的選取欄所組成。
+ 查詢實體時,您會提供投影 (projection) 和搜尋條件根據該實體可用的欄。
+結果會是 {@link android.database.Cursor},擷取到的每個下層表格列在其中都會有一列。
+例如,如果您查詢
+{@link android.provider.ContactsContract.Contacts.Entity} 的聯絡人名稱,並且查詢所有 {@link android.provider.ContactsContract.CommonDataKinds.Email} 列中該名稱的所有原始聯絡人,則會取回 {@link android.database.Cursor},每個 {@link android.provider.ContactsContract.CommonDataKinds.Email} 列都會有一列。
+
+
+
+</p>
+<p>
+ 實體簡化查詢。使用實體,您可以一次擷取聯絡人或原始聯絡人的所有聯絡人資料,而不用先查詢父項表格以取得 ID,再以此 ID 查詢子項表格。另外,聯絡人供應程式會在單一交易中處理針對實體的查詢,以確保所擷取的資料在內部的一致性。
+
+
+
+
+</p>
+<p class="note">
+ <strong>注意:</strong>實體通常不會包含上層表格和下層表格的所有欄。
+如果您嘗試使用的欄名稱未列在實體的欄名稱常數中,將會收到 {@link java.lang.Exception}。
+
+</p>
+<p>
+ 以下程式碼片段展示如何擷取一位聯絡人的所有原始聯絡人列。此程式碼片段屬於大型應用程式的一部分,此應用程式有兩個 Activity:「主要」和「詳細」。
+主要 Activity 會顯示聯絡人列的清單,當使用者選取其中一項時,此 Activity 會將其 ID 傳送給詳細 Activity。
+
+詳細 Activity 會使用 {@link android.provider.ContactsContract.Contacts.Entity},針對所選取的聯絡人,顯示與其關聯的所有原始聯絡人的所有資料列。
+
+
+</p>
+<p>
+ 此程式碼片段是取自「詳細」Activity:
+</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);
+...
+&#64;Override
+public Loader&lt;Cursor&gt; 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()} 的回呼。
+此方法的其中一個傳入引數是內含查詢結果的
+ {@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()},以「批次模式」在聯絡人供應程式中進行資料的插入、更新以及刪除。
+因為聯絡人供應程式會在單一交易中執行
+{@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} 的所有操作,所以您所做的修改不會讓聯絡人存放庫處於不一致的狀態。
+
+
+批次修改同時也有助於插入原始聯絡人及其詳細資料。
+
+</p>
+<p class="note">
+ <strong>注意:</strong>如要修改「單一」<em></em>原始聯絡人,請考慮將意圖傳送到裝置的聯絡人應用程式,而不要在您的應用程式中處理修改操作。這些動作在<a href="#Intents">使用意圖擷取和修改</a>中有更詳細的資料。
+
+
+
+</p>
+<h4>降伏點</h4>
+<p>
+ 包含大量操作的批次修改可能會封鎖其他處理程序,導致整體的使用者體驗不良。
+如要將您想要執行的所有修改,儘可能安排在較少的清單中執行,同時要避免這些修改讓系統無法進行其他操作,則應該要為一或多個操作設定「降伏點」<strong></strong>。
+
+
+ 降伏點是一個 {@link android.content.ContentProviderOperation} 物件,而且其
+{@link android.content.ContentProviderOperation#isYieldAllowed()} 值是設為
+<code>true</code>。當聯絡人供應程式遇到降伏點時,會暫停它的工作,以便讓其他處理程序執行,並關閉目前的交易。
+供應程式再次啟動時,會繼續 {@link java.util.ArrayList} 中的下一項操作,並啟動新的交易。
+
+
+</p>
+<p>
+ 降伏點會讓每次呼叫
+{@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} 產生一個以上的交易。基於這項原因,您必須將上次操作的降伏點設為一組相關的列。
+
+ 例如,您應該為以下兩種上次操作設定降伏點:新增原始聯絡人列及其相關資料列的一組動作,或與單一聯絡人相關的一組列。
+
+
+</p>
+<p>
+ 降伏點也是微型操作的單位。兩個降伏點之間的所有存取會以單一單元來看待為成功或失敗。
+如果沒有設定任何降伏點,則最小的微型操作就是整批操作。
+如果使用降伏點,您可以防止操作降低系統效能,同時確保操作的子集是微型操作。
+
+
+</p>
+<h4>修改反向參考</h4>
+<p>
+ 以一組
+ {@link android.content.ContentProviderOperation} 物件插入新的原始聯絡人及其關聯的資料列時,您必須透過插入原始聯絡人的
+ {@code 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()}
+方法有兩個引數:
+</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> 值是這些結果的其中一個索引,這些結果是以 <code>key</code>值擷取並加以儲存。
+
+這樣可以讓您插入新的原始聯絡人記錄,並取得其
+{@code 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>createContacEntry()</code> 方法的擴充版本。而這個方法是
+ <code><a href="{@docRoot}resources/samples/ContactManager/index.html">
+ Contact Manager</a></code> 範例應用程式中
+ <code>ContactAdder</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&lt;ContentProviderOperation&gt; ops =
+ new ArrayList&lt;ContentProviderOperation&gt;();
+
+ /*
+ * 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} 物件 (第一項操作會新增原始聯絡人列,並傳回其新的 {@code 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>
+ 開放式並行存取控制很適合用在行動裝置,這是因為行動裝置一次只會有一位使用者,而且很少會發生同時存取資料存放庫的情形。
+由於不會使用到鎖定,因此您不必花時間在設定鎖定,或等待其他交易釋放鎖定。
+
+</p>
+<p>
+ 如要在更新單一
+ {@link android.provider.ContactsContract.RawContacts} 列時使用開放式並行存取控制,請遵循以下步驟:
+</p>
+<ol>
+ <li>
+ 隨著您要擷取的其他資料,一起擷取原始聯絡人的 {@link android.provider.ContactsContract.SyncColumns#VERSION} 欄。
+
+ </li>
+ <li>
+ 使用
+ {@link android.content.ContentProviderOperation#newAssertQuery(Uri)} 方法建立適合用於強制執行限制的{@link android.content.ContentProviderOperation.Builder} 物件。
+如果是內容 URI,請使用 {@link android.provider.ContactsContract.RawContacts#CONTENT_URI
+RawContacts.CONTENT_URI} 並附加原始聯絡人的 {@code android.provider.BaseColumns#_ID}。
+
+
+ </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()} 以確保此判斷提示只測試一列。
+
+ </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} 查詢單一原始聯絡人後,建立「判斷提示」
+{@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&lt;Cursor&gt; 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&lt;ContentProviderOperationg&gt;;
+
+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>。
+
+ 裝置的聯絡人應用程式會在 Activity 的生命週期內,將讀取和寫入權限委派給此內容 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.content.Intent} 引數的 [資料] 欄位中傳回給 Activity 的
+{@link android.app.Activity#onActivityResult(int, int, Intent) onActivityResult()}回呼方法。
+
+
+如要取得此值,請呼叫 {@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}。
+編輯器 Activity 可讓使用者編輯與此聯絡人關聯的任何資料。
+
+ </td>
+ <td>
+ {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE
+Contacts.CONTENT_ITEM_TYPE},單一聯絡人。</td>
+ <td>
+ 顯示聯絡人應用程式中的「編輯聯絡人」畫面。顯示您新增至意圖的額外值。
+使用者按一下 [完成]<strong></strong> 來儲存編輯內容時,您的 Activity 會回到前景。
+
+ </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&lt;ContentValues&gt; contactData = new ArrayList&lt;ContentValues&gt;();
+
+
+/*
+ * 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.RawContacts} 列新增 {@link android.provider.ContactsContract.CommonDataKinds.StructuredName} 列。
+
+ </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>
+ 務必使用 {@link android.provider.ContactsContract} 及其子類別中定義的常數,做為授權、內容 URI、URI 路徑、欄名稱、MIME 類型以及
+{@link android.provider.ContactsContract.CommonDataKinds.CommonColumns#TYPE} 值。
+
+ </dt>
+ <dd>
+ 使用這些常數可協助您避免發生錯誤。如果有任何常數已失效,則編譯器會發出通知。
+
+ </dd>
+</dl>
+<h3 id="CustomData">自訂資料列</h3>
+<p>
+ 透過建立自訂的 MIME 類型,您可以插入、編輯、刪除以及擷取 {@link android.provider.ContactsContract.Data} 表格中您自己的資料列。
+儘管您可以將自己的類型特定欄名稱對應到預設的欄名稱,您的列仍受限於使用
+ {@link android.provider.ContactsContract.DataColumns} 中所定義的欄。
+
+在裝置的聯絡人應用程式中,可以顯示您的列中資料,但無法加以編輯或刪除,而且使用者無法新增其他資料。
+
+如要讓使用者修改您自訂的資料列,您必須在自己的應用程式中提供編輯器 Activity。
+
+</p>
+<p>
+ 如要顯示自己的資料,請提供 <code>contacts.xml</code> 檔案,其中要包含
+<code>&lt;ContactsAccountType&gt;</code> 元素以及一或多個其
+<code>&lt;ContactsDataKind&gt;</code> 子元素。詳情請參閱 <a href="#SocialStreamDataKind"><code>&lt;ContactsDataKind&gt; 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>
+ 由於大多數服務都需要在存取資料之前先驗證其身分,因此 Android 系統提供類似的驗證架構,而且通常會與同步配接器架構一起搭配使用。
+
+驗證架構使用外掛程式驗證器,這是
+ {@link android.accounts.AbstractAccountAuthenticator} 的子類別。
+驗證器會以下列步驟驗證使用者的身分:
+
+ <ol>
+ <li>
+ 收集使用者的名稱、密碼或類似資訊 (使用者的<strong>憑證</strong>)。
+
+ </li>
+ <li>
+ 將憑證傳送給服務
+ </li>
+ <li>
+ 檢驗服務的回覆。
+ </li>
+ </ol>
+<p>
+ 如果服務接受此憑證,則驗證器可以儲存憑證供以後使用。
+由於外掛程式驗證器架構的緣故,
+{@link android.accounts.AccountManager} 可以存取驗證器支援且選擇顯示的任何 authtoken,例如 OAuth2 authtoken。
+
+</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()} 方法具現化同步配接器,並提供靜態的「getter」方法將單一執行個體傳回給同步配接器服務的
+{@link android.app.Service#onBind(Intent) onBind()} 方法。
+
+
+ </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>&lt;<a href="{@docRoot}guide/topics/manifest/service-element.html">service</a>&gt;</code> 元素會定義之前說明的同步配接器和驗證器服務元件。
+
+這些元素包含的
+<code>&lt;<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>&gt;</code> 子元素可提供系統的特定資料:
+
+
+
+ <ul>
+ <li>
+ 同步配接器服務的
+ <code>&lt;<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>&gt;</code> 元素,此元素會指向 XML 檔案 <code>res/xml/syncadapter.xml</code>。
+
+此檔案會按順序指出
+將與聯絡人供應程式同步的網路服務 URI,
+以及網路服務的帳戶類型。
+ </li>
+ <li>
+ <strong>選用:</strong>驗證器服務的
+ <code>&lt;<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>&gt;</code> 元素,此元素會指向 XML 檔案
+<code>res/xml/authenticator.xml</code>。
+此檔案會按順序指出此驗證器支援的帳戶類型,以及驗證程序中會出現的 UI 資源。
+
+此元素中指定的帳戶類型必須與同步配接器中指定的帳戶類型相同。
+
+
+ </li>
+ </ul>
+ </dd>
+ </dl>
+<h2 id="SocialStream">社交串流資料</h2>
+<p>
+ {@code android.provider.ContactsContract.StreamItems} 和
+{@code android.provider.ContactsContract.StreamItemPhotos} 表格負責管理社交網路的傳入資料。
+您可以編寫一個同步配接器,將來自您自己網路的串流資料
+新增至這些表格,或是可以從這些表格讀取串流資料,然後
+顯示於您自己的應用程式中,或同時具備這兩種功能。有了這些功能,您的社交網路服務和應用程式就可以整合到 Android 的社交網路體驗。
+
+</p>
+<h3 id="StreamText">社交串流文字</h3>
+<p>
+ 串流項目永遠會與原始聯絡人關聯。
+{@code android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID} 會連結到原始聯絡人的
+ <code>_ID</code> 值。原始聯絡人的帳戶類型和帳戶名稱也會儲存在串流項目列。
+
+</p>
+<p>
+ 串流中的資料會儲存在下列各欄:
+</p>
+<dl>
+ <dt>
+ {@code android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_TYPE}
+ </dt>
+ <dd>
+ <strong>必要。</strong>與此串流項目相關聯的原始聯絡人使用者帳戶類型。
+請記得在插入串流項目時設定此值。
+ </dd>
+ <dt>
+ {@code android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_NAME}
+ </dt>
+ <dd>
+ <strong>必要。</strong>與此串流項目相關聯的原始聯絡人使用者帳戶名稱。
+請記得在插入串流項目時設定此值。
+ </dd>
+ <dt>
+ 識別碼欄
+ </dt>
+ <dd>
+ <strong>必要。</strong>您必須在插入串流項目時插入以下識別碼欄:
+
+ <ul>
+ <li>
+ {@code android.provider.ContactsContract.StreamItemsColumns#CONTACT_ID}:與此串流項目相關聯的聯絡人
+{@code android.provider.BaseColumns#_ID} 值。
+
+ </li>
+ <li>
+ {@code android.provider.ContactsContract.StreamItemsColumns#CONTACT_LOOKUP_KEY}:與此串流項目相關聯的聯絡人
+{@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} 值。
+
+ </li>
+ <li>
+ {@code android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID}:與此串流項目相關聯的原始聯絡人
+{@code android.provider.BaseColumns#_ID} 值。
+
+ </li>
+ </ul>
+ </dd>
+ <dt>
+ {@code android.provider.ContactsContract.StreamItemsColumns#COMMENTS}
+ </dt>
+ <dd>
+ 選用。儲存您可以在串流項目開頭顯示的摘要資訊。
+ </dd>
+ <dt>
+ {@code android.provider.ContactsContract.StreamItemsColumns#TEXT}
+ </dt>
+ <dd>
+ 串流項目的文字,可能是項目來源張貼的內容,或者會產生串流項目動作的描述。
+此欄可以包含
+{@link android.text.Html#fromHtml(String) fromHtml()} 能夠轉譯的任何格式內嵌資源影像。
+供應程式會截斷較長的內容,但會試著避免破壞標籤。
+
+ </dd>
+ <dt>
+ {@code android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP}
+ </dt>
+ <dd>
+ 內含插入或更新串流項目時間的文字字串,
+,以「毫秒」<em></em>為單位。插入或更新串流項目的應用程式負責維護此欄,聯絡人供應程式不會自動加以維護。
+
+
+ </dd>
+</dl>
+<p>
+ 如要顯示串流項目的識別資訊,請使用
+{@code android.provider.ContactsContract.StreamItemsColumns#RES_ICON}、
+{@code android.provider.ContactsContract.StreamItemsColumns#RES_LABEL} 以及
+{@code android.provider.ContactsContract.StreamItemsColumns#RES_PACKAGE} 連結到應用程式中的資源。
+
+</p>
+<p>
+ {@code android.provider.ContactsContract.StreamItems} 表格也包含
+{@code android.provider.ContactsContract.StreamItemsColumns#SYNC1} 到
+{@code android.provider.ContactsContract.StreamItemsColumns#SYNC4} 欄,專門供同步配接器使用。
+
+</p>
+<h3 id="StreamPhotos">社交串流相片</h3>
+<p>
+ {@code android.provider.ContactsContract.StreamItemPhotos} 表格會儲存與串流項目相關聯的相片。
+表格的
+{@code android.provider.ContactsContract.StreamItemPhotosColumns#STREAM_ITEM_ID} 欄會連結到
+ {@code android.provider.ContactsContract.StreamItems} 表格中 {@code android.provider.BaseColumns#_ID} 欄的值。
+相片參照會儲存在表格中的以下各欄:
+
+</p>
+<dl>
+ <dt>
+ {@code android.provider.ContactsContract.StreamItemPhotos#PHOTO} 欄 (BLOB)。
+ </dt>
+ <dd>
+ 相片的二進位檔,由供應程式調整大小以進行儲存和顯示。
+ 此欄是要提供與使用舊版聯絡人供應程式儲存相片的向下相容性。
+不過,在目前版本中,您不應使用此欄來儲存相片。
+請改用 {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID} 或
+{@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI} (下文提供這兩者的相關說明) 在檔案中儲存相片。
+
+此欄現在包含相片的縮圖可供讀取。
+
+ </dd>
+ <dt>
+ {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID}
+ </dt>
+ <dd>
+ 原始聯絡人相片的數字識別碼。將此值附加到常數
+{@link android.provider.ContactsContract.DisplayPhoto#CONTENT_URI DisplayPhoto.CONTENT_URI} 可取得指向單一相片檔案的內容 URI,然後呼叫 {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String)
+openAssetFileDescriptor()} 可取得此相片檔案的控制代碼。
+
+
+ </dd>
+ <dt>
+ {@code 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>
+ 這些表格需要額外的存取權限。如要從中讀取,您的應用程式必須具備 {@code android.Manifest.permission#READ_SOCIAL_STREAM} 權限。
+如要加以修改,您的應用程式必須具備
+{@code android.Manifest.permission#WRITE_SOCIAL_STREAM} 權限。
+
+ </li>
+ <li>
+ 針對 {@code android.provider.ContactsContract.StreamItems} 表格,每個原始聯絡人的儲存列數是有限制的。
+達到此限制後,聯絡人供應程式會自動刪除
+{@code android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP} 最舊的列,為新的串流項目列騰出空間。
+
+如要取得此限制,請發出查詢給內容 URI
+{@code android.provider.ContactsContract.StreamItems#CONTENT_LIMIT_URI}。
+您只要將內容 URI 設為 <code>null</code> 即可,其餘引數不需要處理。
+此查詢會傳回內含單一列的 Cursor 與單一欄
+{@code android.provider.ContactsContract.StreamItems#MAX_ITEMS}。
+
+ </li>
+ </ul>
+
+<p>
+ 類別 {@code android.provider.ContactsContract.StreamItems.StreamItemPhotos} 定義了單一串流項目,且內含相片列的 {@code android.provider.ContactsContract.StreamItemPhotos} 子表格。
+
+
+</p>
+<h3 id="SocialStreamInteraction">社交串流互動</h3>
+<p>
+ 社交串流資料受到聯絡人供應程式與裝置聯絡人應用程式的管理,提供強大的方式將您的社交網路系統與現有聯絡人連接起來。
+
+提供下列功能:
+</p>
+ <ul>
+ <li>
+ 使用同步配接器將您的社交網路服務同步到聯絡人供應程式後,您可以擷取某位使用者的聯絡人最近 Activity,並將它儲存在 {@code android.provider.ContactsContract.StreamItems} 和
+{@code android.provider.ContactsContract.StreamItemPhotos} 表格中,供後續使用。
+
+
+ </li>
+ <li>
+ 除了一般同步之外,您可以在使用者選取要檢視的聯絡人時,觸發您的同步配接器,以擷取其他資料。
+此舉可讓您的同步配接器擷取聯絡人高解析度的相片,以及聯絡人最近的串流項目。
+
+ </li>
+ <li>
+ 藉由向裝置的聯絡人應用程式和聯絡人供應程式註冊通知,您可以在檢視聯絡人時「收到」<em></em>意圖,並於此時更新您服務中的聯絡人狀態。
+
+相較於與同步配接器執行完整同步,
+此方式較快速且使用的頻寬較少。
+ </li>
+ <li>
+ 使用者在裝置的聯絡人應用程式查看聯絡人時,可以將聯絡人新增至您的社交網路服務。
+您可以透過「邀請聯絡人」啟用上述功能。「邀請聯絡人」會啟用一連串的 Activity,將現有聯絡人新增至您的網路和 XML 檔案。此檔案會將您應用程式的詳細資訊提供給裝置的聯絡人應用程式和聯絡人供應程式。
+
+
+
+ </li>
+ </ul>
+<p>
+ 串流項目與聯絡人供應程式的一般同步與其他同步相同。
+如要進一步瞭解同步,請參閱<a href="#SyncAdapters">聯絡人供應程式同步配接器</a>。
+以下兩節說明如何註冊通知和邀請聯絡人。
+
+</p>
+<h4>註冊以處理社交網路檢視</h4>
+<p>
+ 註冊您的同步配接器,使其在使用者查看由您的同步配接器所管理的聯絡人時收到通知:
+
+</p>
+<ol>
+ <li>
+ 在專案的 <code>res/xml/</code> 目錄中建立名稱為 <code>contacts.xml</code>的檔案。
+如果已經有這個檔案,可略過此步驟。
+ </li>
+ <li>
+ 在此檔案中,新增
+<code>&lt;ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"&gt;</code> 元素。
+ 如果這個元素已經存在,可略過此步驟。
+ </li>
+ <li>
+ 為了註冊服務,讓使用者在裝置的聯絡人應用程式中開啟聯絡人的詳細資訊頁面時收到通知,請將
+ <code>viewContactNotifyService="<em>serviceclass</em>"</code> 屬性新增至此元素,其中
+ <code><em>serviceclass</em></code> 是該服務的完整類別名稱,而此服務會收到來自裝置聯絡人應用程式的意圖。
+
+對於通知器服務而言,使用擴充 {@link android.app.IntentService} 的類別可以讓此服務接收意圖。
+
+傳入意圖的資料中含有使用者所點擊該名原始聯絡人的內容 URI。
+您可以從通知器服務繫結,然後呼叫您的同步配接器,以更新原始聯絡人的資料。
+
+ </li>
+</ol>
+<p>
+ 如何註冊使用者點擊串流項目或相片 (或兩者) 時所呼叫的 Activity:
+</p>
+<ol>
+ <li>
+ 在專案的 <code>res/xml/</code> 目錄中建立名稱為 <code>contacts.xml</code>的檔案。
+如果已經有這個檔案,可略過此步驟。
+ </li>
+ <li>
+ 在此檔案中,新增
+<code>&lt;ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"&gt;</code> 元素。
+ 如果這個元素已經存在,可略過此步驟。
+ </li>
+ <li>
+ 為了註冊其中一個 Activity,讓它處理使用者在裝置的聯絡人應用程式中點擊串流項目的 Activity,請將
+ <code>viewStreamItemActivity="<em>activityclass</em>"</code> 屬性新增至此元素,其中
+ <code><em>activityclass</em></code> 是該 Activity 的完整類別名稱,而此 Activity 會收到來自裝置聯絡人應用程式的意圖。
+
+
+ </li>
+ <li>
+ 為了註冊其中一個 Activity,讓它處理使用者在裝置的聯絡人應用程式中點擊串流相片的活動,請將
+ <code>viewStreamItemPhotoActivity="<em>activityclass</em>"</code> 屬性新增至此元素,其中
+ <code><em>activityclass</em></code> 是該 Activity 的完整類別名稱,而此 Activity 會收到來自裝置聯絡人應用程式的意圖。
+
+
+ </li>
+</ol>
+<p>
+ 如要進一步瞭解 <code>&lt;ContactsAccountType&gt;</code> 元素,請參閱 <a href="#SocialStreamAcctType">&lt;ContactsAccountType&gt; 元素</a>。
+
+</p>
+<p>
+ 傳入意圖的資料中含有使用者所按下項目或相片的內容 URI。
+ 如要針對文字項目和相片採取不同的 Activity,請在相同的檔案中同時使用兩個屬性。
+</p>
+<h4>與社交網路服務互動</h4>
+<p>
+ 使用者不需要離開裝置的聯絡人應用程式,就可以邀請聯絡人到您的社交網路網站。
+您可以改為讓裝置的聯絡人應用程式傳送意圖,以邀請聯絡人前往您的 Activity。
+如要進行此設定:
+</p>
+<ol>
+ <li>
+ 在專案的 <code>res/xml/</code> 目錄中建立名稱為 <code>contacts.xml</code>的檔案。
+如果已經有這個檔案,可略過此步驟。
+ </li>
+ <li>
+ 在此檔案中,新增 <code>&lt;ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"&gt;</code> 元素。
+
+ 如果這個元素已經存在,可略過此步驟。
+ </li>
+ <li>
+ 新增下列屬性:
+ <ul>
+ <li><code>inviteContactActivity="<em>activityclass</em>"</code></li>
+ <li>
+ <code>inviteContactActionLabel="&#64;string/<em>invite_action_label</em>"</code>
+ </li>
+ </ul>
+ <code><em>activityclass</em></code> 值是 Activity 的完整類別名稱,以此 Activity 接收意圖。
+<code><em>invite_action_label</em></code> 值是顯示在裝置聯絡人應用程式內 [新增連線]<strong></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">&lt;ContactsAccountType&gt; 元素</h4>
+<p>
+ <code>&lt;ContactsAccountType&gt;</code> 元素控制您的應用程式與聯絡人應用程式之間的互動。
+此元素的語法如下:
+</p>
+<pre>
+&lt;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>"&gt;
+</pre>
+<p>
+ <strong>包含於:</strong>
+</p>
+<p>
+ <code>res/xml/contacts.xml</code>
+</p>
+<p>
+ <strong>可以包含:</strong>
+</p>
+<p>
+ <strong><code>&lt;ContactsDataKind&gt;</code></strong>
+</p>
+<p>
+ <strong>描述:</strong>
+</p>
+<p>
+ 宣告 Android 元件和 UI 標籤,讓使用者可以邀請聯絡人加入社交網路、使用者的社交網路串流更新內容時通知使用者等等。
+
+
+</p>
+<p>
+ 請注意,<code>&lt;ContactsAccountType&gt;</code> 的屬性不需要使用屬性前置詞 <code>android:</code>。
+
+</p>
+<p>
+ <strong>屬性:</strong>
+</p>
+<dl>
+ <dt>{@code inviteContactActivity}</dt>
+ <dd>
+ 使用者從裝置的聯絡人應用程式選取[新增連線]<strong></strong>時,您希望在應用程式中啟動的 Activity 完整類別名稱。
+
+
+ </dd>
+ <dt>{@code inviteContactActionLabel}</dt>
+ <dd>
+ 在 [新增連線]<strong></strong> 選單的
+ {@code inviteContactActivity} 中所指定 Activity 的顯示文字字串。
+ 例如,您可以使用「關注我的網路活動」字串。此標籤可以使用字串資源識別碼。
+
+ </dd>
+ <dt>{@code viewContactNotifyService}</dt>
+ <dd>
+ 使用者檢視聯絡人時,要接收通知的應用程式中的服務完整類別名稱。
+此通知是由裝置的聯絡人應用程式所傳送,這樣可以讓您的應用程式延後要處理大量資料的操作,需要時再加以處理。
+
+例如,您的應用程式可以藉由讀取並顯示聯絡人的高解析度相片,以及最近的社交串流項目,以回應此通知。
+
+如要進一步瞭解此功能,請參閱<a href="#SocialStreamInteraction">社交串流互動</a>。
+您可以在
+ <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">SampleSyncAdapter</a> 範例應用程式的 <code>NotifierService.java</code>中查看通知服務的範例。
+
+
+ </dd>
+ <dt>{@code viewGroupActivity}</dt>
+ <dd>
+ 應用程式中可以顯示群組資訊的 Activity 完整類別名稱。
+使用者在裝置的聯絡人應用程式中按一下群組標籤時,會顯示此 Activity 的 UI。
+
+ </dd>
+ <dt>{@code viewGroupActionLabel}</dt>
+ <dd>
+ 聯絡人應用程式顯示 UI 控制項的標籤,可以讓使用者在您的應用程式中查看群組。
+
+ <p>
+ 例如,如果您在裝置上安裝 Google+ 應用程式,而您將Google+ 與聯絡人應用程式進行同步,您會看到 Google+ 社交圈已列為聯絡人應用程式 [群組]<strong></strong> 標籤中的群組。
+
+如果按一下 Google+ 社交圈,您會看到該社交圈中的人員已列為「群組」。
+系統會在畫面頂端顯示 Google+ 圖示,如果您按一下此圖示,則控制權會切換到 Google+ 應用程式。聯絡人應用程式使用
+{@code viewGroupActivity} 執行此動作,並使用 Google+ 圖示做為
+{@code viewGroupActionLabel} 的值。
+
+
+ </p>
+ <p>
+ 此屬性可以使用字串資源識別碼。
+ </p>
+ </dd>
+ <dt>{@code viewStreamItemActivity}</dt>
+ <dd>
+ 使用者按一下原始聯絡人的串流項目時,裝置的聯絡人應用程式所啟動應用程式中的 Activity 完整類別名稱。
+
+ </dd>
+ <dt>{@code viewStreamItemPhotoActivity}</dt>
+ <dd>
+ 使用者按一下原始聯絡人串流項目中的相片時,裝置的聯絡人應用程式所啟動應用程式中的 Activity 完整類別名稱。
+
+
+ </dd>
+</dl>
+<h4 id="SocialStreamDataKind">&lt;ContactsDataKind&gt; 元素</h4>
+<p>
+ <code>&lt;ContactsDataKind&gt;</code> 元素控制聯絡人應用程式的 UI 中,您的應用程式自訂資料列所顯示的控制項。此元素的語法如下:
+
+</p>
+<pre>
+&lt;ContactsDataKind
+ android:mimeType="<em>MIMEtype</em>"
+ android:icon="<em>icon_resources</em>"
+ android:summaryColumn="<em>column_name</em>"
+ android:detailColumn="<em>column_name</em>"&gt;
+</pre>
+<p>
+ <strong>包含於:</strong>
+</p>
+<code>&lt;ContactsAccountType&gt;</code>
+<p>
+ <strong>描述:</strong>
+</p>
+<p>
+ 使用此元素讓聯絡人應用程式,將自訂資料列的內容顯示為原始聯絡人詳細資訊的一部分。
+<code>&lt;ContactsAccountType&gt;</code> 的每個 <code>&lt;ContactsDataKind&gt;</code> 子元素都代表同步配接器新增至 {@link android.provider.ContactsContract.Data} 表格的自訂資料列類型。
+
+針對您使用的每個自訂 MIME 類型,新增一個
+ <code>&lt;ContactsDataKind&gt;</code> 元素。如果您不要顯示某個自訂資料列的資料,就不用為該列新增元素。
+
+</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>
+ 從資料列擷取兩個值,其中第一個值的欄名稱。此資料列的值會顯示為該項目的第一行。
+第一行的用意是做為資料的摘要使用,但為選用。
+另請參閱
+ <a href="#detailColumn">android:detailColumn</a>。
+ </dd>
+ <dt>{@code android:detailColumn}</dt>
+ <dd>
+ 從資料列擷取兩個值,其中第二個值的欄名稱。此資料列的值會顯示為該項目的第二行。
+另請參閱
+{@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.CommonDataKinds.GroupMembership} MIME 類型儲存在 {@link android.provider.ContactsContract.Data} 表格。
+
+
+</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} 欄是連結到其所屬原始聯絡人的
+ {@code 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} 表格,然後選取原始聯絡人的
+{@code 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>
+ 人員的社交串流資料可能也包括相片。這些資訊都儲存在
+{@code android.provider.ContactsContract.StreamItemPhotos} 表格。<a href="#StreamPhotos">社交串流相片</a>中針對此表格會有更詳細的說明。
+
+</p>
diff --git a/docs/html-intl/intl/zh-tw/guide/topics/providers/content-provider-basics.jd b/docs/html-intl/intl/zh-tw/guide/topics/providers/content-provider-basics.jd
new file mode 100644
index 000000000000..78314784ba9e
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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">
+ 游標 (使用者)</a>
+ </li>
+ <li>
+ <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List7.html">
+ 游標 (電話)</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>
+ 內容供應程式會向外部應用程式以一或多份表格顯示資料,這些表格的樣式類似於關聯式資料庫中的表格。
+每個資料列代表供應程式所收集部分資料類型的單一執行個體,而列中的每個資料欄則代表針對該執行個體收集的個別資料。
+
+
+</p>
+<p>
+ 例如,Android 平台內建的其中一個供應程式是使用者字典,其中儲存使用者想保留的非標準字詞的拼寫方式。
+表 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">字詞</th>
+ <th style="width:20%" align="center" scope="col">應用程式 ID</th>
+ <th style="width:20%" align="center" scope="col">頻率</th>
+ <th style="width:20%" align="center" scope="col">地區</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 列出
+{@link android.content.ContentResolver#query
+query(Uri,projection,selection,selectionArgs,sortOrder)} 的引數及相對應的 SQL SELECT 陳述式:
+</p>
+<p class="table-caption">
+ <strong>表 2:</strong>Query() 與 SQL 查詢的對照表。
+</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> 會對應至供應程式中名為的「table_name」<em></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>)。
+
+當您呼叫用戶端方法來存取供應程式中的表格時,該表格的內容 URI 即為其中一個引數。
+
+
+</p>
+<p>
+ 在上方程式碼中,
+{@link android.provider.UserDictionary.Words#CONTENT_URI} 常數包含使用者字典表格「字詞」的內容 URI。
+{@link android.content.ContentResolver} 物件會剖析該 URI 的授權,然後比較授權和已知供應程式的系統表格,藉此「解析」供應程式。
+
+接著 {@link android.content.ContentResolver} 可以查詢引數分派給正確的供應程式。
+
+
+</p>
+<p>
+ {@link android.content.ContentProvider} 會使用內容 URI 的路徑部分選擇要存取的表格。
+供應程式通常包含用於公開每個表格的「路徑」<strong></strong>。
+</p>
+<p>
+ 以上方程式碼為例,「字詞」的完整 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 值。例如,如要從使用者字典擷取 <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} 則包含可用於將 ID 值附加至 URI 的簡便方法。上方程式碼片段是使用 {@link android.content.ContentUris#withAppendedId
+withAppendedId()} 將 ID 附加至 UserDictionary 內容 URI。
+
+
+</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">&lt;uses-permission&gt;</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() &lt; 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 = &lt;userinput&gt; 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>
+ 建議您使用包含 <code>?</code> 可替換參數和一系列選取引數的選取子句,即使供應程式並非以 SQL 資料庫為基礎亦然。
+
+
+</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>供應程式可能會根據建立查詢物件的屬性限制資料欄的存取權。
+例如,內容供應程式會限制同步配接器存取部分資料欄,避免將這些資料欄傳回 Activity 或服務。
+
+</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> 的資料欄。
+
+ 因為這樣,上述查詢會擷取「字詞」表格的 <code>_ID</code> 欄,即使 {@link android.widget.ListView} 未顯示該資料欄亦然。
+
+ 這項限制也是為何大多數供應程式會針對本身的所有表格設定 <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} 實作方法包含數個用於從物件擷取不同資料類型的「get」方法。
+例如,上方程式碼片段使用了 {@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">&lt;uses-permission&gt;</a></code> 元素在本身的宣示說明檔案中要求相關權限。
+
+當 Android 套件管理員安裝應用程式時,使用者必須授予該應用程式要求的所有權限。
+使用者授予所有權限後,套件管理員才能繼續進行安裝作業;如果使用者不授予權限,則套件管理員就會取消安裝。
+
+
+</p>
+<p>
+ 以下的
+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
+ 元素會要求使用者字典供應程式的讀取存取權:
+</p>
+<pre>
+ &lt;uses-permission android:name="android.permission.READ_USER_DICTIONARY"&gt;
+</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>
+ 新資料列的資料會傳入單一 {@link android.content.ContentValues} 物件,該物件的格式與單列游標類似。
+您不必為這個物件中的資料欄指定相同的資料類型,而且如果您不想指定任何值,可以將資料欄設定為 <code>null</code> 以使用 {@link android.content.ContentValues#putNull ContentValues.putNull()}。
+
+
+</p>
+<p>
+ 該程式碼片段並不會新增 <code>_ID</code> 欄,這是因為系統自動會維護該欄。
+供應程式會將不重複值 <code>_ID</code> 指派給新增的所有資料列。
+供應程式通常會採用該值做為表格的主索引鍵。
+</p>
+<p>
+ <code>newUri</code> 以下方格式傳回的內容 URI 可用於識別新增的資料列:
+
+</p>
+<pre>
+content://user_dictionary/words/&lt;id_value&gt;
+</pre>
+<p>
+ <code>&lt;id_value&gt;</code> 是 ID 為 <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>
+ 刪除資料列的方法與擷取資料列資料類似:您必須為想刪除的資料列指定選取條件,用戶端方法最後會傳回已刪除的資料列數量。
+
+ 以下程式碼片段可刪除應用程式 ID 為「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)
+ </li>
+ <li>
+ 浮點數
+ </li>
+ <li>
+ 長浮點數 (double)
+ </li>
+ </ul>
+<p>
+ 供應程式慣用的其他資料類型為二進位大型物件 (BLOB),這種資料會實作成 64 KB 位元組陣列。
+如果想瞭解可用的資料類型,請查閱 {@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>
+ 如要瞭解標準與自訂 MIME 類型的語法,請參閱 <a href="#MIMETypeReference">MIME 類型參考資料</a>。
+
+</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()} 將這些物件分派給內容供應程式。
+
+
+請將內容供應程式的「授權」<em></em>(而不是特定內容 URI) 傳入這個方法。這樣可讓陣列中的所有 {@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">聯絡人管理員</a>範例應用程式的 <code>ContactAdder.java</code> 來源檔案包含批次存取範例供您參考。
+
+
+
+</p>
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<h2>使用協助程式顯示資料</h2>
+<p>
+ 如果您的應用程式「沒有」<em></em>存取權限,而您仍想使用意圖在其他應用程式中顯示資料。
+例如,日曆應用程式接受用於顯示特定日期或活動的 {@link android.content.Intent#ACTION_VIEW} 意圖。
+
+ 這樣可讓您顯示日曆資訊,而不必自行建立使用者介面。如要進一步瞭解此功能,請參閱<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 權限是特定內容 URI 專用的權限;在接收權限的 Activity 結束之前,這類權限會維持有效狀態。
+具備永久權限的應用程式可授予臨時權限,只要在結果意圖中設定旗標即可:
+
+</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">&lt;provider&gt;</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">&lt;provider&gt;</a></code>
+ 元素的
+<code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission&gt;</a></code>
+ 子元素在本身的宣示說明中為內容 URI 定義 URI 權限。如要進一步瞭解 URI 權限的運作機制,請參閱<a href="{@docRoot}guide/topics/security/security.html">安全性和權限</a>指南的「URI 權限」。
+
+
+</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>
+ 由於該意圖符合聯絡人應用程式的「選取」Activity 的意圖篩選器,因此該 Activity 會在移動到前景。
+
+ </li>
+ <li>
+ 在選取 Activity 中,使用者選取了要更新的聯絡人。
+一旦使用者進行這項動作,選取 Activity 便會呼叫
+{@link android.app.Activity#setResult setResult(resultcode, intent)} 來設定要傳回您應用程式的意圖。
+該意圖包含使用者所選聯絡人的內容 URI,以及「額外」的旗標
+{@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}。
+這些旗標可將 URI 權限授予您的應用程式,以便其讀取內容 URI 指向的聯絡人資料。選取 Activity 隨後會呼叫 {@link android.app.Activity#finish()} 來傳回您應用程式的控制權。
+
+
+
+ </li>
+ <li>
+ 您的 Activity 返回前景,而系統呼叫您 Activity 的
+{@link android.app.Activity#onActivityResult onActivityResult()} 方法。
+這個方法可接收聯絡人應用程式中的選取 Activity 所建立的結果意圖。
+
+ </li>
+ <li>
+ 即使您未在宣示說明中要求供應程式的永久讀取權限,只要利用結果意圖的內容 URI 即可從聯絡人供應程式讀取聯絡人資料。
+
+您之後可以取得聯絡人的出生日期資訊或聯絡人的電子郵件地址,以便傳送電子賀卡給對方。
+
+ </li>
+</ol>
+<h4>使用其他應用程式</h4>
+<p>
+ 允許使用者修改您無法存取的資料的簡單方式,是啟用具備相關權限的應用程式,並且讓使用者透過該應用程式進行修改作業。
+
+</p>
+<p>
+ 例如,日曆應用程式接受可讓您啟用應用程式插入 UI 的
+{@link android.content.Intent#ACTION_INSERT} 意圖。您可以在該意圖中傳入「額外」的資料,供應用程式用於預先填入使用者介面。由於週期性活動的語法較為複雜,因此建議您利用 {@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} 合約類別。
+「字詞」表格的內容 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}。
+ 此類別的參考文件附有程式碼片段範例。其中一個
+{@link android.provider.ContactsContract.Intents.Insert} 子類別為內含意圖常數和意圖資料的合約類別。
+
+</p>
+
+
+<!-- MIME Type Reference -->
+<h2 id="MIMETypeReference">MIME 類型參考資料</h2>
+<p>
+ 內容供應程式可傳回標準 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></em>和子類型<em></em>值。
+針對多個資料欄,類型值<em></em>一律會如下所示
+</p>
+<pre>
+vnd.android.cursor.<strong>dir</strong>
+</pre>
+<p>
+ 或者,針對單一資料欄,類型值一律會如下所示
+</p>
+<pre>
+vnd.android.cursor.<strong>item</strong>
+</pre>
+<p>
+ 。
+</p>
+<p>
+ 子類型<em></em>為供應程式專用。Android 內建的供應程式通常包含簡易的子類型。
+例如,當聯絡人應用程式建立電話號碼資料列時,會為該列設定下列 MIME 類型:
+
+</p>
+<pre>
+vnd.android.cursor.item/phone_v2
+</pre>
+<p>
+ 請注意,子類型值為 <code>phone_v2</code>。
+</p>
+<p>
+ 其他的供應程式開發人員可能會根據供應程式的授權和表格名稱,自行建立專屬的子類型模式。
+例如,考慮一個包含火車時刻表的供應程式。
+ 供應程式的授權為 <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>
+ 根據 Line1 表格的內容 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} 會為某個 MIME 類型的原始聯絡人列定義 {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE} 常數。
+
+
+
+
+</p>
+<p>
+ 如要進一步瞭解個別資料列的內容 URI,請參閱<a href="#ContentURIs">內容 URI</a>。
+
+</p>
diff --git a/docs/html-intl/intl/zh-tw/guide/topics/providers/content-provider-creating.jd b/docs/html-intl/intl/zh-tw/guide/topics/providers/content-provider-creating.jd
new file mode 100644
index 000000000000..3d46ee4b4c80
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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">&lt;provider&gt; 元素</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 應用程式的一或多個類別,以及宣示說明檔案的元素。
+
+您的其中一個類別會實作子類別
+{@link android.content.ContentProvider} (供應程式與其他應用程式之間的介面)。
+雖然內容供應程式的用途是將資料提供給其他應用程式,不過您也可以在應用程式中加入 Activity,讓使用者查詢及修改供應程式所管理的資料。
+
+
+</p>
+<p>
+ 本主題的其餘部分為一份說明建置內容供應程式的步驟清單,以及一份可供您使用的 API 清單。
+
+</p>
+
+
+<!-- Before You Start Building -->
+<h2 id="BeforeYouStart">建置供應程式的前置作業</h2>
+<p>
+ 請先完成下列事項,再開始建置供應程式:
+</p>
+<ol>
+ <li>
+ <strong>評估建置內容供應程式的必要性</strong>。如果您想提供下列功能,您就必須建置內容供應程式:
+
+ <ul>
+ <li>您想將複雜的資料或檔案提供給其他應用程式。</li>
+ <li>您想讓使用者從您的應用程式將複雜的資料複製到其他應用程式。</li>
+ <li>您想使用搜尋架構提供自訂搜尋建議。</li>
+ </ul>
+ <p>
+ 如果您的應用程式內建所有您想提供的功能,您就「不需要」<em></em>建置供應程式來使用 SQLite 資料庫。
+
+ </p>
+ </li>
+ <li>
+ 詳閱<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">內容供應程式基本概念</a>進一步瞭解供應程式 (如果您尚未閱讀該文章的話)。
+
+
+ </li>
+</ol>
+<p>
+ 完成上述事項後,請按照下列步驟建置供應程式:
+</p>
+<ol>
+ <li>
+ 為您的資料設計原始儲存空間。內容供應程式會以兩種方式提供資料:
+ <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 系統內含 SQLite 資料庫 API,可讓 Android 本身的供應程式用於儲存以表格為基礎的資料。
+
+{@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">資料儲存空間</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.provider.BaseColumns#_ID BaseColumns._ID} 是最佳做法,這是因為將供應程式的查詢結果連結至
+{@link android.widget.ListView} 時需要將某個擷取出的資料列命名為
+<code>_ID</code>。
+
+
+ </li>
+ <li>
+ 如果您想提供點陣圖或檔案資料的一大部分,請將資料儲存在檔案中,然後以間接方式提供該檔案,而不要直接將該檔案儲存在表格中。
+
+如果您採用這種做法,請務必通知供應程式的使用者採用
+{@link android.content.ContentResolver} 檔案方法來存取資料。
+ </li>
+ <li>
+ 使用二進位大型物件 (BLOB) 資料類型儲存大小或結構不同的資料。
+例如,您可以使用 BLOB 欄儲存<a href="http://code.google.com/p/protobuf">通訊協定緩衝區</a> 或 <a href="http://www.json.org">JSON 結構</a>。
+
+
+ <p>
+ 此外,您也可以使用 BLOB 實作「按結構定義分門別類」<em></em>的表格。在這種表格中,您需要定義主索引鍵欄、MIME 類型欄和一或多個 BLOB 一般資料欄。
+
+MIME 類型欄中的值會決定 BLOB 欄的資料定義,
+這可讓您在同一表格中儲存多種資料列類型。
+聯絡人供應程式的「資料」表格
+{@link android.provider.ContactsContract.Data} 即為按結構定義分門別類的表格範例。
+
+ </p>
+ </li>
+</ul>
+<!-- Designing Content URIs -->
+<h2 id="ContentURI">設計內容 URI</h2>
+<p>
+ <strong>內容 URI</strong> 是指用於識別供應程式資料的 URI,其中包括整個供應程式的符號名稱 (亦即供應程式的<strong>授權</strong>),以及指向表格或檔案的名稱 (亦即<strong>路徑</strong>)。
+
+選用的 ID 部分則會指向表格中的個別資料欄。
+
+{@link android.content.ContentProvider} 的每個資料存取方法均包括一個內容 URI (引數);該內容 URI 可讓您決定要存取哪個表格、資料列或檔案。
+
+</p>
+<p>
+ 如需內容 URI 的基本概念,請參閱<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">內容供應程式基本概念</a>。
+
+
+</p>
+<h3>設計授權</h3>
+<p>
+ 供應程式通常會包含一個授權,可當做供應程式 Android 內部名稱。為了避免與其他供應程式發生衝突,請務必反向使用網際網路網域擁有權作為供應程式授權的基礎。
+
+此外,也請針對 Android 套件名稱採取此建議做法;您可以將供應程式授權定義為內含供應程式的套件名稱的副檔名。
+
+例如,假設您 Android 套件的名稱為
+ <code>com.example.&lt;appname&gt;</code>,則請將供應程式的授權定義為
+<code>com.example.&lt;appname&gt;.provider</code>。
+</p>
+<h3>設計路徑結構</h3>
+<p>
+ 開發人員通常只要附加指向個別表格的路徑,即可從授權建立內容 URI。
+例如,假設您有「table1」<em></em>和「table2」<em></em>這兩個表格,則您可以結合上述範例中的授權來產生內容 URI
+<code>com.example.&lt;appname&gt;.provider/table1</code> 和
+<code>com.example.&lt;appname&gt;.provider/table2</code>。
+
+路徑並不侷限於單一區隔,而您也不必為每個路徑層級產生表格。
+
+</p>
+<h3>處理內容 URI ID</h3>
+<p>
+ 一般來說,供應程式可利用 URI 尾端資料列的 ID 值接受內容 URI,藉此提供某個資料列的存取權。此外,供應程式通常也可比對 ID 值與表格的 <code>_ID</code> 欄,然後對相符的資料列執行要求的存取動作。
+
+
+
+</p>
+<p>
+ 這種機制可協助採用一般設計模式應用程式存取供應程式,讓應用程式對供應程式執行查詢,並且利用 {@link android.widget.CursorAdapter} 在 {@link android.widget.ListView} 中顯示最終的 {@link android.database.Cursor}。
+
+
+ 定義 {@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> 陳述式中使用整數值,決定要對符合特定模式的內容 URI 採取的動作。
+
+</p>
+<p>
+ 內容 URI 模式會比對採用萬用字元的內容 URI:
+</p>
+ <ul>
+ <li>
+ <strong><code>*</code>:</strong>比對由任何有效字元組成的字串;長度不限。
+ </li>
+ <li>
+ <strong><code>#</code>:</strong>比對由數字組成的字串;長度不限。
+ </li>
+ </ul>
+<p>
+ 以設計及編寫內容 URI 處理方式為例,假設供應程式內含 <code>com.example.app.provider</code> 授權,可識別下列指向表格的內容 URI:
+
+
+</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>content://com.example.app.provider/table3/1</code> 會指定 <code>table3</code> 中 ID 為
+ <code>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> 中單一資料列的內容 URI,例如
+ <code>content://com.example.app.provider/table3/6</code> 會比對其中的
+ <code>6</code> 所指定的資料列。
+
+ </dt>
+</dl>
+<p>
+ 以下程式碼片段說明各種方法在 {@link android.content.UriMatcher} 中的運作方式。
+ 這個程式碼會以不同方式處理整個表格的 URI 以及單一資料列的 URI;針對表格使用內容 URI 模式
+<code>content://&lt;authority&gt;/&lt;path&gt;</code>,針對單一資料列則使用
+<code>content://&lt;authority&gt;/&lt;path&gt;/&lt;id&gt;</code>。
+
+</p>
+<p>
+ {@link android.content.UriMatcher#addURI(String, String, int) addURI()} 方法會將授權和
+路徑對應至某個整數值,而 {@link android.content.UriMatcher#match(Uri)
+ match()} 方法會傳回 URI 的整數值。<code>switch</code> 陳述式則會要查詢整個表格,還是查詢單一記錄:
+
+</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} 嘗試存取您的供應程式,Android 系統便會建立供應程式。
+ </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>
+ 以下兩個程式碼片段展示了
+{@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 類型的方法:
+</p>
+<dl>
+ <dt>
+ {@link android.content.ContentProvider#getType(Uri) getType()}
+ </dt>
+ <dd>
+ 您必須針對任何供應程式實作的其中一個必要方法。
+ </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 媒體類型</a>網站。
+
+</p>
+<p>
+ 針對指向表格資料的資料列的內容 URI,
+{@link android.content.ContentProvider#getType(Uri) getType()} 會採用 Android 廠商專用的 MINE 格式傳回 MIME 類型:
+
+</p>
+<ul>
+ <li>
+ 類型部分:<code>vnd</code>
+ </li>
+ <li>
+ 子類型部分:
+ <ul>
+ <li>
+ 如果 URI 模式適用於單一資料列:<code>android.cursor.<strong>item</strong>/</code>
+ </li>
+ <li>
+ 如果 URI 模式適用於一個以上的資料列:<code>android.cursor.<strong>dir</strong>/</code>
+ </li>
+ </ul>
+ </li>
+ <li>
+ 供應程式專用部分:<code>vnd.&lt;name&gt;</code>.<code>&lt;type&gt;</code>
+ <p>
+ 您需要提供 <code>&lt;name&gt;</code> 和 <code>&lt;type&gt;</code>。
+ <code>&lt;name&gt;</code> 必須是全域唯一值,而 <code>&lt;type&gt;</code> 必須為相對應 URI 模式的專屬值。
+
+建議您使用貴公司的名稱或您應用程式的部分 Android 套件名稱做為 <code>&lt;name&gt;</code>。
+針對
+<code>&lt;type&gt;</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> 中單一資料列的 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> 檔案格式提供相片。
+ 當有應用程式使用篩選器字串 <code>image/*</code> (類型為「圖片」的任何檔案) 呼叫 {@link android.content.ContentResolver#getStreamTypes(Uri, String)
+ContentResolver.getStreamTypes()} 時,{@link android.content.ContentProvider#getStreamTypes(Uri, String)
+ContentProvider.getStreamTypes()} 方法就會傳回如下所示的陣列:
+
+
+</p>
+<pre>
+{ &quot;image/jpeg&quot;, &quot;image/png&quot;, &quot;image/gif&quot;}
+</pre>
+<p>
+ 如果應用程式只想取得 <code>.jpg</code> 檔案,則可以使用篩選器字串 <code>*\/jpeg</code> 呼叫 {@link android.content.ContentResolver#getStreamTypes(Uri, String)
+ContentResolver.getStreamTypes()},此時 {@link android.content.ContentProvider#getStreamTypes(Uri, String)
+ContentProvider.getStreamTypes()} 會傳回如下所示的陣列:
+
+
+<pre>
+{&quot;image/jpeg&quot;}
+</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">資料儲存空間</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">
+ &lt;provider&gt;</a></code> 元素的子元素,在供應程式的宣示說明檔案中設定權限。
+
+您可以選擇讓設定好的權限套用至整個供應程式、特定表格或記錄,或是套用至以上三者。
+
+</p>
+<p>
+ 您可以使用一或多項 <code><a href="{@docRoot}guide/topics/manifest/permission-element.html">
+ &lt;permission&gt;</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>
+ 供應程式層級的單一讀取寫入權限
+ </dt>
+ <dd>
+ 這項權限是由 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+ &lt;provider&gt;</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">
+ &lt;provider&gt;</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">
+ &lt;provider&gt;</a></code> 元素的
+ <code><a href="{@docRoot}guide/topics/manifest/path-permission-element.html">
+ &lt;path-permission&gt;</a></code> 子元素指定您想控制的所有 URI。
+針對您所指定的每個內容 URI,您可以指定讀取/寫入權限、讀取權限或寫入權限,或是以上三種權限。
+讀取及寫入權限的優先等級比讀取/寫入權限來得高。
+此外,路徑層級權限的優先等級比供應程式層級權限來得高。
+
+ </dd>
+ <dt>
+ 臨時權限
+ </dt>
+ <dd>
+ 這種權限層級可將臨時存取權授予某個應用程式,即使該應用程式不具備一般的必要權限。
+臨時存取功能可減少應用程式的宣示說明所需的權限數量。
+
+在啟用臨時權限的情況下,只有會繼續存取您資料的應用程式,需要供應程式的「永久」權限。
+
+
+ <p>
+ 如果想允許外部的圖片檢視器應用程式顯示您供應程式中的相片附加檔案,請將實作電子郵件供應程式和應用程式時所需的權限納入考量。
+
+如要授予圖片檢視器必要的存取權,而不發出權限要求,請設定相片內容 URI 的臨時權限。
+並且將您的電子郵件應用程式設計成在使用者想顯示相片時,將內含相片內容 URI 和權限旗標的意圖傳送給圖片檢視器。
+
+讓圖片檢視器在檢視器沒有供應程式的一般讀取權限的情況下,仍可查詢電子郵件供應程式來擷取相片。
+
+
+ </p>
+ <p>
+ 如要啟用臨時權限,請設定
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+ &lt;provider&gt;</a></code> 元素的
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
+ android:grantUriPermissions</a></code> 元素,或是在
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+ &lt;provider&gt;</a></code> 元素中新增一或多項
+ <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">
+ &lt;grant-uri-permission&gt;</a></code> 子元素。如果您有使用臨時權限,您就必須在從供應程式中移除內容 URI 支援,以及將內容 URI 與臨時權限建立關聯時呼叫 {@link android.content.Context#revokeUriPermission(Uri, int)
+Context.revokeUriPermission()}。
+
+
+ </p>
+ <p>
+ 屬性的值會決定供應程式的可存取部分。
+ 如果將屬性設為 <code>true</code>,則系統會將臨時權限授予整個供應程式,從而覆寫供應程式層級或路徑層級權限所需的任何其他權限。
+
+
+ </p>
+ <p>
+ 如果將這個旗標設為 <code>false</code>,您就必須在
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+ &lt;provider&gt;</a></code> 元素中加入
+ <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">
+ &lt;grant-uri-permission&gt;</a></code> 子元素。每項子元素都會指定要授予臨時存取權的內容 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">&lt;provider&gt; 元素</h2>
+<p>
+ 與 {@link android.app.Activity} 和 {@link android.app.Service} 元件相同,您必須使用
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+ &lt;provider&gt;</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>:供應程式範圍的單一讀取/寫入權限。
+ </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">
+ &lt;provider&gt;</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> &gt; [應用程式]<em></em> &gt; [全部]<em></em>) 中,供應程式標籤的旁邊。
+
+ </li>
+ <li>
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#label">
+ android:label</a></code>:附有供應程式或其資料或以上兩者的說明的資訊標籤。
+這個標籤會顯示在應用程式清單 ([設定]<em></em> &gt; [應用程式]<em></em> &gt; [全部]<em></em>) 中。
+
+ </li>
+ </ul>
+ <p>
+ 如需上述屬性的完整說明,請參閱開發人員指南的
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+ &lt;provider&gt;</a></code> 元素。
+ </p>
+ </dd>
+</dl>
+
+<!-- Intent Access -->
+<h2 id="Intents">意圖和資料存取權</h2>
+<p>
+ 應用程式可透過 {@link android.content.Intent} 以間接方式存取內容供應程式。
+ 利用這種存取方式的應用程式不會呼叫 {@link android.content.ContentResolver} 或
+{@link android.content.ContentProvider} 的任何方法,而是會傳送可啟動 Activity (此 Activity 通常屬於供應程式本身的應用程式) 的意圖。
+目標 Activity 會負責擷取資料並在本身的 UI 中顯示該資料。視意圖中的動作而定,目標 Activity 也可能會提示使用者修改供應程式的資料。
+
+
+ 此外,意圖還可能會包含目標 Activity 顯示在 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/zh-tw/guide/topics/providers/content-providers.jd b/docs/html-intl/intl/zh-tw/guide/topics/providers/content-providers.jd
new file mode 100644
index 000000000000..7f7fa34b9c0c
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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"> 聯絡人管理員</a>應用程式
+
+ </li>
+ <li>
+ <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List2.html"> 「游標 (使用者)」 </a>
+
+
+ </li>
+ <li>
+ <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List7.html"> 「游標 (電話)」</a>
+
+ </li>
+ <li>
+ <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html"> 範例同步配接器</a>
+
+ </li>
+ </ol>
+</div>
+</div>
+<p>
+ 內容供應程式可管理一組結構化資料的存取權、壓縮資料以及提供用於定義資料安全性的機制。
+內容供應程式是一種標準介面,可將某個處理程序中的資料與另一個處理程序中執行的程式碼建立連結。
+
+</p>
+<p>
+ 如果想透過內容供應程式存取資料,請使用您應用程式的 {@link android.content.Context} 中的{@link android.content.ContentResolver} 物件,以用戶端的身分與供應程式通訊。
+
+
+ {@link android.content.ContentResolver} 物件會與供應程式物件 (實作 {@link android.content.ContentProvider} 的類別執行個體) 通訊。
+而供應程式物件則會接收用戶端發出的資料要求、執行要求的動作,以及傳回最終結果。
+
+
+</p>
+<p>
+ 如果您打算與其他應用程式分享您的資料,您不必自行開發供應程式。
+不過,您必須為自己的應用程式準備專屬供應程式,以提供自訂搜尋建議。
+此外,如果您想從自己的應用程式複製複雜的資料或檔案並貼到其他應用程式,也需要準備專屬的供應程式。
+
+</p>
+<p>
+ Android 隨附內容供應程式,可用於管理音訊、影片、圖片、個人聯絡資訊等資料。
+如果想查看 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/zh-tw/guide/topics/providers/document-provider.jd b/docs/html-intl/intl/zh-tw/guide/topics/providers/document-provider.jd
new file mode 100644
index 000000000000..1dc7c46f4387
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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">儲存空間供應程式</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) 導入了「儲存空間存取架構」(Storage Access Framework (SAF)),SAF 可方便使用者透過偏好的文件儲存空間供應程式開啟文件、圖片等其他檔案。
+
+提供簡單易用的標準 UI 可讓使用者在各種應用程式和供應程式中,以相同的方式瀏覽檔案及存取近期開啟的檔案。
+</p>
+
+<p>雲端或本機儲存服務可實作會封裝服務本身的
+{@link android.provider.DocumentsProvider},藉此加入這個生態系統。您只需編寫幾行程式碼,即可將需要存取供應程式文件的用戶端應用程式與 SAF 整合。
+
+</p>
+
+<p>SAF 內含下列項目:</p>
+
+<ul>
+<li><strong>文件供應程式</strong> &mdash; 可讓儲存服務 (例如 Google 雲端硬碟) 顯示所管理檔案的內容供應程式。
+文件供應程式是當作
+{@link android.provider.DocumentsProvider} 類別的子類別使用。文件供應程式結構定義是以傳統檔案階層為依據,不論您為文件供應程式設定的資料儲存方式為何。Android 平台內建數種文件供應程式,例如「下載」、「圖片」和「影片」。
+
+
+
+</li>
+
+<li><strong>用戶端應用程式</strong> &mdash; 可呼叫
+{@link android.content.Intent#ACTION_OPEN_DOCUMENT} 和 (或)
+{@link android.content.Intent#ACTION_CREATE_DOCUMENT} 意圖及接收文件供應程式所傳回檔案的自訂應用程式。
+</li>
+
+<li><strong>挑選器</strong> &mdash; 可讓使用者透過所有符合用戶端應用程式搜尋條件的文件供應程式存取文件的系統 UI。
+</li>
+</ul>
+
+<p>以下是 SAF 提供的部分功能:</p>
+<ul>
+<li>可讓使用者透過所有文件供應程式 (而非單一應用程式) 瀏覽內容。</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>文件供應程式資料模型。「根目錄」會指向單一「文件」,接著該文件會展開成樹狀結構的分支。請注意下列事項:
+</p>
+
+<p></p>
+<ul>
+
+<li>每個文件供應程式都會回報一或多個「根目錄」(也就是文件樹狀結構的起始點)。每個根目錄都有專屬的 {@link android.provider.DocumentsContract.Root#COLUMN_ROOT_ID},可導向至代表該根目錄所含內容的某份文件 (某個目錄)。根目錄的設計架構是動態的,能夠支援多重帳戶、暫時性 USB 儲存裝置或使用者登入/登出等使用狀況。
+
+
+
+
+
+</li>
+
+<li>每個根目錄都內含一份文件,而該文件會指向 N<em></em> 份文件的 1,每份文件又可指向另外 N<em></em> 份文件的 1。
+ </li>
+
+<li>每個儲存空間後端都會透過唯一的
+{@link android.provider.DocumentsContract.Document#COLUMN_DOCUMENT_ID} 來參照個別檔案,藉此顯示這些檔案及目錄。文件 ID 不得重複而且一旦核發便不得更改,原因在於裝置重新啟動時會將這些 ID 用於永久 URI 授權。
+
+
+</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} 意圖後,互動程序便會開始。意圖可能包括用於縮小條件範圍的篩選器 &mdash; 例如「將所有內含 MIME 類型『圖片』的可開啟檔案提供給我」。
+
+</li>
+
+<li>一旦觸發意圖,系統挑選器就會前往所有已註冊的供應程式,並且向使用者顯示相符的內容根目錄。
+</li>
+
+<li>即便底層文件供應程式可能不盡相同,挑選器仍會提供使用者可用於存取文件的標準介面。
+例如圖 2 中的 Google 雲端硬碟供應程式、USB 供應程式和雲端供應程式。
+</li>
+</ul>
+
+<p>圖 3 顯示的是使用者搜尋指定 Google 雲端硬碟帳戶中的圖片時所用的挑選器:
+</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 雲端硬碟後,系統就會顯示相關圖片 (如圖 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} 意圖。
+
+接著,使用者必須選取某款應用程式來選取檔案,而且選定的應用程式必須提供使用者介面,讓使用者瀏覽及挑選可用的檔案。
+
+ </p>
+
+<p>針對搭載 Android 4.4 以上版本的裝置,您的應用程式還可以呼叫
+{@link android.content.Intent#ACTION_OPEN_DOCUMENT} 意圖,以顯示系統所控管的挑選器 UI,方便使用者瀏覽其他應用程式提供的所有檔案。
+
+透過這個單一 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 &quot;file chooser&quot; 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 &quot;opened&quot;, 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 &quot;audio/ogg&quot;.
+ // To search for all documents available via installed storage providers,
+ // it would be &quot;*/*&quot;.
+ intent.setType(&quot;image/*&quot;);
+
+ 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 擷取使用者所需的文件。
+例如:
+</p>
+
+<pre>&#64;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
+ // &quot;if there's anything to look at, look at it&quot; conditionals.
+ if (cursor != null &amp;&amp; cursor.moveToFirst()) {
+
+ // Note it's called &quot;Display Name&quot;. This is
+ // provider-specific, and might not necessarily be the file name.
+ String displayName = cursor.getString(
+ cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
+ Log.i(TAG, &quot;Display Name: &quot; + 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 &quot;unpredictable&quot;. 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 = &quot;Unknown&quot;;
+ }
+ Log.i(TAG, &quot;Size: &quot; + 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 &quot;opened&quot;, 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#COLUMN_FLAGS Document.COLUMN_FLAGS} 含有
+{@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_DELETE SUPPORTS_DELETE},您就可以刪除該文件。
+
+例如:</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 &quot;opened&quot;, 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(&quot;text/plain&quot;);
+
+ 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()
+ &amp; (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+// Check for the freshest data.
+getContentResolver().takePersistableUriPermission(uri, takeFlags);</pre>
+
+<p>除了上述指示外,您還需要完成最後一個步驟。您儲存了您的應用程式最近存取的 URI,但這些 URI 有可能已失效 &mdash; 原因在於其他應用程式刪除或修改了文件。
+
+因此,建議您一律呼叫
+{@code getContentResolver().takePersistableUriPermission()} 檢查最新資料。
+</p>
+
+<h2 id="custom">編寫自訂文件供應程式</h2>
+
+<p>
+如果您想開發可提供檔案儲存服務 (例如雲端儲存服務) 的應用程式,可以編寫自訂文件供應程式透過 SAF 提供您的檔案。
+
+本節說明如何編寫這類程式。
+</p>
+
+
+<h3 id="manifest">宣示說明</h3>
+
+<p>如要實作自訂文件供應程式,請將以下項目加入應用程式的宣示說明:
+</p>
+<ul>
+
+<li>19 以上的 API 級別目標。</li>
+
+<li>宣告自訂儲存空間供應程式的
+<code>&lt;provider&gt;</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>&quot;true&quot;</code> 的 <code>android:exported</code> 屬性。您必須將供應程式匯出,方便其他應用程式加以偵測。
+</li>
+
+<li>設為 <code>&quot;true&quot;</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>&lt;bool name=&quot;atLeastKitKat&quot;&gt;false&lt;/bool&gt;</pre></li>
+
+<li>在位於 {@code res/values-v19/} 的 {@code bool.xml} 資源檔案中,新增以下程式碼:
+ <pre>&lt;bool name=&quot;atLeastKitKat&quot;&gt;true&lt;/bool&gt;</pre></li>
+</ul></li>
+
+<li>內含
+{@code android.content.action.DOCUMENTS_PROVIDER} 動作的意圖篩選器,讓您的供應程式能夠在系統搜尋供應程式時顯示在挑選器中。
+</li>
+
+</ul>
+<p>以下是內含供應程式的範例宣示說明例外狀況:</p>
+
+<pre>&lt;manifest... &gt;
+ ...
+ &lt;uses-sdk
+ android:minSdkVersion=&quot;19&quot;
+ android:targetSdkVersion=&quot;19&quot; /&gt;
+ ....
+ &lt;provider
+ android:name=&quot;com.example.android.storageprovider.MyCloudProvider&quot;
+ android:authorities=&quot;com.example.android.storageprovider.documents&quot;
+ android:grantUriPermissions=&quot;true&quot;
+ android:exported=&quot;true&quot;
+ android:permission=&quot;android.permission.MANAGE_DOCUMENTS&quot;
+ android:enabled=&quot;&#64;bool/atLeastKitKat&quot;&gt;
+ &lt;intent-filter&gt;
+ &lt;action android:name=&quot;android.content.action.DOCUMENTS_PROVIDER&quot; /&gt;
+ &lt;/intent-filter&gt;
+ &lt;/provider&gt;
+ &lt;/application&gt;
+
+&lt;/manifest&gt;</pre>
+
+<h4 id="43">支援搭載 Android 4.3 以下版本的裝置</h4>
+
+<p>只有搭載 Android 4.4 以上版本的裝置可使用
+{@link android.content.Intent#ACTION_OPEN_DOCUMENT} 意圖。如果您想讓應用程式支援 {@link android.content.Intent#ACTION_GET_CONTENT} 以便與搭載 Android 4.3 以下版本的裝置相容,請針對搭載 Android 4.4 以上版本的裝置停用宣示說明中的 {@link android.content.Intent#ACTION_GET_CONTENT} 意圖篩選器。
+
+
+
+
+文件供應器和 {@link android.content.Intent#ACTION_GET_CONTENT} 是完全不同的項目。
+
+如果您同時支援這兩個項目,您的應用程式就會重複出現在系統挑選器 UI 中,讓使用者可透過兩種不同方式存取您儲存的資料,
+
+而這樣會造成混淆。</p>
+
+<p>以下提供針對搭載 Android 4.4 以上版本的裝置停用
+{@link android.content.Intent#ACTION_GET_CONTENT} 意圖篩選器的建議做法:
+</p>
+
+<ol>
+<li>在位於 {@code res/values/} 的 {@code bool.xml} 資源檔案中,新增以下程式碼:
+ <pre>&lt;bool name=&quot;atMostJellyBeanMR2&quot;&gt;true&lt;/bool&gt;</pre></li>
+
+<li>在位於 {@code res/values-v19/} 的 {@code bool.xml} 資源檔案中,新增以下程式碼:
+ <pre>&lt;bool name=&quot;atMostJellyBeanMR2&quot;&gt;false&lt;/bool&gt;</pre></li>
+
+<li>新增
+<a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">Activity 別名</a>來針對搭載 Android 4.4 (API 級別 19) 以上版本的裝置停用 {@link android.content.Intent#ACTION_GET_CONTENT} 意圖篩選器。
+
+例如:
+
+<pre>
+&lt;!-- This activity alias is added so that GET_CONTENT intent-filter
+ can be disabled for builds on API level 19 and higher. --&gt;
+&lt;activity-alias android:name=&quot;com.android.example.app.MyPicker&quot;
+ android:targetActivity=&quot;com.android.example.app.MyActivity&quot;
+ ...
+ android:enabled=&quot;@bool/atMostJellyBeanMR2&quot;&gt;
+ &lt;intent-filter&gt;
+ &lt;action android:name=&quot;android.intent.action.GET_CONTENT&quot; /&gt;
+ &lt;category android:name=&quot;android.intent.category.OPENABLE&quot; /&gt;
+ &lt;category android:name=&quot;android.intent.category.DEFAULT&quot; /&gt;
+ &lt;data android:mimeType=&quot;image/*&quot; /&gt;
+ &lt;data android:mimeType=&quot;video/*&quot; /&gt;
+ &lt;/intent-filter&gt;
+&lt;/activity-alias&gt;
+</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} 參數代表呼叫者想返回的特定欄位。
+這個程式碼片隊會建立新游標並在其中加入一列 &mdash; 也就是根目錄或頂層目錄 (例如「下載」或「圖片」)。
+
+大多數供應程式只有一個根目錄。而您可以有多個根目錄,例如擁有多個使用者帳戶的情況下。
+在這種情況下,只要在游標中加入第二列即可。
+</p>
+
+<pre>
+&#64;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 &quot;MyCloud&quot;.
+ 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 &quot;Recents&quot; 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>&#64;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>&#64;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.provider.DocumentsProvider#openDocument
+openDocument()} 來傳回代表特定檔案的
+{@link android.os.ParcelFileDescriptor}。其他應用程式可利用傳回的 {@link android.os.ParcelFileDescriptor} 傳輸資料。
+使用者選取檔案而且用戶端應用程式呼叫
+{@link android.content.ContentResolver#openFileDescriptor openFileDescriptor()} 要求存取該檔案後,系統就會呼叫這個方法。範例:
+
+</p>
+
+<pre>&#64;Override
+public ParcelFileDescriptor openDocument(final String documentId,
+ final String mode,
+ CancellationSignal signal) throws
+ FileNotFoundException {
+ Log.v(TAG, &quot;openDocument, mode: &quot; + 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() {
+ &#64;Override
+ public void onClose(IOException e) {
+
+ // Update the file with the cloud server. The client is done
+ // writing.
+ Log.i(TAG, &quot;A file with id &quot; +
+ documentId + &quot; has been closed!
+ Time to &quot; +
+ &quot;update the server.&quot;);
+ }
+
+ });
+ } catch (IOException e) {
+ throw new FileNotFoundException(&quot;Failed to open document with id &quot;
+ + documentId + &quot; and mode &quot; + 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/zh-tw/guide/topics/resources/accessing-resources.jd b/docs/html-intl/intl/zh-tw/guide/topics/resources/accessing-resources.jd
new file mode 100644
index 000000000000..3a5a96121d94
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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
+&#64;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">資源類型</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>儘管資源 ID 都指定於 {@code R} 類別,您不需要為了取得資源 ID 而加以查看。資源 ID 的組成如下:
+</p>
+<ul>
+ <li>資源類型<em></em>:每一種資源會以「類型」分類,例如 {@code
+string}、{@code drawable} 以及 {@code layout}。如需有關不同類型的詳細資訊,請參閱<a href="available-resources.html">資源類型</a>。
+ </li>
+ <li>資源名稱<em></em>可能是:檔案名稱,不含副檔名;或 XML {@code android:name} 屬性中的值,如果資源是簡單值 (例如字串)。
+
+</li>
+</ul>
+
+<p>您有兩種方式可存取資源:</p>
+<ul>
+ <li><strong>在程式碼中:</strong>使用 {@code R} 類別中子類別的靜態整數,例如:
+
+ <pre class="classic no-pretty-print">R.string.hello</pre>
+ <p>{@code string} 是資源類型,而 {@code hello} 是資源名稱。若您以此格式提供資源 ID 時,很多 Android API 都可以存取您的資源。
+請參閱<a href="#ResourcesFromCode">在程式碼中存取資源</a>。
+</p>
+ </li>
+ <li><strong>在 XML 中:</strong>使用特殊 XML 語法,也可以對應到您在 {@code R} 類別中定義的資源 ID,例如:
+
+ <pre class="classic no-pretty-print">&#64;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/},因為要從
+{@code res/} 讀取資源的唯一方式是透過資源 ID。不過,您可以將資源儲存在
+{@code assets/} 目錄。
+</p>
+<p>儲存在 {@code assets/} 目錄中的檔案「不會」<em></em>指定資源 ID,因此您無法透過 {@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>&lt;package_name&gt;</em>.]R.<em>&lt;resource_type&gt;</em>.<em>&lt;resource_name&gt;</em>
+</pre>
+
+<ul>
+ <li>{@code &lt;package_name&gt;}<em></em> 資源所在的封裝名稱 (從您自己的封裝中參照資源時,不需要此名稱)。
+</li>
+ <li>{@code &lt;resource_type&gt;}<em></em> 是資源類型的 {@code R} 子類別。</li>
+ <li>{@code &lt;resource_name&gt;}<em></em> 可以是不含副檔名的資源檔案名稱,或是 XML 元素中的 {@code android:name} 屬性值 (簡單值)。
+
+</li>
+</ul>
+<p>請參閱<a href="available-resources.html">資源類型</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} 檔案 &mdash; 此檔案是在編譯專案時由 {@code aapt} 工具所產生。
+下次編譯時會覆寫所有變更內容。</p>
+
+
+
+<h2 id="ResourcesFromXml">存取 XML 中的資源</h2>
+
+<p>您可以使用現有資源的參照,為某些 XML 屬性和元素定義值。
+您在建立版面配置檔案時,會經常以此方式提供字串和影像讓小工具使用。
+</p>
+
+<p>例如,如果您要將 {@link android.widget.Button} 加入版面配置,應該使用按鈕文字的<a href="string-resource.html">字串資源</a>:
+</p>
+
+<pre>
+&lt;Button
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="<strong>@string/submit</strong>" /&gt;
+</pre>
+
+
+<h3>語法</h3>
+
+<p>在 XML 資源中參照資源的語法如下:</p>
+
+<pre class="classic no-pretty-print">
+&#64;[<em>&lt;package_name&gt;</em>:]<em>&lt;resource_type&gt;</em>/<em>&lt;resource_name&gt;</em>
+</pre>
+
+<ul>
+ <li>{@code &lt;package_name&gt;} 資源所在的封裝名稱 (從同一個封裝中參照資源時,不需要此名稱)
+</li>
+ <li>{@code &lt;resource_type&gt;} 是資源類型的
+{@code R} 子類別。</li>
+ <li>{@code &lt;resource_name&gt;} 可以是不含副檔名的資源檔案名稱,或是 XML 元素中的 {@code android:name} 屬性值 (簡單值)。
+
+</li>
+</ul>
+
+<p>請參閱<a href="available-resources.html">資源類型</a>,以取得關於每個資源類型及其參照方式的詳細資訊。
+</p>
+
+
+<h3>使用案例</h3>
+
+<p>有時候您必須在 XML 中使用資源,而不能使用值 (例如,將可繪項目影像套用至小工具)。不過,您也可以在 XML 中接受簡單值的任何位置使用資源。
+例如,如果您有下列資源檔案,其中內含<a href="more-resources.html#Color">色彩資源</a>和<a href="string-resource.html">字串資源</a>:
+</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;resources>
+ &lt;color name="opaque_red">#f00&lt;/color>
+ &lt;string name="hello">Hello!&lt;/string>
+&lt;/resources>
+</pre>
+
+<p>您可以在下列版面配置檔案中使用這些資源,以設定文字色彩和文字字串:
+</p>
+
+<pre>
+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
+&lt;EditText xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
+ android:layout_width=&quot;fill_parent&quot;
+ android:layout_height=&quot;fill_parent&quot;
+ android:textColor=&quot;<strong>&#64;color/opaque_red</strong>&quot;
+ android:text=&quot;<strong>&#64;string/hello</strong>&quot; /&gt;
+</pre>
+
+<p>在此情況下,您不用在資源參照中指定封裝名稱,因為資源是來自您自己的封裝。
+如要參照系統資源,則需要使用封裝名稱。
+範例:</p>
+
+<pre>
+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
+&lt;EditText xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
+ android:layout_width=&quot;fill_parent&quot;
+ android:layout_height=&quot;fill_parent&quot;
+ android:textColor=&quot;<strong>&#64;android:color/secondary_text_dark</strong>&quot;
+ android:text=&quot;&#64;string/hello&quot; /&gt;
+</pre>
+
+<p class="note"><strong>注意:</strong>您一律都要使用字串資源,便於應用程式當地語系化。
+如需關於建立替代資源 (例如當地語系化的字串) 的詳細資訊,請參閱<a href="providing-resources.html#AlternativeResources">提供替代資源</a>。
+
+
+如需將應用程式當地語系化的詳細指南,請參閱<a href="localization.html">當地語系化</a>。
+</p>
+
+<p>您甚至可以在 XML 中使用資源以建立別名。例如:您可以用其他可繪項目資源的別名,建立可繪項目資源:
+</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;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>&lt;package_name&gt;</em>:][<em>&lt;resource_type&gt;</em>/]<em>&lt;resource_name&gt;</em>
+</pre>
+
+<p>例如,您可以參照屬性,讓文字色彩符合系統設計風格的「主要」文字色彩,方式如下:
+</p>
+
+<pre>
+&lt;EditText id=&quot;text&quot;
+ android:layout_width=&quot;fill_parent&quot;
+ android:layout_height=&quot;wrap_content&quot;
+ android:textColor=&quot;<strong>?android:textColorSecondary</strong>&quot;
+ android:text=&quot;&#64;string/hello_world&quot; /&gt;
+</pre>
+
+<p>這裡的 {@code android:textColor} 屬性指出目前設計風格中樣式屬性的名稱。
+Android 現在會將套用至 {@code android:textColorSecondary} 樣式屬性的值,當成此小工具中 {@code android:textColor} 的值。
+因為系統資源工具知道在此環境中會有一個屬性資源,您不需要明確陳述其類型 (
+<code>?android:attr/textColorSecondary</code>)&mdash; 可以不需要寫上出 {@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}&lt;String&gt;(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">清單檢視</a>開發人員指南。
+</p>
+
diff --git a/docs/html-intl/intl/zh-tw/guide/topics/resources/overview.jd b/docs/html-intl/intl/zh-tw/guide/topics/resources/overview.jd
new file mode 100644
index 000000000000..68197d17233a
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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">本地化</a></li>
+ </ol>
+
+ <h2>參考資料</h2>
+ <ol>
+ <li><a href="available-resources.html">資源類型</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>兩個不同的裝置,個別使用預設的版面配置 (應用程式未提供替代的版面配置)。
+</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>兩個不同的裝置,個別使用不同螢幕大小所提供的不同版面配置。
+</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 說明相同的應用程式為較大的螢幕新增替代版面配置資源的情況。
+</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>如何管理在 Activity 執行期間發生的設定變更。</dd>
+ <dt><strong><a href="localization.html">本地化</a></strong></dt>
+ <dd>從細節到整體的說明,指引您使用替代資源將應用程式本地化。雖然這只是替代資源的一種特殊用途,但為了觸及更多使用者,這樣做非常重要。
+
+</dd>
+ <dt><strong><a href="available-resources.html">資源類型</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/zh-tw/guide/topics/resources/providing-resources.jd b/docs/html-intl/intl/zh-tw/guide/topics/resources/providing-resources.jd
new file mode 100644
index 000000000000..0938dc00e12d
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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">資源類型</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/} 目錄包含所有資源 (在子目錄中):一個影像資源、兩個版面配置資源、啟動器圖示的 {@code mipmap/} 目錄,以及字串資源檔案。
+
+資源目錄名稱非常重要,在表 1 有相關說明。
+</p>
+
+<p class="note"><strong>注意:</strong>如需有關使用 mipmap 資料夾的詳細資訊,請參閱<a href="{@docRoot}tools/projects/index.html#mipmap">管理專案總覽</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">tween 動畫</a>的 XML 檔案。
+(屬性動畫也能儲存在這個目錄中,但建議將屬性動畫放在{@code animator/} 目錄中,以區分這兩個類型。)
+
+</td>
+ </tr>
+
+ <tr>
+ <td><code>color/</code></td>
+ <td>定義色彩狀態清單的 XML 檔案。請參閱<a href="color-list-resource.html">色彩狀態清單資源</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>九宮格影像 (可重新調整大小的點陣圖)</li>
+ <li>狀態清單</li>
+ <li>形狀</li>
+ <li>動畫可繪項目</li>
+ <li>其他可繪項目</li>
+ </ul>
+ <p>請參閱<a href="drawable-resource.html">可繪項目資源</a>。</p>
+ </td>
+ </tr>
+
+ <tr>
+ <td><code>mipmap/</code></td>
+ <td>適用於不同啟動器圖示密度的可繪項目檔案。如需有關使用 {@code mipmap/} 資料夾管理啟動器圖示的詳細資訊,請參閱<a href="{@docRoot}tools/project/index.html#mipmap">管理專案總覽</a>。
+
+</td>
+ </tr>
+
+ <tr>
+ <td><code>layout/</code></td>
+ <td>定義使用者介面版面配置的 XML 檔案。
+ 請參閱<a href="layout-resource.html">版面配置資源</a>。</td>
+ </tr>
+
+ <tr>
+ <td><code>menu/</code></td>
+ <td>定義應用程式選單 (例如,選項選單、操作選單或子選單) 的 XML 檔案。
+請參閱<a href="menu-resource.html">選單資源</a>。</td>
+ </tr>
+
+ <tr>
+ <td><code>raw/</code></td>
+ <td><p>以原始格式儲存的任意檔案。如要使用原始
+{@link java.io.InputStream} 開啟這些資源,使用資源 ID 呼叫 {@link android.content.res.Resources#openRawResource(int)
+Resources.openRawResource()},資源 ID 為 {@code R.raw.<em>filename</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 檔案名稱定義單一資源,而位於 {@code values/} 目錄的檔案則會描述多個資源。
+針對這個目錄中的檔案,{@code &lt;resources&gt;} 元素的每個子項都會定義單一資源。
+
+例如,{@code &lt;string&gt;} 元素建立一個
+{@code R.string} 資源,{@code &lt;color&gt;} 元素建立一個 {@code R.color}資源。
+</p>
+ <p>由於每個資源都是以自己的 XML 元素定義,您可以依照自己的喜好命名檔案,並將不同的資源類型放在一個檔案中。
+然而,為了更加清楚,您可以將唯一資源類型放在不同的檔案中。
+例如,針對您可以在此目錄建立的資源,這裡提供一些檔案名稱慣例:
+</p>
+ <ul>
+ <li>arrays.xml 適用於資源陣列 (<a href="more-resources.html#TypedArray">具類型的陣列</a>)。</li>
+ <li>colors.xml 適用於<a href="more-resources.html#Color">色彩值</a></li>
+ <li>dimens.xml 適用於<a href="more-resources.html#Dimension">維度值</a>。</li>
+ <li>strings.xml 適用於<a href="string-resource.html">字串值</a>。
+</li>
+ <li>styles.xml 適用於<a href="style-resource.html">樣式</a>。</li>
+ </ul>
+ <p>請參閱<a href="string-resource.html">字串資源</a>、
+<a href="style-resource.html">樣式資源</a>和
+<a href="more-resources.html">更多資源類型</a>。</p>
+ </td>
+ </tr>
+
+ <tr>
+ <td><code>xml/</code></td>
+ <td>可以在執行階段讀取的任意 XML 檔案,方法是呼叫 {@link
+android.content.res.Resources#getXml(int) Resources.getXML()}。各種 XML 設定檔案都必須儲存在這裡,例如<a href="{@docRoot}guide/topics/search/searchable-config.html">可搜尋項目設定</a>。
+
+<!-- or preferences configuration. --></td>
+ </tr>
+</table>
+
+<p class="caution"><strong>注意:</strong>千萬不要將資源檔案直接儲存在
+{@code res/} 目錄內 &mdash; 會發生編譯錯誤。</p>
+
+<p>如需特定資源類型的詳細資訊,請參閱<a href="available-resources.html">資源類型</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>兩個不同的裝置,個別使用不同的版面配置資源。</p>
+</div>
+
+<p>幾乎每個應用程式都應提供替代資源以支援特定裝置設定。
+例如,您應該為不同的螢幕密度包含替代可繪項目資源,並為不同語言提供替代字串資源。
+Android 會在執行階段偵測目前的裝置設定,並為您的應用程式載入適當的資源。
+
+</p>
+
+<p>如要為一組資源指定特定設定的替代項目:</p>
+<ol>
+ <li>在 {@code res/} 建立一個新的目錄,命名的格式為 {@code
+<em>&lt;resources_name&gt;</em>-<em>&lt;config_qualifier&gt;</em>}。
+ <ul>
+ <li><em>{@code &lt;resources_name&gt;}</em> 是對應預設資源 (定義在表 1) 的目錄名稱。
+</li>
+ <li><em>{@code &lt;qualifier&gt;}</em> 是用來指定要使用這些資源之個別設定的名稱 (定義在表 2)。
+</li>
+ </ul>
+ <p>您可以附加一個以上的 <em>{@code &lt;qualifier&gt;}</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 支援多種設定限定詞,而且您可以將多個限定詞加到一個目錄名稱,並用破折號分隔每個限定詞。
+表 2 依優先等級列出有效的設定限定詞 &mdash; 如果您針對一個資源目錄使用多個限定詞,您必須依表格中列出的順序將它們新增到目錄名稱。
+
+
+</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>語言是以兩個字母的 <a href="http://www.loc.gov/standards/iso639-2/php/code_list.php">ISO 639-1</a> 語言代碼定義,後面可以視需要加上兩個字母的 <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">當地語系化</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&lt;N&gt;dp</code><br/><br/>
+ 範例:<br/>
+ <code>sw320dp</code><br/>
+ <code>sw600dp</code><br/>
+ <code>sw720dp</code><br/>
+ 等等。
+ </td>
+ <td>
+ <p>螢幕的基本大小,也就是可用
+螢幕區域的最短維度。具體而言,裝置的 smallestWidth 是螢幕最短的可用高度和寬度 (您也可以把它當成螢幕的「最小寬度」)。
+您可以使用此限定詞確保無論螢幕目前的方向為何,您的應用程式至少有 {@code &lt;N&gt;} dps 的寬度可供 UI 使用。
+
+</p>
+ <p>例如,如果您的版面配置需要隨時保持至少 600 dp 的最小螢幕區域維度,則您可以使用此限定詞建立版面配置資源 {@code
+res/layout-sw600dp/}。
+系統只會在可用螢幕的最小維度至少是 600dp 時使用這些資源,無論 600dp 的長度對使用者而言是高度或寬度都一樣。
+
+smallestWidth 是螢幕的固定螢幕大小特性;<strong>裝置的 smallestWidth 不會隨著螢幕方向的改變而變更。</strong>
+</p>
+ <p>裝置的 smallestWidth 會將螢幕裝飾和系統 UI 列入計算。例如,如果裝置的螢幕上有一些永久的 UI 元素,且這些元素佔用了 smallestWidth 座標軸上的空間,系統會宣告 smallestWidth 小於實際螢幕大小,因為這些是 UI 無法使用的螢幕像素。
+
+
+因此,您使用的值應該是版面配置所需的實際最小維度<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,以及 {@link
+android.content.res.Configuration#smallestScreenWidthDp} 設定欄位,此欄位保留裝置的 smallestWidth 值。
+
+</p>
+ <p>如需設計不同螢幕及使用此限定詞的詳細資訊,請參閱<a href="{@docRoot}guide/practices/screens_support.html">支援多個螢幕</a>開發人員指南。
+
+</p>
+ </td>
+ </tr>
+ <tr id="ScreenWidthQualifier">
+ <td>可用寬度</td>
+ <td><code>w&lt;N&gt;dp</code><br/><br/>
+ 範例:<br/>
+ <code>w720dp</code><br/>
+ <code>w1024dp</code><br/>
+ 等等。
+ </td>
+ <td>
+ <p>指定資源應使用的最小可用螢幕寬度,以 {@code dp} 單位計算 &mdash; 由 <code>&lt;N&gt;</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">支援多個螢幕</a>開發人員指南。
+
+</p>
+ </td>
+ </tr>
+ <tr id="ScreenHeightQualifier">
+ <td>可用高度</td>
+ <td><code>h&lt;N&gt;dp</code><br/><br/>
+ 範例:<br/>
+ <code>h720dp</code><br/>
+ <code>h1024dp</code><br/>
+ 等等。
+ </td>
+ <td>
+ <p>指定資源應使用的最小可用螢幕高度,以「dp」單位計算 &mdash; 由 <code>&lt;N&gt;</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">支援多個螢幕</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>如果所有資源都使用比目前螢幕更大<em></em>的大小限定詞,系統將不會<strong></strong>使用這些資源,您的應用程式將會在執行階段當機 (例如,如果所有版面配置資源都標記為 {@code
+xlarge} 限定詞,但裝置為一般大小螢幕)。
+
+</p>
+ <p>已新增至 API 級別 4。<em></em></p>
+
+ <p>請參閱<a href="{@docRoot}guide/practices/screens_support.html">支援多個螢幕</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}:在電視上顯示的裝置,提供在離使用者很遠的大螢幕上顯示 UI 的「十英呎」體驗,主要透過 DPAD 或其他非指標互動指定方向。
+
+
+</li>
+ <li>{@code appliance}:做為設備使用的裝置,沒有顯示器
+</li>
+ <li>{@code watch}:裝置有佩戴在手腕上的顯示器</li>
+ </ul>
+ <p>已新增至 API 級別 8、電視已新增至 API 13、手錶已新增至 API 20。<em></em></p>
+ <p>如要瞭解從座架插入或移除裝置時,您的應用程式可以如何回應的相關資訊,請參閱<a href="{@docRoot}training/monitoring-device-state/docking-monitoring.html">判斷和監控座架狀態和類型</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}:特特特高密度使用 (僅限啟動器圖示,請參閱支援多個螢幕中的<a href="{@docRoot}guide/practices/screens_support.html#xxxhdpi-note">注意</a><em></em>);約 640dpi。
+
+已新增至 API 級別 18。
+<em></em></li>
+ <li>{@code nodpi}:如果您不想縮放點陣圖資源以符合裝置密度,可使用此設定。
+</li>
+ <li>{@code tvdpi}:介於 mdpi 和 hdpi 的螢幕;約 213dpi。這不屬於「主要」密度群組。
+這大部分用於電視,大多數應用程式應該不需要用到 &mdash;mdpi 和 hdpi 資源對大多數應用程式已經足夠,系統將視需要縮放它們。
+
+這個限定詞由 API 級別 13 導入。</li>
+ </ul>
+ <p>六個主要密度之間有一個 3:4:6:8:12:16 縮放比例 (忽略tvdpi 密度)。
+因此,ldpi 的 9x9 點陣圖等同於 mdpi 的 12x12 點陣圖、hdpi 的 18x18 點陣圖、xhdpi 的 24x24 點陣圖,以此類推。
+</p>
+ <p>如果您覺得影像資源在電視或其他特定裝置上看起來不夠美觀,而想嘗試 tvdpi 資源,比例因數為 1.33*mdpi。
+例如,mdpi 螢幕上的 100px x 100px 影像在 tvdpi 螢幕應該是 133px x 133px。
+</p>
+ <p class="note"><strong>注意:</strong>使用密度限定詞不代表資源僅適用於該密度的螢幕。
+<em></em>如果您提供的替代資源沒有更符合目前裝置設定的限定詞,系統將使用<a href="#BestMatch">最符合</a>的資源。
+
+</p>
+ <p>請參閱<a href="{@docRoot}guide/practices/screens_support.html">支援多個螢幕</a>,深入瞭解如何處理不同的螢幕密度,以及 Android會如何縮放點陣圖以符合目前的密度。
+
+</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}:裝置有硬體 qwerty 軟體鍵盤,無論使用者是否可見。
+
+</li>
+ <li>{@code 12key}:裝置有硬體 12 鍵鍵盤,無論使用者是否可見。
+</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}:不提供導覽鍵 (例如,位於密合蓋子的後方)。
+</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}:裝置有導覽用的方向鍵 (d-pad)。</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 (裝置安裝 Android1.6 以上版本)。
+
+請參閱 <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">Android API 級別</a>文件以取得有關這些值的詳細資訊。
+</p>
+ </td>
+ </tr>
+</table>
+
+
+<p class="note"><strong>注意:</strong>有些設定限定詞從 Android1.0 就已新增,因此並非所有 Android 版本都支援所有限定詞。
+使用新的限定詞會以隱含的方式新增平台版本的限定詞,因此較舊的裝置一定會忽略它。
+例如,使用
+ <code>w600dp</code> 限定詞最自動包含 <code>v13</code> 限定詞,因為可用寬度限定詞是 API 級別 13 的新項目。
+為了避免發生任何問題,永遠要包含一組預設資源 (一組沒有限定詞的資源<em></em>)。
+如需詳細資訊,請參閱<a href="#Compatibility">使用資源提供最佳的裝置相容性</a>一節。
+
+</p>
+
+
+
+<h3 id="QualifierRules">限定詞名稱規則</h3>
+
+<p>這裡有一些使用設定限定詞名稱的規則:</p>
+
+<ul>
+ <li>您可以為一組資源指定多個限定詞,以破折號分隔。例如,
+<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>每個限定詞類型只支援一個值。例如,如果您想在西班牙文和法文使用相同的可繪項目檔案,則不能將目錄命名為 <em></em>
+<code>drawable-rES-rFR/</code>。
+您必須有兩個資源目錄,例如
+<code>drawable-rES/</code> 和 <code>drawable-rFR/</code>,這兩個目錄要包含適當的檔案。
+但是,您不需要實際將相同的檔案複製到這兩位置。您可以為資源建立別名。
+請參閱下方的
+<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},且必須為不同的地區設定提供唯一的版本。
+但是,加拿大英文和加拿大法文這兩個地區設定必須使用相同的版本。
+您可能會假設必須在加拿大英文和加拿大法文這兩個資源目錄中複製相同的影像,但並不需要這樣做。
+
+您可以將這兩個地區設定的影像儲存成 {@code icon_ca.png} ({@code icon.png} 以外的任何名稱),然後將該影像放入預設的 {@code res/drawable/} 目錄。
+
+之後,在 {@code
+res/drawable-en-rCA/} 建立一個 {@code icon.xml} 檔案,以及建立 {@code res/drawable-fr-rCA/},用於參照使用 {@code &lt;bitmap&gt;} 元素的 {@code icon_ca.png} 資源。
+這樣可以讓您只儲存一個版本的 PNG 檔案,以及指向該檔案的兩個小 XML 檔案。
+(範例 XML 檔案如下所示。)</p>
+
+
+<h4>可繪項目</h4>
+
+<p>如要為現有的可繪項目建立別名,請使用 {@code &lt;bitmap&gt;} 元素。
+例如:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;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
+R.drawable.icon_ca} 資源 (儲存在 {@code res/drawable/}) 的別名。
+</p>
+
+
+<h4>版面配置</h4>
+
+<p>如要為現有的可繪項目建立別名,請使用以 {@code &lt;merge&gt;} 包裝的{@code &lt;include&gt;} 元素。
+例如:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;merge>
+ &lt;include layout="@layout/main_ltr"/>
+&lt;/merge>
+</pre>
+
+<p>如果您將此檔案儲存成 {@code main.xml},系統會將它編譯成可當作 {@code R.layout.main} 參照的資源,但它實際上是 {@code R.layout.main_ltr} 資源的別名。
+
+</p>
+
+
+<h4>字串和其他簡單值</h4>
+
+<p>如要為現有的字串建立別名,只要將所需字串的資源 ID 當作新字串的值即可。
+例如:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;resources>
+ &lt;string name="hello">Hello&lt;/string>
+ &lt;string name="hi">@string/hello&lt;/string>
+&lt;/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>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;resources>
+ &lt;color name="yellow">#f00&lt;/color>
+ &lt;color name="highlight">@color/red&lt;/color>
+&lt;/resources>
+</pre>
+
+
+
+
+<h2 id="Compatibility">使用資源提供最佳的裝置相容性</h2>
+
+<p>如要讓您的應用程式支援多個裝置設定,務必要為您應用程式使用的每個資源類型提供預設資源。
+</p>
+
+<p>例如,如果您的應用程式支援多個語言,一律要包含一個 {@code
+values/} 目錄 (儲存字串的位置),其中「不包含」<em></em><a href="#LocaleQualifier">語言和區域限定詞</a>。如果您將所有字串檔案放在含有語言和區域限定詞的目錄中,當執行應用程式的裝置,其語言設定不受字串支援時,應用程式就會當機。
+
+不過,只要您提供預設 {@code values/} 資源,
+應用程式就能正常運作 (即便使用者不懂該語言 &mdash; 仍然比當機好)。
+</p>
+
+<p>同樣地,如果您根據螢幕方向提供不同的版面配置資源,您應該選擇一個方向做為您的預設值。
+例如,不要在 {@code
+layout-land/} 提供橫向版面配置資源及在 {@code layout-port/} 提供直向版面配置資源,而是留下一個做為預設值,例如 {@code layout/} 做為橫向和 {@code layout-port/} 做為直向。
+</p>
+
+<p>提供預設資源很重要,這不只是因為您的應用程式可能執行您未預期到的設定,還因為新的 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 或高,當您提供含有<em></em><a href="#DensityQualifier">螢幕密度</a>限定詞的替代可繪項目資源時,則不需要預設可繪項目資源。
+
+即使沒有預設可繪項目資源,Android 仍然可從替代螢幕密度中找到最符合的項目,並視需要縮放點陣圖。
+
+不過,為了在所有裝置類型獲得最佳體驗,您應該為這三種密度類型提供替代可繪項目。
+</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>drawable-fr-rCA/</code> 目錄,因為它與 <code>en-GB</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>螢幕像素密度是唯一沒有因為衝突而被排除的限定詞。
+即使裝置的螢幕密度是 hdpi 但仍然沒有排除
+<code>drawable-port-ldpi/</code>,因為此刻每個螢幕密度都視為相符。
+如需詳細資訊,請參閱<a href="{@docRoot}guide/practices/screens_support.html">支援多個螢幕</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">支援多個螢幕</a>。
+</p>
+ </li>
+
+ <li>重複步驟 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>根據螢幕大小限定詞選取資源時,如果沒有最符合的資源,系統會使用適用於比目前螢幕更小之螢幕設計的資源 (例如,如有需要,大型螢幕會使用一般大小螢幕資源)。
+
+然而,如果唯一可用的資源比目前螢幕<em>更大</em>,系統將<strong>不會</strong>使用這些資源,如果沒有其他資源符合裝置設定,則應用程式將會當機 (例如,如果所有版面配置資源都標記為 {@code xlarge} 限定詞,但裝置為一般大小螢幕)。
+
+
+
+</p>
+
+<p class="note"><strong>注意:</strong>限定詞的優先等級<em></em> (在<a href="#table2">表 2</a>) 比完全符合裝置的限定詞數量更重要。
+例如,在上述步驟 4,清單的最後一個選擇包含三個完全符合裝置的限定詞 (方向、觸控螢幕類型和輸入方法),而 <code>drawable-en</code> 只有一個相符的參數(語言)。
+
+
+然而,語言的優先等級高於這些其他限定詞,因此將排除
+<code>drawable-port-notouch-12key</code>。</p>
+
+<p>如需深入瞭解在應用程式使用資源的方法,請繼續閱讀<a href="accessing-resources.html">存取資源</a>。</p>
diff --git a/docs/html-intl/intl/zh-tw/guide/topics/resources/runtime-changes.jd b/docs/html-intl/intl/zh-tw/guide/topics/resources/runtime-changes.jd
new file mode 100644
index 000000000000..7a8b3ae7fc3a
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/guide/topics/resources/runtime-changes.jd
@@ -0,0 +1,281 @@
+page.title=處理執行階段變更
+page.tags=Activity、生命週期
+@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">快速的螢幕方向變更
+</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">Activity 生命週期</a>將您的 Activity 還原為之前的狀態,其中 Android 會先呼叫
+{@link android.app.Activity#onSaveInstanceState(Bundle) onSaveInstanceState()} 再終結您的 Activity,讓您能儲存應用程式狀態的相關資料。
+
+
+之後,您便能在 {@link android.app.Activity#onCreate(Bundle) onCreate()} 或 {@link
+android.app.Activity#onRestoreInstanceState(Bundle) onRestoreInstanceState()} 期間還原狀態。
+</p>
+
+<p>如要測試您的應用程式是否使用原本的應用程式狀態重新啟動,您應該在應用程式執行各種工作時呼叫設定變更 (例如變更螢幕方向)。
+
+您的應用程式應該能隨時重新啟動而不會遺失使用者資料或狀態,以便處理設定變更這類事件,或是使用者接聽來電,然後很久後才在應用程式程序可能終結後才返回應用程式的這類情況。
+
+
+如要瞭解如何還原您的 Activity 狀態,請參閱 <a href="{@docRoot}guide/components/activities.html#Lifecycle">Activity 生命週期</a>。</p>
+
+<p>不過,您可能遇到重新啟動應用程式以及還原大量資料的成本很昂貴,而且會產生使用者體驗不佳的情況。
+在這種情況下,您有兩種其他選擇:
+</p>
+
+<ol type="a">
+ <li><a href="#RetainingAnObject">變更設定期間保留物件</a>
+ <p>允許您的 Activity 在設定變更時重新啟動,但將可設定狀態的物件帶到 Activity 的新執行個體中。
+</p>
+
+ </li>
+ <li><a href="#HandlingTheChange">自行處理設定變更</a>
+ <p>避免系統在某些設定變更期間重新啟動您的 Activity,但在設定變更時接收回呼,您便能視需要手動更新您的 Activity。
+
+</p>
+ </li>
+</ol>
+
+
+<h2 id="RetainingAnObject">變更設定期間保留物件</h2>
+
+<p>如果重新啟動您的 Activity 需要復原大量資料、重新建立網路連線或執行其他密集型操作,則由於設定變更造成的完整重新啟動可能會拖慢使用者體驗。
+
+此外,您可能無法透過 {@link android.os.Bundle} 完全還原您的 Activity 狀態,這是系統透過 {@link android.app.Activity#onSaveInstanceState(Bundle) onSaveInstanceState()} 回呼所為您所儲存的&mdash;它的設計並不是用來傳送大型物件 (例如點陣圖),而且其中的資料必須先序列化再還原序列化,這會耗用大量記憶體並讓設定變更變慢。
+
+
+
+在這種情況下,您可以在 Activity 因設定變更而重新啟動時,透過保留 {@link
+android.app.Fragment} 的方式來減少重新初始化 Activity 的負擔。
+這個片段可包含您要保留可設定狀態物件的參考資料。
+</p>
+
+<p>當 Android 系統因設定變更而關閉您的 Activity 時,您標示要保留的 Activity 片段不會被終結。
+您可以將這類片段新增至您的 Activity 以保留可設定狀態的物件。
+</p>
+
+<p>如要在執行階段設定變更期間,在片段中保留可設定狀態的物件:</p>
+
+<ol>
+ <li>延伸 {@link android.app.Fragment} 類別並宣告可設定狀態物件的參考資料。
+</li>
+ <li>片段建立之後,呼叫 {@link android.app.Fragment#setRetainInstance(boolean)}。
+ </li>
+ <li>將片段新增至您的 Activity。</li>
+ <li>當 Activity 重新啟動時,使用 {@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
+ &#64;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.app.Activity} 相關的物件,例如 {@link
+android.graphics.drawable.Drawable}、{@link android.widget.Adapter}、{@link android.view.View} 或任何與 {@link android.content.Context} 關聯的其他物件。
+
+如果您這樣做,會流失原始 Activity 執行個體的所有檢視和資源。
+(資源流失表示您的應用程式會繼續保留資源但無法回收記憶體,因此會流失大量記憶體。)
+
+</p>
+
+<p>然後使用 {@link android.app.FragmentManager} 將片段新增至您的 Activity。您可以在執行階段設定變更期間,於 Activity 再次啟動時,從片段取得資料物件。
+
+例如,將您的 Activity 定義如下:</p>
+
+<pre>
+public class MyActivity extends Activity {
+
+ private RetainedFragment dataFragment;
+
+ &#64;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()
+ ...
+ }
+
+ &#64;Override
+ public void onDestroy() {
+ super.onDestroy();
+ // store the data in the fragment
+ dataFragment.setData(collectMyLoadedData());
+ }
+}
+</pre>
+
+<p>在此範例中,{@link android.app.Activity#onCreate(Bundle) onCreate()} 會在 Activity 新增片段或還原參考資料。
+{@link android.app.Activity#onCreate(Bundle) onCreate()} 也會在片段執行個體內儲存可設定狀態的物件。
+
+{@link android.app.Activity#onDestroy() onDestroy()} 會在保留的片段執行個體內更新可設定狀態的物件。
+</p>
+
+
+
+
+
+<h2 id="HandlingTheChange">自行處理設定變更</h2>
+
+<p>如果您的應用程式在特定設定變更期間不需要更新資源,「且」<em></em>您具有效能限制,要求您避免 Activity 重新啟動,則您可以宣告您的 Activity 自行處理設定變更,這樣可避免系統重新啟動您的 Activity。
+
+
+</p>
+
+<p class="note"><strong>注意:</strong>自行處理設定變更讓替代資源的使用變得更加困難,因為系統無法幫您自動套用。
+
+當您必須避免因為設定變更而造成重新啟動時,應將這個方式視為最後手段,而且不建議對大部分的應用程式使用。
+</p>
+
+<p>如要宣告您的 Activity 處理設定變更,可在宣示說明檔案中編輯適當的 <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</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>例如,下列宣示說明程式碼宣告同時處理螢幕方向變更和鍵盤可用性變更的 Activity:
+</p>
+
+<pre>
+&lt;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} 中的欄位時,您可判斷新的設定,並且更新您介面中使用的資源來進行適當的變更。
+
+此時,會呼叫這個方法,Activity 的 {@link android.content.res.Resources} 物件會根據新設定進行更新以傳回資源,因此您便能輕鬆地重新設定 UI 的元素,系統無需重新啟動您的 Activity。
+
+
+</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
+"orientation"} 值之外,您還必須包含 {@code "screenSize"} 值。
+
+也就是說,您必須宣告 {@code
+android:configChanges="orientation|screenSize"}。不過,如果您的應用程式是針對 API 級別 12 或更低級別,則您的 Activity 一律要自行處理這個設定變更 (即使在 Android 3.2 或更高版本的裝置上執行時,這個設定變更也不會重新啟動您的 Activity)。
+
+</p>
+
+<p>例如,下列 {@link
+android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()} 實作會檢查目前的裝置方向:
+</p>
+
+<pre>
+&#64;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#setImageResource(int)
+setImageResource()} 重新設定任何 {@link android.widget.ImageView}並且針對新設定,使用適當的資源 (如<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>當您宣告您的 Activity 以處理設定變更時,您要負責為提供的替代項目重新設定所有元素。
+如果您宣告您的 Activity 以處理方向變更,而且具有應該在橫向與直向之間進行方向變更的影像,則您必須在 {@link
+android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()} 期間對每個元素重新指派每個資源。
+
+</p>
+
+<p>如果您不需要根據這些設定變更來更新您的應用程式,可改為不必<em></em>實作 {@link
+android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()}。
+在此情況下,仍然可使用設定變更前使用的所有資源,而您只要避免重新啟動您的 Activity 即可。
+
+不過,您的應用程式應該能夠關閉以及重新啟動成之前原本的狀態,因此在一般 Activity 生命週期期間無法保留您的狀態時,就不應考慮使用這個方法。
+
+這不只是因為有其他設定變更讓您無法防止重新啟動應用程式,還因為有您應該處理事件,例如當使用者離開應用程式後,使用者返回應用程式之前應用程式已終結。
+
+
+</p>
+
+<p>如需有關您在 Activity 中可以處理哪些設定變更的詳細資訊,請參閱 <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/zh-tw/guide/topics/ui/controls.jd b/docs/html-intl/intl/zh-tw/guide/topics/ui/controls.jd
new file mode 100644
index 000000000000..0f27ae4e8803
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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>在使用者介面中加入輸入控制項,就如同將 XML 元素加到 <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML 版面配置</a>一樣簡單。例如,以下是包含文字欄位和按鈕的版面配置:
+</p>
+
+<pre style="clear:right">
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="horizontal">
+ &lt;EditText android:id="@+id/edit_message"
+ android:layout_weight="1"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:hint="@string/edit_message" />
+ &lt;Button android:id="@+id/button_send"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/button_send"
+ android:onClick="sendMessage" />
+&lt;/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>功用與核取方塊類似,但會限制使用者只能從一組選項中選取一個選項。</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>可供使用者從一組選項中選取單一值的下拉式清單。</td>
+ <td>{@link android.widget.Spinner Spinner} </td>
+ </tr>
+ <tr>
+ <td><a href="controls/pickers.html">挑選器</a></td>
+ <td>可供使用者透過向上/向下按鈕或滑動手勢選取單一值的對話方塊。此外,挑選器還會提供 <code>DatePicker</code> 程式碼小工具和 <code>TimePicker</code> 小工具,分別讓使用者輸入日期值 (年、月、日) 以及時間值 (小時、分鐘、AM/PM);系統會自動根據使用者所在的地區為這些值設定對應的格式。</td>
+ <td>{@link android.widget.DatePicker}、{@link android.widget.TimePicker}</td>
+ </tr>
+</table>
diff --git a/docs/html-intl/intl/zh-tw/guide/topics/ui/declaring-layout.jd b/docs/html-intl/intl/zh-tw/guide/topics/ui/declaring-layout.jd
new file mode 100644
index 000000000000..72755715e3a2
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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">Activity</a> 或<a href="{@docRoot}guide/topics/appwidgets/index.html">應用程式小工具</a>的使用者介面) 的視覺結構。您可以兩種方式宣告版面配置:
+</p>
+<ul>
+<li><strong>在 XML 中宣告 UI 元素</strong>。Android 提供的 XML 字彙不僅簡單明瞭,還可對應至 View 類別和子類別 (例如小工具和版面配置)。
+</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">Eclipse 專用的 ADT 外掛程式</a>可提供 XML 的版面配置預覽 &mdash; 只要開啟您想預覽的 XML 檔案,然後選取 [版面配置]<strong></strong> 標籤即可。
+
+</li>
+ <li>同時也建議您使用 <a href="{@docRoot}tools/debugging/debugging-ui.html#hierarchyViewer">階層檢視器</a>工具針對版面配置進行除錯 &mdash; 這項工具會顯示版面配置屬性值、繪製線框並在其中加上編距/邊界標記,以及提供完整檢視 (如果您是透過模擬器或裝置進行除錯的話)。
+
+
+
+</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 字彙,快速設計 UI 版面配置和其中包含的螢幕元素,方法與採用 HTML 建立網頁相同 &mdash; 都需要建置一系列巢狀元素。 </p>
+
+<p>每個版面配置檔案均需包含 1 個根元素 (必須為 View 或 ViewGroup 物件)。定義根元素後,您就可以將額外的物件或小工具新增為子元素,逐步建置檢檢視階層視階層來定義您的版面配置。例如,以下是使用直向 {@link android.widget.LinearLayout} 以納入
+{@link android.widget.TextView} 和 {@link android.widget.Button} 的 XML 版面配置:</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+ &lt;TextView android:id="@+id/text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Hello, I am a TextView" />
+ &lt;Button android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Hello, I am a Button" />
+&lt;/LinearLayout>
+</pre>
+
+<p>在 XML 中宣告版面配置後,請使用 <code>.xml</code> 副檔名將檔案儲存到 Android 專案的 <code>res/layout/</code> 目錄中,藉此讓系統妥善加以編譯。
+ </p>
+
+<p>如要進一步瞭解 XML 版面配置檔案的語法,請參閱<a href="{@docRoot}guide/topics/resources/layout-resource.html">版面配置資源</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>,您就必須針對如下所示的 Activity 載入該 XML:
+
+
+
+
+</p>
+<pre>
+public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main_layout);
+}
+</pre>
+
+<p>Android 架構會在 Activity 啟動時呼叫 Activity 中的 <code>onCreate()</code> 回呼方法 (如需生命週期相關資訊,請參閱 <a href="{@docRoot}guide/components/activities.html#Lifecycle">Activity</a>)。
+
+
+</p>
+
+
+<h2 id="attributes">屬性</h2>
+
+<p>所有 View 和 ViewGroup 物件均支援本身專用的各種 XML 屬性。部分屬性僅適用於 View 物件 (例如 TextView 可支援 <code>textSize</code> 屬性),不過可能延伸這個類別的 View 物件也會沿用這些屬性。由於某些屬性是沿用自 View 根類別,因此會成為所有 View 物件的常用屬性 (例如 <code>id</code> 屬性)。
+
+
+
+而系統會將其他屬性視為「版面配置參數」,這些屬性可說明 View 物件的特定版面配置方向 (View 由物件的 ViewGroup 上層物件所定義)。
+
+</p>
+
+<h3 id="id">ID</h3>
+
+<p>任何 View 物件都可能包含一個相關聯的整數 ID,可用於識別樹狀結構中的 View。在應用程式編寫期間,雖然這個 ID 通常是在 XML 版面配置檔案的 <code>id</code> 屬性中指派為字串,系統仍會將其解讀為整數。此為所有 View 物件常用的 XML 屬性 (由 {@link android.view.View} 類別所定義);您會經常使用的這項屬性。以下是 XML 標記中的 ID 語法:
+
+
+
+
+</p>
+<pre>android:id="&#64;+id/my_button"</pre>
+
+<p>字串開頭的 @ 符號可指示 XML 剖析器應剖析或展開 ID 字串的其餘部分,並且將其視為 ID 資源。
+加號符號 (+) 表示此為系統必須建立並加到資源 (<code>R.java</code> 檔案) 中的新資源名稱。
+Android 架構提供了多種其他 ID 資源。
+參照 Android 資源 ID 時,您不必加入 + 符號,但必須加入 <code>android</code> 套件命名空間,如下所示:
+</p>
+<pre>android:id="&#64;android:id/empty"</pre>
+<p>只要加入 <code>android</code> 套件命名空間,系統就會從 <code>android.R</code> 資源類別參照 ID,而不是從本機資源類別。
+</p>
+
+<p>以下是透過應用程式建立檢視和參照的一般方法:</p>
+<ol>
+ <li>在版面配置檔案中定義檢視/小工具,並為該檔案指派不重複 ID:
+<pre>
+&lt;Button android:id="&#64;+id/my_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="&#64;string/my_button_text"/>
+</pre>
+ </li>
+ <li>接著,建立檢視物件執行個體,並從版面配置中擷取該執行個體 (通常使用 <code>{@link android.app.Activity#onCreate(Bundle) onCreate()}</code> 方法進行擷取):
+
+<pre>
+Button myButton = (Button) findViewById(R.id.my_button);
+</pre>
+ </li>
+</ol>
+<p>請務必在建立 {@link android.widget.RelativeLayout} 時為檢視物件定義 ID。在相關的版面配置中,同層級的檢視可將本身的版面配置與其他同層級的檢視建立關聯,而不重複 ID 正是這些版面配置的參照依據。
+
+</p>
+<p>整個樹狀結構的 ID 不必是不重複 ID,但您所搜尋樹狀結構部分的 ID 就必須是不重複 ID (由於您搜尋的部分通常是整個樹狀結構,因此建議您為其定義不重複 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} 的巢狀類別。這個子類別包含定義下層檢視大小和位置的屬性類型,而這些屬性類型也適用於檢視群組。
+
+如圖 1 所示,上層檢視群組為每個下層檢視 (包括下層檢視群組) 定義了版面配置參數。
+</p>
+
+<img src="{@docRoot}images/layoutparams.png" alt="" />
+<p class="img-caption"><strong>圖 1.</strong>檢視層級以及與每個檢視相關聯的版面配置參數。
+</p>
+
+<p>請注意,所有 LayoutParams 子類別都包含用於設定值的專屬語法。
+而每個子元素都必須定義適用於其上層元素的 LayoutParams,即便子元素也會為其下層物件定義不同的 LayoutParams。
+ </p>
+
+<p>所有檢視群組均包含寬度和高度 (<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> ) 可指示檢視自行將大小擴展成上層檢視群組允許的上限。
+</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>座標表示),以及兩個尺寸值 (以寬度和高度表示)。
+
+位置和尺寸的單位均為像素。
+
+ </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>
+ 檢視的大小是以寬度和高度表示。單一檢視會包含兩組寬度和高度值。
+
+ </p>
+
+ <p>
+ 第一組值稱為「寬度測定值」<em></em>和「高度測定值」<em></em>,
+可定義檢視在上層項目中的尺寸。
+您可以呼叫 {@link android.view.View#getMeasuredWidth()} 和 {@link android.view.View#getMeasuredHeight()} 來取得尺寸測定值。
+
+
+ </p>
+
+ <p>
+ 第二組值簡稱「寬度」<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>
+ 雖然檢視可定義邊距,但無法針對邊界提供任何支援。
+不過,檢視群組可提供這類支援。詳情請參閱
+{@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>雖然您可以將版面配置套疊在一起來符合您的 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 &mdash; 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>這種版面配置可將其下層物件整合至單一水平或垂直列。如果視窗長度超過螢幕長度,線性版面配置就會建立捲軸方便使用者捲動畫面。
+</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} 版面配置的中間人 &mdash; {@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>這種版面配置可顯示能夠捲動的單欄清單。</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.view.View},藉此填入 {@link android.widget.AdapterView} (例如 {@link android.widget.ListView} 或 {@link android.widget.GridView}。
+</p>
+
+<p>Android 提供數個 {@link android.widget.Adapter} 子類別可用於擷取不同資料類型以及為 {@link android.widget.AdapterView} 建置檢視。
+以下是兩種常見的配接器:
+</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&lt;String> adapter = new ArrayAdapter&lt;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.TextView} 以外的所有項目建立檢視 (例如,如果您想為所有陣列項目建立 {@link android.widget.ImageView}),請延伸 {@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},以及下列兩個陣列:
+</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
+fromColumns} 項目插入相對應的 {@code toViews} 檢視,藉此利用提供的版面配置為
+{@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/zh-tw/guide/topics/ui/dialogs.jd b/docs/html-intl/intl/zh-tw/guide/topics/ui/dialogs.jd
new file mode 100644
index 000000000000..b0ae12ea3a19
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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">建立對話方塊片段</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">針對大型螢幕將 Activity 顯示為對話方塊</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>這種對話方塊可以顯示一個標題、最多三個按鈕、一系列可選取項目或一個自訂版面配置。
+</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">進度和 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 中的可嵌入元件 (例如當您想讓對話方塊使用者介面在大型和小型螢幕上呈現不同外觀時)。
+
+</p>
+
+<p>本指南的以下各節說明如何搭配 {@link android.app.AlertDialog} 物件使用 {@link
+android.support.v4.app.DialogFragment}。
+如果您是想建立日期或時間挑選器,請改為參閱<a href="{@docRoot}guide/topics/ui/controls/pickers.html">挑選器</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.support.v4.app.DialogFragment</code> 類別,而「不是」<em></em><code>android.app.DialogFragment</code>。
+
+</p>
+
+
+<h2 id="DialogFragment">建立對話方塊片段</h2>
+
+<p>如果想建立多種對話方塊設計 &mdash; 包括自訂版面配置和<a href="{@docRoot}design/building-blocks/dialogs.html">對話方塊</a>設計指南中所述的對話方塊設計 &mdash; 只要延伸
+{@link android.support.v4.app.DialogFragment} 然後利用
+{@link android.support.v4.app.DialogFragment#onCreateDialog
+onCreateDialog()} 回呼方法建立 {@link android.app.AlertDialog} 即可。
+
+</p>
+
+<p>例如,假設您利用 {@link android.support.v4.app.DialogFragment} 管理以下的基本
+{@link android.app.AlertDialog}:</p>
+
+<pre>
+public class FireMissilesDialogFragment extends DialogFragment {
+ &#64;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>
+包含一段訊息和兩個動作按鈕的對話方塊。</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>單一對話方塊最多只能包含 3 個動作按鈕。</p></li>
+</ol>
+
+<p>{@link android.app.AlertDialog.Builder} 類別提供的 API 可讓您建立包含這些內容類型 (包括自訂版面配置) 的 {@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>正面</dt>
+ <dd>這種按鈕的用途是接受及繼續進行特定動作 (「確定」按鈕)。</dd>
+ <dt>負面</dt>
+ <dd>這種按鈕的用途是取消動作。</dd>
+ <dt>中立</dt>
+ <dd>如果使用者不想繼續進行特定動作,但並非要取消動作,請使用這種按鈕。
+這種按鈕會顯示在正面和負面按鈕之間。
+範例:[稍後提醒我] 按鈕。</dd>
+</dl>
+
+<p>您可以將以上其中一種按鈕加入 {@link
+android.app.AlertDialog};換句話說,您最多只能加入一個「正面」按鈕。</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">
+&#64;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">使用配接器建置版面配置</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>例如,以下說明如何建立如圖 4 所示能夠在 {@link java.util.ArrayList} 中儲存所選項目的多重選項清單:
+
+</p>
+
+<pre style="clear:right">
+&#64;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() {
+ &#64;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() {
+ &#64;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() {
+ &#64;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>
+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ &lt;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" />
+ &lt;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" />
+ &lt;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"/>
+&lt;/LinearLayout>
+</pre>
+
+<p class="note"><strong>提示:</strong>在預設情況下,如果您設定 {@link android.widget.EditText} 元素使用 {@code "textPassword"} 輸入類型,字型系列就會設為等寬字型,因此您必須將該元素的字型系列變更為 {@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,第二個參數則是版面配置的上層檢視)。接著,您可以呼叫 {@link android.app.AlertDialog#setView setView()} 來取代對話方塊中的版面配置。
+
+
+
+
+
+</p>
+
+<pre>
+&#64;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() {
+ &#64;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.Activity} 顯示為對話方塊,而不是使用 {@link android.app.Dialog} API。
+
+方法很簡單,只要建立 Activity 然後在 <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
+&lt;activity&gt;}</a> 宣示說明元素中將其主題設為
+{@link android.R.style#Theme_Holo_Dialog Theme.Holo.Dialog} 即可:
+</p>
+
+<pre>
+&lt;activity android:theme="&#64;android:style/Theme.Holo.Dialog" >
+</pre>
+<p>這樣一來,Activity 就會顯示在對話方塊視窗,而不是以全螢幕模式顯示。</p>
+</div>
+
+
+
+<h2 id="PassingEvents">將事件傳回對話方塊的主控件</h2>
+
+<p>使用者在對話方塊中輕觸任一動作按鈕或從清單中選取一個項目後,您的 {@link android.support.v4.app.DialogFragment} 可能會自行執行必要動作,不過,您通常會想將事件傳送到 Activity 或對話方塊開啟的片段。
+
+
+如要這麼做,請透過每個點擊事件類型適用的方法定義介面,然後在會接收對話方塊的動作事件的主機元件中實作該介面。
+
+</p>
+
+<p>例如,以下是定義用於將事件傳回主機 Activity 的介面的 {@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
+ &#64;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>代管對話方塊的 Activity 會建立包含對話方塊片段的建構函式的對話方塊執行個體,以及透過您實作的 {@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
+ &#64;Override
+ public void onDialogPositiveClick(DialogFragment dialog) {
+ // User touched the dialog's positive button
+ ...
+ }
+
+ &#64;Override
+ public void onDialogNegativeClick(DialogFragment dialog) {
+ // User touched the dialog's negative button
+ ...
+ }
+}
+</pre>
+
+<p>由於主機 Activity 會實作 {@code NoticeDialogListener} &mdash; 如上所述的 {@link android.support.v4.app.Fragment#onAttach onAttach()} 回呼方法會強制執行這個 Activity &mdash; 因此對話方塊片段可以使用介面回呼方法將點擊事件傳送到 Activity:
+
+
+</p>
+
+<pre>
+public class NoticeDialogFragment extends DialogFragment {
+ ...
+
+ &#64;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.FragmentManager},請呼叫
+{@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()}。例如:</p>
+
+<pre>
+public void confirmFireMissiles() {
+ DialogFragment newFragment = new FireMissilesDialogFragment();
+ newFragment.show(getSupportFragmentManager(), "missiles");
+}
+</pre>
+
+<p>第二個引數 {@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>以下的 {@link android.support.v4.app.DialogFragment} 範例可顯示為對話方塊或可嵌入片段 (使用名為 <code>purchase_items.xml</code> 的版面配置):
+</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. */
+ &#64;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. */
+ &#64;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>
+&lt;!-- Default boolean values -->
+&lt;resources>
+ &lt;bool name="large_layout">false&lt;/bool>
+&lt;/resources>
+</pre>
+
+<p class="code-caption">res/values-large/bools.xml</p>
+<pre>
+&lt;!-- Large screen boolean values -->
+&lt;resources>
+ &lt;bool name="large_layout">true&lt;/bool>
+&lt;/resources>
+</pre>
+
+<p>接著,您可以在呼叫 Activity 的 {@link android.app.Activity#onCreate onCreate()} 方法時初始化 {@code mIsLargeLayout} 值:
+</p>
+
+<pre>
+boolean mIsLargeLayout;
+
+&#64;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">針對大型螢幕將 Activity 顯示為對話方塊</h3>
+
+<p>您可以針對大型螢幕將 {@link android.app.Activity} 顯示為對話方塊,而不是將對話方塊顯示為全螢幕 UI,藉此達到相同結果。
+
+您要採用的方法取決於您的應用程式設計,但如果您的應用程式是針對小型螢幕進行設計,將 Activity 顯示為對話方塊通常就能獲得良好效果,而如果您想針對平板電腦改善使用者體驗,請將生命週期較短的 Activity 顯示為對話方塊。
+
+
+</p>
+
+<p>如果只想針對大型螢幕將 Activity 顯示為對話方塊,請為 <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
+&lt;activity&gt;}</a> 宣示元素套用 {@link android.R.style#Theme_Holo_DialogWhenLarge Theme.Holo.DialogWhenLarge} 主題:
+
+</p>
+
+<pre>
+&lt;activity android:theme="&#64;android:style/Theme.Holo.DialogWhenLarge" >
+</pre>
+
+<p>如要進一步瞭解如何運用主題設定 Activity 的樣式,請參閱<a href="{@docRoot}guide/topics/ui/themes.html">樣式和主題</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()}「而不是」<em></em>{@link android.support.v4.app.DialogFragment#onCancel onCancel()}。
+
+
+因此,我們通常建議您在使用者點擊您對話方塊中的「正面」<em></em>按鈕以便將對話方塊從檢視移除時,呼叫 {@link android.support.v4.app.DialogFragment#dismiss dismiss()}。
+
+</p>
+
+
diff --git a/docs/html-intl/intl/zh-tw/guide/topics/ui/menus.jd b/docs/html-intl/intl/zh-tw/guide/topics/ui/menus.jd
new file mode 100644
index 000000000000..be1fa7f0dfda
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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">允許將 Activity 新增至其他選單</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">動作列</a></li>
+ <li><a href="{@docRoot}guide/topics/resources/menu-resource.html">選單資源</a></li>
+ <li><a href="http://android-developers.blogspot.com/2012/01/say-goodbye-to-menu-button.html">和選單按鈕說再見
+</a></li>
+ </ol>
+</div>
+</div>
+
+<p>選單在許多類型的應用程式中都是常見的使用者介面元件。為提供熟悉且一致的使用者體驗,您應該使用
+{@link android.view.Menu} API 來呈現 Activity 中的使用者動作與其他選項。
+</p>
+
+<p>從 Android 3.0 (API 級別 11) 開始,提供 Android 的裝置不再需要提供專屬的「選單」<em></em>按鈕。
+有此變更之後,Android 應用程式應可脫離對傳統有 6 個項目的選單面板的依賴,改為提供動作列來呈現一般的使用者動作。
+
+</p>
+
+<p>雖然有些選單項目的設計與使用者體驗有所變更,但依然是根據
+{@link android.view.Menu} API 來定義一組動作與選項的語意。本指南說明如何在所有版本的 Android 上,建立三個基本類型的選單或動作呈現方式:
+
+</p>
+
+<dl>
+ <dt><strong>選項選單和動作列</strong></dt>
+ <dd><a href="#options-menu">選項選單</a>是 Activity 的主要選單項目集合。
+您應該將對應用程式有全域影響的動作放置在此,例如「搜尋」、「撰寫電子郵件」及「設定」。
+
+ <p>如果您是為 Android 2.3 以下版本進行開發,使用者可按下「選單」<em></em>按鈕來顯示選項選單面板。
+</p>
+ <p>在 Android 3.0 以上版本,選項選單的項目是當成螢幕上的動作項目與溢出選項組合,以<a href="{@docRoot}guide/topics/ui/actionbar.html">動作列</a>呈現。
+從 Android 3.0 開始,「選單」<em></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>彈出式選單顯示的項目清單會以垂直清單的方式,錨定在呼叫該選單的檢視。
+它很適合用來提供與特定內容有關的動作溢出,或針對第二部分的命令提供選項。
+彈出式選單中的動作「不」<strong></strong>應直接影響對應內容,應由內容關聯動作直接影響。
+
+彈出式選單主要用於您 Activity 中與內容區域相關的延伸動作。
+
+ <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>中定義選單與其相關項目,而不是在您 Activity 的程式碼中建置選單。
+接著,您可以擴大 Activity 或片段中的選單資源 (當成
+{@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>&lt;menu></code></dt>
+ <dd>定義選單項目的容器 {@link android.view.Menu}。<code>&lt;menu></code> 元素必須是檔案的根節點,並可保留一或多個
+<code>&lt;item></code> 與 <code>&lt;group></code> 元素。
+</dd>
+
+ <dt><code>&lt;item></code></dt>
+ <dd>建立代表選單中單一項目的 {@link android.view.MenuItem}。此元素可以包含巢狀
+<code>&lt;menu></code> 元素以建立子選單。</dd>
+
+ <dt><code>&lt;group></code></dt>
+ <dd>可供 {@code &lt;item&gt;} 元素選用的不可見容器。它可讓您將選單項目分類,以便分享屬性,例如有效狀態與可見度。
+如需詳細資訊,請參閱<a href="#groups">建立選單群組</a>。
+</dd>
+</dl>
+
+
+<p>稱為 <code>game_menu.xml</code> 的範例選單如下:</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
+ &lt;item android:id="@+id/new_game"
+ android:icon="@drawable/ic_new_game"
+ android:title="@string/new_game"
+ android:showAsAction="ifRoom"/&gt;
+ &lt;item android:id="@+id/help"
+ android:icon="@drawable/ic_help"
+ android:title="@string/help" /&gt;
+&lt;/menu&gt;
+</pre>
+
+<p><code>&lt;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">選單資源</a>。</p>
+
+<p>您可以藉由將 {@code &lt;menu&gt;} 元素新增為 {@code &lt;item&gt;} 的子項,將子選單新增至任何選單 (子選單除外) 的項目。
+當您的應用程式有很多可按主題分類的功能,例如 PC 應用程式選單列中的項目 (檔案、編輯、檢視等等) 時,子選單相當有用。
+
+例如:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
+ &lt;item android:id="@+id/file"
+ android:title="@string/file" &gt;
+ &lt;!-- "file" submenu --&gt;
+ &lt;menu&gt;
+ &lt;item android:id="@+id/create_new"
+ android:title="@string/create_new" /&gt;
+ &lt;item android:id="@+id/open"
+ android:title="@string/open" /&gt;
+ &lt;/menu&gt;
+ &lt;/item&gt;
+&lt;/menu&gt;
+</pre>
+
+<p>如要在 Activity 中使用選單,您必須使用 {@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>您應該在選項選單中包括與目前 Activity 內容關聯動作和其他選項,例如「搜尋」、「撰寫電子郵件」及「設定」。
+</p>
+
+<p>選項選單中的項目會顯示在螢幕上的哪個位置,取決於您為其開發應用程式的版本。
+</p>
+
+<ul>
+ <li>如果您為「Android 2.3.x (API 級別 10) 以下版本」<strong></strong>開發應用程式,當使用者按下[選單]<em></em> 按鈕,選項選單的內容會顯示在螢幕底部,如圖 1 所示。
+
+開啟時,第一個可見部分就是最多可保留六個選單項目的圖示選單。
+
+如果您的選單包含六個以上的項目,Android 會將第六個與其餘的項目放入溢出選單,使用者可透過選取[更多]<em></em> 來開啟。
+
+</li>
+
+ <li>如果您為「Android 3.0 (API 級別 11) 以上版本」<strong></strong>開發應用程式,選項選單中的項目會顯示在<a href="{@docRoot}guide/topics/ui/actionbar.html">動作列</a>。
+在預設情況下,系統會將所有項目放入動作溢出,使用者可以利用動作列右側的動作溢出圖示來顯示 (或按裝置的「選單」<em></em>按鈕,如果有的話)。
+
+為了能夠快速存取重要的動作,您可以將 {@code android:showAsAction="ifRoom"} 新增至對應的 {@code &lt;item&gt;} 元素,將要顯示在動作列的幾個項目升階 (請參閱圖 2)。
+
+
+
+ <p>如需動作項目與其他動作列行為的詳細資訊,請參閱<a href="{@docRoot}guide/topics/ui/actionbar.html">動作列</a>指南。 </p>
+<p class="note"><strong>注意:</strong>即使您「並非」<em></em>為 Android 3.0 以上版本進行開發,您仍可建置自己的動作列版面配置,達到類似的效果。
+如需如何支援舊版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 圖片庫</a>應用程式的動作列,顯示導覽索引標籤與相機動作項目 (再加上動作溢出按鈕)。
+</p>
+
+<p>您可以從 {@link android.app.Activity} 子類別或 {@link android.app.Fragment} 子類別宣告選項選單的項目。
+如果您的 Activity 與片段都宣告選項選單的項目,兩者會在 UI 中結合。
+
+先顯示 Activity 的項目,接著會依片段新增至 Activity 的順序顯示各片段的項目。
+您可以視需要在您想移動的 {@code &lt;item&gt;} 中,利用其 {@code android:orderInCategory}屬性重新排列選單項目的順序。
+</p>
+
+<p>如要指定 Activity 的選項選單,可覆寫 {@link
+android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} (片段會提供自己的
+{@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()} 回呼)。在這種方法中,您可以將選單資源(<a href="#xml">在 XML 中完成定義</a>) 擴大回呼中提供的 {@link
+android.view.Menu}。
+例如:</p>
+
+<pre>
+&#64;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.MenuItem} API,您也可以使用 {@link android.view.Menu#add(int,int,int,int)
+add()} 來新增選單項目,以及利用 {@link android.view.Menu#findItem findItem()} 擷取項目來修訂它們的屬性。
+</p>
+
+<p>如果您是為 Android 2.3.x 以下版本開發應用程式,當使用者初次開啟選單時,系統會呼叫 {@link
+android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()},以建立選項選單。
+如果您是為 Android 3.0 以上版本開發應用程式,啟動 Activity 時,系統會呼叫
+{@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()},以在動作列顯示項目。
+</p>
+
+
+
+<h3 id="RespondingOptionsMenu">處理點擊事件</h3>
+
+<p>使用者從選項選單 (包括動作列中的動作項目) 中選取項目時,系統會呼叫您 Activity 的
+{@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>
+&#64;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()} 的超級類別實作 (預設實作會傳回 false)。
+</p>
+
+<p>如果您的 Activity 包含片段,系統會先呼叫 Activity 的 {@link
+android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()},再依片段的新增順序呼叫各片段,直到其中之一傳回
+{@code true} 或所有片段均已呼叫。
+</p>
+
+<p class="note"><strong>提示:</strong>Android 3.0 新增的功能可讓您在 XML 中使用
+{@code android:onClick} 屬性定義選單項目的點擊行為。該屬性值必須是使用選單的 Activity 所定義的方法名稱。
+它必須是公用方法且接受單一
+{@link android.view.MenuItem} 參數,當系統呼叫此方法時,它會傳送選取的選單項目。
+如需詳細資訊與範例,請參閱<a href="{@docRoot}guide/topics/resources/menu-resource.html">選單資源</a>文件。</p>
+
+<p class="note"><strong>提示:</strong>如果您的應用程式包含多個 Activity 且有一些提供相同的選項選單,可考慮建立只實作
+{@link android.app.Activity#onCreateOptionsMenu(Menu)
+onCreateOptionsMenu()} 與 {@link android.app.Activity#onOptionsItemSelected(MenuItem)
+onOptionsItemSelected()} 方法的 Activity。
+接著,針對應共用相同選項選單的 Activity 擴充此類別。
+如此一來,您可以管理一組處理選單動作的程式碼,以及每一個繼承選單行為的子系類別。
+
+
+如果您想要將選單項目新增至其中一個子系 Activity,請覆寫該 Activity 中的 {@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()} 應該只用來建立初始選單狀態,您不要在 Activity 生命週期間用來進行變更。
+</p>
+
+<p>如果您想要根據 Activity 生命週期當中發生的事件來修改選項選單,您可以使用
+{@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()} 方法這麼做。
+這個方法會將目前存在的
+{@link android.view.Menu} 物件傳送給您加以修改,例如新增、移除或停用項目
+(片段也會提供 {@link
+android.app.Fragment#onPrepareOptionsMenu onPrepareOptionsMenu()} 回呼)。</p>
+
+<p>在 Android 2.3.x 以下版本,每當使用者開啟選項選單 (按下 [選單]<em></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>您有兩種方式可提供內容關聯動作:</p>
+<ul>
+ <li>在<a href="#FloatingContextMenu">浮動內容選單</a>中。當使用者長按 (按住不放) 某個宣告支援內容選單的檢視時,選單會顯示為浮動的選單項目清單 (類似於對話方塊)。
+
+使用者一次可對一個項目執行內容關聯動作。
+</li>
+
+ <li>在<a href="#CAB">內容關聯動作模式</a>中。此模式是
+{@link android.view.ActionMode} 的系統實作,在畫面頂端將會影響將所選項目的動作項目顯示在「內容關聯動作列」<em></em>。
+此模式處於使用中時,使用者能一次對多個項目執行某一動作 (如果您的應用程式允許的話)。
+</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>如果您的 Activity 使用 {@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>
+&#64;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} 物件。
+
+如果 Activity 有數個分別提供不同內容選單的檢視,您可以使用這些參數來決定要擴大的內容選單。
+
+</p>
+</li>
+
+<li>實作 {@link android.app.Activity#onContextItemSelected(MenuItem)
+onContextItemSelected()}。
+ <p>當使用者選取選單項目時,系統會呼叫此方法,以便您執行適當的動作。
+例如:</p>
+
+<pre>
+&#64;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,使用
+{@code
+android:id} 屬性在 XML 中指派給各個選單項目,如<a href="#xml">在 XML 中定義選單</a>一節所述。
+</p>
+
+<p>當您成功處理選單項目時會傳回 {@code true}。如果您不處理選單項目,請將選單項目傳送至超級類別實作。
+如果您的 Activity 包括片段,該 Activity 會先收到此回呼。
+在不處理時呼叫超級類別,系統就可以一次一個 (依片段的新增順序) 將事件傳送至各片段中的個別回呼方法,直到傳回
+{@code true} 或 {@code false}。
+(
+{@link android.app.Activity} 與 {@code android.app.Fragment} 的預設實作會傳回 {@code
+false},因此當您不處理時,務必要呼叫超級類別。)</p>
+</li>
+</ol>
+
+
+<h3 id="CAB">使用內容關聯動作模式</h3>
+
+<p>內容關聯動作模式是 {@link android.view.ActionMode} 的系統實作,執行內容關聯動作時著重於與使用者互動。
+當使用者選取項目而啟用此模式時,「內容關聯動作列」<em></em>會出現在畫面頂端,呈現使用者可在目前所選項目上執行的動作。
+
+此模式啟用時,使用者能選取多個項目 (如果您允許的話)、取消選取項目,還可以在 Activity 內繼續瀏覽 (在您允許的範圍內)。
+
+當使用者取消選取所有項目、按下 [後退] 按鈕,或選取該列左側的[完成]<em></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>針對提供內容相關動作的檢視,您應該就下列兩種事件之一 (或兩者) 呼叫內容關聯動作模式:
+</p>
+<ul>
+ <li>使用者長按檢視。</li>
+ <li>使用者選取檢視內的核取方塊或類似 UI 元件。</li>
+</ul>
+
+<p>應用程式如何呼叫內容關聯動作模式以及如何定義每個動作的行為,視您的設計而定。
+基本上可分為兩種設計:</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
+ &#64;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.
+ &#64;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
+ &#64;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
+ &#64;Override
+ public void onDestroyActionMode(ActionMode mode) {
+ mActionMode = null;
+ }
+};
+</pre>
+
+<p>請注意,這些事件回呼幾乎和<a href="#options-menu">選項選單</a>的回呼一模一樣,只是每一個都會傳送與事件關聯的 {@link
+android.view.ActionMode} 物件。您可以使用 {@link
+android.view.ActionMode} API 對 CAB 進行各種變更,例如使用
+{@link android.view.ActionMode#setTitle setTitle()} 與 {@link
+android.view.ActionMode#setSubtitle setSubtitle()} 修改標題與子標題 (指出已選取的項目數量相當有用)。
+</p>
+
+<p>同時請注意,當動作模式終結時,上述範例會將 {@code mActionMode} 變數設為 null。
+在下個步驟中,您將看到它是如何初始化,以及如何儲存 Activity 或片段中的成員變數,非常實用。
+</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()} 加以設定以供檢視群組使用。在接聽器的回呼方法中,您可以指定內容相關動作列的動作、回應動作項目的點擊事件,以及處理從 {@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() {
+
+ &#64;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
+ }
+
+ &#64;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;
+ }
+ }
+
+ &#64;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;
+ }
+
+ &#64;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.
+ }
+
+ &#64;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>為與特定內容關聯動作提供溢出樣式選單 (例如 Gmail 的電子郵件標頭,如圖 4 所示)。<em></em>
+
+ <p class="note"><strong>注意:</strong>內容選單一般用於會「影響」<em></em>所選取內容的動作,與這並不相同。
+對於會影響所選取內容的動作,請使用<a href="#CAB">內容關聯動作模式</a>或<a href="#FloatingContextMenu">浮動內容選單</a>。
+</p></li>
+ <li>提供命令句的第二部分 (例如,標示為「新增」的按鈕會產生包含不同「新增」選項的彈出式選單)。
+</li>
+ <li>提供類似於 {@link android.widget.Spinner} (不保留永續性選擇) 的下拉式清單。
+</li>
+</ul>
+
+
+<p class="note"><strong>注意:</strong> API 級別 11 以上版本才可以使用 {@link android.widget.PopupMenu}。
+</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} 物件。針對 14 以上的 API 級別,您可以改用
+{@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>
+&lt;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>接著,該 Activity 可以顯示彈出式選單,如下所示:</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>在 14 以上的 API 級別中,您可以利用 {@link
+android.widget.PopupMenu#inflate PopupMenu.inflate()} 將兩行結合來擴大選單。</p>
+
+<p>當使用者選取某項目或輕觸選單區域外時會關閉選單。
+您可以使用 {@link
+android.widget.PopupMenu.OnDismissListener} 來接聽關閉事件。</p>
+
+<h3 id="PopupEvents">處理點擊事件</h3>
+
+<p>如要在使用者選取選單項目時執行動作,您必須呼叫 {@link android.widget.PopupMenu#setOnMenuItemClickListener
+setOnMenuItemclickListener()} 來實作 {@link
+android.widget.PopupMenu.OnMenuItemClickListener} 介面並向您的 {@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();
+}
+
+&#64;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 &lt;item&gt;} 元素堆疊在選單資源中的 {@code &lt;group&gt;}元素內,或使用 {@link
+android.view.Menu#add(int,int,int,int) add()} 方法指定群組 ID 來建立群組。
+</p>
+
+<p>以下是包含群組的範例選單資源:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
+ &lt;item android:id="@+id/menu_save"
+ android:icon="@drawable/menu_save"
+ android:title="@string/menu_save" /&gt;
+ &lt;!-- menu group --&gt;
+ &lt;group android:id="@+id/group_delete"&gt;
+ &lt;item android:id="@+id/menu_archive"
+ android:title="@string/menu_archive" /&gt;
+ &lt;item android:id="@+id/menu_delete"
+ android:title="@string/menu_delete" /&gt;
+ &lt;/group&gt;
+&lt;/menu&gt;
+</pre>
+
+<p>群組中的項目和第一個項目都會顯示在同一層,選單中的這三個項目都屬於同層級。
+不過,您可以參考群組 ID 並使用上方所述的方法,修改群組當中兩個項目的特性。
+系統也絕不會將群組的項目分離。
+例如,如果您針對每個項目宣告 {@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 &lt;item&gt;} 元素中的 {@code
+android:checkable} 屬性,為個別的選單項目定義可勾選行為,或利用 {@code &lt;group&gt;} 元素中的 {@code android:checkableBehavior} 屬性來為整個群組定義。
+例如,此選單群組中的所有項目都可以利用選項按鈕勾選。
+</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
+ &lt;group android:checkableBehavior="single"&gt;
+ &lt;item android:id="@+id/red"
+ android:title="@string/red" /&gt;
+ &lt;item android:id="@+id/blue"
+ android:title="@string/blue" /&gt;
+ &lt;/group&gt;
+&lt;/menu&gt;
+</pre>
+
+<p>{@code android:checkableBehavior} 屬性可接受其中一項:
+<dl>
+ <dt>{@code single}</dt>
+ <dd>只能勾選群組中的一個項目 (圓形按鈕)</dd>
+ <dt>{@code all}</dt>
+ <dd>可勾選所有項目 (核取方塊)</dd>
+ <dt>{@code none}</dt>
+ <dd>沒有任何項目可供勾選</dd>
+</dl>
+
+<p>您可以使用
+{@code &lt;item&gt;} 元素中的 {@code android:checked} 屬性將預設的勾選狀態套用至項目,並使用 {@link
+android.view.MenuItem#setChecked(boolean) setChecked()} 方法在程式碼中變更它。</p>
+
+<p>已選取可勾選項目時,系統會呼叫所選取個別項目的回呼方法 (例如 {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()})。
+您必須在這裡設定核取方塊的狀態,原因是核取方塊或選項按鈕並不會自動變更其狀態。
+
+您可以利用
+{@link android.view.MenuItem#isChecked()} 來查詢項目的目前狀態 (使用者選取它之前的狀態),然後利用
+{@link android.view.MenuItem#setChecked(boolean) setChecked()} 來設定勾選狀態。例如:</p>
+
+<pre>
+&#64;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>如果您不以這種方式設定已勾選狀態,將無法在使用者選取時變更項目 (核取方塊或選項按鈕) 的可見狀態。
+
+當您確實設定狀態,Activity 會保留項目的已勾選狀態,當使用者稍後開啟選單時,即可看見您設定的已勾選狀態。
+
+</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}來啟動 Activity (不論是您的應用程式或另一應用程式中的 Activity)。
+當您知道想要使用的意圖,同時有應繼承該意圖的特定選單項目時,您可在使用者選取項目時才回呼的適當方法實作期間使用
+{@link android.app.Activity#startActivity(Intent) startActivity()} 執行該意圖 (例如 {@link
+android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} callback) 回呼)。
+
+</p>
+
+<p>不過,如果您不確定使用者的裝置是否包含可處理該意圖的應用程式,而新增可呼叫它的選單項目會導致選單項目無法運作,原因可能是該意圖不會解析成 Activity。
+
+
+為解決這個問題,當 Android 在處理您意圖的裝置上找到 Activity 時,Android 會讓您將選單項目動態新增至選單。
+</p>
+
+<p>如何根據接受意圖的可用 Activity 來新增選單項目:</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>
+&#64;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>找到的各個 Activity 提供的意圖篩選器如果與定義的意圖相符,就會新增選單項目,使用意圖篩選器的 <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">允許將 Activity 新增至其他選單</h3>
+
+<p>您也能向其他應用程式提供 Activity 的服務,這樣即可在其他應用程式的選單中包含您的應用程式 (與上述的角色顛倒)。
+</p>
+
+<p>如要包含在其他應用程式選單中,您必須照常定義意圖篩選器,但務必為意圖篩選器類別納入
+{@link android.content.Intent#CATEGORY_ALTERNATIVE} 和/或 {@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} 值。
+
+例如:</p>
+<pre>
+&lt;intent-filter label="&#64;string/resize_image">
+ ...
+ &lt;category android:name="android.intent.category.ALTERNATIVE" />
+ &lt;category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
+ ...
+&lt;/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">NotePad</a> 範例程式碼。
+
+</p>
diff --git a/docs/html-intl/intl/zh-tw/guide/topics/ui/notifiers/notifications.jd b/docs/html-intl/intl/zh-tw/guide/topics/ui/notifiers/notifications.jd
new file mode 100644
index 000000000000..b8537445cff0
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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">啟動 Activity 時保留導覽</a>
+ <ol>
+ <li><a href="#DirectEntry">設定一般 Activity PendingIntent</a></li>
+ <li><a href="#ExtendedNotification">設定特殊 Activity PendingIntent</a></li>
+ </ol>
+ </li>
+ <li><a href="#Progress">在通知中顯示進度</a>
+ <ol>
+ <li><a href="#FixedProgress">顯示時間長度固定的進度指示器</a></li>
+ <li><a href="#ActivityIndicator">顯示持續性 Activity 指示器</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&amp;feature=player_detailpage#t=1672s">4.1 版中的通知
+</a>
+ </li>
+ </ol>
+<h2>另請參閱</h2>
+<ol>
+ <li>
+ <a href="{@docRoot}design/patterns/notifications.html">Android 設計:通知</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>除非另外註明,否則本指南參照<a href="{@docRoot}tools/support-library/index.html">支援程式庫</a> 4 版中的
+{@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>您會為
+{@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} 物件中的通知指定 UI 資訊與動作。
+如要建立通知本身,您可以呼叫
+{@link android.support.v4.app.NotificationCompat.Builder#build NotificationCompat.Builder.build()},其傳回的
+{@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>
+ 動作雖屬選用性質,但您至少必須將一個動作新增至通知。
+ 動作可讓使用者從通知直接移至您應用程式中的
+{@link android.app.Activity},他們能在那裡查看一或多個事件或執行進一步工作。
+
+</p>
+<p>
+ 通知可以提供多個動作。您應該一律定義會在使用者按一下通知時觸發的動作。
+這個動作通常會開啟您應用程式中的
+{@link android.app.Activity}。您也可以將按鈕新增至通知來執行其他動作,例如延遲鬧鐘或立即回應文字訊息。自 Android 4.1 起才提供此功能。
+
+如果您使用其他動作按鈕,也務必要在您應用程式的 {@link android.app.Activity} 中提供此功能。
+
+如需詳情,請參閱<a href="#Compatibility">處理相容性</a>。
+</p>
+<p>
+ 在 {@link android.app.Notification} 內,動作本身是由
+{@link android.app.PendingIntent} 完成定義,其中包含的
+{@link android.content.Intent} 會啟動您應用程式中的
+{@link android.app.Activity}。如要將
+{@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)
+NotificationCompat.Builder.setPriority()},然後傳入其中一個 {@link
+android.support.v4.app.NotificationCompat} 優先順序常數。共有五個優先順序級別,範圍從
+{@link
+android.support.v4.app.NotificationCompat#PRIORITY_MIN} (-2) 到 {@link
+android.support.v4.app.NotificationCompat#PRIORITY_MAX} (2)。如未加以設定,優先順序會預設為
+{@link
+android.support.v4.app.NotificationCompat#PRIORITY_DEFAULT} (0)。
+</p>
+<p> 如要瞭解如何設定適當的優先順序級別,請參閱<a href="{@docRoot}design/patterns/notifications.html">通知</a>設計指南中的「正確地設定及管理通知優先順序」。
+
+
+</p>
+<!-- ------------------------------------------------------------------------------------------ -->
+<h3 id="SimpleNotification">建立簡易通知</h3>
+<p>
+ 下列程式碼片段說明簡易的通知,指定要在使用者按一下通知時開啟的 Activity。
+請注意,以下程式碼會建立
+{@link android.support.v4.app.TaskStackBuilder} 物件,並使用此物件建立動作的
+{@link android.app.PendingIntent}。如要進一步瞭解這種模式,請參閱<a href="#NotificationResponse">啟動 Activity 時保留導覽</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 &lt; 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 以上版本才能使用的擴充通知功能。
+
+</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} 物件,並將
+{@link android.app.Notification} 連同您先前使用的相同 ID 一起發出。如果仍可看見先前的通知,系統會更新 {@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>
+ 使用者個別關閉通知,或透過「全部清除」的方式關閉通知 (如果可以清除通知的話)。
+
+ </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">啟動 Activity 時保留導覽</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} 屬性。一般有兩種情況:
+</p>
+<dl>
+ <dt>
+ 一般 Activity
+ </dt>
+ <dd>
+ 您即將啟動的 {@link android.app.Activity} 屬於應用程式的一般工作流程。
+在這種情況下,設定 {@link android.app.PendingIntent}以啟動全新工作,再連同返回堆疊一起提供 {@link android.app.PendingIntent},可再次產生應用程式的一般
+
+ <i>返回</i> 行為。
+ <p>
+ Gmail 應用程式的通知可示範這種情況。當您點選某一封電子郵件訊息的通知後,您會看到訊息本身。
+輕觸 [返回]<b></b>可將您從 Gmail 帶回主螢幕,就像您剛才從主螢幕進入 Gmail,而不是從通知進入。
+
+
+ </p>
+ <p>
+ 不論您所在的應用程式為何,當您輕觸通知時,都會發生這種情況。
+例如,如果您在 Gmail 撰寫訊息,而您點選某一封電子郵件的通知,就會立即前往該封電子郵件。
+輕觸 <i>[返回]</i>
+ 會將您帶往收件匣,然後再到主螢幕,而不是到您正在撰寫的訊息。
+
+ </p>
+ </dd>
+ <dt>
+ 特殊 Activity
+ </dt>
+ <dd>
+ 只有從通知啟動這個 {@link android.app.Activity} 時,使用者才會看到它。
+ 在某種意義上,{@link android.app.Activity}藉由提供難以在通知本身顯示的資訊來擴充通知。
+針對這種情況,請設定
+{@link android.app.PendingIntent} 以全新工作啟動。您不必建立返回堆疊,原因是啟動的
+{@link android.app.Activity} 不屬於應用程式的 Activity 流程。
+按一下 <i>[返回]</i> 還是會將使用者帶回主螢幕。
+
+ </dd>
+</dl>
+<!-- ------------------------------------------------------------------------------------------ -->
+<h3 id="DirectEntry">設定一般 Activity 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">&lt;meta-data&gt;</a></code> 元素新增為
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</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><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#val">android:value</a>="&lt;parent_activity_name&gt;"</code>,其中 <code>&lt;parent_activity_name&gt;</code> 是上層
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code> 元素的
+<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#nm">android:name</a></code> 值。
+
+
+如需範例,請參閱下列 XML。
+ </p>
+ </li>
+ <li>
+ 此外您還需要新增 Android 4.1 以上版本的支援。為此,請將
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#parent">android:parentActivityName</a></code> 屬性新增到您要啟動 {@link android.app.Activity} 的
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code> 元素。
+
+
+ </li>
+ </ol>
+ <p>
+ 最後的 XML 看起來會如下所示:
+ </p>
+<pre>
+&lt;activity
+ android:name=".MainActivity"
+ android:label="&#64;string/app_name" &gt;
+ &lt;intent-filter&gt;
+ &lt;action android:name="android.intent.action.MAIN" /&gt;
+ &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
+ &lt;/intent-filter&gt;
+&lt;/activity&gt;
+&lt;activity
+ android:name=".ResultActivity"
+ android:parentActivityName=".MainActivity"&gt;
+ &lt;meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".MainActivity"/&gt;
+&lt;/activity&gt;
+</pre>
+ </li>
+ <li>
+ 根據啟動
+{@link android.app.Activity} 的 {@link android.content.Intent} 建立返回堆疊:
+ <ol style="list-style-type: lower-alpha;">
+ <li>
+ 建立 {@link android.content.Intent} 以啟動 {@link android.app.Activity}。
+ </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},
+這項工作是在下個步驟中完成。
+ </p>
+ </li>
+ <li>
+ 呼叫
+{@link android.support.v4.app.TaskStackBuilder#addNextIntent addNextIntent()} 來新增會從通知啟動 {@link android.app.Activity} 的 {@link android.content.Intent}。
+
+ 將您在第一個步驟中建立的 {@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">設定特殊 Activity PendingIntent</h3>
+<p>
+ 下一節說明如何設定特殊 Activity
+{@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">&lt;activity&gt;</a></code> 元素
+
+ <dl>
+ <dt>
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#nm">android:name</a>="<i>activityclass</i>"</code>
+ </dt>
+ <dd>
+ Activity 的完整類別名稱。
+ </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>
+&lt;activity
+ android:name=".ResultActivity"
+...
+ android:launchMode="singleTask"
+ android:taskAffinity=""
+ android:excludeFromRecents="true"&gt;
+&lt;/activity&gt;
+...
+</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>
+ 通知可包含動畫進度指示器,向使用者顯示進行中操作的狀態。
+如果您隨時可預估操作花費的時間以及完成程度,可以使用形式「明確」的指示器 (進度列)。
+
+如果您無法預估操作的時間長度,請使用形式「不明確」的指示器 (Activity 指示器)。
+
+</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() {
+ &#64;Override
+ public void run() {
+ int incr;
+ // Do the "lengthy" operation 20 times
+ for (incr = 0; incr &lt;= 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">顯示持續性 Activity 指示器</h3>
+<p>
+ 如要顯示不明確的 Activity 指示器,可利用
+{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, true)}(可忽略前兩個引數) 將這類指示器新增至通知,然後發出通知。
+結果是指示器會有和進度列相同的樣式,只不過其中的動畫會持續播放。
+
+</p>
+<p>
+ 在操作一開始發出通知。動畫會持續播放,直到您修改通知為止。
+操作完成時,可呼叫
+{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, false)},然後更新通知以移除 Activity 指示器。
+
+ 請務必這樣做,不然即使操作完成後,動畫還是會繼續播放。此外,請務必變更通知文字來指出操作已完成。
+
+</p>
+<p>
+ 如要查看 Activity 指示器如何運作,請參考上方的程式碼片段。找出下列幾行程式碼:
+</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>顯示抬頭通知的全螢幕 Activity
+ </p>
+</div>
+
+<h2 id="Heads-up">抬頭通知</h2>
+
+<p>針對 Android 5.0 (API 級別 21),當裝置處於使用中 (也就是裝置已解鎖且螢幕處於開啟) 時,通知能以小型浮動視窗顯示 (也稱為「抬頭」<em></em>通知)。
+
+這些通知類似於精簡版的通知,只不過抬頭通知也會顯示動作按鈕。
+
+使用者不需要離開目前的應用程式,就可以執行動作或關閉抬頭通知。
+</p>
+
+<p>可能觸發抬頭通知的範例情況包括:</p>
+
+<ul>
+ <li>使用者的 Activity 處於全螢幕模式 (應用程式使用
+{@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 應用程式可能會顯示「您有 3 則簡訊」<em></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.Builder#addAction(android.app.Notification.Action) addAction()} 方法使用 {@link android.app.Notification.MediaStyle} 範本,將動作轉換成可點擊的圖示。
+
+
+</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#setContent setContent()},而不是呼叫像是 {@link android.support.v4.app.NotificationCompat.Builder#setContentTitle setContentTitle()} 的方法。
+
+
+如要設定自訂通知中的內容詳細資料,可使用 {@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/zh-tw/guide/topics/ui/overview.jd b/docs/html-intl/intl/zh-tw/guide/topics/ui/overview.jd
new file mode 100644
index 000000000000..44d05a82ebc2
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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>應用程式每個元件的使用者介面是使用 {@link
+android.view.View} 與 {@link android.view.ViewGroup} 物件的階層來定義,如圖 1 所示。每個檢視群組都是不可見容器,用以組織子檢視,而子檢視可能是輸入控制項或其他繪製部分 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>&lt;TextView&gt;</code> 元素可在您的 UI 中建立 {@link android.widget.TextView} 小工具,而
+<code>&lt;LinearLayout&gt;</code> 元素可以建立 {@link android.widget.LinearLayout} 檢視群組。
+ </p>
+
+<p>例如,上面有一個文字檢視與按鈕的簡單垂直版面配置,看起來像這樣:</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical" >
+ &lt;TextView android:id="@+id/text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="I am a TextView" />
+ &lt;Button android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="I am a Button" />
+&lt;/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/zh-tw/guide/topics/ui/settings.jd b/docs/html-intl/intl/zh-tw/guide/topics/ui/settings.jd
new file mode 100644
index 000000000000..91ac929e0fa1
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/guide/topics/ui/settings.jd
@@ -0,0 +1,1202 @@
+page.title=設定
+page.tags=偏好設定、偏好設定 Activity、偏好設定片段
+
+@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">建立偏好設定 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">設定設計指南</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 簡訊應用程式設定的螢幕擷取畫面。
+選取一個 {@link android.preference.Preference} 定義的項目可以開啟介面變更設定。
+</p>
+
+
+
+
+<h2 id="Overview">總覽</h2>
+
+<p>現在不使用 {@link android.view.View} 物件建置使用者介面,而是使用您在 XML 檔案中所宣告 {@link android.preference.Preference} 類別的各種子類別來建置設定。
+
+</p>
+
+<p>一個 {@link android.preference.Preference} 物件是單一設定的建置區塊。
+每個 {@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>布林值</li>
+ <li>浮動</li>
+ <li>整數</li>
+ <li>長整數</li>
+ <li>字串</li>
+ <li>字串 {@link java.util.Set}</li>
+</ul>
+
+<p>由於您的應用程式設定 UI 是使用 {@link android.preference.Preference} 物件,而不是 {@link android.view.View} 物件建置,因此您需要使用專門的 {@link android.app.Activity} 或 {@link android.app.Fragment} 子類別來顯示清單設定:
+
+
+</p>
+
+<ul>
+ <li>如果應用程式支援的 Android 版本早於 3.0 (API 級別 10 及較早版本),您必須以 {@link android.preference.PreferenceActivity} 類別延伸的形式建置 Activity。
+</li>
+ <li>在 Android 3.0 及更新版本上,您應該使用傳統 {@link android.app.Activity},它託管了顯示應用程式設定的 {@link android.preference.PreferenceFragment}。
+
+然而,當您有多個設定群組時,還可以使用 {@link android.preference.PreferenceActivity} 在大螢幕建立兩個面板的版面配置。
+</li>
+</ul>
+
+<p>如何設定 {@link android.preference.PreferenceActivity} 和 {@link
+android.preference.PreferenceFragment} 執行個體在<a href="#Activity">建立偏好設定 Activity</a> 和<a href="#Fragment">使用偏好設定片段</a>小節中有相關說明。
+</p>
+
+
+<h3 id="SettingTypes">偏好設定</h3>
+
+<p>應用程式的每個設定都會以 {@link
+android.preference.Preference} 類別的特定子類別代表。每個子類別包含一組核心屬性,可讓您為設定指定標題等項目和預設值。
+每個子類別還提供自己專屬的屬性和使用者介面。
+例如,圖 1 顯示簡訊應用程式設定的螢幕擷取畫面。
+設定畫面中的每個清單項目都由不同的 {@link
+android.preference.Preference} 物件支援。</p>
+
+<p>下列為幾個最常見的偏好設定:</p>
+
+<dl>
+ <dt>{@link android.preference.CheckBoxPreference}</dt>
+ <dd>為啟用或停用的設定顯示含有核取方塊的項目。儲存的值是布林值 (如果選取 <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} 物件具現化,但您仍應該在 XML 中定義設定清單,並在其中包含 {@link android.preference.Preference} 物件的階層。
+
+使用 XML 檔案定義設定集合是較建議的做法,因為該檔案提供的易讀結構很容易更新。
+而且,雖然您仍然可以在執行階段修改集合,但您的應用程式設定通常是預先定義好的。
+</p>
+
+<p>每個 {@link android.preference.Preference} 子類別都可透過與類別名稱相符的 XML 元素進行宣告,例如 {@code &lt;CheckBoxPreference&gt;}。
+</p>
+
+<p>您必須將 XML 檔案儲存在 {@code res/xml/} 目錄中。雖然您可以自由命名檔案,但在傳統上會命名為 {@code preferences.xml}。
+您通常只需要一個檔案,因為階層 (會開啟自己的設定清單) 中的子目錄是透過 {@link android.preference.PreferenceScreen} 的巢狀執行個體進行宣告。
+
+</p>
+
+<p class="note"><strong>注意:</strong>如果您想要為設定建立多個面板的版面配置,則您需要為每個片段準備個別的 XML 檔案。
+</p>
+
+<p>XML 檔案的根節點必須是 {@link android.preference.PreferenceScreen
+&lt;PreferenceScreen&gt;} 元素。您要將每個 {@link
+android.preference.Preference} 新增到此元素內。您在 {@link android.preference.PreferenceScreen &lt;PreferenceScreen&gt;} 元素內新增的每個子項會在設定清單中顯示為單一項目。
+
+</p>
+
+<p>例如:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+ &lt;CheckBoxPreference
+ android:key="pref_sync"
+ android:title="@string/pref_sync"
+ android:summary="@string/pref_sync_summ"
+ android:defaultValue="true" />
+ &lt;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" />
+&lt;/PreferenceScreen>
+</pre>
+
+<p>此範例中有一個 {@link android.preference.CheckBoxPreference} 和一個 {@link
+android.preference.ListPreference}。這兩個項目都包含下列三個屬性:</p>
+
+<dl>
+ <dt>{@code android:key}</dt>
+ <dd>需要這個屬性才能保留資料值的偏好設定。它會指定當系統將此設定值儲存於 {@link
+android.content.SharedPreferences} 時要使用的唯一索引鍵 (字串)。
+
+ <p>只有在下列情況下不需要此屬性:<em></em>偏好設定為 {@link android.preference.PreferenceCategory} 或 {@link android.preference.PreferenceScreen},或者偏好設定指定 {@link android.content.Intent} 進行呼叫 (搭配 <a href="#Intents">{@code &lt;intent&gt;}</a> 元素) 或 {@link android.app.Fragment} 進行顯示 (搭配 <a href="{@docRoot}reference/android/preference/Preference.html#attr_android:fragment">{@code
+android:fragment}</a> 屬性)。
+
+</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 &lt;PreferenceCategory&gt;} 元素指定。 <br/><b>2.</b>標題以 {@code android:title} 屬性指定。
+</p>
+</div>
+
+
+<p>如果您的設定清單超過約 10 個項目,您可以新增標題來定義設定群組,或在分開的畫面顯示這些群組。
+
+這些選項在下列幾節有詳細的描述。</p>
+
+
+<h3 id="Groups">建立設定群組</h3>
+
+<p>如果您的清單有 10 個以上的項目,掃描、理解和處理這些項目對使用者而言可能會很困難。
+如要解決這個問題,可將部分或所有設定分成不同的群組,有效地將一長串清單分成多個簡短的清單。
+
+一組包含相關設定的群組可以下列其中一種方式顯示:</p>
+
+<ul>
+ <li><a href="#Titles">使用標題</a></li>
+ <li><a href="#Subscreens">使用子畫面</a></li>
+</ul>
+
+<p>您可以使用上述一種或兩種分組技巧來整理您的應用程式設定。決定要使用哪種方法或如何分割設定時,您應該要依照 Android 設計<a href="{@docRoot}design/patterns/settings.html">設定</a>指南中的指導方針進行。
+
+</p>
+
+
+<h4 id="Titles">使用標題</h4>
+
+<p>如果您想要在設定群組間使用標題區分 (如圖 2 所示),將 {@link android.preference.Preference} 物件的每個群組放入 {@link
+android.preference.PreferenceCategory}。
+</p>
+
+<p>例如:</p>
+
+<pre>
+&lt;PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+ &lt;PreferenceCategory
+ android:title="&#64;string/pref_sms_storage_title"
+ android:key="pref_key_storage_settings">
+ &lt;CheckBoxPreference
+ android:key="pref_key_auto_delete"
+ android:summary="&#64;string/pref_summary_auto_delete"
+ android:title="&#64;string/pref_title_auto_delete"
+ android:defaultValue="false"... />
+ &lt;Preference
+ android:key="pref_key_sms_delete_limit"
+ android:dependency="pref_key_auto_delete"
+ android:summary="&#64;string/pref_summary_delete_limit"
+ android:title="&#64;string/pref_title_sms_delete"... />
+ &lt;Preference
+ android:key="pref_key_mms_delete_limit"
+ android:dependency="pref_key_auto_delete"
+ android:summary="&#64;string/pref_summary_delete_limit"
+ android:title="&#64;string/pref_title_mms_delete" ... />
+ &lt;/PreferenceCategory>
+ ...
+&lt;/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
+&lt;PreferenceScreen&gt;} 元素建立的項目會在選取時開啟獨立的清單以顯示巢狀設定。
+</p>
+
+<p>例如:</p>
+
+<pre>
+&lt;PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+ &lt;!-- opens a subscreen of settings -->
+ &lt;PreferenceScreen
+ android:key="button_voicemail_category_key"
+ android:title="&#64;string/voicemail"
+ android:persistent="false">
+ &lt;ListPreference
+ android:key="button_voicemail_provider_key"
+ android:title="&#64;string/voicemail_provider" ... />
+ &lt;!-- opens another nested subscreen -->
+ &lt;PreferenceScreen
+ android:key="button_voicemail_setting_key"
+ android:title="&#64;string/voicemail_settings"
+ android:persistent="false">
+ ...
+ &lt;/PreferenceScreen>
+ &lt;RingtonePreference
+ android:key="button_voicemail_ringtone_key"
+ android:title="&#64;string/voicemail_ringtone_title"
+ android:ringtoneType="notification" ... />
+ ...
+ &lt;/PreferenceScreen>
+ ...
+&lt;/PreferenceScreen>
+</pre>
+
+
+<h3 id="Intents">使用意圖</h3>
+
+<p>在某些情況下,您可能會希望偏好設定項目開啟不同的 Activity 而不是設定畫面,例如,開啟網路瀏覽器以檢視網頁。
+如要在使用者選取偏好設定項目時呼叫 {@link
+android.content.Intent},請新增 {@code &lt;intent&gt;} 元素做為對應 {@code &lt;Preference&gt;} 元素的子項。
+</p>
+
+<p>例如,您可以使用下列方法透過偏好設定項目開啟網頁:</p>
+
+<pre>
+&lt;Preference android:title="@string/prefs_web_page" >
+ &lt;intent android:action="android.intent.action.VIEW"
+ android:data="http://www.example.com" />
+&lt;/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">建立偏好設定 Activity</h2>
+
+<p>如要在 Activity 中顯示設定,延伸 {@link
+android.preference.PreferenceActivity} 類別。這是傳統 {@link
+android.app.Activity} 類別的延伸,可根據 {@link
+android.preference.Preference} 物件的階層顯示設定清單。當使用者進行變更時,{@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 檔案中宣告的偏好設定新增到 Activity 中。
+例如,下列為功能 {@link android.preference.PreferenceActivity} 所需的基本程式碼:
+</p>
+
+<pre>
+public class SettingsActivity extends PreferenceActivity {
+ &#64;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} 新增到任何 Activity &mdash; 您不需要使用 {@link android.preference.PreferenceActivity}。
+</p>
+
+<p><a href="{@docRoot}guide/components/fragments.html">片段</a>單就 Activity 而言,可為您的應用程式提供更有彈性的架構,無論您建置哪一種 Activity 都一樣。
+
+因此,我們建議您盡可能使用 {@link
+android.preference.PreferenceFragment} 來控制設定的顯示,而不要使用 {@link
+android.preference.PreferenceActivity}。</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 {
+ &#64;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.Activity},做法與任何其他
+{@link android.app.Fragment} 一樣。例如:</p>
+
+<pre>
+public class SettingsActivity extends Activity {
+ &#64;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()}。
+不過,必須小心,只能在片段附加到 Activity 時才能呼叫 {@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>
+&lt;!-- default value is a boolean -->
+&lt;CheckBoxPreference
+ android:defaultValue="true"
+ ... />
+
+&lt;!-- default value is a string -->
+&lt;ListPreference
+ android:defaultValue="@string/pref_syncConnectionTypes_default"
+ ... />
+</pre>
+
+<p>之後,從您應用程式主 Activity &mdash; 以及使用者第一次進入您應用程式所使用的任何其他 Activity &mdash; 的 {@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>這個方法採用三種引數:</p>
+<ul>
+ <li>您的應用程式 {@link android.content.Context}。</li>
+ <li>您要設定預設值之偏好設定 XML 檔案的資源 ID。</li>
+ <li>布林值指出預設值是否要設定一次以上。
+<p>如果為 <code>false</code>,系統只會在過去從未呼叫此方法時設定預設值 (或者預設值共用偏好設定檔案的 {@link android.preference.PreferenceManager#KEY_HAS_SET_DEFAULT_VALUES} 為 false)。
+
+</p></li>
+</ul>
+
+<p>只要將第三個引數設為 <code>false</code>,您可以在每次 Activity 啟動時很安全地呼叫此方法,而不會將使用者儲存的偏好設定重設為預設值。
+
+不過,如果您將它設為 <code>true</code>,會將任何之前的值覆寫為預設值。
+</p>
+
+
+
+<h2 id="PreferenceHeaders">使用偏好設定標頭</h2>
+
+<p>在少數情況下,您可能會想將設定設計為只在第一個畫面顯示<a href="#Subscreens">子畫面</a>清單(與系統設定應用程式一樣,如圖 4 和 5 所示)。
+
+當您為 Android 3.0 及更新版本開發這類設計時,您應該使用 Android 3.0 的新「標頭」功能,而不是使用巢狀 {@link android.preference.PreferenceScreen} 元素建置子畫面。
+
+</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 所示。</p>
+
+<p>即使應用程式支援的 Android 版本較 3.0 舊,您還是可以建置應用程式在新版的裝置上使用 {@link android.preference.PreferenceFragment} 顯示兩個面板,同時仍然支援舊版裝置上的傳統多畫面階層 (請參閱<a href="#BackCompatHeaders">使用偏好設定標頭支援舊版</a>)。
+
+
+
+</p>
+
+<img src="{@docRoot}images/ui/settings/settings-headers-tablet.png" alt="" />
+<p class="img-caption"><strong>圖 4.</strong>含標頭的兩個面板版面配置。 <br/><b>1.</b>標頭以 XML 標頭檔案定義。
+ <br/><b>2.</b>每個設定群組是由標頭檔案 {@code &lt;header&gt;} 元素指定的{@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 &lt;preference-headers&gt;} 元素中的單一 {@code &lt;header&gt;} 元素指定。
+例如:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
+ &lt;header
+ android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentOne"
+ android:title="@string/prefs_category_one"
+ android:summary="@string/prefs_summ_category_one" />
+ &lt;header
+ android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentTwo"
+ android:title="@string/prefs_category_two"
+ android:summary="@string/prefs_summ_category_two" >
+ &lt;!-- key/value pairs can be included as arguments for the fragment. -->
+ &lt;extra android:name="someKey" android:value="someHeaderValue" />
+ &lt;/header>
+&lt;/preference-headers>
+</pre>
+
+<p>有了 {@code android:fragment} 屬性,每個標頭會宣告當使用者選取標頭時,應該開啟的 {@link
+android.preference.PreferenceFragment} 執行個體。</p>
+
+<p>{@code &lt;extras&gt;} 元素可讓您將鍵值配對傳送到 {@link
+android.os.Bundle} 中的片段。片段可以透過呼叫 {@link
+android.app.Fragment#getArguments()} 擷取引數。您可以因各種理由將引數傳送到片段,但其中一個最好的理由是針對每個群組重複使用 {@link
+android.preference.PreferenceFragment} 中相同的子類別,並使用引數指定應載入片段的偏好設定 XML 檔案。
+
+</p>
+
+<p>例如,當每個標頭使用 {@code "settings"} 索引鍵定義 {@code &lt;extra&gt;} 引數時,下列片段可在多個設定群組重複使用:
+</p>
+
+<pre>
+public static class SettingsFragment extends PreferenceFragment {
+ &#64;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 {
+ &#64;Override
+ public void onBuildHeaders(List&lt;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()} 方法,這是因為 Activity 唯一需要做的工作就是載入標頭。
+</p>
+
+
+<h3 id="BackCompatHeaders">使用偏好設定標頭支援舊版</h3>
+
+<p>如果您應用程式支援的 Android 版本比 3.0 舊,您仍然可以在 Android 3.0 及更新版本執行時,使用標頭提供兩個面板的版面配置。
+您只需要建立一個額外的偏好設定 XML 檔案,該檔案要使用行為與標頭項目 (供舊版 Android 使用) 一樣的基本 {@link android.preference.Preference
+&lt;Preference&gt;} 元素。
+
+</p>
+
+<p>但是,不會開啟新的 {@link android.preference.PreferenceScreen},每個 {@link
+android.preference.Preference &lt;Preference&gt;} 元素會傳送一個 {@link android.content.Intent} 到 {@link android.preference.PreferenceActivity},以指定要載入的偏好設定 XML 檔案。
+
+</p>
+
+<p>例如,下列為使用 Android 3.0及更新版本的偏好設定標頭 XML 檔案 ({@code res/xml/preference_headers.xml}):
+</p>
+
+<pre>
+&lt;preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
+ &lt;header
+ android:fragment="com.example.prefs.SettingsFragmentOne"
+ android:title="@string/prefs_category_one"
+ android:summary="@string/prefs_summ_category_one" />
+ &lt;header
+ android:fragment="com.example.prefs.SettingsFragmentTwo"
+ android:title="@string/prefs_category_two"
+ android:summary="@string/prefs_summ_category_two" />
+&lt;/preference-headers>
+</pre>
+
+<p>而,這裡有個偏好設定檔案為 Android 3.0 以下版本提供相同的標頭 ({@code res/xml/preference_headers_legacy.xml}):
+</p>
+
+<pre>
+&lt;PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+ &lt;Preference
+ android:title="@string/prefs_category_one"
+ android:summary="@string/prefs_summ_category_one" >
+ &lt;intent
+ android:targetPackage="com.example.prefs"
+ android:targetClass="com.example.prefs.SettingsActivity"
+ android:action="com.example.prefs.PREFS_ONE" />
+ &lt;/Preference>
+ &lt;Preference
+ android:title="@string/prefs_category_two"
+ android:summary="@string/prefs_summ_category_two" >
+ &lt;intent
+ android:targetPackage="com.example.prefs"
+ android:targetClass="com.example.prefs.SettingsActivity"
+ android:action="com.example.prefs.PREFS_TWO" />
+ &lt;/Preference>
+&lt;/PreferenceScreen>
+</pre>
+
+<p>因為 Android 3.0 已加入對 {@code &lt;preference-headers&gt;} 的支援,系統只會在 Androd 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>
+&#64;Override
+public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ ...
+
+ if (Build.VERSION.SDK_INT &lt; Build.VERSION_CODES.HONEYCOMB) {
+ // Load the legacy preferences headers
+ addPreferencesFromResource(R.xml.preference_headers_legacy);
+ }
+}
+
+// Called only on Honeycomb and later
+&#64;Override
+public void onBuildHeaders(List&lt;Header> target) {
+ loadHeadersFromResource(R.xml.preference_headers, target);
+}
+</pre>
+
+<p>最後一件要做的事,是處理傳送到 Activity 的 {@link android.content.Intent},以識別要載入的偏好設定檔案。
+擷取意圖的動作,並將它與偏好設定 XML {@code &lt;intent&gt;} 標籤中使用的已知動作字串進行比對:
+</p>
+
+<pre>
+final static String ACTION_PREFS_ONE = "com.example.prefs.PREFS_ONE";
+...
+
+&#64;Override
+public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ String action = getIntent().getAction();
+ if (action != null &amp;&amp; action.equals(ACTION_PREFS_ONE)) {
+ addPreferencesFromResource(R.xml.preferences);
+ }
+ ...
+
+ else if (Build.VERSION.SDK_INT &lt; Build.VERSION_CODES.HONEYCOMB) {
+ // Load the legacy preferences headers
+ addPreferencesFromResource(R.xml.preference_headers_legacy);
+ }
+}
+</pre>
+
+<p>請注意,{@link
+android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} 的連續呼叫會將所有偏好設定堆疊在單一清單中,因此請確定將條件鏈結到 else-if 陳述式時只會呼叫它一次。
+
+</p>
+
+
+
+
+
+<h2 id="ReadingPrefs">讀取偏好設定</h2>
+
+<p>根據預設,透過呼叫靜態方法 {@link
+android.preference.PreferenceManager#getDefaultSharedPreferences
+PreferenceManager.getDefaultSharedPreferences()},您應用程式中的所有偏好設定會儲存可從應用程式內任何地方存取的檔案中。
+這會傳回 {@link
+android.content.SharedPreferences} 物件,其中包含與您 {@link
+android.preference.PreferenceActivity} 使用之 {@link android.preference.Preference} 物件關聯的所有鍵值配對。
+</p>
+
+<p>例如,下列說明如何從應用程式中的任何其他 Activity 讀取其中一個偏好設定值:
+</p>
+
+<pre>
+SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
+String syncConnPref = sharedPref.getString(SettingsActivity.KEY_PREF_SYNC_CONN, "");
+</pre>
+
+
+
+<h3 id="Listening">接聽偏好設定變更</h3>
+
+<p>使用者變更其中一個偏好設定後,您想要立即收到通知的原因有好幾個。
+如要在任何偏好設定發生變更時收到回呼,實作 {@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()},而且在 Activity 中實作介面可能對您來說會更為容易。
+例如:</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} 或其他多選擇設定時,如果設定變更為顯示目前狀態 (如圖 5 顯示的休眠設定),您應該呼叫 {@link
+android.preference.Preference#setSummary setSummary()}。
+</p>
+
+<p class="note"><strong>注意:</strong>如 Android 設計文件中有關<a href="{@docRoot}design/patterns/settings.html">設定</a>的說明所述,我們建議您在每次使用者變更偏好設定時更新 {@link android.preference.ListPreference} 的摘要,以描述目前的設定。
+
+</p>
+
+<p>為了在 Activity 中正確管理生命週期,我們建議您分別在 {@link
+android.app.Activity#onResume} 和 {@link android.app.Activity#onPause} 回呼期間,註冊和解決註冊您的 {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener}:
+</p>
+
+<pre>
+&#64;Override
+protected void onResume() {
+ super.onResume();
+ getPreferenceScreen().getSharedPreferences()
+ .registerOnSharedPreferenceChangeListener(this);
+}
+
+&#64;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>
+&lt;activity android:name="SettingsActivity" ... >
+ &lt;intent-filter>
+ &lt;action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
+ &lt;category android:name="android.intent.category.DEFAULT" />
+ &lt;/intent-filter>
+&lt;/activity>
+</pre>
+
+<p>這個意圖篩選器向系統指出,是 Activity 在控制您的應用程式資料使用量。
+因此,當使用者從系統設定應用程式檢查您的應用程式使用了多少資料量時,可以使用 [檢視應用程式設定] 按鈕啟動您的<em></em> {@link android.preference.PreferenceActivity},讓使用者精簡您應用程式使用的資料量。
+
+
+</p>
+
+
+
+
+
+
+
+<h2 id="Custom">建置自訂偏好設定</h2>
+
+<p>Android 架構包含各式各樣的 {@link android.preference.Preference} 子類別,可讓您建置所種不同設定類型的 UI。不過,您可能會發現內建解決方案中可能沒有您所需的設定,例如數字挑選器或日期挑選器。
+
+
+在這類情況下,您需要延伸 {@link android.preference.Preference} 類別或其中一個其他子類別,以建立自訂的偏好設定。
+</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} 類別的 {@code persist*()} 方法隨時儲存設定值,例如,如果設定值是整數,使用 {@link
+android.preference.Preference#persistInt persistInt()},或者使用 {@link android.preference.Preference#persistBoolean persistBoolean()} 儲存布林值。
+</p>
+
+<p class="note"><strong>注意:</strong>每個 {@link android.preference.Preference} 只能儲存一個資料類型,因此您必須使用適合您自訂 {@link android.preference.Preference} 使用之資料類型的 {@code persist*()} 方法。
+
+</p>
+
+<p>當您選擇保留設定時,可以依據您延伸的 {@link
+android.preference.Preference} 類別加以設定。如果您延伸 {@link
+android.preference.DialogPreference},則應該只在對話方塊因正值結果 (使用者選取 [確定] 按鈕) 關閉時保留該值。
+</p>
+
+<p>當 {@link android.preference.DialogPreference} 關閉時,系統會呼叫 {@link
+android.preference.DialogPreference#onDialogClosed onDialogClosed()} 方法。這個方法包括一個布林值引數,指定使用者結果是否為「正值」&mdash; 如果值為
+<code>true</code>,則表示使用者選取正值按鈕,而您應該儲存新值。
+例如:
+</p>
+
+<pre>
+&#64;Override
+protected void onDialogClosed(boolean positiveResult) {
+ // When the user selects "OK", persist the new value
+ if (positiveResult) {
+ persistInt(mNewValue);
+ }
+}
+</pre>
+
+<p>在此範例中,<code>mNewValue</code> 是保留設定目前值的類別成員。
+呼叫 {@link android.preference.Preference#persistInt persistInt()} 可將值儲存到 {@link android.content.SharedPreferences} 檔案 (自動使用 XML 檔案中為此 {@link android.preference.Preference} 指定的索引鍵)。
+
+</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>,則您應該使用在第二引數中傳送的預設值。
+</p>
+
+<pre>
+&#64;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>您<strong>無法</strong>使用 <code>defaultValue</code> 作為 {@code getPersisted*()} 方法中的預設值,因為當 <code>restorePersistedValue</code> 為 <code>true</code> 時,其值永遠是 null。
+
+</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>
+&#64;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} 子類別負責在 Activity 或片段重新啟動 (例如,當使用者旋轉螢幕時) 時,儲存和還原其狀態。
+
+如要正確的儲存和還原 {@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
+ }
+
+ &#64;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&lt;SavedState> CREATOR =
+ new Parcelable.Creator&lt;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>
+&#64;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;
+}
+
+&#64;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/zh-tw/guide/topics/ui/ui-events.jd b/docs/html-intl/intl/zh-tw/guide/topics/ui/ui-events.jd
new file mode 100644
index 000000000000..68714e8b2b59
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/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,有多種方法可以攔截使用者與應用程式互動的事件。
+如果考慮的是使用者介面內的事件,方法就是從與使用者互動的特定檢視物件中擷取事件。
+檢視類別提供執行此動作的方法。</p>
+
+<p>在您用來撰寫版面配置的各種檢視類別中,您會發現多種公用回呼方法,對 UI 事件似乎相當實用。
+當該物件發生個別動作時,Android 架構會呼叫這些方法。
+例如,輕觸檢視 (例如按鈕) 時,會在該物件上呼叫 <code>onTouchEvent()</code> 方法。
+不過,為了攔截這個事件,您必須延伸類別並覆寫方法。
+然而,延伸每個檢視物件以便處理這類事件並不實際。
+這就是檢視類別也包含巢狀介面與回呼的集合的原因,這樣您就能更輕鬆地定義。
+這些介面稱為<a href="#EventListeners">事件接聽器</a>,就是用來擷取使用者與您 UI 互動的票券。
+</p>
+
+<p>雖然您更常使用事件接聽器來接聽使用者互動,未來您可能會想要延伸檢視類別以建置自訂元件。
+或許您想要延伸 {@link android.widget.Button} 類別讓一些項目更為出色。
+
+在這種情況下,您能夠使用類別<a href="#EventHandlers">事件處理常式</a>來為您的類別定義預設事件行為。
+</p>
+
+
+<h2 id="EventListeners">事件接聽器</h2>
+
+<p>事件接聽器是 {@link android.view.View} 類別中的一個介面,該類別包含單一回呼方法。
+當使用者與 UI 中的項目互動並觸發接聽器所註冊的檢視時,Android 架構就會呼叫這些方法。
+</p>
+
+<p>事件接聽器介面包含下列回呼方法:</p>
+
+<dl>
+ <dt><code>onClick()</code></dt>
+ <dd>從 {@link android.view.View.OnClickListener}。使用者輕觸項目 (處於輕觸模式時),或將焦點放在具有導覽鍵或軌跡球的項目上,然後按適當的 "enter" 鍵或按下軌跡球時,就會呼叫。
+
+
+</dd>
+ <dt><code>onLongClick()</code></dt>
+ <dd>從 {@link android.view.View.OnLongClickListener}。使用者輕觸並按住項目 (處於輕觸模式時),或將焦點放在具有導覽鍵或軌跡球的項目上,然後按住適當的 "enter" 鍵或按住軌跡球 (一秒) 時,就會呼叫。
+
+
+</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>這些方法是其個別介面的唯一要素。如要定義其中一種方法並處理您的事件,可在您的 Activity 中實作巢狀介面或將它定義為匿名類別。然後,將您的實作執行個體傳送至個別的 <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>您也會發現在 Activity 中實作 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> 接收您 Activity 內的所有事件。
+
+</p>
+
+<p>此外,當您思考應用程式的文字輸入時,請記住,許多裝置只有軟體輸入方法。
+這類方法不需要以按鍵為基礎;有些可能會使用語音輸入、手寫等方式。即使輸入方法出現類似鍵盤的介面,也通常<strong>不會</strong>觸發事件的
+<code>{@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()}</code> 系列。
+您不應該建置需要按下特定按鍵才能控制的 UI,除非您想將應用程式限制為使用硬體鍵盤的裝置。
+
+尤其是當使用者按 Return 鍵時,不要藉助這些方法來驗證輸入;改為使用像 {@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>您還必須注意其他一些方法,這些方法不屬於檢視類別,但會直接影響您能夠處理事件的方式。
+因此,在版面配置中管理更複雜的事件時,請考量下列其他方法:
+</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>
+整個系統 (所有視窗和 Activity) 都會保留輕觸模式的狀態。如要查詢目前的狀態,您可以呼叫
+{@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>焦點移動是以演算法為依據,在指定的方向尋找最接近的項目。
+在少數情況下,預設的演算法與開發人員預期的行為可能不符。
+在這些情況下,您可以在版面配置檔案使用下列 XML 屬性進行明確的覆寫:
+
+<var>nextFocusDown</var>、 <var>nextFocusLeft</var>、 <var>nextFocusRight</var>和
+<var>nextFocusUp</var>。在移出焦點的檢視中,新增下列其中一個屬性<em></em>。
+將屬性的值定義為應該成為焦點之檢視的 ID<em></em>。
+例如:</p>
+<pre>
+&lt;LinearLayout
+ android:orientation="vertical"
+ ... >
+ &lt;Button android:id="@+id/top"
+ android:nextFocusUp="@+id/bottom"
+ ... />
+ &lt;Button android:id="@+id/bottom"
+ android:nextFocusDown="@+id/top"
+ ... />
+&lt;/LinearLayout>
+</pre>
+
+<p>一般來說,在這個直式版面配置中,從第一個按鈕往上瀏覽或從第二個按鈕往下瀏覽都不會到任何地方。
+現在,上方按鈕已將下方按鈕定義為
+ <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>如要接聽焦點事件 (在檢視獲得或失去焦點時收到通知),可使用
+<code>{@link android.view.View.OnFocusChangeListener#onFocusChange(View,boolean) onFocusChange()}</code> (如上述<a href="#EventListeners">事件接聽器</a>中所討論)。
+</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>
+-->