處理設定變更

部分裝置設定可能會在應用程式執行期間變更。這些設定包括但不限於:

  • 應用程式顯示大小
  • 螢幕方向
  • 字型大小和粗細
  • 語言代碼
  • 深色模式與淺色模式
  • 可用鍵盤

這些設定變更大多是由使用者互動而產生。舉例來說,旋轉或摺疊裝置會變更應用程式可用的螢幕空間。同樣地,改變字型大小、語言或偏好的主題等裝置設定,也會變更 Configuration 物件中各自對應的值。

這些參數通常需要對應用程式 UI 進行大幅變更,因此 Android 平台為這些變更建構了專門的機制,也就是「Activity 重建」

重建活動

發生設定變更時,系統會重新建立 Activity。為此,系統會呼叫 onDestroy 並刪除現有的 Activity 例項,接著使用 onCreate 建立新的例項,並運用新的更新設定初始化這個新的 Activity 例項。也就是說,系統也會使用新設定重建使用者介面。

通常 Activity 會做為可組合項的主機。重新建立 Activity 時,Compose 也會使用新的設定值重建 UI。

重建行為可讓應用程式根據與新裝置設定相符的替代資源自動重新載入應用程式,協助應用程式適應新設定

重建範例

假設可組合函式會使用字串資源顯示靜態標題:

// In the res/values/strings.xml file
// <string name="compose">Jetpack Compose</string>

// In your Compose code
Text(
    text = stringResource(R.string.compose)
)

建立 Activity 時,Text 可組合函式會讀取目前的設定 (例如語言),並解析適當的字串資源。

如果語言有變,系統會重新建立活動。發生這種情況時,Compose 會重新建立 UI。由於 stringResource 會讀取目前的設定,因此標題會自動更新為正確的本地化值。

重建作業也會清除在 Activity 中以欄位形式保留的任何狀態。

如要在設定變更時保留 UI 狀態,請使用建議的狀態管理模式。請使用 ViewModel 處理資料和商業邏輯,並使用 rememberSaveable 處理 UI 層級狀態。透過這些機制,狀態會在 Activity 重建時保留,而 UI 會更新以反映新設定。

如要進一步瞭解如何在 Compose 中儲存狀態,請參閱「在 Compose 中儲存 UI 狀態」。

使用者的期望

應用程式的使用者會預期狀態能夠保留。如果使用者正在填寫表單,並且以多視窗模式開啟另一個應用程式來參照資訊,則當使用者返回到已清除內容的表單,或返回到應用程式的其他位置,就會造成使用者體驗不佳。開發人員必須透過設定變更和活動重建,提供一致的使用者體驗。

如要驗證應用程式是否能保留狀態,可以在應用程式於前景和背景運作時,執行會導致設定變更的動作。這些活動包含:

  • 旋轉裝置
  • 進入多視窗模式
  • 在多視窗模式或任意形式視窗中調整應用程式大小
  • 摺疊搭配多個螢幕的摺疊式裝置
  • 變更系統主題,例如深色模式與淺色模式
  • 變更字型大小
  • 變更系統或應用程式語言
  • 連接或拔除硬體鍵盤
  • 連接或拔除座架

您可以採用幾種方式,透過 Activity 重建來保留相關狀態。要使用的方式取決於您想保留的狀態類型:

  • 本機常駐性可用於處理複雜或大型資料的程序終止。常駐性本機儲存空間包含資料庫或 DataStore
  • 保留的物件 (例如 ViewModel 例項),可在使用者積極使用應用程式時,處理記憶體中的 UI 相關狀態。
  • rememberSaveable,在設定變更和系統啟動的程序終止後,保留暫時性 UI 狀態。這適用於取決於使用者輸入內容、捲動位置或導覽的狀態,但不屬於 ViewModel

如要進一步瞭解每種方式適用的 API,以及每個 API 的適用時機,請參閱「儲存 UI 狀態」一文。

限制活動重建

您可以避免系統為特定設定變更自動重建活動。在僅使用 Compose 的新式應用程式中,UI 會以任一方式重新組合,但建議直接處理設定變更。

根據預設,設定變更會強制系統刪除並重建 Activity,包括 UI 和衍生自 Activity 的任何物件。如果您宣告 Activity 會自行處理設定變更,系統會防止這種情況發生。而是只更新 Configuration 物件,Compose 會使用新值重組 UI。

直接在 Compose 中處理設定變更有許多優點:

  • 提升效能:重新組合 UI 的成本比完整的 Activity 重建週期低,尤其是進行小幅變更時。
  • 流暢動畫:避免重新啟動 Activity,即可在設定變更時執行連續動畫,例如裝置旋轉時的平滑版面配置轉場效果。
  • 保留狀態:保留 Activity 執行個體可降低在螢幕旋轉等事件期間,暫時性 UI 狀態遺失的風險。請注意,您仍須處理系統啟動程序終止時的狀態保留作業。

如要為特定設定變更停用活動重建功能,請將設定類型加入 AndroidManifest.xml 檔案 <activity> 項目中的 android:configChanges。可能的值會列在 android:configChanges 屬性的說明文件中。

