神奇的Compose - 效能監控篇
我報名參加金石計劃1期挑戰——瓜分10萬獎池,這是我的第1篇文章,點選檢視活動詳情
背景
在android開發中,無論是基於xml開發的view體系,還是compose,開發效能,頁面的效能也深深影響著我們的app,xml開發中,我們可以用Layout Inspector(AS tools選項)進行ui介面層級的檢視,用於排查我們的ui層級是否合理,是否存在頁面繪製的問題。雖然有這麼一個好的工具,但是Layout Inspector在普通機型上用起來卻不是那麼方便,一直存在著效能問題(雖然我的開發是m1晶片的mac,但是跑起來也是非常艱難,哭😭!)雖然compose以高效能高效率被開發者接收,但是這個高效率也並不是永遠那麼“值得信賴”,因為智慧重組也是有侷限的,這部分內容可以在神奇的Compose- 開篇有介紹!所以,判斷我們compose效能是否好壞,沒錯,官方也提供了相關的檢測手段!Interpreting Compose Compiler Metrics
使用compiler-metrics
為了檢測compose-compiler的效能,compose官方也釋出了檢測外掛,可以直接在我們的build.gradle新增以下程式碼
啟動
可直接在terminal執行以下命令,用於啟用compose編譯檢測
.gradlew -Pandroidx.enableComposeCompilerMetrics=true :compose:runtime:runtime:compileKotlin
生成報告
.gradlew -Pandroidx.enableComposeCompilerReports=true :compose:runtime:runtime:compileKotlin
其他的gradle module可以配置
compileKotlin {
freeCompilerArgs += listOf(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=<directory>"
)
}
compileKotlin {
freeCompilerArgs += listOf(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=<directory>"
)
}
其中directory表示我們想要生成的報告路徑,當然,以上幾種方式都不太方便我們啟用檢測,比如我們想要在release包配置不檢測,debug檢測或者其他包檢測的時候,就不是那麼方便了,所以這裡給出一個非常好的寫法,直接在根目錄build.gradle配置即可
subprojects {
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
kotlinOptions {
if (project.findProperty("myapp.enableComposeCompilerReports") == "true") {
freeCompilerArgs += [
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" +
project.buildDir.absolutePath + "/compose_metrics"
]
freeCompilerArgs += [
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" +
project.buildDir.absolutePath + "/compose_metrics"
]
}
}
}
}
上述配置了一個開關,如果想要啟用檢測,只需要把myapp.enableComposeCompilerReports這個屬性設定為true即可,比如以下
./gradlew assembleRelease -Pmyapp.enableComposeCompilerReports=true
生成的compose效能報告如下
生成檔案解析
- app_release-classes:當前掃描到的class的情況
- app_release-composables.csv csv格式檔案,這裡我們不太關注
- app_release-composables.txt 當前所以composable函式資訊
- app_release-module.json json格式輸出的當前compose中的具體資訊統計
相關的資料應該很容易理解,這裡就不再贅述,值得注意的是,我們可以看到上面的compose函式中,有的函式被標記為 restartable
,有的是skippable
,有的是兩者都有,有的是隻有restartable
,這個是什麼含義呢?
restartable
:可組合,代表著compose中的函式是否可以參加重組,目前應該所有的幾乎所有@Composable
修飾函式都可以參加重組。
skippable
:是否可以跳過重組,這是什麼意思呢?在我們compose函式中,重組不是每一次都需要發生的,當此次的compose函式沒有發生變化,就會跳過重組(key相同且內容沒有變化時)我們在可以反編譯compose函式可以看到相關的函式(編譯時生成)
$composer2.skipToGroupEnd();
這個就屬於跳過重組!這裡跟 restartable
形成區別,並不是所有的composable函式都可以在編譯時生成跳過重組的方法,我們用以下對比例子來說明:
不帶有skippable修飾
class TestData2 {
var text = ""
}
```
@Composable
fun Testing1(data: TestData2) {
Text(text = data.text)
} ``` 此時該函式就不帶有skippable修飾,因為其中依賴的TestData2中的text屬性是可變的
反編譯後:
帶有skippable修飾
相反的,我們使用不可變的data類的時候,就可以生成可skippable的composable函式
data class TestData(val text:String)
```
@Composable
fun Testing(data: TestData) {
Text(text = data.text)
} ```
反編譯後:
這裡我們做一個小結論,如果想要composable函式具有跳過重組的能力時,所依賴的外部屬性必須都是stable的,常見的(Boolean,Int,Long,String,Float,Double,函式型別等等)都是穩定的,一些預設非stable的,比如interface等類,如果我們想要提高重組的效能,就可以用@Stable修飾,告訴compose編譯器生成跳過重組的邏輯!
一個小坑
不過值得注意的是,list型別,即使我們用@Stable修飾,還是被認為是unstable 所依賴的composable函式依舊是不可skip(不帶有skippable)
```
@Composable
@Stable
fun Testing3(data: List
}
```
總結
到這裡,我們應該能夠使用compiler-metrics去檢測我們的compose專案啦!發現我們需要優化的點,這個非常重要!
最後筆者有話說:神奇的compose系列文章其實更加偏重實戰技巧與底層解析,可能對不太瞭解compose的朋友閱讀上會產生相應的干擾,但是不要緊!繼續衝就對啦!附上compose官方連結 http://developer.android.google.cn/jetpack/androidx/releases/compose?hl=zh_cn
- Lambda - 認識java lambda與kotlin lambda的細微差異
- 寫給android開發的Linux 訊號 - 下篇
- 神奇的年終總結
- “Signal”背後的bug與解決
- Parcel-Binder流水線的打包俠
- 避免踩坑,記憶體不足時系統回收Activity的流程解析
- Suspend函式與回撥的互相轉換
- 聊一聊Kotlin協程"低階"api
- Android效能優化 - 包體積殺手之R檔案內聯原理與實現
- 從val跟var瞭解虛擬機器世界
- Android效能優化 - 捕獲java crash的那些事
- Android效能優化-執行緒監控與執行緒統一
- Android效能優化 - plt hook 與native執行緒監控
- 神奇的Compose - 效能監控篇
- 最近很火的反除錯,你知道它是什麼嗎?
- 神奇的共享記憶體
- 學完ASM Tree api,再也不怕hook了
- 對移動端app容災的思考
- 為什麼說獲取堆疊從來就不是一件簡單的事情
- 聽說Compose與RecyclerView結合會有水土不服?