Compose 學(xué)習(xí)總結(jié)

Compose發(fā)布正式版已經(jīng)有一段時(shí)間了。趁最近比較閑,抓緊學(xué)習(xí)一波。

學(xué)習(xí)過(guò)程中,主要以實(shí)戰(zhàn)項(xiàng)目中常用技術(shù)為目標(biāo)。下面是項(xiàng)目地址,會(huì)長(zhǎng)期更新,希望能給正在學(xué)習(xí)Compose的小伙伴一點(diǎn)參考。同時(shí)您有什么好的建議,也可以提issue給我,我們一起討論。

項(xiàng)目地址:https://github.com/guozhiqiang123/compose-study

目標(biāo)

  • 配合Retrofit+Okhttp實(shí)現(xiàn)數(shù)據(jù)加載并展示
  • 實(shí)現(xiàn)列表的上拉加載更多、下來(lái)刷新
  • 項(xiàng)目采用單頁(yè)面
  • 使用compose-navigation實(shí)現(xiàn)路由導(dǎo)航
  • 使用ViewModel+LiveData實(shí)現(xiàn)MVVM架構(gòu)
  • 使用ViewModel+Flow(LiveData)實(shí)現(xiàn)MVI架構(gòu)
  • 導(dǎo)航動(dòng)畫(huà)使用
  • compose中嵌入原生控件
  • 常見(jiàn)的動(dòng)畫(huà)使用
  • 全局狀態(tài)的管理
  • 適配平板
  • 暗黑適配
  • 多主題定制,切換
  • 自定義組件
  • 視頻列表實(shí)現(xiàn)和優(yōu)化
  • 嵌入網(wǎng)頁(yè),和js交互
  • compose-permission使用
  • compose-pager使用
  • 流式布局實(shí)現(xiàn)和優(yōu)化
  • Material3主題適配
  • 實(shí)現(xiàn)至少兩個(gè)復(fù)雜頁(yè)面并交互
  • 登錄功能,并實(shí)現(xiàn)全局登錄狀態(tài)的同步
  • 本地?cái)?shù)據(jù)存儲(chǔ)Room、DataStore等組件的使用
  • 自定義頁(yè)面狀態(tài)管理組件
  • 代碼質(zhì)量檢測(cè)工具
  • 老項(xiàng)目混寫(xiě)Compose
  • 其他更高級(jí)的功能,想到再補(bǔ)充

知識(shí)點(diǎn)

這只是我自己學(xué)習(xí)過(guò)程中的筆記和思考,可能不是完全正確,如有錯(cuò)誤,忘指正!

SnackBar的使用

//第一步:
val snackbarHostState = remember { SnackbarHostState() }
//通過(guò)kotlin Channel發(fā)送消息
val channel = remember { Channel<String>(Channel.CONFLATED) }

//第二步:
LaunchedEffect(key1 = channel) {
    channel.receiveAsFlow().collect {
        snackbarHostState.showSnackbar(it)
    }
}

//第三步:
 Scaffold(
        modifier = Modifier.fillMaxSize(),
        backgroundColor = Color.Transparent,
        scaffoldState = rememberScaffoldState(snackbarHostState = snackbarHostState)
   ) {
}

//第四步:
channel.trySend("需要顯示的文本")

和ViewModel配合使用

使用ViewModel擴(kuò)展函數(shù)需要添加下面組件:

implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1"
//示例代碼
@Composable
fun HomeMainPage(viewModel: HomeMainViewModel = viewModel()) {}

將LiveData轉(zhuǎn)換成State需要添加下面組件:

implementation "androidx.compose.runtime:runtime-livedata:1.2.1"
//示例代碼
val counter = viewModel.counter.observeAsState()

軟鍵盤(pán)顯示/隱藏的控制

 val keyboard = LocalSoftwareKeyboardController.current
 // ...
 onClick = {
     keyboard?.hide()
     keyboard?.show()
 }

不借助State手動(dòng)刷新(不推薦這么做)

//觸發(fā)當(dāng)前Composable的recomposition
currentRecomposeScope.invalidate()

Effect的使用

教程:https://juejin.cn/post/6930785944580653070

流程:


Compose組件生命周期

DisposableEffect

和生命周期相關(guān)的邏輯執(zhí)行使用。比如廣播注冊(cè)和反注冊(cè)、監(jiān)聽(tīng)和注銷(xiāo)監(jiān)聽(tīng)等等。

key1傳Unit或者true,首次渲染執(zhí)行一次,重組則不再執(zhí)行。key1傳State,則State值變化,則再次執(zhí)行。

SideEffect

每次重組都需要執(zhí)行的副作用。比如日志打印等等。

LaunchedEffect

