diff options
Diffstat (limited to 'docs/html-intl/intl/zh-tw/training/basics')
13 files changed, 2474 insertions, 0 deletions
diff --git a/docs/html-intl/intl/zh-tw/training/basics/activity-lifecycle/index.jd b/docs/html-intl/intl/zh-tw/training/basics/activity-lifecycle/index.jd new file mode 100644 index 0000000..4225184 --- /dev/null +++ b/docs/html-intl/intl/zh-tw/training/basics/activity-lifecycle/index.jd @@ -0,0 +1,72 @@ +page.title=管理應用行為顯示生命週期 +page.tags=應用行為顯示生命週期 +helpoutsWidget=true + +trainingnavtop=true +startpage=true + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + + +<h2>相依性和先決條件</h2> +<ul> + <li>如何建立 Android 專案 (請參閱<a href="{@docRoot}training/basics/firstapp/creating-project.html">建立 Android +專案</a>)</li> +</ul> + + +<h2>您也應該閱讀</h2> +<ul> + <li><a href="{@docRoot}guide/components/activities.html">應用行為顯示</a></li> +</ul> + + +<h2>試試看</h2> + +<div class="download-box"> + <a href="http://developer.android.com/shareables/training/ActivityLifecycle.zip" class="button">下載示範</a> + <p class="filename">ActivityLifecycle.zip</p> +</div> + +</div> +</div> + +<p>使用者在應用程式內部、由內到外、由外到內執行導覽時,應用程式中的 {@link android.app.Activity} 執行個體會在生命週期的不同狀態之間進行轉換。 + +例如,在您的應用行為顯示首次啟動時,會進入系統的前景,並成為使用者的焦點。 + +在此過程中,Android 系統會針對設定使用者介面與其他元件所在的應用行為顯示,呼叫一系列生命週期方法。 +若使用者執行的行為會啟動其他應用行為顯示或切換至其他應用程式,系統會在您的應用行為顯示進入背景 (在此處應用行為顯示將不再可見,但執行個體及其狀態保持不變) 時,針對該應用行為顯示呼叫另一組生命週期方法。 + + +</p> + +<p>在生命週期回呼方法內,您可以宣告在使用者離開並重新進入應用行為顯示時,應用行為顯示採用的行為。 +例如,若您建置串流影片播放器,可能會在使用者切換至其他應用程式時暫停影片播放,並終止網路連線。在使用者返回時,您可以重新連接至網路,讓使用者從先前暫停的位置繼續播放影片。 + + +</p> + +<p>本課程將說明每個 {@link +android.app.Activity} 執行個體都會接收的生命週期重要回呼方法,並說明如何使用這些方法,以便應用行為顯示的運作能符合使用者的預期,而且在應用行為顯示不需要系統資源時不耗用系統資源。 +</p> + +<h2>課程</h2> + +<dl> + <dt><b><a href="starting.html">啟動應用行為顯示</a></b></dt> + <dd>了解應用行為顯示生命週期的有關基本概念、使用者啟動應用程式的方式,以及建立基本應用行為顯示的執行方式。 +</dd> + <dt><b><a href="pausing.html">暫停並繼續應用行為顯示</a></b></dt> + <dd>了解應用行為顯示暫停 (遭部分遮蓋) 與繼續時的狀況,以及在這些狀態變更期間應執行的操作。 +</dd> + <dt><b><a href="stopping.html">停止並重新啟動應用行為顯示</a></b></dt> + <dd>了解在使用者完全離開應用行為顯示與返回應用行為顯示時的狀況。</dd> + <dt><b><a href="recreating.html">重新建立應用行為顯示</a></b></dt> + <dd>了解在應用行為顯示遭終結時的狀況,以及如何在需要時重新建置應用行為顯示狀態。 +</dd> +</dl> + diff --git a/docs/html-intl/intl/zh-tw/training/basics/activity-lifecycle/pausing.jd b/docs/html-intl/intl/zh-tw/training/basics/activity-lifecycle/pausing.jd new file mode 100644 index 0000000..8c0843d --- /dev/null +++ b/docs/html-intl/intl/zh-tw/training/basics/activity-lifecycle/pausing.jd @@ -0,0 +1,147 @@ +page.title=暫停並繼續應用行為顯示 +page.tags=應用行為顯示生命週期 +helpoutsWidget=true + +trainingnavtop=true + +@jd:body + +<div id="tb-wrapper"> + <div id="tb"> + + <h2>本課程示範</h2> + <ol> + <li><a href="#Pause">暫停您的應用行為顯示</a></li> + <li><a href="#Resume">繼續您的應用行為顯示</a></li> + </ol> + + <h2>您也應該閱讀</h2> + <ul> + <li><a href="{@docRoot}guide/components/activities.html">應用行為顯示</a> + </li> + </ul> + +<h2>試試看</h2> + +<div class="download-box"> + <a href="http://developer.android.com/shareables/training/ActivityLifecycle.zip" class="button">下載示範</a> + <p class="filename">ActivityLifecycle.zip</p> +</div> + + </div> +</div> + +<p>在應用程式正常使用期間,有時前景應用行為顯示會受到其他視覺元件的遮蓋,導致該應用行為顯示<em>暫停</em>。 +例如,若開啟半透明的應用行為顯示 (諸如採用對話方塊風格的應用行為顯示),前一個應用行為顯示會暫停。 +只要應用行為顯示仍部分可見,但目前並非焦點,就會保持暫停狀態。 +</p> + +<p>但是,若應用行為顯示完全遭遮蓋且不可見,則會<em>停止</em> (下一課將對此進行討論)。 +</p> + +<p>在您的應用行為顯示進入暫停狀態時,系統會針對您的 {@link android.app.Activity} 呼叫 {@link +android.app.Activity#onPause onPause()} 方法,您可藉此停止在暫停時不應繼續的進行中行為 (例如影片),或保留使用者持續離開您的應用程式時應永久儲存的資訊。若使用者從暫停狀態返回至您的應用行為顯示,系統會繼續執行該應用行為顯示,並呼叫 {@link android.app.Activity#onResume onResume()} 方法。 + + + +</p> + +<p class="note"><strong>注意:</strong>若您的應用行為顯示收到對 {@link +android.app.Activity#onPause()} 的呼叫,可能表示該應用行為顯示將暫停片刻,隨後使用者會將焦點重新移到您的應用行為顯示上。 +但是,這通常首先表示使用者離開您的應用行為顯示。 +</p> + +<img src="{@docRoot}images/training/basics/basic-lifecycle-paused.png" /> +<p class="img-caption"><strong>圖 1.</strong>若半透明的應用行為顯示遮蓋您的應用行為顯示,系統會呼叫 {@link android.app.Activity#onPause onPause()},您的應用行為顯示會進行等候 (狀態為「已暫停」) (1)。 + +若使用者在應用行為顯示仍處於暫停狀態時返回至應用行為顯示,系統將呼叫 {@link android.app.Activity#onResume onResume()} (2)。 +</p> + + +<h2 id="Pause">暫停您的應用行為顯示</h2> + +<p>若系統為您的應用行為顯示呼叫 {@link android.app.Activity#onPause()},嚴格來說意味著您的應用行為顯示仍是部分可見,但多數情況下表示使用者離開應用行為顯示,該應用行為顯示很快將進入「已停止」狀態。 + +通常,您應使用 {@link android.app.Activity#onPause()} 回呼執行以下操作: +</p> + +<ul> + <li>停止動畫或會耗用 CPU 資源的其他進行中行為。</li> + <li>認可未儲存的變更,但是只有在使用者希望離開時永久儲存此類變更 (例如電子郵件草稿) 的情況下才執行此操作。 +</li> + <li>釋放系統資源,例如廣播接收器、感應器 (如 GPS) 的控點,或釋放在您的應用行為顯示暫停時可能影響電池使用壽命 (且使用者不再需要) 的資源。 + +</li> +</ul> + +<p>例如,若您的應用程式使用 {@link android.hardware.Camera},則使用 {@link android.app.Activity#onPause()} 方法可以良好地將其釋放。 +</p> + +<pre> +@Override +public void onPause() { + super.onPause(); // Always call the superclass method first + + // Release the Camera because we don't need it when paused + // and other activities might need to use it. + if (mCamera != null) { + mCamera.release() + mCamera = null; + } +} +</pre> + +<p>一般而言,您<strong>不</strong>應使用 {@link android.app.Activity#onPause()} 將使用者變更 (例如表單中輸入的個人資訊) 儲存至永久儲存空間。 +只有在您確信使用者希望自動儲存變更 (例如在起草電子郵件的情況下) 時,才應將使用者變更保留在 {@link android.app.Activity#onPause()} 中的永久儲存空間內。但是在 {@link +android.app.Activity#onPause()} 期間,您應避免執行耗用大量 CPU 資源的工作 (例如寫入至資料庫),因為這會降低向下一個應用行為顯示進行視覺轉換的速度 (您應改為在 {@link android.app.Activity#onStop onStop()} 期間執行高負荷的關機作業)。 + + + + +</p> + +<p>對於使用 {@link android.app.Activity#onPause +onPause()} 方法執行的作業,應保持相對簡單,以便在您的應用行為顯示實際正在停止的情況下,實現向使用者下一個目標的快速轉換。 +</p> + +<p class="note"><strong>注意:</strong>您的應用行為顯示暫停後,{@link +android.app.Activity} 執行個體將保留在記憶體中,應用行為顯示繼續時將重新呼叫該執行個體。您無需重新初始化在使用回呼方法 (導致產生「已繼續」狀態) 期間建立的元件。 + +</p> + + + +<h2 id="Resume">繼續您的應用行為顯示</h2> + +<p>若使用者從「已暫停」狀態繼續執行您的應用行為顯示,系統會呼叫 {@link +android.app.Activity#onResume()} 方法。</p> + +<p>請注意,每次您的應用行為顯示進入前景時 (包括第一次建立該應用行為顯示時),系統都會呼叫此方法。 +因此,您應實作 {@link +android.app.Activity#onResume()},以初始化您在 {@link +android.app.Activity#onPause()} 期間釋放的元件,並執行每次應用行為顯示進入「已繼續」狀態時必須進行的其他初始化 (例如開始播放動畫,以及對只有在應用行為顯示具有使用者焦點時才使用的元件進行初始化)。 + +</p> + +<p>以下 {@link android.app.Activity#onResume()} 範例是上述 {@link android.app.Activity#onPause()} 範例的對應,會針對應用行為顯示暫停時釋放的相機執行初始化。 + +</p> + +<pre> +@Override +public void onResume() { + super.onResume(); // Always call the superclass method first + + // Get the Camera instance as the activity achieves full user focus + if (mCamera == null) { + initializeCamera(); // Local method to handle camera init + } +} +</pre> + + + + + + + diff --git a/docs/html-intl/intl/zh-tw/training/basics/activity-lifecycle/recreating.jd b/docs/html-intl/intl/zh-tw/training/basics/activity-lifecycle/recreating.jd new file mode 100644 index 0000000..4b0efda --- /dev/null +++ b/docs/html-intl/intl/zh-tw/training/basics/activity-lifecycle/recreating.jd @@ -0,0 +1,178 @@ +page.title=重新建立應用行為顯示 +page.tags=應用行為顯示生命週期 +helpoutsWidget=true + +trainingnavtop=true + +@jd:body + +<div id="tb-wrapper"> + <div id="tb"> + + <h2>本課程示範</h2> + <ol> + <li><a href="#SaveState">儲存您的應用行為顯示狀態</a></li> + <li><a href="#RestoreState">還原您的應用行為顯示狀態</a></li> + </ol> + + <h2>您也應該閱讀</h2> + <ul> + <li><a href="{@docRoot}training/basics/supporting-devices/screens.html">支援不同的螢幕</a> +</li> + <li><a href="{@docRoot}guide/topics/resources/runtime-changes.html">處理執行階段變更</a></li> + <li><a href="{@docRoot}guide/components/activities.html">應用行為顯示</a> + </li> + </ul> + + </div> +</div> + +<p>在某些情況下,您的應用行為顯示會因應用程式的正常行為 (例如使用者按下 <em>[返回]</em>按鈕) 而遭終結,或您的應用行為顯示透過呼叫 {@link android.app.Activity#finish()} 來示意自身發生毀損。 + +此外,在您的應用行為顯示目前已停止並且已長時間未使用時,或者在系統因前景應用行為顯示需要更多資源而必須關閉背景程序以復原記憶體時,系統可能會終結您的應用行為顯示。 + +</p> + +<p>若您的應用行為顯示因使用者按下 <em>[返回]</em>按鈕而遭終結,或應用行為顯示將自身終止,則系統中該 {@link android.app.Activity} 執行個體的概念將永遠無法實現,因為該行為表示不再需要此應用行為顯示。 + +但是,若系統因系統限制 (而非因應用程式正常行為) 而終結應用行為顯示,則雖然實際的 {@link android.app.Activity} 執行個體不會執行,但系統會記住該執行個體曾經存在,因此若使用者重新導覽至該應用行為顯示,系統會使用對應用行為顯示遭終結時的狀態進行描述的一組已儲存資料,建立該應用行為顯示的新執行個體。 + + + +系統用於還原先前狀態的已儲存資料稱為「執行個體狀態」,是 {@link android.os.Bundle} 物件中所儲存索引鍵值配對的集合。 + +</p> + +<p class="caution"><strong>注意:</strong>使用者每次旋轉螢幕時,都會終結並重新建立您的應用行為顯示。 +螢幕變更方向時,系統會終結並重新建立前景應用行為顯示,因為螢幕組態已變更,您的應用行為顯示可能需要載入替代資源 (例如版面配置)。 + +</p> + +<p>依預設,系統會使用 {@link android.os.Bundle} 執行個體狀態將每個 {@link android.view.View} 物件的有關資訊 (例如輸入至 {@link android.widget.EditText} 物件中的文字值) 儲存至您的應用行為顯示版面配置中。 + +因此,若終結並重新建立您的應用行為顯示執行個體,會將版面配置的狀態還原為其先前的狀態,您無需輸入任何程式碼。 + +但是,您可能希望還原更多的應用行為顯示狀態資訊,例如成員變數 (可追蹤應用行為顯示中使用者的進度)。 + +</p> + +<p class="note"><strong>注意:</strong>若要讓 Android 系統還原應用行為顯示中檢視的狀態, +<strong>每個檢視都必須具有唯一的 ID</strong> (由 <a href="{@docRoot}reference/android/view/View.html#attr_android:id">{@code +android:id}</a> 屬性提供)。 +</p> + +<p>若要儲存有關應用行為顯示狀態的其他資料,您必須覆寫 {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()} 回呼方法。系統會在使用者離開您的應用行為顯示時呼叫此方法,並向其傳遞 {@link android.os.Bundle} 物件 (在您的應用行為顯示遭到非預期終結時將儲存該物件)。 + + + +若系統必須稍後重新建立應用行為顯示執行個體,會將同一 {@link +android.os.Bundle} 物件傳遞至 {@link android.app.Activity#onRestoreInstanceState +onRestoreInstanceState()} 與 {@link android.app.Activity#onCreate onCreate()} 方法。 + +</p> + +<img src="{@docRoot}images/training/basics/basic-lifecycle-savestate.png" /> +<p class="img-caption"><strong>圖 2.</strong>系統開始停止您的應用行為顯示時,會呼叫 {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()} (1),因此您可以指定在必須重新建立 {@link android.app.Activity} 執行個體時希望儲存的其他狀態資料。若已終結應用行為顯示,且必須重新建立該執行個體,系統會將 (1) 中定義的狀態資料傳遞至 {@link android.app.Activity#onCreate onCreate()} 方法 (2) 與 {@link android.app.Activity#onRestoreInstanceState onRestoreInstanceState()} 方法 (3)。 + + + + + + +</p> + + + +<h2 id="SaveState">儲存您的應用行為顯示狀態</h2> + +<p>在您的應用行為顯示開始停止時,系統會呼叫 {@link android.app.Activity#onSaveInstanceState +onSaveInstanceState()},因此您的應用行為顯示可將狀態資訊與索引鍵值配對的集合一併儲存。 +此方法的預設實作會儲存應用行為顯示的檢視層次狀態相關資訊 (例如 {@link android.widget.EditText} 小工具中的文字或 {@link android.widget.ListView} 的捲動位置)。 + +</p> + +<p>若要儲存應用行為顯示的其他狀態資訊,您必須實作 {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()},並將索引鍵值配對新增至 {@link android.os.Bundle} 物件。 + +例如:</p> + +<pre> +static final String STATE_SCORE = "playerScore"; +static final String STATE_LEVEL = "playerLevel"; +... + +@Override +public void onSaveInstanceState(Bundle savedInstanceState) { + // Save the user's current game state + savedInstanceState.putInt(STATE_SCORE, mCurrentScore); + savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel); + + // Always call the superclass so it can save the view hierarchy state + super.onSaveInstanceState(savedInstanceState); +} +</pre> + +<p class="caution"><strong>注意:</strong>請始終呼叫 {@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()} 的超級類別實作,以便預設實作可儲存檢視階層的狀態。 +</p> + + + +<h2 id="RestoreState">還原您的應用行為顯示狀態</h2> + +<p>在重新建立先前終結的應用行為顯示時,您可以從 {@link android.os.Bundle} 復原系統向您的應用行為顯示傳遞的已儲存狀態。 + +{@link android.app.Activity#onCreate onCreate()} 與 {@link +android.app.Activity#onRestoreInstanceState onRestoreInstanceState()} 回呼方法會接收同一 {@link android.os.Bundle} (包含執行個體狀態資訊)。 +</p> + +<p>由於不論系統是建立應用行為顯示的新執行個體,還是重新建立先前的執行個體,都會呼叫 {@link android.app.Activity#onCreate onCreate()} 方法,因此您必須先檢查狀態 {@link android.os.Bundle} 是否為 null,然後再嘗試對其進行讀取。 + +若其為 null,表示系統正在建立應用行為顯示的新執行個體,否則表示正在還原先前已終結的執行個體。 + +</p> + +<p>例如,以下為您展示了如何在 {@link android.app.Activity#onCreate +onCreate()} 中還原某些狀態資料:</p> + +<pre> +@Override +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); // Always call the superclass first + + // Check whether we're recreating a previously destroyed instance + if (savedInstanceState != null) { + // Restore value of members from saved state + mCurrentScore = savedInstanceState.getInt(STATE_SCORE); + mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL); + } else { + // Probably initialize members with default values for a new instance + } + ... +} +</pre> + +<p>您可以選擇並非在 {@link android.app.Activity#onCreate onCreate()} 期間還原狀態,而是實作 {@link +android.app.Activity#onRestoreInstanceState onRestoreInstanceState()},系統會在呼叫 {@link android.app.Activity#onStart()} 方法後呼叫該項目。 + +只有存在要還原的已儲存狀態時,系統才會呼叫 {@link +android.app.Activity#onRestoreInstanceState onRestoreInstanceState()},因此您無需檢查 {@link android.os.Bundle} 是否為 null: +</p> + +<pre> +public void onRestoreInstanceState(Bundle savedInstanceState) { + // Always call the superclass so it can restore the view hierarchy + super.onRestoreInstanceState(savedInstanceState); + + // Restore state members from saved instance + mCurrentScore = savedInstanceState.getInt(STATE_SCORE); + mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL); +} +</pre> + +<p class="caution"><strong>注意:</strong>請始終呼叫 {@link +android.app.Activity#onRestoreInstanceState onRestoreInstanceState()} 的超級類別實作,以便預設實作可還原檢視階層的狀態。 +</p> + +<p>若要詳細了解因執行階段中的重新啟動事件 (例如在旋轉螢幕時) 而重新建立應用行為顯示,請閱讀<a href="{@docRoot}guide/topics/resources/runtime-changes.html">處理執行階段變更</a>。 +</p> + diff --git a/docs/html-intl/intl/zh-tw/training/basics/activity-lifecycle/starting.jd b/docs/html-intl/intl/zh-tw/training/basics/activity-lifecycle/starting.jd new file mode 100644 index 0000000..3453ac5 --- /dev/null +++ b/docs/html-intl/intl/zh-tw/training/basics/activity-lifecycle/starting.jd @@ -0,0 +1,285 @@ +page.title=啟動應用行為顯示 +page.tags=應用行為顯示的生命週期 +helpoutsWidget=true + +trainingnavtop=true + +@jd:body + + +<div id="tb-wrapper"> + <div id="tb"> + + <h2>本課程示範</h2> +<ol> + <li><a href="#lifecycle-states">了解生命週期回呼</a></li> + <li><a href="#launching-activity">指定您應用程式的啟動器應用行為顯示</a></li> + <li><a href="#Create">建立新執行個體</a></li> + <li><a href="#Destroy">終結應用行為顯示</a></li> +</ol> + + <h2>您也應該閱讀</h2> + <ul> + <li><a href="{@docRoot}guide/components/activities.html">應用行為顯示</a></li> + </ul> + +<h2>試試看</h2> + +<div class="download-box"> + <a href="http://developer.android.com/shareables/training/ActivityLifecycle.zip" class="button">下載示範</a> + <p class="filename">ActivityLifecycle.zip</p> +</div> + + </div> +</div> + +<p>在其他程式設計範例中,使用 {@code main()} 方法啟動應用程式,而 Android 系統與此不同,透過呼叫與 {@link android.app.Activity} 執行個體生命週期的特定階段相對應的特定回呼方法,在該執行個體中啟動程式碼。 + + +可以採用一系列回呼方法啟動應用行為顯示,也可以採用一系列回呼方法終結應用行為顯示。 +</p> + +<p>本課程將概述最重要的生命週期方法,並為您展示如何處理第一個生命週期回呼 (該回呼會建立應用行為顯示的新執行個體)。 +</p> + + + +<h2 id="lifecycle-states">了解生命週期回呼</h2> + +<p>在應用行為顯示的生命週期內,系統會以類似於階梯金字塔的順序,呼叫一組核心生命週期方法。 +換言之,應用行為顯示生命週期的每個階段都是金字塔上的一個台階。 +在系統建立新應用行為顯示執行個體時,每個回呼方法都會將應用行為顯示狀態向頂部移動一個台階。 +在金字塔的頂部,應用行為顯示將在前景中執行,使用者可以與應用行為顯示互動。 +</p> + +<p>在使用者開始離開應用行為顯示時,系統會呼叫可將應用行為顯示狀態沿金字塔下移的其他方法,以終結應用行為顯示。 +在某些狀況下,應用行為顯示會沿金字塔僅移動部分台階,然後開始等候 (例如若使用者切換至其他應用程式),應用行為顯示可以由此移回頂部 (若使用者返回該應用行為顯示),並在使用者先前停止的位置繼續。 + + +</p> + + +<img src="{@docRoot}images/training/basics/basic-lifecycle.png" /> +<p class="img-caption"><strong>圖 1.</strong>應用行為顯示生命週期的簡化圖例 (以階梯金字塔表示)。 +此圖例顯示,對於讓應用行為顯示向頂部的「已繼續」狀態邁上一個台階所用的每個回呼,都存在可讓應用行為顯示下移的回呼方法。 + +應用行為顯示也可以從「已暫停」及「已停止」狀態返回至「已繼續」狀態。 +</p> + + +<p>視應用行為顯示的複雜程度而定,您可能不需要實作所有生命週期方法。 +但是,請務必了解每個生命週期方法,並實作能確保您的應用程式以使用者預期方式運作的生命週期方法。 +正確實作應用行為顯示生命週期方法可確保您的應用程式以多種方式良好運作,包括: +</p> +<ul> + <li>使用您的應用程式時,若使用者接電話或切換至其他應用程式,不會發生當機。 +</li> + <li>使用者未主動使用時,不會耗用寶貴的系統資源。 +</li> + <li>若使用者離開您的應用程式並在稍後返回,使用者的進度不會遺失。 +</li> + <li>若螢幕方向在橫向與直向之間旋轉,不會發生當機或遺失使用者的進度。 +</li> +</ul> + +<!-- +<p class="table-caption"><strong>Table 1.</strong> Activity lifecycle state pairs and callback +methods.</p> +<table> + <tr> + <th scope="col">Lifecycle State</th> + <th scope="col">Startup Method</th> + <th scope="col">Teardown Method</th> + </tr> + <tr> + <td>Created / Destroyed</td> + <td>{@link android.app.Activity#onCreate onCreate()}</td> + <td>{@link android.app.Activity#onDestroy()}</td> + </tr> + <tr> + <td>Started / Stopped</td> + <td>{@link android.app.Activity#onStart()}</td> + <td>{@link android.app.Activity#onStop()}</td> + </tr> + <tr> + <td>Resumed / Resumed</td> + <td>{@link android.app.Activity#onResume()}</td> + <td>{@link android.app.Activity#onPause()}</td> + </tr> +</table> +--> + +<p>在以下課程中您將了解到,某些情況下應用行為顯示會在不同的狀態之間進行轉換,如圖 1 所示。 +但是在這些狀態中,只有三種可以是靜態狀態。 +換言之,應用行為顯示長時間存在時,只能具備這三種狀態的其中之一: +</p> +<dl> + <dt>已繼續</dt> + <dd>若具備此狀態,應用行為顯示將位於前景中,使用者可以與應用行為顯示互動 (有時也稱為「執行中」狀態)。 +</dd> + <dt>已暫停</dt> + <dd>若具備此狀態,該應用行為顯示的一部分會遭其他應用行為顯示遮蓋,— +位於前景中的其他應用行為顯示處於半透明狀態,或未覆蓋整個螢幕。已暫停的應用行為顯示不會接收使用者輸入,也無法執行任何程式碼。 + + <dt>已停止</dt> + <dd>若具備此狀態,應用行為顯示將完全隱藏,使用者無法看到;會將該應用行為顯示視為位於背景中。 +停止後,會保留應用行為顯示執行個體及其所有狀態資訊 (例如成員變數),但其無法執行任何程式碼。 +</dd> +</dl> + +<p>其他狀態 (「已建立」與「已啟動」) 都是暫時狀態,系統透過呼叫下一個生命週期回呼方法,會從這些狀態快速移至下一個狀態。 +換言之,在系統呼叫 {@link android.app.Activity#onCreate onCreate()} 後,會快速呼叫 {@link +android.app.Activity#onStart()},然後快速呼叫 {@link +android.app.Activity#onResume()}。 +</p> + +<p>以上所述是應用行為顯示的基本生命週期。現在您將開始了解某些特定生命週期行為。 +</p> + + + +<h2 id="launching-activity">指定您應用程式的啟動器應用行為顯示</h2> + +<p>若使用者從主螢幕中選取您的應用程式圖示,系統會針對應用程式中您已宣告作為「啟動器」(或「主程式」) 應用行為顯示的 {@link android.app.Activity},呼叫 {@link +android.app.Activity#onCreate onCreate()} 方法。 +此應用行為顯示將作為您應用程式使用者介面的主要進入點。 +</p> + +<p>您可以定義 Android 宣示說明檔案 (即 <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">{@code AndroidManifest.xml}</a>,位於您專案目錄的根目錄中) 中用作主要應用行為顯示的應用行為顯示。 +</p> + +<p>必須在宣示說明中使用 <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code +<intent-filter>}</a> (包括 {@link +android.content.Intent#ACTION_MAIN MAIN} 行為與 {@link android.content.Intent#CATEGORY_LAUNCHER LAUNCHER} 類別) 宣告您應用程式的主要應用行為顯示。 +例如:</p> + +<pre> +<activity android:name=".MainActivity" android:label="@string/app_name"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> +</activity> +</pre> + +<p class="note"><strong>注意:</strong>使用 Android SDK 工具建立新 Android 專案時,預設專案檔案包括宣示說明中使用此篩選器宣告的 {@link android.app.Activity} 類別。 + +</p> + +<p>若未針對您的其中一項應用行為顯示宣告 {@link android.content.Intent#ACTION_MAIN MAIN} 行為或 {@link android.content.Intent#CATEGORY_LAUNCHER LAUNCHER} 類別,您的應用程式圖示將不會顯示在主螢幕的應用程式清單中。 + +</p> + + + +<h2 id="Create">建立新執行個體</h2> + +<p>大多數應用程式都包括多項不同的應用行為顯示,使用者可以藉此執行不同的行為。不論應用行為顯示是使用者按一下應用程式圖示時建立的主要應用行為顯示,還是您的應用程式為回應使用者行為而啟動的其他應用行為顯示,系統都會呼叫 {@link android.app.Activity#onCreate onCreate()} 方法,以建立 {@link android.app.Activity} 的每個新執行個體。 + + + +</p> + +<p>您必須實作 {@link android.app.Activity#onCreate onCreate()} 方法以執行基本的應用程式啟動邏輯,在應用行為顯示的整個生命週期內,該操作應僅執行一次。 +例如,實作 {@link android.app.Activity#onCreate onCreate()} 將定義使用者介面,並且可能會啟動某些類別範圍的變數。 + +</p> + +<p>例如,以下 {@link android.app.Activity#onCreate onCreate()} 方法範例展示的一些程式碼將執行應用行為顯示的某些基礎設定,諸如宣告使用者介面 (在 XML 版面配置檔案中定義)、定義成員變數,以及設定 UI 的某些部分。 + + +</p> + +<pre> +TextView mTextView; // Member variable for text view in the layout + +@Override +public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Set the user interface layout for this Activity + // The layout file is defined in the project res/layout/main_activity.xml file + setContentView(R.layout.main_activity); + + // Initialize member TextView so we can manipulate it later + mTextView = (TextView) findViewById(R.id.text_message); + + // Make sure we're running on Honeycomb or higher to use ActionBar APIs + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + // For the main activity, make sure the app icon in the action bar + // does not behave as a button + ActionBar actionBar = getActionBar(); + actionBar.setHomeButtonEnabled(false); + } +} +</pre> + +<p class="caution"><strong>注意:</strong>僅在 Android 2.0 (API 層級為 5) 及更高版本中,可以透過此方式使用 {@link android.os.Build.VERSION#SDK_INT} 防止舊版系統執行新 API。 + +在舊版系統中,將發生執行階段例外狀況。</p> + +<p>{@link android.app.Activity#onCreate onCreate()} 執行完成後,系統會連續快速呼叫 {@link android.app.Activity#onStart()} 與 {@link android.app.Activity#onResume()} 方法。 + +您的應用行為顯示永遠不會具備「已建立」或「已啟動」狀態。嚴格來說,在呼叫 {@link android.app.Activity#onStart()} 時,使用者可以看到應用行為顯示,但隨後會快速呼叫 {@link android.app.Activity#onResume()},應用行為顯示將保持「已繼續」狀態,直到發生某些狀況 (例如接聽電話、使用者導覽至其他應用行為顯示,或裝置螢幕關閉) 變更該狀態為止。 + + + +</p> + +<p>在後續的其他課程中,您將了解在應用行為顯示的生命週期期間,其他啟動方法 ({@link +android.app.Activity#onStart()} 與 {@link android.app.Activity#onResume()}) 在用於從「已暫停」或「已停止」狀態繼續執行應用行為顯示時如何提供助益。 +</p> + +<p class="note"><strong>注意:</strong>{@link android.app.Activity#onCreate onCreate()} 方法包括稱為 <code>savedInstanceState</code> 的參數,在有關<a href="recreating.html">重新建立應用行為顯示</a>的後續課程中將討論該參數。 + +</p> + + +<img src="{@docRoot}images/training/basics/basic-lifecycle-create.png" /> +<p class="img-caption"><strong>圖 2.</strong>應用行為顯示生命週期結構的另一個圖例 (著重展示系統建立應用行為顯示的新執行個體時依次呼叫的三個主要回呼:{@link android.app.Activity#onCreate onCreate()}、{@link +android.app.Activity#onStart()} 及 {@link android.app.Activity#onResume()}。 + +完成這一系列的回呼後,應用行為顯示將具備「已繼續」狀態,此時使用者可以與應用行為顯示互動,直到使用者切換至其他應用行為顯示為止。 + +</p> + + + + + + + +<h2 id="Destroy">終結應用行為顯示</h2> + +<p>應用行為顯示的第一個生命週期回呼是 {@link android.app.Activity#onCreate +onCreate()},最後一個回呼是 {@link android.app.Activity#onDestroy}。系統針對您的應用行為顯示呼叫此方法作為最終訊號,表示正從系統記憶體中完全移除您的應用行為顯示執行個體。 + +</p> + +<p>大多數應用程式不需要實作此方法,因為區域類別參考與應用行為顯示一併終結,您的應用行為顯示應在 {@link +android.app.Activity#onPause} 與 {@link android.app.Activity#onStop} 期間執行大多數清理。 +但是,若您的應用行為顯示包括 {@link +android.app.Activity#onCreate onCreate()} 期間建立的背景執行緒,或包括其他長時間執行的資源 (若未正確關閉,可能會導致記憶體流失),您應在 {@link +android.app.Activity#onDestroy} 期間終止這些執行緒或資源。 + +</p> + +<pre> +@Override +public void onDestroy() { + super.onDestroy(); // Always call the superclass + + // Stop method tracing that the activity started during onCreate() + android.os.Debug.stopMethodTracing(); +} +</pre> + +<p class="note"><strong>注意:</strong>在所有情況下,系統會在已呼叫 {@link android.app.Activity#onPause} 與 {@link +android.app.Activity#onStop} 後呼叫 {@link android.app.Activity#onDestroy},但在 {@link android.app.Activity#onCreate onCreate()} 方法中呼叫 {@link +android.app.Activity#finish()} 的情況除外。 + +在某些情況下 (例如您應用行為顯示的執行目的在於臨時確定是否啟動其他應用行為顯示),您可能會從 {@link +android.app.Activity#onCreate onCreate()} 中呼叫 {@link android.app.Activity#finish()} 以終結應用行為顯示。 +若是如此,系統會立即呼叫 {@link android.app.Activity#onDestroy},而不會呼叫其他任何生命週期方法。 + +</p> diff --git a/docs/html-intl/intl/zh-tw/training/basics/activity-lifecycle/stopping.jd b/docs/html-intl/intl/zh-tw/training/basics/activity-lifecycle/stopping.jd new file mode 100644 index 0000000..a2da5ca --- /dev/null +++ b/docs/html-intl/intl/zh-tw/training/basics/activity-lifecycle/stopping.jd @@ -0,0 +1,187 @@ +page.title=停止並重新啟動應用行為顯示 +page.tags=應用行為顯示生命週期 +helpoutsWidget=true + +trainingnavtop=true + +@jd:body + +<div id="tb-wrapper"> + <div id="tb"> + + <h2>本課程示範</h2> + <ol> + <li><a href="#Stop">停止您的應用行為顯示</a></li> + <li><a href="#Start">啟動/重新啟動您的應用行為顯示</a></li> + </ol> + + <h2>您也應該閱讀</h2> + <ul> + <li><a href="{@docRoot}guide/components/activities.html">應用行為顯示</a> + </li> + </ul> + +<h2>試試看</h2> + +<div class="download-box"> + <a href="http://developer.android.com/shareables/training/ActivityLifecycle.zip" class="button">下載示範</a> + <p class="filename">ActivityLifecycle.zip</p> +</div> + + </div> +</div> + +<p>正確停止並重新啟動您的應用行為顯示是應用行為顯示生命週期內的重要程序,該程序可確保使用者感知您的應用程式在持續運作,而且不會遺失進度。在以下一些重要情況下,會停止並重新啟動您的應用行為顯示: + +</p> + +<ul> + <li>使用者開啟 [最近的應用程式] 視窗,並從您的應用程式切換至其他應用程式。在您的應用程式內,目前位於前景中的應用行為顯示將停止。 +若使用者從主螢幕啟動器圖示或 [最近的應用程式] 視窗返回至您的應用程式,應用行為顯示將重新啟動。 +</li> + <li>使用者在您的應用程式中執行啟動新應用行為顯示的行為。建立第二個應用行為顯示時,目前的應用行為顯示將停止。 +若使用者隨後按下 <em>[返回]</em> 按鈕,第一個應用行為顯示將重新啟動。 +</li> + <li>使用者在其電話上使用您的應用程式時,會接聽電話。</li> +</ul> + +<p>{@link android.app.Activity} 類別可提供兩種生命週期方法,即 {@link +android.app.Activity#onStop()} 與 {@link android.app.Activity#onRestart()},您可藉此明確處理如何停止並重新啟動您的應用行為顯示控點。 +處於暫停狀態時,會發生部分 UI 受阻的狀況,但停止狀態與此不同,可保證 UI 不再可見,使用者的焦點在於獨立的應用行為顯示 (或完全獨立的應用程式) 中。 + +</p> + +<p class="note"><strong>注意:</strong>由於在您的 {@link android.app.Activity} 執行個體停止時,系統會將其保留在系統記憶體中,因此您可能完全不需要實作 {@link android.app.Activity#onStop()} 與 {@link android.app.Activity#onRestart()} (甚至 {@link +android.app.Activity#onStart()}) 方法。 + +對於相對簡單的大多數應用行為顯示,應用行為顯示會正常停止並重新啟動,您可能只需要使用 {@link +android.app.Activity#onPause()} 暫停進行中的行為,並與系統資源中斷連線。 +</p> + +<img src="{@docRoot}images/training/basics/basic-lifecycle-stopped.png" /> +<p class="img-caption"><strong>圖 1.</strong>使用者離開您的應用行為顯示時,系統將呼叫 {@link android.app.Activity#onStop onStop()} 以停止應用行為顯示 (1)。 +若使用者在停止應用行為顯示時返回,系統將呼叫 {@link android.app.Activity#onRestart onRestart()} (2),然後快速呼叫 {@link android.app.Activity#onStart onStart()} (3) 與 {@link +android.app.Activity#onResume()} (4)。 + +請注意,不論何種狀況導致應用行為顯示停止,系統始終會先呼叫 {@link android.app.Activity#onPause onPause()},然後呼叫 {@link +android.app.Activity#onStop onStop()}。 +</p> + + + +<h2 id="Stop">停止您的應用行為顯示</h2> + +<p>您的應用行為顯示收到對 {@link android.app.Activity#onStop()} 方法的呼叫時,將不再可見,並會在使用者不使用時釋放不需要的幾乎所有資源。 + +在停止您的應用行為顯示後,若系統需要復原系統記憶體,可能會終結執行個體。 +在極少數狀況下,系統可能只會終止應用程式的程序,而不會呼叫應用行為顯示的最終 {@link android.app.Activity#onDestroy()} 回呼,因此請您務必使用 {@link android.app.Activity#onStop()} 釋放可能導致記憶體流失的資源。 + +</p> + +<p>雖然會先呼叫 {@link android.app.Activity#onPause onPause()} 方法,然後呼叫 {@link android.app.Activity#onStop()},但是您應使用 {@link android.app.Activity#onStop onStop()} 執行規模更大、耗用 CPU 資源更多的關閉作業,諸如將資訊寫入至資料庫。 + + +</p> + +<p>例如,以下範例展示了 {@link android.app.Activity#onStop onStop()} 的實作,該實作將註記草稿的內容儲存至永續性儲存體: +</p> + +<!-- TODO: Find a better example for onStop, because this kind of thing should probably use a +separate thread but that's too complicated to show here. --> +<pre> +@Override +protected void onStop() { + super.onStop(); // Always call the superclass method first + + // Save the note's current draft, because the activity is stopping + // and we want to be sure the current note progress isn't lost. + ContentValues values = new ContentValues(); + values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText()); + values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle()); + + getContentResolver().update( + mUri, // The URI for the note to update. + values, // The map of column names and new values to apply to them. + null, // No SELECT criteria are used. + null // No WHERE columns are used. + ); +} +</pre> + +<p>您的應用行為顯示停止後,{@link android.app.Activity} 物件將保留在記憶體中,應用行為顯示繼續時將重新呼叫該物件。 +您無需重新初始化在使用回呼方法 (導致產生「已繼續」狀態) 期間建立的元件。 +此外,系統還會追蹤版面配置中每個 {@link android.view.View} 的目前狀態,因此若使用者在 {@link android.widget.EditText} 小工具中輸入文字,將保留該內容,您無需對其執行儲存與還原。 + + +</p> + +<p class="note"><strong>注意:</strong>即使系統在您的應用行為顯示停止時將其終結,該應用行為顯示仍在 {@link android.os.Bundle} (索引鍵值配對的二進位大型物件) 中保留 {@link android.view.View} 物件 (例如 {@link +android.widget.EditText} 中的文字) 的狀態,若使用者重新導覽至應用行為顯示的同一執行個體,會還原這些物件 (<a href="recreating.html">下一課</a>將更詳細地討論在終結並重新建立您的應用行為顯示時使用 {@link android.os.Bundle} 儲存其他狀態資料)。 + + +</p> + + + +<h2 id="Start">啟動/重新啟動您的應用行為顯示</h2> + +<p>您的應用行為顯示從停止狀態回到前景中時,會收到對 {@link android.app.Activity#onRestart()} 的呼叫。 +此外,系統還會呼叫 {@link +android.app.Activity#onStart()} 方法,每次您的應用行為顯示變為可見時 (不論是重新啟動還是第一次建立),都會執行此操作。 +但是,只有在應用行為顯示從停止狀態繼續時,才會呼叫 {@link +android.app.Activity#onRestart()} 方法,因此,您可將其用於執行只有在先前停止但未終結應用行為顯示時才需要執行的特殊還原工作。 + +</p> + +<p>應用程式需要使用 {@link android.app.Activity#onRestart()} 來還原應用行為顯示狀態的狀況並不常見,因此針對適用於普通應用程式的這一方法,不存在任何指導方針。 + +但是,由於您的 {@link android.app.Activity#onStop()} 方法將基本上清除應用行為顯示的所有資源,因此在應用行為顯示重新啟動時,您需要重新啟動這些資源。 + +此外,在首次建立應用行為顯示時 (此時不存在既有的應用行為顯示執行個體),您也需要重新啟動這些資源。 +因此,您通常應使用 {@link android.app.Activity#onStart()} 回呼方法作為 {@link android.app.Activity#onStop()} 方法的對應,因為系統在建立您的應用行為顯示以及從停止狀態重新啟動應用行為顯示時,都會呼叫 {@link +android.app.Activity#onStart()}。 + + +</p> + +<p>例如,由於使用者可能離開應用程式很長時間後才回到應用程式,因此使用 {@link android.app.Activity#onStart()} 方法可以良好地驗證所需的系統功能是否已啟用: + +</p> + +<pre> +@Override +protected void onStart() { + super.onStart(); // Always call the superclass method first + + // The activity is either being restarted or started for the first time + // so this is where we should make sure that GPS is enabled + LocationManager locationManager = + (LocationManager) getSystemService(Context.LOCATION_SERVICE); + boolean gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); + + if (!gpsEnabled) { + // Create a dialog here that requests the user to enable GPS, and use an intent + // with the android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS action + // to take the user to the Settings screen to enable GPS when they click "OK" + } +} + +@Override +protected void onRestart() { + super.onRestart(); // Always call the superclass method first + + // Activity being restarted from stopped state +} +</pre> + + + + +<p>系統終結您的應用行為顯示時,會針對您的 {@link android.app.Activity} 呼叫 {@link android.app.Activity#onDestroy()} 方法。 +由於通常您應該已使用 {@link android.app.Activity#onStop()} 釋放大多數資源,因此在收到對 {@link +android.app.Activity#onDestroy()} 的呼叫之前,大多數應用程式幾乎都不需要執行操作。 +此方法將為您提供對可能導致記憶體流失的資源執行清理的最後機會,因此您應確保已終結其他執行緒,並確保已停止長時間執行的其他行為 (例如方法追蹤)。 + + +</p> + diff --git a/docs/html-intl/intl/zh-tw/training/basics/data-storage/databases.jd b/docs/html-intl/intl/zh-tw/training/basics/data-storage/databases.jd new file mode 100644 index 0000000..f3706f1 --- /dev/null +++ b/docs/html-intl/intl/zh-tw/training/basics/data-storage/databases.jd @@ -0,0 +1,317 @@ +page.title=在 SQL 資料庫中儲存資料 +page.tags=資料儲存空間 +helpoutsWidget=true + +trainingnavtop=true + +@jd:body + + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>本課程示範</h2> +<ol> + <li><a href="#DefineContract">定義結構描述與合約</a></li> + <li><a href="#DbHelper">使用 SQL Helper 建立資料庫</a></li> + <li><a href="#WriteDbRow">將資訊置入資料庫中</a></li> + <li><a href="#ReadDbRow">讀取資料庫中的資訊</a></li> + <li><a href="#DeleteDbRow">刪除資料庫中的資訊</a></li> + <li><a href="#UpdateDbRow">更新資料庫</a></li> +</ol> + +<h2>您也應該閱讀</h2> +<ul> + <li><a href="{@docRoot}guide/topics/data/data-storage.html#db">使用資料庫</a></li> +</ul> + +<!-- +<h2>Try it out</h2> + +<div class="download-box"> + <a href="{@docRoot}shareables/training/Sample.zip" class="button">Download the sample</a> + <p class="filename">Sample.zip</p> +</div> +--> + +</div> +</div> + + +<p>對於重複資料或結構化資料 (例如連絡資訊),將其儲存至資料庫是理想的選擇。 +本課程假設您已大體熟悉 SQL 資料庫,並協助您開始在 Android 上使用 SQLite 資料庫。 + +{@link android.database.sqlite} 套件中提供在 Android 上使用資料庫所需的 API。 +</p> + + +<h2 id="DefineContract">定義結構描述與合約</h2> + +<p>SQL 資料庫的其中一項主要準則是結構描述,即針對資料庫組織方式的正式宣告。 +在您建立資料庫所用的 SQL 陳述式中,會反映結構描述。 +您可能會發現,建立伴隨類別 (也稱為<em>合約</em>類別) 會非常有益,該類別會以系統化的自我記錄方式,明確指定結構描述的配置。 + +</p> + +<p>合約類別是常數 (可為 URI、表格與欄定義名稱) 的容器。 +藉由合約類別,您可在同一套件內的所有其他類別中使用相同的常數。 +您可藉此在一個位置變更欄名稱,然後將其傳播到全部程式碼中。 +</p> + +<p>組織合約類別的良好方式,是將適用於整個資料庫的全域定義置於類別的根層級, +然後,針對列舉欄的每個表格建立內部類別。 +</p> + +<p class="note"><strong>注意:</strong>透過實作 {@link +android.provider.BaseColumns} 介面,您的內部類別可繼承主索引鍵欄位 (稱為 {@code _ID}),某些 Android 類別 (諸如 cursor adaptor) 希望其具備該欄位。 + +此操作並非必需的操作,但是可協助您的資料庫與 Android 架構協調運作。 +</p> + +<p>例如,以下程式碼片段會定義單一表格的表格名稱與欄名稱: +</p> + + +<pre> +public final class FeedReaderContract { + // To prevent someone from accidentally instantiating the contract class, + // give it an empty constructor. + public FeedReaderContract() {} + + /* Inner class that defines the table contents */ + public static abstract class FeedEntry implements BaseColumns { + public static final String TABLE_NAME = "entry"; + public static final String COLUMN_NAME_ENTRY_ID = "entryid"; + public static final String COLUMN_NAME_TITLE = "title"; + public static final String COLUMN_NAME_SUBTITLE = "subtitle"; + ... + } +} +</pre> + + + +<h2 id="DbHelper">使用 SQL Helper 建立資料庫</h2> + +<p>定義資料庫的外觀之後,您應實作多種方法以建立並維護資料庫與表格。 +以下所示是可建立及刪除表格的某些典型陳述式: +</P> + +<pre> +private static final String TEXT_TYPE = " TEXT"; +private static final String COMMA_SEP = ","; +private static final String SQL_CREATE_ENTRIES = + "CREATE TABLE " + FeedEntry.TABLE_NAME + " (" + + FeedEntry._ID + " INTEGER PRIMARY KEY," + + FeedEntry.COLUMN_NAME_ENTRY_ID + TEXT_TYPE + COMMA_SEP + + FeedEntry.COLUMN_NAME_TITLE + TEXT_TYPE + COMMA_SEP + + ... // Any other options for the CREATE command + " )"; + +private static final String SQL_DELETE_ENTRIES = + "DROP TABLE IF EXISTS " + FeedEntry.TABLE_NAME; +</pre> + +<p>如同在裝置的<a href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">內部儲存空間</a>儲存檔案一樣,Android 會將您的資料庫儲存在與應用程式關聯的私用磁碟空間內。 + +依預設,其他應用程式無法存取此區域,因此您的資料安全無虞。 +</p> + +<p>{@link +android.database.sqlite.SQLiteOpenHelper} 類別中提供一組有用的 API。若使用此類別取得資料庫的參考,只有在需要執行且<em>並非處於應用程式啟動期間</em>時,系統才會執行資料庫的建立與更新操作 (執行時間可能很長)。 + + + +您只需呼叫 {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase} 或 +{@link android.database.sqlite.SQLiteOpenHelper#getReadableDatabase} 即可。 +</p> + +<p class="note"><strong>注意:</strong>由於這些操作的時間可能很長,因此請確保您在背景執行緒 (例如 {@link android.os.AsyncTask} 或 {@link android.app.IntentService}) 中呼叫 {@link +android.database.sqlite.SQLiteOpenHelper#getWritableDatabase} 或 {@link +android.database.sqlite.SQLiteOpenHelper#getReadableDatabase}。 + +</p> + +<p>若要使用 {@link android.database.sqlite.SQLiteOpenHelper},請建立可覆寫 {@link +android.database.sqlite.SQLiteOpenHelper#onCreate onCreate()}、{@link +android.database.sqlite.SQLiteOpenHelper#onUpgrade onUpgrade()} 與 {@link +android.database.sqlite.SQLiteOpenHelper#onOpen onOpen()} 回呼方法的子類別。 +您還可以實作 {@link android.database.sqlite.SQLiteOpenHelper#onDowngrade onDowngrade()},但這並非必需的操作。 + +</p> + +<p>例如,以下展示了 {@link +android.database.sqlite.SQLiteOpenHelper} (使用上述某些命令) 的實作:</p> + +<pre> +public class FeedReaderDbHelper extends SQLiteOpenHelper { + // If you change the database schema, you must increment the database version. + public static final int DATABASE_VERSION = 1; + public static final String DATABASE_NAME = "FeedReader.db"; + + public FeedReaderDbHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + public void onCreate(SQLiteDatabase db) { + db.execSQL(SQL_CREATE_ENTRIES); + } + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + // This database is only a cache for online data, so its upgrade policy is + // to simply to discard the data and start over + db.execSQL(SQL_DELETE_ENTRIES); + onCreate(db); + } + public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { + onUpgrade(db, oldVersion, newVersion); + } +} +</pre> + +<p>若要存取您的資料庫,請啟動 {@link +android.database.sqlite.SQLiteOpenHelper} 的子類別:</p> + +<pre> +FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(getContext()); +</pre> + + + + +<h2 id="WriteDbRow">將資訊置入資料庫中</h2> + +<p>透過將 {@link android.content.ContentValues} 物件傳遞至 {@link android.database.sqlite.SQLiteDatabase#insert insert()} 方法,可將資料插入至資料庫: +</p> + +<pre> +// Gets the data repository in write mode +SQLiteDatabase db = mDbHelper.getWritableDatabase(); + +// Create a new map of values, where column names are the keys +ContentValues values = new ContentValues(); +values.put(FeedEntry.COLUMN_NAME_ENTRY_ID, id); +values.put(FeedEntry.COLUMN_NAME_TITLE, title); +values.put(FeedEntry.COLUMN_NAME_CONTENT, content); + +// Insert the new row, returning the primary key value of the new row +long newRowId; +newRowId = db.insert( + FeedEntry.TABLE_NAME, + FeedEntry.COLUMN_NAME_NULLABLE, + values); +</pre> + +<p>{@link android.database.sqlite.SQLiteDatabase#insert insert()} 的第一個引數即為表格名稱。 +第二個引數將提供欄的名稱, + 在 {@link android.content.ContentValues} 為空時,架構可在該欄中插入 NULL (若您將其設為 {@code "null"},則在無值時,架構不會插入列)。 + +</p> + + + + +<h2 id="ReadDbRow">讀取資料庫中的資訊</h2> + +<p>若要從資料庫進行讀取,請使用 {@link android.database.sqlite.SQLiteDatabase#query query()} 方法,然後向其傳遞您的選取條件與所需的欄。該方法會合併 {@link android.database.sqlite.SQLiteDatabase#insert insert()} 與 {@link android.database.sqlite.SQLiteDatabase#update update()} 的元素,對您希望擷取的資料 (而非要插入的資料) 進行定義的欄清單除外。 + + + +將在 {@link android.database.Cursor} 物件中,為您傳回查詢結果。 +</p> + +<pre> +SQLiteDatabase db = mDbHelper.getReadableDatabase(); + +// Define a <em>projection</em> that specifies which columns from the database +// you will actually use after this query. +String[] projection = { + FeedEntry._ID, + FeedEntry.COLUMN_NAME_TITLE, + FeedEntry.COLUMN_NAME_UPDATED, + ... + }; + +// How you want the results sorted in the resulting Cursor +String sortOrder = + FeedEntry.COLUMN_NAME_UPDATED + " DESC"; + +Cursor c = db.query( + FeedEntry.TABLE_NAME, // The table to query + projection, // The columns to return + selection, // The columns for the WHERE clause + selectionArgs, // The values for the WHERE clause + null, // don't group the rows + null, // don't filter by row groups + sortOrder // The sort order + ); +</pre> + +<p>若要查看游標指示的列,請使用其中一種 {@link android.database.Cursor} move 方法,您必須始終先呼叫該方法,然後再開始讀取值。 +一般而言,您應呼叫 {@link android.database.Cursor#moveToFirst} 來執行啟動,如此會將「讀取位置」置於結果中的第一個項目。 + +對於每列,您可以呼叫其中一種 {@link android.database.Cursor} get 方法 (例如 {@link android.database.Cursor#getString +getString()} 或 {@link android.database.Cursor#getLong getLong()}),以讀取欄的值。 +對於每種 get 方法,您必須傳遞所需欄的索引位置,可以呼叫 {@link android.database.Cursor#getColumnIndex getColumnIndex()} 或 +{@link android.database.Cursor#getColumnIndexOrThrow getColumnIndexOrThrow()} 取得該位置。例如: + + +</p> + +<pre> +cursor.moveToFirst(); +long itemId = cursor.getLong( + cursor.getColumnIndexOrThrow(FeedEntry._ID) +); +</pre> + + + + +<h2 id="DeleteDbRow">刪除資料庫中的資訊</h2> + +<p>若要刪除表格中的列,您需要提供識別這些列的選取條件。 +資料庫 API 可提供建立選取條件的機制 (能防止 SQL 插入)。 +該機制會將選取規格分為選取子句與選取引數。 +子句可定義要查看的欄,您也可以藉此合併欄測試。 + +引數是要測試的值,繫結在子句中。由於對結果的處理方式不同於規則 SQL 陳述式,因此結果不會遭受 SQL 插入。 + +</p> + +<pre> +// Define 'where' part of query. +String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?"; +// Specify arguments in placeholder order. +String[] selectionArgs = { String.valueOf(rowId) }; +// Issue SQL statement. +db.delete(table_name, selection, selectionArgs); +</pre> + + + +<h2 id="UpdateDbRow">更新資料庫</h2> + +<p>若您需要修改資料庫值的子集,請使用 {@link +android.database.sqlite.SQLiteDatabase#update update()} 方法。</p> + +<p>更新表格會合併 {@link +android.database.sqlite.SQLiteDatabase#insert insert()} 的內容值語法與 {@link android.database.sqlite.SQLiteDatabase#delete delete()} 的 {@code where} 語法。 +</p> + +<pre> +SQLiteDatabase db = mDbHelper.getReadableDatabase(); + +// New value for one column +ContentValues values = new ContentValues(); +values.put(FeedEntry.COLUMN_NAME_TITLE, title); + +// Which row to update, based on the ID +String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?"; +String[] selectionArgs = { String.valueOf(rowId) }; + +int count = db.update( + FeedReaderDbHelper.FeedEntry.TABLE_NAME, + values, + selection, + selectionArgs); +</pre> + diff --git a/docs/html-intl/intl/zh-tw/training/basics/data-storage/files.jd b/docs/html-intl/intl/zh-tw/training/basics/data-storage/files.jd new file mode 100644 index 0000000..8b8d0a7 --- /dev/null +++ b/docs/html-intl/intl/zh-tw/training/basics/data-storage/files.jd @@ -0,0 +1,379 @@ +page.title=儲存檔案 +page.tags=資料儲存空間 +helpoutsWidget=true + +trainingnavtop=true + +@jd:body + + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>本課程示範</h2> +<ol> + <li><a href="#InternalVsExternalStorage">選擇內部或外部儲存空間</a></li> + <li><a href="#GetWritePermission">取得外部儲存空間的權限</a></li> + <li><a href="#WriteInternalStorage">將檔案儲存在內部儲存空間</a></li> + <li><a href="#WriteExternalStorage">將檔案儲存在外部儲存空間</a></li> + <li><a href="#GetFreeSpace">查詢可用空間</a></li> + <li><a href="#DeleteFile">刪除檔案</a></li> +</ol> + +<h2>您也應該閱讀</h2> +<ul> + <li><a href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">使用內部儲存空間</a> +</li> + <li><a href="{@docRoot}guide/topics/data/data-storage.html#filesExternal">使用外部儲存空間</a> +</li> +</ul> + +</div> +</div> + +<p>Android 使用的檔案系統類似於其他平台上的磁碟式檔案系統。 +本課程將說明如何透過 Android 檔案系統,使用 {@link java.io.File} +API 讀取並寫入檔案。 +</p> + +<p>{@link java.io.File} 物件適用於以從頭到尾的順序,無一略過地讀取或寫入大量資料。 +該物件的用途很廣,例如非常適用於影像檔案或透過網路交換的項目。 +</p> + +<p>本課程將顯示如何在您的應用程式中執行與檔案相關的基本任務。本課程假設您已熟悉 Linux 檔案系統的基本概念,以及 +{@link java.io} 中的標準檔案輸入/輸出 API。 +</p> + + +<h2 id="InternalVsExternalStorage">選擇內部或外部儲存空間</h2> + +<p>所有 Android 裝置都有兩個檔案儲存區域:「內部」與「外部」儲存空間。這些名稱源自 Android 發展的初期,當時大多數裝置都提供內建靜態記憶體 (內部儲存空間),以及諸如 micro SD 卡等卸除式儲存媒體 (外部儲存空間)。有些裝置將永久儲存空間分為「內部」與「外部」分割區,因此即使沒有卸除式儲存媒體,也始終存在兩個儲存空間,不論外部儲存空間是否為卸除式媒體,API 行為都相同。以下清單將概述每個儲存空間的狀況。 + + + + + +</p> + +<div class="col-5" style="margin-left:0"> +<p><b>內部儲存空間:</b></p> +<ul> +<li>裝置始終具備內部儲存空間。</li> +<li>依預設,只有您的應用程式能存取此空間內儲存的檔案。</li> +<li>使用者解除安裝您的應用程式時,系統會從內部儲存空間移除您應用程式的所有檔案。 +</li> +</ul> +<p>若您希望確保使用者與其他應用程式都無法存取您的檔案,使用內部儲存空間是最佳選擇。 +</p> +</div> + +<div class="col-7" style="margin-right:0"> +<p><b>外部儲存空間:</b></p> +<ul> +<li>裝置並非始終具備外部儲存空間,因為使用者可以將外部儲存空間掛接為 USB 儲存裝置,在某些情況下也可以從裝置上移除外部儲存空間。 +</li> +<li>其他應用程式可以讀取外部儲存空間,因此您可能無法對該空間內儲存的檔案遭讀取的情況進行控制。 +</li> +<li>若使用者解除安裝您的應用程式,只有在您將應用程式的檔案儲存在 {@link android.content.Context#getExternalFilesDir +getExternalFilesDir()} 的目錄中時,系統才會從外部儲存空間移除您應用程式的檔案。 +</li> +</ul> +<p>對於不需要存取限制的檔案,以及您希望與其他應用程式共用的檔案,或允許使用者使用電腦存取的檔案,外部儲存空間是最佳的儲存位置。 + +</p> +</div> + + +<p class="note" style="clear:both"> +<strong>秘訣:</strong>雖然應用程式依預設會安裝在內部儲存空間,但是您可以在宣示說明中指定 <a href="{@docRoot}guide/topics/manifest/manifest-element.html#install">{@code +android:installLocation}</a> 屬性,以便可以將應用程式安裝在外部儲存空間。 + +在 APK 的大小很大,且使用者的外部儲存空間大於內部儲存空間時,使用者非常喜歡使用該選項。 +如需詳細資訊,請參閱<a href="{@docRoot}guide/topics/data/install-location.html">應用程式安裝位置</a>。 +</p> + + +<h2 id="GetWritePermission">取得外部儲存空間的權限</h2> + +<p>若要寫入至外部儲存空間,您必須在<a href="{@docRoot}guide/topics/manifest/manifest-intro.html">宣示說明檔案</a>中要求 {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} 權限: +</p> + +<pre> +<manifest ...> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + ... +</manifest> +</pre> + +<div class="caution"><p><strong>注意:</strong> +目前,所有應用程式無需特殊權限即可讀取外部儲存空間。 +但是,此狀況在將來的版本中將有所變更。若您的應用程式需要讀取外部儲存空間 (但不寫入該空間),您需要宣告 {@link +android.Manifest.permission#READ_EXTERNAL_STORAGE} 權限。 +若要確保您的應用程式仍以預期方式運作,您應立即宣告此權限,然後變更即會生效。 +</p> +<pre> +<manifest ...> + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + ... +</manifest> +</pre> +<p>但是,若您的應用程式使用 {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} 權限,則也以隱含方式具備外部儲存空間讀取權限。 +</p> +</div> + +<p>您無需任何權限即可將檔案儲存在內部儲存空間。 +您的應用程式始終具備內部儲存空間目錄中檔案的讀取與寫入權限。 +</p> + + + + + +<h2 id="WriteInternalStorage">將檔案儲存在內部儲存空間</h2> + +<p>將檔案儲存在內部儲存空間時,您可以呼叫以下兩種方法的其中之一,以 +{@link java.io.File} 擷取相應目錄:</p> + +<dl> + <dt>{@link android.content.Context#getFilesDir}</dt> + <dd>傳回代表您應用程式所用內部目錄的 {@link java.io.File}。</dd> + <dt>{@link android.content.Context#getCacheDir}</dt> + <dd>傳回代表您應用程式暫存快取檔案所用內部目錄的 {@link java.io.File}。 +請確保於不再需要檔案時刪除檔案,並針對您在任何指定時間所用的記憶體數量實作合理的大小限制,例如 1MB。 + +若系統所用的儲存空間開始不足,可能會刪除您的快取檔案而不提供警告。 +</dd> +</dl> + +<p>若要在上述其中一個目錄中建立新檔案,可以使用 {@link +java.io.File#File(File,String) File()} 建構函式,然後傳送會指定您內部儲存空間目錄的 {@link java.io.File} (由上述其中一種方法提供)。 +例如:</p> + +<pre> +File file = new File(context.getFilesDir(), filename); +</pre> + +<p>或者,您可以呼叫 {@link +android.content.Context#openFileOutput openFileOutput()},以取得寫入內部目錄中檔案的 {@link java.io.FileOutputStream}。 +例如,以下展示了如何將某些文字寫入至檔案: +</p> + +<pre> +String filename = "myfile"; +String string = "Hello world!"; +FileOutputStream outputStream; + +try { + outputStream = openFileOutput(filename, Context.MODE_PRIVATE); + outputStream.write(string.getBytes()); + outputStream.close(); +} catch (Exception e) { + e.printStackTrace(); +} +</pre> + +<p>或者,若您需要快取某些檔案,應改用 {@link +java.io.File#createTempFile createTempFile()}。例如,以下方法會從 {@link java.net.URL} 中擷取檔案名稱,然後在您應用程式的內部快取目錄中建立具有該名稱的檔案: + +</p> + +<pre> +public File getTempFile(Context context, String url) { + File file; + try { + String fileName = Uri.parse(url).getLastPathSegment(); + file = File.createTempFile(fileName, null, context.getCacheDir()); + catch (IOException e) { + // Error while creating file + } + return file; +} +</pre> + +<p class="note"><strong>注意:</strong> +您應用程式的內部儲存空間目錄由位於 Android 檔案系統特殊位置的應用程式套件名稱指定。嚴格來說,若將檔案模式設為可讀取,則其他應用程式可以讀取您的內部檔案。 + + +但是,其他應用程式也需要知道您的應用程式套件名稱與檔案名稱。 +除非您將檔案明確設為可讀取或可寫入,否則其他應用程式無法瀏覽您的內部目錄,也沒有讀取或寫入存取權。 +因此,只要您針對內部儲存空間中的檔案使用 {@link android.content.Context#MODE_PRIVATE},其他應用程式將永遠無法存取這些檔案。 + +</p> + + + + + +<h2 id="WriteExternalStorage">將檔案儲存在外部儲存空間</h2> + +<p>由於可能不具備外部儲存空間—例如使用者將儲存裝置掛接至 PC,或移除提供外部儲存空間的 SD 卡—,因此您始終應先驗證磁碟區可用,然後再對其執行存取。 + +您可以呼叫 {@link android.os.Environment#getExternalStorageState},以查詢外部儲存空間狀態。 +若傳回的狀態等於 {@link android.os.Environment#MEDIA_MOUNTED},則可以讀取並寫入檔案。 + +例如,以下方法可用於判斷儲存空間的可用性: +</p> + +<pre> +/* Checks if external storage is available for read and write */ +public boolean isExternalStorageWritable() { + String state = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED.equals(state)) { + return true; + } + return false; +} + +/* Checks if external storage is available to at least read */ +public boolean isExternalStorageReadable() { + String state = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED.equals(state) || + Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { + return true; + } + return false; +} +</pre> + +<p>雖然使用者與其他應用程式可以修改外部儲存空間,但是可在外部儲存空間儲存兩種類別的檔案: +</p> + +<dl> + <dt>公用檔案</dt> + <dd>這些檔案將供其他應用程式及使用者自由使用。 +若使用者解除安裝您的應用程式,這些檔案仍可供使用者使用。 + + <p>例如,由您的應用程式拍攝的相片或下載的其他檔案都是公用檔案。</p> + </dd> + <dt>私用檔案</dt> + <dd>這些檔案本屬於您的應用程式,在使用者解除安裝您的應用程式時應予以刪除。雖然嚴格來說,由於這些檔案位於外部儲存空間,因此可供使用者與其他應用程式存取,但實際上這些檔案對於您應用程式之外的使用者並無價值。使用者解除安裝您的應用程式時,系統會刪除您應用程式外部私用目錄中的所有檔案。 + + + + + <p>例如,您的應用程式下載的附加資源,或暫存媒體檔案都是私用檔案。</p> + </dd> +</dl> + +<p>若您希望將公用檔案儲存在外部儲存空間,請使用 +{@link android.os.Environment#getExternalStoragePublicDirectory +getExternalStoragePublicDirectory()} 方法取得代表外部儲存空間內相應目錄的 {@link java.io.File}。 +該方法採用對要儲存的檔案類型進行指定 (以便能合理區分這些檔案與其他公用檔案) 的引數,諸如 {@link android.os.Environment#DIRECTORY_MUSIC} 或 {@link +android.os.Environment#DIRECTORY_PICTURES}。 + +例如:</p> + +<pre> +public File getAlbumStorageDir(String albumName) { + // Get the directory for the user's public pictures directory. + File file = new File(Environment.getExternalStoragePublicDirectory( + Environment.DIRECTORY_PICTURES), albumName); + if (!file.mkdirs()) { + Log.e(LOG_TAG, "Directory not created"); + } + return file; +} +</pre> + + +<p>若您希望儲存應用程式私用的檔案,可以呼叫 {@link +android.content.Context#getExternalFilesDir getExternalFilesDir()},然後向其傳送名稱 (表示您希望使用的目錄類型),從而擷取相應目錄。 + +以此方式建立的每個目錄都會新增至父系目錄 (該目錄會封裝您應用程式的所有外部儲存空間檔案),並在使用者解除安裝您的應用程式時由系統刪除。 + +</p> + +<p>例如,以下所示的方法可用於建立個別相簿的目錄:</p> + +<pre> +public File getAlbumStorageDir(Context context, String albumName) { + // Get the directory for the app's private pictures directory. + File file = new File(context.getExternalFilesDir( + Environment.DIRECTORY_PICTURES), albumName); + if (!file.mkdirs()) { + Log.e(LOG_TAG, "Directory not created"); + } + return file; +} +</pre> + +<p>若預先定義的任何子目錄名稱都不適用於您的檔案,您可以改為呼叫 {@link +android.content.Context#getExternalFilesDir getExternalFilesDir()} 並傳送 {@code null}。此操作 +會傳回外部儲存空間內您應用程式私用目錄的根目錄。</p> + +<p>請記住,{@link android.content.Context#getExternalFilesDir getExternalFilesDir()} 會在使用者解除安裝您的應用程式時所刪除的目錄中建立目錄。若您希望要儲存的檔案在使用者解除安裝您的應用程式後仍可用—例如您的應用程式是相機,而使用者希望保留相片—,應改用 {@link android.os.Environment#getExternalStoragePublicDirectory +getExternalStoragePublicDirectory()}。 + + + +</p> + + +<p>不論是將 {@link +android.os.Environment#getExternalStoragePublicDirectory +getExternalStoragePublicDirectory()} 用於共用的檔案,還是將 {@link android.content.Context#getExternalFilesDir +getExternalFilesDir()} 用於您應用程式私用的檔案,請務必使用由 API 常數 (例如 {@link android.os.Environment#DIRECTORY_PICTURES}) 提供的目錄名稱。 + + +這些目錄名稱可確保系統正確處理檔案。 +例如,系統媒體掃描程式會將 {@link +android.os.Environment#DIRECTORY_RINGTONES} 中儲存的檔案視為鈴聲,而非音樂。 +</p> + + + + +<h2 id="GetFreeSpace">查詢可用空間</h2> + +<p>若您預先知道要儲存的資料量,可以呼叫 {@link java.io.File#getFreeSpace} 或 {@link +java.io.File#getTotalSpace} 以探明在不會導致 {@link +java.io.IOException} 的情況下空間是否充足。 +上述方法可分別提供儲存磁碟區內目前可用空間量與空間總量。 +該資訊還可以用於避免填充的儲存磁碟區超過特定臨界值。 +</p> + +<p>但是,系統不保證您可以寫入 {@link java.io.File#getFreeSpace} 所示的位元組數量。 +若傳回的數值較您要儲存的資料量略大,或檔案系統的已使用空間不到 90%,則繼續寫入可能是安全的。否則,可能不應寫入儲存空間。 + + +</p> + +<p class="note"><strong>注意:</strong>在儲存檔案之前,您無需檢查可用空間量。 +您可以嘗試立即寫入檔案,然後在發生 {@link java.io.IOException} 時執行捕捉即可。 +若您不知道需要的確切空間量,可能需要執行該作業。 +例如,若您在儲存檔案之前,將 PNG 影像轉化為 JPEG 以變更檔案的編碼,就不會預先知道檔案的大小。 + +</p> + + + + +<h2 id="DeleteFile">刪除檔案</h2> + +<p>不再需要檔案時,應一律刪除檔案。最直接的檔案刪除方式是讓開啟的檔案參考在自身上呼叫 {@link java.io.File#delete}。 +</p> + +<pre> +myFile.delete(); +</pre> + +<p>若檔案儲存在內部儲存空間,您也可以呼叫 {@link android.content.Context#deleteFile deleteFile()},讓 {@link android.content.Context} 尋找並刪除檔案: +</p> + +<pre> +myContext.deleteFile(fileName); +</pre> + +<div class="note"> +<p><strong>注意:</strong>使用者解除安裝您的應用程式時,Android 系統會刪除以下檔案: +</p> +<ul> +<li>您在內部儲存空間儲存的所有檔案</li> +<li>您使用 {@link +android.content.Context#getExternalFilesDir getExternalFilesDir()} 在外部儲存空間儲存的所有檔案。</li> +</ul> +<p>但是,您應定期手動刪除使用 {@link android.content.Context#getCacheDir()} 建立的所有快取檔案,並定期刪除不再需要的其他檔案。 + +</p> +</div> + diff --git a/docs/html-intl/intl/zh-tw/training/basics/data-storage/index.jd b/docs/html-intl/intl/zh-tw/training/basics/data-storage/index.jd new file mode 100644 index 0000000..9ff1fc0 --- /dev/null +++ b/docs/html-intl/intl/zh-tw/training/basics/data-storage/index.jd @@ -0,0 +1,57 @@ +page.title=儲存資料 +page.tags=資料儲存空間,檔案,sql,資料庫,偏好設定 +helpoutsWidget=true + +trainingnavtop=true +startpage=true + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>相依性和先決條件</h2> +<ul> + <li>Android 1.6 (API 層級為 4) 或更高版本</li> + <li>熟悉地圖的索引鍵值集合</li> + <li>熟悉 Java 檔案 I/O API</li> + <li>熟悉 SQL 資料庫</li> +</ul> + +<h2>您也應該閱讀</h2> +<ul> + <li><a href="{@docRoot}guide/topics/data/data-storage.html">儲存選項</a></li> +</ul> + +</div> +</div> + +<p>在 {@link android.app.Activity#onPause onPause()} 期間,大多數 Android 應用程式都需要儲存資料 (即使僅儲存應用程式狀態的有關資訊),因此使用者的進度不會遺失。 +大多數非一般的應用程式還需要儲存使用者設定,某些應用程式必須管理檔案與資料庫中的大量資訊。 + +本課程將為您介紹 Android 中的主要資料儲存選項,包括: +</p> + +<ul> + <li>將簡單資料類型的索引鍵值配對儲存至共用偏好設定檔案 +</li> + <li>將任意檔案儲存至 Android 的檔案系統</li> + <li>使用由 SQLite 管理的資料庫</li> +</ul> + + +<h2>課程</h2> + +<dl> + <dt><b><a href="shared-preferences.html">儲存索引鍵值組</a></b></dt> + <dd>了解如何使用共用的偏好設定檔案將少量資訊儲存至索引鍵值配對。 +</dd> + + <dt><b><a href="files.html">儲存檔案</a></b></dt> + <dd>了解如何儲存基本檔案 (例如儲存通常循序讀取的很長一系列資料)。 +</dd> + + <dt><b><a href="databases.html">在 SQL 資料庫中儲存資料</a></b></dt> + <dd>了解如何使用 SQLite 資料庫讀取及寫入結構化資料。</dd> + +</dl> diff --git a/docs/html-intl/intl/zh-tw/training/basics/data-storage/shared-preferences.jd b/docs/html-intl/intl/zh-tw/training/basics/data-storage/shared-preferences.jd new file mode 100644 index 0000000..46f8f20 --- /dev/null +++ b/docs/html-intl/intl/zh-tw/training/basics/data-storage/shared-preferences.jd @@ -0,0 +1,120 @@ +page.title=儲存索引鍵值組 +page.tags=資料儲存空間 +helpoutsWidget=true + +trainingnavtop=true + +@jd:body + + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>本課程示範</h2> +<ol> + <li><a href="#GetSharedPreferences">取得 SharedPreferences 的控點</a></li> + <li><a href="#WriteSharedPreference">寫入至共用的偏好設定</a></li> + <li><a href="#ReadSharedPreference">從共用的偏好設定進行讀取</a></li> +</ol> + +<h2>您也應該閱讀</h2> +<ul> + <li><a href="{@docRoot}guide/topics/data/data-storage.html#pref">使用共用的偏好設定</a></li> +</ul> + +</div> +</div> + + +<p>若您希望儲存相對較小的索引鍵值集合,應使用 {@link android.content.SharedPreferences} API。 +{@link android.content.SharedPreferences} 物件指向包含索引鍵值配對的檔案,並提供讀取及寫入這些配對的簡單方法。 + +每個 {@link android.content.SharedPreferences} 檔案都由架構管理,可以是公用或私用檔案。 + +</p> + +<p>本課程將為您展示如何使用 {@link android.content.SharedPreferences} API 儲存及擷取簡單值。 +</p> + +<p class="note"><strong>注意:</strong>{@link android.content.SharedPreferences} API 僅用於讀取及寫入索引鍵值配對,不應將其與 {@link android.preference.Preference} API 混淆,後者可協助您建置應用程式設定的使用者介面 (然而這些 API 使用 {@link android.content.SharedPreferences} 作為其儲存應用程式設定的實作方式)。 + + + +如需有關使用 {@link +android.preference.Preference} API 的資訊,請參閱<a href="{@docRoot}guide/topics/ui/settings.html">設定</a>指南。</p> + +<h2 id="GetSharedPreferences">取得 SharedPreferences 的控點</h2> + +<p>您可以呼叫以下兩種方法的其中之一,以建立新的共用偏好設定檔案或存取既有的共用偏好設定檔案: +</p> +<ul> + <li>{@link android.content.Context#getSharedPreferences(String,int) +getSharedPreferences()} — 若您需要使用多個共用偏好設定檔案 (根據名稱進行識別,第一個參數將指定名稱),請使用此方法。 +您可以從應用程式中的任何 {@link android.content.Context} 呼叫此方法。 +</li> + <li>{@link android.app.Activity#getPreferences(int) getPreferences()} — 若您只需針對應用行為顯示使用一個共用偏好設定檔案,請從 {@link android.app.Activity} 使用此方法。 + +由於此方法會擷取屬於該應用行為顯示的預設共用偏好設定檔案,因此您無需提供名稱。 +</li> +</ul> + +<p>例如,以下程式碼會在 {@link android.app.Fragment} 內執行。該程式碼會存取共用偏好設定檔案 (根據資源字串 {@code R.string.preference_file_key} 識別),並使用私用模式開啟該檔案 (因此只有您的應用程式可以存取該檔案)。 + + +</p> + +<pre> +Context context = getActivity(); +SharedPreferences sharedPref = context.getSharedPreferences( + getString(R.string.preference_file_key), Context.MODE_PRIVATE); +</pre> + +<p>對您的共用偏好設定檔案進行命名時,您應使用能唯一識別您應用程式的名稱,例如 {@code "com.example.myapp.PREFERENCE_FILE_KEY"} +</p> + +<p>或者,若您針對應用行為顯示只需使用一個共用偏好設定檔案,可以使用 {@link android.app.Activity#getPreferences(int) getPreferences()} 方法: +</p> + +<pre> +SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE); +</pre> + +<p class="caution"><strong>注意:</strong>若您使用 {@link android.content.Context#MODE_WORLD_READABLE} 或 {@link +android.content.Context#MODE_WORLD_WRITEABLE} 建立共用偏好設定檔案,則知道檔案識別碼的其他任何應用程式都能存取您的資料。 + +</p> + + +<h2 id="WriteSharedPreference">寫入至共用的偏好設定</h2> + +<p>若要寫入至共用偏好設定檔案,請針對您的 {@link android.content.SharedPreferences} 呼叫 {@link +android.content.SharedPreferences#edit},以建立 {@link +android.content.SharedPreferences.Editor}。</p> + +<p>傳遞您希望使用諸如 {@link +android.content.SharedPreferences.Editor#putInt putInt()} 及 {@link +android.content.SharedPreferences.Editor#putString putString()} 等方法寫入的索引鍵與值。然後呼叫 {@link +android.content.SharedPreferences.Editor#commit} 以儲存變更。例如:</p> + +<pre> +SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE); +SharedPreferences.Editor editor = sharedPref.edit(); +editor.putInt(getString(R.string.saved_high_score), newHighScore); +editor.commit(); +</pre> + + +<h2 id="ReadSharedPreference">從共用的偏好設定進行讀取</h2> + +<p>若要擷取共用偏好設定檔案中的值,請呼叫諸如 {@link +android.content.SharedPreferences#getInt getInt()} 與 {@link +android.content.SharedPreferences#getString getString()} 等方法,然後針對您希望使用的值提供索引鍵,以及 (可選) 在索引鍵不存在時傳回的預設值。 + +例如:</p> + +<pre> +SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE); +int defaultValue = getResources().getInteger(R.string.saved_high_score_default); +long highScore = sharedPref.getInt(getString(R.string.saved_high_score), defaultValue); +</pre> + diff --git a/docs/html-intl/intl/zh-tw/training/basics/intents/filters.jd b/docs/html-intl/intl/zh-tw/training/basics/intents/filters.jd new file mode 100644 index 0000000..2088b27 --- /dev/null +++ b/docs/html-intl/intl/zh-tw/training/basics/intents/filters.jd @@ -0,0 +1,236 @@ +page.title=允許其他應用程式啟動您的應用行為顯示 +page.tags=意圖 +helpoutsWidget=true + +trainingnavtop=true + +@jd:body + +<div id="tb-wrapper"> + <div id="tb"> + +<h2>本課程示範</h2> +<ol> + <li><a href="#AddIntentFilter">新增意圖篩選器</a></li> + <li><a href="#HandleIntent">在應用行為顯示中處理意圖</a></li> + <li><a href="#ReturnResult">傳回結果</a></li> +</ol> + +<h2>您也應該閱讀</h2> +<ul> + <li><a href="{@docRoot}training/sharing/index.html">共用簡單資料</a></li> + <li><a href="{@docRoot}training/secure-file-sharing/index.html">共用檔案</a> +</ul> + </div> +</div> + +<p>前兩課著重說明一個方面:從您的應用程式啟動其他應用程式的應用行為顯示。但是,若您的應用程式能執行可能適用於其他應用程式的行為,則應準備回應其他應用程式的行為要求。 + +例如,若您建置的社交應用程式可用於與使用者的好友分享訊息或相片,則支援 {@link android.content.Intent#ACTION_SEND} 意圖可為您帶來顯著受益,使用者藉此可從其他應用程式啟動「共用」行為,並啟動您的應用程式來執行該行為。 + + +</p> + +<p>若要允許其他應用程式啟動您的應用行為顯示,需要在您的宣示說明檔案中針對對應的 <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> 元素新增 <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code <intent-filter>}</a> 元素。 +</p> + +<p>若您的應用程式安裝在裝置上,系統會識別您的意圖篩選器,並將資訊新增至安裝的所有應用程式都支援的意圖內部目錄中。在應用程式使用隱含意圖呼叫 {@link android.app.Activity#startActivity +startActivity()} 或 {@link android.app.Activity#startActivityForResult startActivityForResult()} 時,系統會找出能回應意圖的一或多項應用行為顯示。 + + + +</p> + + + +<h2 id="AddIntentFilter">新增意圖篩選器</h2> + +<p>若要正確定義您的應用行為顯示可以處理的意圖,您新增的每個意圖篩選器都應儘可能具體地說明應用行為顯示所接受行為與資料的類型。 + +</p> + +<p>若應用行為顯示的意圖篩選器執行 {@link android.content.Intent} 物件的以下條件,系統會將指定的 {@link android.content.Intent} 傳送至該應用行為顯示: +</p> + +<dl> + <dt>行為</dt> + <dd>對要執行的行為進行命名的字串。通常是平台所定義值 (例如 {@link android.content.Intent#ACTION_SEND} 或 {@link android.content.Intent#ACTION_VIEW}) 的其中之一。 + + <p>請在您的意圖篩選器中使用 <a href="{@docRoot}guide/topics/manifest/action-element.html">{@code <action>}</a> 元素指定此項目。在此元素中指定的值必須是行為的完整字串名稱,而非 API 常數 (請參閱以下範例)。 + +</p></dd> + + <dt>資料</dt> + <dd>對意圖所關聯資料的描述。 + <p>請在意圖篩選器中使用 <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code <data>}</a> 元素指定此項目。在此元素中使用一或多個屬性,您可以僅指定 MIME 類型、URI 首碼、URI 配置,或指定這些項目的組合,以及表示所接受資料類型的其他項目。 + + +</p> + <p class="note"><strong>注意:</strong>若您不需要宣告 {@link android.net.Uri} 資料的有關詳情 (例如若您的應用行為顯示處理其他類型的「額外」資料,而非處理 URI),應僅指定 {@code android:mimeType} 屬性以宣告應用行為顯示處理的資料類型,例如 {@code text/plain} 或 {@code image/jpeg}。 + + +</p> +</dd> + <dt>類別</dt> + <dd>提供對處理意圖的應用行為顯示進行特性描述的其他方式,通常與使用者的手勢或應用行為顯示的啟動位置有關。 +系統支援多種不同的類別,但大多數類別很少使用。 +然而依預設,所有隱含意圖都與 {@link android.content.Intent#CATEGORY_DEFAULT} 一併定義。 + + <p>請在意圖篩選器中使用 <a href="{@docRoot}guide/topics/manifest/category-element.html">{@code <category>}</a> 元素指定此項目。 +</p></dd> +</dl> + +<p>在意圖篩選器中,您可以宣告每個條件以及 <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code <intent-filter>}</a> 元素中巢套的對應 XML 元素,以宣告應用行為顯示所接受的條件。 + +</p> + +<p>例如,若資料類型為文字或影像,以下應用行為顯示具備的意圖篩選器可處理 {@link +android.content.Intent#ACTION_SEND} 意圖:</p> + +<pre> +<activity android:name="ShareActivity"> + <intent-filter> + <action android:name="android.intent.action.SEND"/> + <category android:name="android.intent.category.DEFAULT"/> + <data android:mimeType="text/plain"/> + <data android:mimeType="image/*"/> + </intent-filter> +</activity> +</pre> + +<p>傳入的每項意圖只會指定一項行為與一種資料類型,但是在每個 <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code +<intent-filter>}</a> 中,可以宣告 <a href="{@docRoot}guide/topics/manifest/action-element.html">{@code +<action>}</a>、<a href="{@docRoot}guide/topics/manifest/category-element.html">{@code +<category>}</a> 與 <a href="{@docRoot}guide/topics/manifest/data-element.html">{@code +<data>}</a> 元素的多個執行個體。 + +</p> + +<p>若兩個行為與資料配對在行為方面彼此排斥,您應建立單獨的意圖篩選器,以指定與哪些資料類型配對時可接受哪些行為。 + +</p> + +<p>例如,假設您的應用行為顯示可處理 {@link +android.content.Intent#ACTION_SEND} 與 {@link +android.content.Intent#ACTION_SENDTO} 意圖的文字與影像。在此情況下,您必須針對兩個行為定義兩個單獨的意圖篩選器,因為 {@link +android.content.Intent#ACTION_SENDTO} 意圖必須使用 {@link android.net.Uri} 資料指定接收者的地址 (使用 {@code send} 或 {@code sendto} URI 配置)。 + +例如:</p> + +<pre> +<activity android:name="ShareActivity"> + <!-- filter for sending text; accepts SENDTO action with sms URI schemes --> + <intent-filter> + <action android:name="android.intent.action.SENDTO"/> + <category android:name="android.intent.category.DEFAULT"/> + <data android:scheme="sms" /> + <data android:scheme="smsto" /> + </intent-filter> + <!-- filter for sending text or images; accepts SEND action and text or image data --> + <intent-filter> + <action android:name="android.intent.action.SEND"/> + <category android:name="android.intent.category.DEFAULT"/> + <data android:mimeType="image/*"/> + <data android:mimeType="text/plain"/> + </intent-filter> +</activity> +</pre> + +<p class="note"><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} 類別一樣。 +若您在意圖篩選器中未宣告該類別,不會將任何隱含意圖解析為您的應用行為顯示。 +</p> + +<p>如需有關傳送及接收 {@link android.content.Intent#ACTION_SEND} 意圖 (執行社交共用行為) 的詳細資訊,請參閱有關<a href="{@docRoot}training/sharing/receive.html">接收其他應用程式的簡單資料</a>的課程。 +</p> + + +<h2 id="HandleIntent">在應用行為顯示中處理意圖</h2> + +<p>若要確定您應用行為顯示中將採用的行為,您可以讀取用於啟動該應用行為顯示的 {@link +android.content.Intent}。</p> + +<p>您的應用行為顯示啟動時,請呼叫 {@link android.app.Activity#getIntent()} 以擷取啟動該應用行為顯示的 {@link android.content.Intent}。 +在應用行為顯示的生命週期期間,您隨時可以執行該作業,但通常應在早期回呼 (例如 {@link android.app.Activity#onCreate onCreate()} 或 {@link android.app.Activity#onStart()}) 期間執行。 + +</p> + +<p>例如:</p> + +<pre> +@Override +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.main); + + // Get the intent that started this activity + Intent intent = getIntent(); + Uri data = intent.getData(); + + // Figure out what to do based on the intent type + if (intent.getType().indexOf("image/") != -1) { + // Handle intents with image data ... + } else if (intent.getType().equals("text/plain")) { + // Handle intents with text ... + } +} +</pre> + + +<h2 id="ReturnResult">傳回結果</h2> + +<p>若您希望將結果傳回至呼叫您意圖的應用行為顯示,只需呼叫 {@link +android.app.Activity#setResult(int,Intent) setResult()} 以指定結果代碼及結果 {@link +android.content.Intent} 即可。在您的操作已完成,且使用者應返回原始的應用行為顯示時,請呼叫 {@link android.app.Activity#finish()} 以關閉 (並終結) 您的應用行為顯示。 +例如: +</p> + +<pre> +// Create intent to deliver some kind of result data +Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri"); +setResult(Activity.RESULT_OK, result); +finish(); +</pre> + +<p>您必須始終一併指定結果代碼與結果。結果通常是 {@link +android.app.Activity#RESULT_OK} 或 {@link android.app.Activity#RESULT_CANCELED}。然後,您可以視需要為其他資料提供 {@link android.content.Intent}。 +</p> + +<p class="note"><strong>注意:</strong>依預設,會將結果設為 {@link +android.app.Activity#RESULT_CANCELED}。因此,若使用者在完成行為之前以及在您設定結果之前按下 [後退] 按鈕<em></em>,原始應用行為顯示會收到「已取消」結果。 + +</p> + +<p>若您只需傳回表示其中一種結果選項的整數,可將結果代碼設為大於 0 的任意值。 +若您使用結果代碼以提供整數,且無需納入 {@link android.content.Intent},可以呼叫 {@link +android.app.Activity#setResult(int) setResult()},然後僅傳遞結果代碼。 +例如:</p> + +<pre> +setResult(RESULT_COLOR_RED); +finish(); +</pre> + +<p>在此情況下,可能只會有少數結果,因此結果代碼是本機定義的整數 (大於 0)。 +若您將結果傳回至您應用程式內的應用行為顯示,此功能會非常適用,因為接收結果的應用行為顯示可以參考公用常數,以確定結果代碼的值。 + +</p> + +<p class="note"><strong>注意:</strong>無需檢查是否已使用 {@link +android.app.Activity#startActivity startActivity()} 或 {@link +android.app.Activity#startActivityForResult startActivityForResult()} 啟動您的應用行為顯示。 +若啟動應用行為顯示的意圖希望產生結果,只需呼叫 {@link +android.app.Activity#setResult(int,Intent) setResult()} 即可。 +若原始應用行為已呼叫 {@link +android.app.Activity#startActivityForResult startActivityForResult()},則系統將向其傳遞您提供給 {@link android.app.Activity#setResult(int,Intent) setResult()} 的結果;否則,結果將被忽略。 + +</p> + + + + + + diff --git a/docs/html-intl/intl/zh-tw/training/basics/intents/index.jd b/docs/html-intl/intl/zh-tw/training/basics/intents/index.jd new file mode 100644 index 0000000..70492f4 --- /dev/null +++ b/docs/html-intl/intl/zh-tw/training/basics/intents/index.jd @@ -0,0 +1,62 @@ +page.title=與其他應用程式互動 +page.tags=意圖,應用行為的顯示 +helpoutsWidget=true + +trainingnavtop=true +startpage=true + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>相依性和先決條件</h2> +<ul> + <li>了解應用行為顯示生命週期的基本知識 (請參閱<a href="{@docRoot}training/basics/activity-lifecycle/index.html">管理應用行為顯示生命週期</a>) +</li> +</ul> + + +<h2>您也應該閱讀</h2> +<ul> + <li><a href="{@docRoot}training/sharing/index.html">共用簡單資料</a></li> + <li><a href="{@docRoot}training/secure-file-sharing/index.html">共用檔案</a> + <li><a href="http://android-developers.blogspot.com/2009/11/integrating-application-with-intents.html">將應用程式與意圖整合 (部落格文章)</a> +</li> + <li><a href="{@docRoot}guide/components/intents-filters.html">意圖和意圖篩選器</a> +</li> +</ul> + +</div> +</div> + +<p>Android 應用程式通常具有多個<a href="{@docRoot}guide/components/activities.html">應用行為顯示</a>。每個應用行為顯示都會顯示使用者介面,使用者可藉此執行特定任務 (例如檢視地圖或拍照)。若要將使用者從一個應用行為顯示傳送至另一個應用行為顯示,您的應用程式必須使用 {@link +android.content.Intent} 來定義應用程式執行作業的「意圖」。 + +使用某方法 (例如 {@link +android.app.Activity#startActivity startActivity()}) 將 {@link android.content.Intent} 傳遞至系統時, +系統會使用 {@link +android.content.Intent} 來識別並啟動相應的應用程式元件。若使用意圖,應用程式甚至可以藉此啟動獨立應用程式中包含的應用行為顯示。 +</p> + +<p>{@link android.content.Intent} 可以是<em>明確的</em>,以啟動特定元件 +(特定 {@link android.app.Activity} 執行個體),也可以是<em>隱含的</em>,以啟動可處理預期行為 (例如「拍照」) 的元件。 +</p> + +<p>本課程將為您展示如何使用 {@link android.content.Intent} 來執行與其他應用程式的某些基本互動,例如啟動其他應用程式、接收該應用程式的結果,以及讓您的應用程式能回應其他應用程式的意圖。 + +</p> + +<h2>課程</h2> + +<dl> + <dt><b><a href="sending.html">將使用者傳送至其他應用程式</a></b></dt> + <dd>展示如何建立隱含意圖以啟動能執行行為的其他應用程式。 +</dd> + <dt><b><a href="result.html">從應用行為顯示取得結果</a></b></dt> + <dd>展示如何啟動其他應用行為顯示並接收應用行為顯示傳回的結果。</dd> + <dt><b><a href="filters.html">允許其他應用程式啟動您的應用行為顯示</a></b></dt> + <dd>展示如何透過定義對您的應用程式所接受的隱含意圖進行宣告的意圖篩選器,讓應用程式中的應用行為顯示可供其他應用程式使用。 +</dd> +</dl> + diff --git a/docs/html-intl/intl/zh-tw/training/basics/intents/result.jd b/docs/html-intl/intl/zh-tw/training/basics/intents/result.jd new file mode 100644 index 0000000..9fabe91 --- /dev/null +++ b/docs/html-intl/intl/zh-tw/training/basics/intents/result.jd @@ -0,0 +1,178 @@ +page.title=從應用行為顯示取得結果 +page.tags=意圖 +helpoutsWidget=true + +trainingnavtop=true + +@jd:body + +<div id="tb-wrapper"> + <div id="tb"> + +<h2>本課程示範</h2> +<ol> + <li><a href="#StartActivity">啟動應用行為顯示</a></li> + <li><a href="#ReceiveResult">接收結果</a></li> +</ol> + +<h2>您也應該閱讀</h2> +<ul> + <li><a href="{@docRoot}training/sharing/index.html">共用簡單資料</a></li> + <li><a href="{@docRoot}training/secure-file-sharing/index.html">共用檔案</a> +</ul> + + </div> +</div> + +<p>啟動其他應用行為顯示不必是單向作業。您也可以啟動其他應用行為顯示,然後接收傳回的結果。 +若要接收結果,請呼叫 {@link android.app.Activity#startActivityForResult +startActivityForResult()} (而非 {@link android.app.Activity#startActivity +startActivity()})。</p> + +<p>例如,您的應用程式可以啟動相機應用程式,然後接收所拍攝的相片作為結果。或者,您可以啟動人員應用程式 (以便讓使用者選取連絡人),然後接收作為結果的連絡人詳細資料。 + +</p> + +<p>當然,必須將提供回應的應用行為顯示設計為傳回結果。執行時,該應用行為顯示會以其他 {@link android.content.Intent} 物件的形式傳送結果。 +您的應用行為顯示會在 {@link android.app.Activity#onActivityResult onActivityResult()} 回呼中接收該結果。 +</p> + +<p class="note"><strong>注意:</strong>呼叫 {@link android.app.Activity#startActivityForResult startActivityForResult()} 時,您可以使用明確或隱含的意圖。 +啟動您的其中一個應用行為顯示以接收結果時,您應使用明確的意圖,以確保收到預期結果。 + +</p> + + +<h2 id="StartActivity">啟動應用行為顯示</h2> + +<p>啟動應用行為顯示以接收結果時,您使用的 {@link android.content.Intent} 物件沒有任何特殊之處,但是您需要將附加整數引數傳遞至 {@link +android.app.Activity#startActivityForResult startActivityForResult()} 方法。 +</p> + +<p>該整數引數是識別您要求的「要求代碼」。在您接收結果 {@link android.content.Intent} 時,回呼會提供同一要求代碼,以便您的應用程式可以正確識別結果並判斷如何處理結果。 + +</p> + +<p>例如,以下展示了如何啟動應用行為顯示 (使用者可藉此挑選連絡人):</p> + +<pre> +static final int PICK_CONTACT_REQUEST = 1; // The request code +... +private void pickContact() { + Intent pickContactIntent = new Intent(Intent.ACTION_PICK, Uri.parse("content://contacts")); + pickContactIntent.setType(Phone.CONTENT_TYPE); // Show user only contacts w/ phone numbers + startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST); +} +</pre> + + +<h2 id="ReceiveResult">接收結果</h2> + +<p>使用者處理隨後的應用行為顯示並返回時,系統會呼叫應用行為顯示的 {@link android.app.Activity#onActivityResult onActivityResult()} 方法。 +此方法包括三個引數: +</p> + +<ul> + <li>您傳遞至 {@link +android.app.Activity#startActivityForResult startActivityForResult()} 的要求代碼。</li> + <li>由第二個應用行為顯示指定的結果代碼。此代碼是 {@link +android.app.Activity#RESULT_OK} (若操作成功) 或 {@link +android.app.Activity#RESULT_CANCELED} (若因故使用者退出或操作失敗)。 +</li> + <li>攜帶結果資料的 {@link android.content.Intent}。</li> +</ul> + +<p>例如,以下為您展示了如何處理「挑選連絡人」意圖的結果:</p> + +<pre> +@Override +protected void onActivityResult(int requestCode, int resultCode, Intent data) { + // Check which request we're responding to + if (requestCode == PICK_CONTACT_REQUEST) { + // Make sure the request was successful + if (resultCode == RESULT_OK) { + // The user picked a contact. + // The Intent's data Uri identifies which contact was selected. + + // Do something with the contact here (bigger example below) + } + } +} +</pre> + +<p>在此範例中,由 Android 的連絡人或人員應用程式傳回的結果 {@link android.content.Intent} 可提供內容 {@link android.net.Uri} (能識別使用者所選取的連絡人)。 + +</p> + +<p>若要成功處理結果,您必須了解結果 {@link android.content.Intent} 將採用的格式。 +若傳回結果的應用行為顯示是您的其中一個應用行為顯示,上述作業會非常簡單。 +Android 平台隨附的應用程式會針對特定結果資料提供您可以依賴的 API。 +例如,人員應用程式 (某些舊版上的連絡人應用程式) 會始終傳回含內容 URI (可識別選取的連絡人) 的結果,相機應用程式會在 {@code "data"} 額外項目中傳回 {@link android.graphics.Bitmap} (請參閱有關<a href="{@docRoot}training/camera/index.html">拍攝相片</a>的課程)。 + + +</p> + + +<h4>額外說明:讀取連絡人資料</h4> + +<p>上述程式碼展示如何從人員應用程式取得結果,並未詳述如何實際讀取結果的資料,因為這需要進行更高級的 +<a href="{@docRoot}guide/topics/providers/content-providers.html">內容提供者</a>相關討論。 + +但是,若您對此感到好奇,以下提供了另外一些程式碼,這些程式碼會展示如何查詢結果資料,以便取得所選連絡人的電話號碼: +</p> + +<pre> +@Override +protected void onActivityResult(int requestCode, int resultCode, Intent data) { + // Check which request it is that we're responding to + if (requestCode == PICK_CONTACT_REQUEST) { + // Make sure the request was successful + if (resultCode == RESULT_OK) { + // Get the URI that points to the selected contact + Uri contactUri = data.getData(); + // We only need the NUMBER column, because there will be only one row in the result + String[] projection = {Phone.NUMBER}; + + // Perform the query on the contact to get the NUMBER column + // We don't need a selection or sort order (there's only one result for the given URI) + // CAUTION: The query() method should be called from a separate thread to avoid blocking + // your app's UI thread. (For simplicity of the sample, this code doesn't do that.) + // Consider using {@link android.content.CursorLoader} to perform the query. + Cursor cursor = getContentResolver() + .query(contactUri, projection, null, null, null); + cursor.moveToFirst(); + + // Retrieve the phone number from the NUMBER column + int column = cursor.getColumnIndex(Phone.NUMBER); + String number = cursor.getString(column); + + // Do something with the phone number... + } + } +} +</pre> + +<p class="note"><strong>注意:</strong>在 Android 2.3 (API 級別為 9) 版之前,若在 {@link android.provider.ContactsContract.Contacts Contacts Provider} (例如以上所示) 上執行查詢,需要您的應用程式宣告 {@link +android.Manifest.permission#READ_CONTACTS} 權限 (請參閱<a href="{@docRoot}guide/topics/security/security.html">安全性與權限</a>)。 + +但是,從 Android 2.3 版開始,在連絡人提供者傳回結果時,連絡人/人員應用程式會為您的應用程式授予讀取連絡人提供者的臨時權限。 + +該臨時權限僅適用於要求的特定連絡人,因此除非您已宣告 {@link +android.Manifest.permission#READ_CONTACTS} 權限,否則無法查詢並非由意圖的 {@link android.net.Uri} 指定的連絡人。 + +</p> + + + + + + + + + + + + + + + diff --git a/docs/html-intl/intl/zh-tw/training/basics/intents/sending.jd b/docs/html-intl/intl/zh-tw/training/basics/intents/sending.jd new file mode 100644 index 0000000..70e8316 --- /dev/null +++ b/docs/html-intl/intl/zh-tw/training/basics/intents/sending.jd @@ -0,0 +1,256 @@ +page.title=將使用者傳送至其他應用程式 +page.tags=意圖 +helpoutsWidget=true + +trainingnavtop=true + +@jd:body + + +<div id="tb-wrapper"> + <div id="tb"> + +<h2>本課程示範</h2> +<ol> + <li><a href="#Build">建置隱含意圖</a></li> + <li><a href="#Verify">驗證存在接收意圖的應用程式</a></li> + <li><a href="#StartActivity">使用意圖啟動應用行為顯示</a></li> + <li><a href="#AppChooser">顯示應用程式選擇器</a></li> +</ol> + +<h2>您也應該閱讀</h2> +<ul> + <li><a href="{@docRoot}training/sharing/index.html">共用簡單資料</a></li> +</ul> + + </div> +</div> + +<p>應用程式可以根據將要執行的「行為」,將使用者傳送至其他應用程式 +,這是 Android 最重要的功能之一。例如,若您希望在地圖上顯示應用程式中的企業地址,不必在應用程式中建置顯示地圖的應用行為顯示。 + +您可以改為使用 {@link android.content.Intent} 建立檢視地址的要求。 +隨後,Android 系統會啟動能在地圖上顯示地址的應用程式。 +</p> + +<p>正如第一課<a href="{@docRoot}training/basics/firstapp/index.html">建置您的第一個應用程式</a>中所述,您必須使用意圖在您應用程式中的應用行為顯示之間進行導覽。您執行此作業時通常具有<em>明確意圖</em>,該意圖可定義您希望啟動的元件的確切類別名稱。 + + +但是,若您希望使用單獨的應用程式執行諸如「檢視地圖」等行為,則必須使用<em>隱含意圖</em>。 +</p> + +<p>本課程將為您展示如何針對特定行為建立隱含意圖,以及如何使用該意圖啟動在其他應用程式中執行該行為的應用行為顯示。 +</p> + + + +<h2 id="Build">建置隱含意圖</h2> + +<p>隱含意圖不會宣告要啟動元件的類別名稱,而是宣告要執行的行為。 +該行為將指定您希望執行的動作,例如<em>檢視</em>、<em>編輯</em>、<em>傳送</em>或<em>取得</em>項目。 +意圖通常還包括與行為關聯的資料,例如您希望檢視的地址或希望傳送的電子郵件。視您希望建立的意圖而定,該資料可能是 {@link android.net.Uri} 或其他多種資料類型的其中之一,意圖也可能完全不需要資料。 + + +</p> + +<p>若您的資料是 {@link android.net.Uri},可以使用簡單的 {@link +android.content.Intent#Intent(String,Uri) Intent()} 建構函式來定義行為與資料。 +</p> + +<p>例如,以下範例將展示如何建立啟動電話的意圖 (使用 {@link +android.net.Uri} 資料指定電話號碼):</p> + +<pre> +Uri number = Uri.parse("tel:5551234"); +Intent callIntent = new Intent(Intent.ACTION_DIAL, number); +</pre> + +<p>您的應用程式透過呼叫 {@link android.app.Activity#startActivity +startActivity()} 來呼叫該意圖時,電話應用程式會啟動對指定電話號碼的撥號。</p> + +<p>以下將展示其他一些意圖及其行為與 {@link android.net.Uri} 資料配對: +</p> + +<ul> + <li>檢視地圖: +<pre> +// Map point based on address +Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California"); +// Or map point based on latitude/longitude +// Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z param is zoom level +Intent mapIntent = new Intent(Intent.ACTION_VIEW, location); +</pre> + </li> + <li>檢視網頁: +<pre> +Uri webpage = Uri.parse("http://www.android.com"); +Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage); +</pre> + </li> +</ul> + +<p>其他類型的隱含意圖需要「額外」資料提供其他資料類型 (例如字串)。 +您可以使用各種 {@link +android.content.Intent#putExtra(String,String) putExtra()} 方法新增一或多項額外資料。</p> + +<p>依預設,系統會根據包括的 {@link android.net.Uri} 資料,判斷意圖所需的相應 MIME 類型。 +若您未將 {@link android.net.Uri} 包括在意圖中,通常應使用 {@link android.content.Intent#setType setType()} 指定意圖所關聯資料的類型。 + +設定 MIME 類型會進一步指定哪些類型的應用行為顯示應接收意圖。 +</p> + +<p>以下展示的一些意圖將新增額外資料以指定所需行為:</p> + +<ul> + <li>傳送具有附件的電子郵件: +<pre> +Intent emailIntent = new Intent(Intent.ACTION_SEND); +// The intent does not have a URI, so declare the "text/plain" MIME type +emailIntent.setType(HTTP.PLAIN_TEXT_TYPE); +emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jon@example.com"}); // recipients +emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject"); +emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text"); +emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment")); +// You can also attach multiple items by passing an ArrayList of Uris +</pre> + </li> + <li>建立行事曆事件: +<pre> +Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI); +Calendar beginTime = Calendar.getInstance().set(2012, 0, 19, 7, 30); +Calendar endTime = Calendar.getInstance().set(2012, 0, 19, 10, 30); +calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis()); +calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis()); +calendarIntent.putExtra(Events.TITLE, "Ninja class"); +calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo"); +</pre> +<p class="note"><strong>注意:</strong>針對行事曆事件的這一意圖僅支援至少為 14 的 API 級別。 +</p> + </li> +</ul> + +<p class="note"><strong>注意:</strong>請儘可能具體地定義 {@link +android.content.Intent},這一點非常重要。例如,若您希望使用 {@link android.content.Intent#ACTION_VIEW} 意圖顯示影像,應將 MIME 類型指定為 {@code image/*}。 + +如此可防止意圖觸發能「檢視」其他類型資料的應用程式 (例如地圖應用程式)。 +</p> + + + +<h2 id="Verify">驗證存在接收意圖的應用程式</h2> + +<p>雖然 Android 平台保證特定意圖將解析為內建應用程式 (例如電話、電子郵件或日曆應用程式) 的其中之一,但您應一律先納入驗證步驟,然後再呼叫意圖。 + +</p> + +<p class="caution"><strong>注意:</strong>若您呼叫意圖,而裝置上不提供能處理該意圖的任何應用程式, +則您的應用程式將當機。</p> + +<p>若要驗證存在可回應意圖的應用行為顯示,請呼叫 {@link +android.content.pm.PackageManager#queryIntentActivities queryIntentActivities()} 以取得能處理 {@link android.content.Intent} 的應用行為顯示清單。 +若傳回的 {@link +java.util.List} 非空,您可以安全使用意圖。例如:</p> + +<pre> +PackageManager packageManager = {@link android.content.Context#getPackageManager()}; +List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, + PackageManager.MATCH_DEFAULT_ONLY); +boolean isIntentSafe = activities.size() > 0; +</pre> + +<p>若 <code>isIntentSafe</code> 為 <code>true</code>,則至少有一個應用程式將回應意圖。 +若其為 <code>false</code>,則沒有任何應用程式能處理該意圖。</p> + +<p class="note"><strong>注意:</strong>對於使用該意圖的功能,若您需要在使用者嘗試使用該功能之前停用該功能,應在您的應用行為顯示第一次啟動時,執行這項檢查。 + +若您知道能處理該意圖的特定應用程式,還可為使用者提供應用程式下載連結 (請參閱如何<a href="{@docRoot}distribute/tools/promote/linking.html">在 Google +Play 上連結您的產品</a>)。 +</p> + + +<h2 id="StartActivity">使用意圖啟動應用行為顯示</h2> + +<div class="figure" style="width:200px;margin-top:-10px"> + <img src="{@docRoot}images/training/basics/intents-choice.png" alt="" /> + <p class="img-caption"><strong>圖 1.</strong>選取對話方塊 (在多個應用程式可處理意圖時顯示) 的範例。 +</p> +</div> + +<p>在您建立 {@link android.content.Intent} 並設定額外資訊後,請呼叫 {@link +android.app.Activity#startActivity startActivity()} 將其傳送至系統。若系統識別出有多個應用行為顯示可以處理意圖,會顯示對話方塊,供使用者選取要使用的應用程式,如圖 1 所示。 + +若只有一個應用行為顯示可以處理該意圖,系統會立即啟動該應用行為顯示。 +</p> + +<pre> +startActivity(intent); +</pre> + +<p>以下所示的完整範例將展示如何建立檢視地圖的意圖、驗證存在處理該意圖的應用程式,然後啟動該應用程式: +</p> + +<pre> +// Build the intent +Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California"); +Intent mapIntent = new Intent(Intent.ACTION_VIEW, location); + +// Verify it resolves +PackageManager packageManager = {@link android.content.Context#getPackageManager()}; +List<ResolveInfo> activities = packageManager.queryIntentActivities(mapIntent, 0); +boolean isIntentSafe = activities.size() > 0; + +// Start an activity if it's safe +if (isIntentSafe) { + startActivity(mapIntent); +} +</pre> + + + +<h2 id="AppChooser">顯示應用程式選擇器</h2> + +<div class="figure" style="width:200px;margin-top:-10px"> + <img src="{@docRoot}images/training/basics/intent-chooser.png" alt="" /> + <p class="img-caption"><strong>圖 2.</strong>選擇器對話方塊。</p> +</div> + +<p>請注意,若您將 {@link android.content.Intent} 傳遞至 {@link +android.app.Activity#startActivity startActivity()} 以啟動應用行為顯示,且有多個應用程式回應該意圖,則使用者可以選取依預設要使用的應用程式 (透過選取對話方塊底部的核取方塊,請參閱圖 1)。 + +若在執行行為時使用者通常希望每次使用同一應用程式,例如開啟網頁 (使用者可能只使用一個網頁瀏覽器) 或拍攝相片 (使用者可能更喜歡使用一個相機),則此功能非常有用。 + +</p> + +<p>但是,若有多個應用程式可以處理要執行的行為,且使用者可能更希望每次使用不同的應用程式 (例如對於「共用」行為,使用者可能會透過多個應用程式來共用項目),您應明確顯示選擇器對話方塊,如圖 2 所示。 + + +選擇器對話方塊會強制使用者選取行為每次使用的應用程式 (使用者無法選取行為的預設應用程式)。 + +</p> + +<p>若要顯示選擇器,請使用 {@link +android.content.Intent#createChooser createChooser()} 建立 {@link android.content.Intent},並將其傳遞至 {@link +android.app.Activity#startActivity startActivity()}。例如:</p> + +<pre> +Intent intent = 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 chooser +Intent chooser = Intent.createChooser(intent, title); + +// Verify the intent will resolve to at least one activity +if (intent.resolveActivity(getPackageManager()) != null) { + startActivity(chooser); +} +</pre> + +<p>以上範例會顯示對話方塊 (將回應意圖的應用程式清單傳遞至 {@link +android.content.Intent#createChooser createChooser()} 方法),並使用提供的文字作為對話方塊的標題。 +</p> + + + |