提供流暢體驗的設計

即使您的應用程式速度飛快、反應靈敏,某些設計決策仍會因為與其他應用程式或對話方塊的非預期互動、資料意外遺失、意外封鎖等因素而造成使用者問題。為了避免這些問題,建議您瞭解應用程式執行時的情境,以及可能影響應用程式的系統互動。簡而言之,您應盡力開發能與系統和其他應用程式完美互動的應用程式。

常見的順暢性問題是應用程式的背景程序 (例如服務或廣播接收器) 彈出對話方塊來回應某些事件。這看似無害的行為,尤其是在模擬器上單獨建構及測試應用程式時。但是,當應用程式在實際裝置上執行時,應用程式在背景程序顯示對話方塊時可能沒有使用者焦點。因此,應用程式最終可能會在有效應用程式的後方顯示其對話方塊,或是聚焦於目前應用程式,並在使用者執行操作 (例如撥號) 之前顯示對話方塊。這項行為對您的應用程式或使用者毫無幫助。

為避免發生這些問題,應用程式應使用適當的系統功能來通知使用者:Notification 類別。應用程式可利用通知,在狀態列中顯示圖示,讓使用者無法聚焦並中斷使用者,藉此告知使用者已發生事件。

另一個順暢性問題的例子是,活動未正確實作 onPause() 和其他生命週期方法,導致意外遺失狀態或使用者資料。或者,如果您的應用程式公開要提供給其他應用程式使用的資料,您應透過 ContentProvider 公開資料,而不要透過全球可讀取的原始檔案或資料庫公開資料。

這些範例的常見之處在於,它們與系統和其他應用程式完美搭配。Android 系統的設計旨在將應用程式視為鬆耦合元件的聯合元件,而不是一堆黑箱程式碼。如此一來,開發人員就可以像這些元件的較大聯盟一樣檢視整個系統。這項優點可讓您以簡潔又完美的方式與其他應用程式整合,因此建議您自行設計程式碼,傳回令人愛不釋手的程式碼。

本文件探討常見的順暢性問題,以及如何避免這些問題。

不要捨棄資料

提醒您,Android 是行動平台。聽起來似乎很明顯,但一定要記得,其他活動 (例如「來電」應用程式) 隨時可能會彈出自己的活動畫面。這會觸發 onSaveInstanceState() 和 onPause() 方法,並可能導致應用程式終止。

如果使用者在其他活動出現時,在應用程式中編輯資料,則應用程式可能會在終止時失去該項資料。當然,除非您先儲存進行中的工作。「Android 方式」就是這麼簡單:接受或編輯輸入的 Android 應用程式應覆寫 onSaveInstanceState() 方法,並以適當的方式儲存狀態。當使用者再次造訪應用程式時,應能夠擷取資料。

郵件應用程式是一個典型的行為應用範例。如果使用者在其他活動啟動時撰寫電子郵件,應用程式應將處理中的電子郵件儲存為草稿。

不要公開原始資料

當您穿著內衣時,不適合走到那條街上,您的資料也應該來自何處。雖然您可以向全世界公開特定類型的應用程式,但這通常不是最好的做法。公開原始資料需要其他應用程式瞭解您的資料格式;如果您變更格式,其他所有不類似更新的應用程式都會中斷。

「Android Way」的用途是建立 ContentProvider,透過簡潔明瞭且可維護的 API,將您的資料提供給其他應用程式。使用 ContentProvider 就像插入 Java 語言介面,藉此分割並元件化兩段緊密耦合的程式碼。也就是說,您可以在不變更 ContentProvider 公開的介面的情況下修改資料的內部格式,而這不會影響其他應用程式。

不要打斷使用者

如果使用者在通話期間執行應用程式 (例如通話期間的「電話」應用程式),他們就會是安全的行為。因此,除了直接回應目前 Activity 中的使用者輸入內容,我們都建議避免發布不必要的活動。

也就是說,請勿從背景執行的 BroadcastReceiver 或 Service 呼叫 startActivity()。這樣做將中斷任何目前正在執行的應用程式,並導致您的困擾。更糟的是,您的活動可能會變成「按鍵行為吃角子」,並收到使用者在提供之前活動之前的某些輸入內容。視應用程式的行為而定,這可能是壞消息。

您應改用 NotificationManager 設定通知,而非直接從背景產生活動 UI。這些通知會顯示在狀態列中,使用者只要隨時點選這些按鈕,就可以查看應用程式必須顯示的內容。

(請注意,如果您的活動已在前景執行,則不適用上述所有情況:在這種情況下,使用者預期會看到下一個活動以回應輸入內容)。

有許多待辦事項嗎?在討論串中執行

如果應用程式需要執行一些昂貴或長時間執行的運算,建議您將其移至執行緒。如此一來,系統就不會向使用者顯示「應用程式無回應」對話方塊,最終結果會是應用程式的非常刺激。