以下資訊清單程式碼會在螢幕方向和鍵盤可用性變更時,停用 MyActivityActivity 重建功能:

<activity
    android:name=".MyActivity"
    android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
    android:label="@string/app_name">

回應設定變更

應用程式可利用 Jetpack Compose 輕鬆回應設定變更。但是,如果在可行的情況下為所有設定變更停用 Activity 重建功能,應用程式仍必須正確處理設定變更。

使用 LocalConfiguration 本機組合時,Compose UI 階層可適用 Configuration 物件。每次此物件變更時,從 LocalConfiguration.current 讀取的可組合函式都會重組。如要瞭解本機組合的運作方式,請參閱「使用 CompositionLocal 的本機範圍資料」相關說明。

範例

在以下範例中,可組合函式會顯示具有特定格式的日期。該可組合函式會使用 LocalConfiguration.current 呼叫 ConfigurationCompat.getLocales,回應系統語言代碼設定的變更。

@Composable
fun DateText(year: Int, dayOfYear: Int) {
    val dateTimeFormatter = DateTimeFormatter.ofPattern(
        "MMM dd",
        ConfigurationCompat.getLocales(LocalConfiguration.current)[0]
    )
    Text(
        dateTimeFormatter.format(LocalDate.ofYearDay(year, dayOfYear))
    )
}

為避免在語言代碼變更時重建 Activity,代管 Compose 程式碼的 Activity 需要選擇停用語言代碼設定變更。如要這樣做,請將 android:configChanges 設為 locale|layoutDirection

設定變更:重要概念和最佳做法

處理設定變更時,您需要瞭解下列重要概念:

  • 設定:裝置設定會定義 UI 向使用者顯示的方式,例如應用程式顯示大小、語言代碼或系統主題。在 Compose 中,您可以使用 LocalConfiguration 存取設定值。
  • 設定變更:設定會隨著使用者互動而變更。例如,使用者可能會變更裝置設定或與裝置實際互動的方式。您無法防止設定變更。
  • Activity 重建:在預設情況下,設定變更會導致 Activity 重建。這項內建機制可根據新設定重新初始化應用程式狀態。
  • Activity 刪除: Activity 重建會導致系統刪除舊 Activity 例項並建立新例項。舊例項現已過時,避免在生命週期範圍以外保留對生命週期範圍物件的參照。
  • 狀態:Activity 例項中的狀態不會顯示在新 Activity 例項中,因為這是兩個不同的物件例項。請勿將狀態繫結至 Activity,而是使用建議的 API 保留應用程式和使用者的狀態,如「儲存 UI 狀態」一文所述。
  • 選擇停用:為特定設定變更類型選擇停用活動重建功能時,您必須確保應用程式能正確更新,回應新的設定。對於大多數 Compose 應用程式,我們不建議這麼做。

為提供良好的使用者體驗,請留意下列最佳做法:

  • 為頻繁的設定變更預做準備:無論 API 級別、板型規格或 UI 工具包為何,請勿假設設定變更很少發生或完全不會發生。當使用者變更設定時,會期望應用程式能夠更新,並根據新設定繼續正確運作。
  • 保留狀態:Activity 重建發生時,不要遺失使用者的狀態。請使用 ViewModelrememberSaveable 等 API,保留狀態,如「儲存 UI 狀態」一文所述。
  • 避免將選擇停用做為快速修正方式:請勿將選擇停用 Activity 重建功能,當做避免遺失狀態的捷徑。停用活動重建功能必須履行處理變更的承諾,而您可能會因為其他設定變更、程序終止或關閉應用程式的 Activity 重建而遺失狀態。因此,您無法完全停用 Activity 重建功能。請保留狀態,如「儲存 UI 狀態」一文所述。
  • 不要避免設定變更:不要為了避免設定變更或 Activity 重建,對螢幕方向、顯示比例或是否可調整大小設下限制。這會對想以自己偏好方式使用應用程式的使用者產生負面影響。

處理以大小為依據的設定變更

以大小為依據的設定變更隨時都會發生,如果應用程式在大螢幕裝置上執行,當使用者進入多視窗模式時就更有可能發生。使用者預期應用程式能夠在該環境中順利運作。

大小變更分為兩種一般類型:大幅變更和小幅變更。「大幅」變更是指由於螢幕大小的差異 (例如寬度、高度或最小寬度),將不同額外資源組合套用到新設定的情形。這些資源包括應用程式本身定義的資源,以及任何資源提供的程式庫。

針對以大小為依據的設定變更限制活動重建

如果您針對以大小為依據的設定變更停用 Activity 重建功能,系統不會重新建立 Activity,而會改為接收對 Activity.onConfigurationChanged 的呼叫。讀取 LocalConfiguration.current 的任何可組合函式都會自動重組,以反映新的大小。

如果資訊清單檔案中設有 android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout",系統會針對以大小為依據的設定變更,停用 Activity 重建功能。

其他資源

如要進一步瞭解如何處理設定變更,請參閱下列其他資源:

說明文件

Views content