需要調(diào)用協(xié)程函數(shù)的時(shí)候使用。

key1傳Unit或者true,首次渲染執(zhí)行一次,重組則不再執(zhí)行。key1傳State,如果State值變化,則再次執(zhí)行。

如果是條件啟動(dòng)該副作用,條件應(yīng)該寫(xiě)在外面,而不是LaunchedEffect里面,盡量減少資源的浪費(fèi)。

Compose函數(shù)中dp轉(zhuǎn)px

import androidx.compose.ui.platform.LocalDensity

val pxValue = with(LocalDensity.current) { 16.dp.toPx() }

// or

val pxValue = LocalDensity.current.run { 16.dp.toPx() }

設(shè)置部分文字不可復(fù)制

 // 設(shè)置可選區(qū)域
 SelectionContainer {
     // Column等價(jià)于豎直的LinearLayout
     Column {
         Text(text = "可以選中我,可以選中我,可以選中我")

         // 設(shè)置不可選區(qū)域
         DisableSelection {
                Text(text = "選不中我,選不中我,選不中")
         }

         // 位于可選區(qū)域內(nèi),可選
         Text(text = "可以選中我,可以選中我,可以選中我")
     }
 }

物理返回鍵的處理

使用BackHandler進(jìn)行攔截,但是不能寫(xiě)在MaterialTheme的代碼塊中,否則不生效

@Composable
fun TestPage(){
    BackHandler {
        //TODO:攔截物理返回鍵
    }
    
    MaterialTheme {
        androidx.compose.material.Scaffold {
            Box(Modifier.padding(it)) {
                
            }
        }
    }
}

我的一點(diǎn)看法

我之前用Flutter寫(xiě)過(guò)幾個(gè)demo,逐漸熟悉了寫(xiě)Flutter后,感覺(jué)寫(xiě)起來(lái)真好。特別是Android Studio各種智能補(bǔ)全,寫(xiě)起來(lái)特別流暢。所以一直比較抵觸學(xué)Compose,總感覺(jué)比Flutter書(shū)寫(xiě)體驗(yàn)差太多了。不過(guò)我畢竟還是一個(gè)Android開(kāi)發(fā)嘛,還指望著吃這碗飯,所以Android這邊的新技術(shù)也要學(xué)習(xí)起來(lái)。

寫(xiě)這篇文章的時(shí)候,我前前后后學(xué)Compose大概花了一周。主要是remember和Effect都是新概念,從接觸到理解個(gè)大概,花了一些時(shí)間。如果有學(xué)習(xí)過(guò)React前端技術(shù)的,應(yīng)該立馬就能明白,可惜我并沒(méi)有這樣的經(jīng)驗(yàn)。

學(xué)習(xí)了基本的組件后,我就開(kāi)始寫(xiě)上面這個(gè)項(xiàng)目,剛開(kāi)始寫(xiě)起來(lái)有點(diǎn)生疏。比如狀態(tài)提升什么的,剛開(kāi)始寫(xiě)完全沒(méi)注意到。不過(guò)隨著業(yè)務(wù)逐漸偏向于實(shí)戰(zhàn)項(xiàng)目,不斷重構(gòu)和優(yōu)化代碼,狀態(tài)提升這個(gè)東西,自然而然就有了。

代碼寫(xiě)的好不好,性能怎么樣。除了直覺(jué)感受,更重要的是要有工具來(lái)檢測(cè),于是又到處搜文章看,然后嘗試大佬們推薦的做法。工具有了之后,又把之前性能不好的地方重構(gòu)了下。

總體來(lái)說(shuō),目前Compose已經(jīng)很好了,我個(gè)人感覺(jué)性能上不比原生差。而且函數(shù)組合方式真的比類(lèi)繼承好使多了,非常靈活,而且少很多模板代碼。寫(xiě)動(dòng)畫(huà)真的不要太爽,原生項(xiàng)目寫(xiě)個(gè)動(dòng)畫(huà)有多痛苦,相信做過(guò)原生開(kāi)發(fā)的小伙伴都知道。另外自定義控件比原生容易多了,原生自定義需要理解很多概念,什么ViewGroup,View,事件傳遞等等。而Compose相對(duì)來(lái)說(shuō)理解的概念就少多了,而且代碼更簡(jiǎn)潔。有時(shí)候寥寥幾句代碼,就能實(shí)現(xiàn)很復(fù)雜的組件。

希望想在Android領(lǐng)域繼續(xù)討飯吃的小伙伴都學(xué)起來(lái)吧!

感謝你們(排名不分先后)

持續(xù)更新中...

除了項(xiàng)目持續(xù)更新,該文章也會(huì)持續(xù)更新。大家一起學(xué)習(xí),共同進(jìn)步!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容