根據預設,Activity 及其所有檢視區塊的程式碼都會在同一個執行緒中執行。這個執行緒也會處理 UI 事件。舉例來說,當使用者按下某個按鍵時,鍵向下事件就會新增至活動的主要執行緒佇列中。事件處理常式系統必須快速取消佇列並處理該事件;如果不能,系統會在應用程式停止運作的幾秒後結束,並向使用者提供終止服務。

如果您有長時間執行的程式碼,內嵌在 Activity 中執行的程式碼會在事件處理常式執行緒上執行,可有效封鎖事件處理常式。這會延遲輸入處理作業,並導致 ANR 對話方塊。如要避免這種情況,請將計算移至執行緒。您可以參閱這份回應設計原則文件,瞭解相關做法。

請勿超載單一活動畫面

任何值得使用的應用程式都可能有多個不同的畫面。設計 UI 畫面時,請務必使用多個 Activity 物件執行個體。

視開發背景而定,您可能會將「活動」解讀為類似 Java 小工具,而該活動是應用程式的進入點。但是,這不太準確:如果 Applet 子類別是 Java Applet 的單一進入點,則應將 Activity 視為應用程式的多個進入點之一。「main」活動與任何其他可能唯一的差別在於,「main」只是唯一對 AndroidManifest.xml 檔案中的「android.intent.action.MAIN」動作表示興趣的人。

因此,設計應用程式時,請將應用程式視為活動物件的聯盟。如此一來,您的程式碼長期下來就更容易維護,同時良好的副作用也能搭配 Android 的應用程式歷史記錄和「返回堆疊」模型順利運作。

擴充系統主題

至於使用者介面的外觀和風格,請務必巧妙融合。應用程式與使用者預期的使用者介面有落差,導致使用者感到不快。設計 UI 時,請盡量避免自行滾動式設計。而是改用主題。您可以視需要覆寫或擴充主題中的這些部分,但至少應從與所有其他應用程式相同的 UI 基礎開始建構。詳情請參閱「樣式與主題」。

將使用者介面設計為支援多種螢幕解析度

不同的 Android 裝置支援不同的螢幕解析度。有些人甚至能即時變更解析度,例如切換至橫向模式。請務必確保版面配置和可繪項目具有彈性,能在各種裝置螢幕上正確顯示。

幸好,這個方法非常簡單。簡單來說,您必須針對圖片解析度提供不同版本的圖片 (如有),然後設計適合各種尺寸的版面配置。(例如,請避免使用硬式編碼的位置,而是改用相對版面配置)。當您完成這麼多作業時,系統會處理其餘工作,而您的應用程式在任何裝置上都能正常顯示。

假設網路速度緩慢

Android 裝置內建各種網路連線選項。所有應用程式都會提供部分資料存取佈建,但有些佈建速度比其他佈建速度快。不過,最小的分母是 GPRS,這是適用於 GSM 網路的非 3G 資料服務。即使是支援 3G 的裝置,也會花費大量時間在非 3G 網路,因此緩慢的網路會長時間保持不變。

因此,您應一律編寫應用程式的程式碼,盡可能降低網路存取次數和頻寬。您無法假設網路速度很快,因此建議您一律規劃速度較慢的網路。這對使用者來說是一大福音,能不能提升使用者的體驗。但是,您可能也要避免這種問題:應用程式有時雖然可供使用,但根據使用者在任何指定時間點推斷剩下的部分,可能不太受歡迎。

這裡的潛在問題是,如果使用模擬器,很容易就能落入這個陷阱,因為模擬器會使用桌上型電腦的網路連線。系統幾乎保證會比行動網路速度更快,因此建議您在模擬網路速度較慢的模擬器上變更設定。您可以在 Android Studio 中透過 AVD Manager 或在啟動模擬器時透過指令列選項執行此操作。

不要假設使用觸控螢幕或鍵盤

Android 支援多種手機板型規格。這是為了讓部分 Android 裝置配備完整的「QWERTY」鍵盤,而有些裝置則會有 40 鍵、12 鍵或其他按鍵設定。同樣地,某些裝置會有觸控螢幕,但許多裝置則沒有。

建構應用程式時,請記住這一點。不要假設特定鍵盤配置,除非您確實想限制應用程式,使其只能用於這些裝置。

節省裝置電池電力

但行動裝置往往會一直插到牆上,不見得非常行動裝置。行動裝置是電池供電,如果能延長電池續航力,每個人都更快樂 (特別是使用者)。處理器和無線電是影響最大電池電力的兩大消費者;因此,請務必盡量減少應用程式的工作,並盡量避免頻繁使用網路。

大幅減少應用程式使用的處理器時間,關鍵就在於編寫有效的程式碼。如要盡可能降低使用無線電時的耗電量,請務必妥善處理錯誤情況,並只擷取您需要的內容。例如,如果網路作業失敗,就不要持續重試網路作業。如果失敗一次,可能是因為使用者收不到訊號,所以如果您立即嘗試,則可能會再次失敗;這樣只會浪費電池電力。

使用者相當聰明:如果您的程式很餓,您就可以放心將他們發現的。此時,您可以確定的是,您的程式不會長時間安裝。