Compose 学习总结

Compose发布正式版已经有一段时间了。趁最近比较闲,抓紧学习一波。

学习过程中,主要以实战项目中常用技术为目标。下面是项目地址,会长期更新,希望能给正在学习Compose的小伙伴一点参考。同时您有什么好的建议,也可以提issue给我,我们一起讨论。

项目地址:https://github.com/guozhiqiang123/compose-study

目标

  • 配合Retrofit+Okhttp实现数据加载并展示
  • 实现列表的上拉加载更多、下来刷新
  • 项目采用单页面
  • 使用compose-navigation实现路由导航
  • 使用ViewModel+LiveData实现MVVM架构
  • 使用ViewModel+Flow(LiveData)实现MVI架构
  • 导航动画使用
  • compose中嵌入原生控件
  • 常见的动画使用
  • 全局状态的管理
  • 适配平板
  • 暗黑适配
  • 多主题定制,切换
  • 自定义组件
  • 视频列表实现和优化
  • 嵌入网页,和js交互
  • compose-permission使用
  • compose-pager使用
  • 流式布局实现和优化
  • Material3主题适配
  • 实现至少两个复杂页面并交互
  • 登录功能,并实现全局登录状态的同步
  • 本地数据存储Room、DataStore等组件的使用
  • 自定义页面状态管理组件
  • 代码质量检测工具
  • 老项目混写Compose
  • 其他更高级的功能,想到再补充

知识点

这只是我自己学习过程中的笔记和思考,可能不是完全正确,如有错误,忘指正!

SnackBar的使用

//第一步:
val snackbarHostState = remember { SnackbarHostState() }
//通过kotlin Channel发送消息
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扩展函数需要添加下面组件:

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

将LiveData转换成State需要添加下面组件:

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

软键盘显示/隐藏的控制

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

不借助State手动刷新(不推荐这么做)

//触发当前Composable的recomposition
currentRecomposeScope.invalidate()

Effect的使用

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

流程:


Compose组件生命周期

DisposableEffect

和生命周期相关的逻辑执行使用。比如广播注册和反注册、监听和注销监听等等。

key1传Unit或者true,首次渲染执行一次,重组则不再执行。key1传State,则State值变化,则再次执行。

SideEffect

每次重组都需要执行的副作用。比如日志打印等等。

LaunchedEffect

需要调用协程函数的时候使用。

key1传Unit或者true,首次渲染执行一次,重组则不再执行。key1传State,如果State值变化,则再次执行。

如果是条件启动该副作用,条件应该写在外面,而不是LaunchedEffect里面,尽量减少资源的浪费。

Compose函数中dp转px

import androidx.compose.ui.platform.LocalDensity

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

// or

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

设置部分文字不可复制

 // 设置可选区域
 SelectionContainer {
     // Column等价于竖直的LinearLayout
     Column {
         Text(text = "可以选中我,可以选中我,可以选中我")

         // 设置不可选区域
         DisableSelection {
                Text(text = "选不中我,选不中我,选不中")
         }

         // 位于可选区域内,可选
         Text(text = "可以选中我,可以选中我,可以选中我")
     }
 }

物理返回键的处理

使用BackHandler进行拦截,但是不能写在MaterialTheme的代码块中,否则不生效

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

我的一点看法

我之前用Flutter写过几个demo,逐渐熟悉了写Flutter后,感觉写起来真好。特别是Android Studio各种智能补全,写起来特别流畅。所以一直比较抵触学Compose,总感觉比Flutter书写体验差太多了。不过我毕竟还是一个Android开发嘛,还指望着吃这碗饭,所以Android这边的新技术也要学习起来。

写这篇文章的时候,我前前后后学Compose大概花了一周。主要是remember和Effect都是新概念,从接触到理解个大概,花了一些时间。如果有学习过React前端技术的,应该立马就能明白,可惜我并没有这样的经验。

学习了基本的组件后,我就开始写上面这个项目,刚开始写起来有点生疏。比如状态提升什么的,刚开始写完全没注意到。不过随着业务逐渐偏向于实战项目,不断重构和优化代码,状态提升这个东西,自然而然就有了。

代码写的好不好,性能怎么样。除了直觉感受,更重要的是要有工具来检测,于是又到处搜文章看,然后尝试大佬们推荐的做法。工具有了之后,又把之前性能不好的地方重构了下。

总体来说,目前Compose已经很好了,我个人感觉性能上不比原生差。而且函数组合方式真的比类继承好使多了,非常灵活,而且少很多模板代码。写动画真的不要太爽,原生项目写个动画有多痛苦,相信做过原生开发的小伙伴都知道。另外自定义控件比原生容易多了,原生自定义需要理解很多概念,什么ViewGroup,View,事件传递等等。而Compose相对来说理解的概念就少多了,而且代码更简洁。有时候寥寥几句代码,就能实现很复杂的组件。

希望想在Android领域继续讨饭吃的小伙伴都学起来吧!

感谢你们(排名不分先后)

持续更新中...

除了项目持续更新,该文章也会持续更新。大家一起学习,共同进步!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容