社區(qū)說|Jetpack Compose 架構(gòu)與原理

1.Composable 快速介紹
一段代碼和運行結(jié)果示例

加上@Composable 注解后,Koltin 函數(shù)會變成一個可視化的 UI,函數(shù)體的執(zhí)行順序不變??梢钥闯觯?/p>
Composable的本質(zhì)是函數(shù)
復雜一些的例子??,與 xml 的區(qū)別在于是代碼級別的所見即所得。

2.Compose 編譯器插件
Compose 架構(gòu)圖如下:

compose 編譯器插件是架構(gòu)最底層的部分,屬于功能架構(gòu)的基本能力,compose的很多核心能力都是基于編譯器插件實現(xiàn)的。
編譯器插件如何實現(xiàn) compose 的能力呢?,一個案例代碼:

在編譯流程中,編譯器插件對代碼進行處理:

經(jīng)過 compose 編譯器插件處理后,函數(shù)參數(shù)會多出一個 Composer 參數(shù):

類似 kotlin 中的掛起函數(shù),suspend 關(guān)鍵字修飾的函數(shù)經(jīng)過編譯之后,會帶有一個 continuation 參數(shù)。
為什么 compose 使用注解而不是關(guān)鍵字實現(xiàn)呢?因為 compose 是工程應用級別的,而非語言本身的特性。
compose 函數(shù)經(jīng)過編譯器轉(zhuǎn)換之后的完整代碼如下:

在初次執(zhí)行時,會創(chuàng)建RestartGroup、Scope,調(diào)用 Text()、結(jié)束RestartGroup、返回Scope、參數(shù)變化時觸發(fā)重組。
3.Recompose 與性能優(yōu)化
一個復雜的compose代碼示例:

先定義一個state,延遲一秒更新 state 的值,greeting 函數(shù)使用到了state的值,運行日志如下:

可以看到,state的值變更導致了整個頁面的重組。
優(yōu)化
改變 state 參數(shù)的傳值方式,greeting 不接收一個具體的值,而是接收函數(shù)參數(shù):

改動后的執(zhí)行流程日志如下:

可以看到,跟之前界面初始流程不變,但是state 值更新后,只有g(shù)retting 函數(shù)發(fā)生重組,main screen 沒有觸發(fā)重組。 -- 節(jié)省了資源消耗,這也是官方推薦的使用方式。
優(yōu)化背后的原理:Laziness
實現(xiàn)laziness 比較簡單,用 lambda 就可以實現(xiàn):

重組作用域
和前文中編譯后的scope概念是一致的

每個函數(shù)都有自己的scope 。state的讀取發(fā)生在 main scope 中,當 state 值改變之后,就會觸發(fā) main screen 的 scope 的重新執(zhí)行,從而觸發(fā) greeting 的重新執(zhí)行
而代碼優(yōu)化之后,state的讀取發(fā)生在 greeting 的 scope 中,因此state 值變更指揮觸發(fā) greeting 的scope的重新執(zhí)行:

這就是通過 laziness 來最小化 讀寫 scope 的優(yōu)化案例,也是官方推薦的優(yōu)化方案。
Compose 生命周期

從 Composition 到 Layout 再到 Draw。Composition 就是我們的 compose 函數(shù)執(zhí)行的過程,recompose 就是 recomposition
性能優(yōu)化建議
- 1、Defer reads as long as possible 盡可能延遲讀數(shù)據(jù)的時機(上文提到的 laziness 優(yōu)化示例)
- 2、Use derivedStateOf to limit recomposition。使用 XtateOf 的子類限制重組
- 3、Avoid backwards writes。 避免在重組時寫數(shù)據(jù)(否則可能會導致類似遞歸的惡性循環(huán)重組)
一個用 laziness 優(yōu)化的官方案例。優(yōu)化前:

優(yōu)化后:


4.Compose 的架構(gòu)設(shè)計

5.基于 Compose 的基礎(chǔ)設(shè)施,我們還能做什么?
基于 runtime 和 snapshot ,可以自己實現(xiàn) ui架構(gòu):

運行效果

使用 Moasic鞋 ui 界面:

Applier 是對ui進行操作的抽象。在Android 平臺實現(xiàn)是LayoutNode,在Moasic 項目實現(xiàn)是MoasicNode。

UiApplier 的反省是 LayoutNode,是Android 的實現(xiàn)。

MoasicNodeApplier 是 Moasic 項目的實現(xiàn):


底層抽象做的足夠好,非常通用,上層才能隨意定制實現(xiàn)。
6. Compose 與 Android
Compose 與 Android 有一個交互的節(jié)點,但最終還是會走 View的生命周期函數(shù):



這個方法就是把compose的內(nèi)存結(jié)構(gòu)最終變成 ui結(jié)構(gòu)的關(guān)鍵函數(shù)


7、擴展資料
- 極客時間《Kotlin編程第一課》
- 《兩小時入門 Jetpack Compose(上)》
- 《兩小時入門 Jetpack Compose(下)》
- 《Compose 原理與性能優(yōu)化》