嚴格略過是 Compose 編譯器提供的模式。啟用後,編譯器的行為會發生兩種變化:
啟用嚴格略過模式
Kotlin 2.0.20 預設會啟用強力略過模式。
如要在 2.0.20 之前的版本中,為 Gradle 模組啟用強化略過功能,請在 Gradle 設定的 composeCompiler 區塊中加入下列選項:
android { ... }
composeCompiler {
enableStrongSkippingMode = true
}
可組合函式略過性
在略過和可組合函式方面,強略過模式會放寬 Compose 編譯器通常會套用的部分穩定性規則。根據預設,如果可組合函式的所有引數都有穩定值,Compose 編譯器會將該函式標示為可略過。嚴格略過模式會改變這種情況。
啟用嚴格略過模式後,所有可重新啟動的可組合函式都會變成可略過。無論參數是否不穩定,都適用這項規定。 無法重新啟動的可組合函式仍無法略過。
略過時機
為判斷是否要在重組期間略過可組合函式,Compose 會比較每個參數的值與先前的值。比較類型取決於參數的穩定性。
- 不穩定參數則使用例項相等性 (
===) 比較 - 系統會使用物件相等性 (
Object.equals()) 比較穩定參數
如果所有參數都符合這些要求,Compose 會在重組期間略過可組合項。
您可能希望可組合項不採用強化略過模式。也就是說,您可能需要可重新啟動但不可略過的可組合項。在這種情況下,請使用 @NonSkippableComposable 註解。
@NonSkippableComposable
@Composable
fun MyNonSkippableComposable {}
將類別加上穩定註解
如要使用物件相等性 (Object.equals()) 而非執行個體相等性 (===) 比較物件,請繼續使用 @Stable 或 @Immutable 為指定類別加上註解。
新增 @Stable 或 @Immutable 前,請留意下列優缺點:
- Compose 模組中具有穩定屬性的類別已穩定:在以 Compose 編譯器編譯的模組中,具有穩定類型
val屬性的類別會自動推論為穩定,並使用.equals(),不需要@Immutable或@Stable。 - 僅使用低成本
.equals()檢查為類別加上註解:如果編譯器無法推斷穩定性 (例如來自非 Compose 模組的類別),且經常分配具有相同值的新例項,請新增@Stable或@Immutable,前提是類別的.equals()檢查成本低廉。 - 為含有集合的模型加上註解時,請務必謹慎:如果為含有集合的模型加上
@Stable或@Immutable(或將List替換為ImmutableList),Compose 會在每次重組時,使用.equals()比較集合中的每個元素。如果是用於延遲版面配置 (LazyColumn、LazyRow、LazyGrid) 的大型集合或模型,比較每個元素的速度可能比使用例項相等 (===) 或直接重組更慢。
Lambda 記憶
嚴格略過模式也會對可組合項中的 lambda 啟用更多記憶功能。啟用嚴格略過模式後,系統會自動記住可組合函式中的每個 lambda。
範例
如要在使用強化略過功能時,對可組合項中的 lambda 進行記憶,編譯器會使用 remember 呼叫包裝 lambda。並以 lambda 的擷取內容做為索引鍵。
假設您有 lambda,如以下範例所示:
@Composable
fun MyComposable(unstableObject: Unstable, stableObject: Stable) {
val lambda = {
use(unstableObject)
use(stableObject)
}
}
啟用嚴格略過模式後,編譯器會將 lambda 納入 remember 呼叫中,藉此記住 lambda:
@Composable
fun MyComposable(unstableObject: Unstable, stableObject: Stable) {
val lambda = remember(unstableObject, stableObject) {
{
use(unstableObject)
use(stableObject)
}
}
}
鍵的比較規則與可組合函式相同。執行階段會使用執行個體相等性比較不穩定索引鍵。系統會使用物件相等性比較穩定索引鍵。
記憶和重組
這項最佳化功能可大幅增加執行階段在重組期間略過的可組合項數量。如果沒有記憶功能,執行階段在重組期間,更有可能為任何採用 lambda 參數的可組合函式分配新的 lambda。因此,新 lambda 的參數與上次組合結構不同。這會導致重組。
避免記憶
如果您有不想記憶的 lambda,請使用 @DontMemoize 註解。
val lambda = @DontMemoize {
...
}
APK 大小
編譯時,可略過的可組合項產生的程式碼,會比不可略過的可組合項多。啟用嚴格略過模式後,編譯器會將幾乎所有可組合函式標示為可略過,並將所有 lambda 包裝在 remember{...} 中。因此,啟用嚴格略過模式對應用程式的 APK 大小影響極小。
在 Now In Android 中啟用強力略過功能後,APK 大小增加了 4 KB。大小差異主要取決於特定應用程式中先前不可略過的可組合項數量,但應該相對較小。