Thinking in Compose

Jetpack Compose

Compose 终于迎来了第一个 Beta 版本,这意味着其 API 已经基本稳定了,所以这个时候开始学习 Compose 是最合适的。这篇主要是我在读了官方文档后做的笔记,关于 Compose 的开发模式以及需要注意的地方。

什么是 Compose

Jetpack Compose is a modern declarative UI Toolkit for Android. Compose makes it easier to write and maintain your app UI by providing a declarative API that allows you to render your app UI without imperatively mutating frontend views.

和 React-Native、Flutter、SwiftUI 一样,Compose 是一种声明式编程的 UI 框架。简单来说,就是让你可以直接使用 Kotlin 代码编写视图,而不需要每次从视图树中获取视图并进行修改。

声明式编程范式

传统方式的缺点

视图树中的每个组件都在内部维护着自己的状态(State)。在修改组件之前需要先找到该组件,然后调用相应的方法去修改状态(命令式)。这种方式不旦繁琐,而且容易产生 bug,比如修改视图状态时造成冲突。

Declarative UI model

只需声明组件,当状态发生变化时,重新生成并更新视图,在 Compose 框架中此过程叫做 Recomposition。不过,在实际情况下,为了减少性能损耗,Compose 框架会判断哪些组件需要更新,从而只更新需要更新的部分。

优点1:将可变的状态暴露成方法参数,从而可以和架构模式中一些组件(比如 ViewModel)结合起来使用:Compose 接受初始数据,当用户输入数据时将事件通知给 ViewModel 去处理,然后 ViewModel 再通知 Compose 重新对视图进行渲染。

优点2:动态性。可以充分发挥 Kotlin 语言的优势,只需要很少的代码就可以轻松写出灵活多变的视图结构。

Composable 函数的组成部分

@Composable
fun Greeting(name: String) {
    Text("Hello, $name!")
}
  • Composable 函数必须使用 @Composable 注解。使用该注解告诉 Compose 编译器可以将该方法转换成 UI。
  • Composable 函数接收参数。
  • Composable 函数没有返回值。
  • Composable 函数运行具有等幂性(idempotent)、无副作用(side-effect free)、运行快的特点。
    • 等幂性即使用相同参数调用一次和调用多次的结果相同,不依赖全局变量或者随机结果函数。
    • 只修改 UI 而不产生任何 side-effects,即不造成除 composeable 函数以外的任何变化,比如修改成员属性或者全局变量的值、读写数据库、更改 ViewModel 的状态等等。

Recomposition

传统开发方式中,当我们需要修改视图的时候,会先找到该视图然后进行修改,但是在 Compose 框架中,我们通过重新调用 composable 函数(传入新数据),然后由 Compose 框架对视图进行修改,此过程就叫做 recomposition

之前说过,重新生成整个视图树代价高昂,所以出于性能考虑,Compose 框架只会对发生变化的部分进行修改,此过程也被叫做 intelligent recomposition

正因如此,在 recomposition 的过程中,一些函数、lambda 表达式有可能会被跳过,也是因为这个原因,我们才不能依赖任何 side-effects,比如:

  • 对一个共享对象的属性值进行修改
  • 更新 ViewModel 中的 Observable
  • 更新 SharedPreference

另外,composable 函数可能被多次执行,甚至每一帧执行一次(比如执行动画的时候),所以如果你的 composable 函数中包含一些耗时操作(比如读写 SharedPreference),最好放到子线程中进行,比如使用 Coroutine 并将结果作为参数传递到 composable 函数中。

除此之外,在使用 Compose 的过程中还需要注意以下这些问题。

Composable 函数不一定会按顺序执行

通过情况下,composable 函数的确会按顺序执行,但是当一个 composable 函数中包含其它 composable 函数时,就不一定是按顺序执行的了。Compose 框架会识别出具有更高优先级的 UI 组件,并对它们优先进行渲染。所以,当嵌套使用 composable 函数的时候,要记得每个 composable 函数必须是独立的,不能依赖其它 composable 函数的执行状态。

Composable 函数可能同步执行

在 recomposition 过程中,为了加快运行速度,多个 composable 函数可能会同时被执行。另外,这也意味着某些 composable 函数会被放到后台子线程中执行。比如,当 composable 函数参数中包含 ViewModel 中的方法,那么该方法有可能在多个线程中被执行了多次。所以,我们不能在 composable 中引入 side-effects。

Recomposition 会尽可能多地被跳过

正如之前所说,Compose 只会更新需要更新的部分,剩下的部分会被跳过。

Recomposition 是乐观的并且可能会取消并重新执行

每当参数发生变化的时候,recomposition 就会发生。乐观的意思是 Compose 通常会认为在接收到新的参数变化之前,已经完成了上一次的 recomposition,所以,当参数发生变化时,如果上一次 recomposition 还没完成,Compose 会优先取消掉它并使用新的参数重新执行 recomposition。

同样的,如果你在 composable 函数中包含 side-effects,比如修改了某个全局参数,那么该参数有可能在 recompositon 取消并重新执行的过程中被修改了多次。所以,再次提醒,一定要保持 composable 函数的等幂性 idempotent 和无 side-effects。

Composable 函数可能被频繁执行

在某些情况下,composable 函数可能每帧都被执行一次,比如使用动画的时候。所以,记住不要在 composable 函数中执行诸如 IO 等耗时的操作。一般的做法是将数据定义在 composable 函数的参数中,如果获取数据比较耗时则应该放在子线程中,然后使用 MutableState 或者 LiveData 对数据进行接收。

链接:Thinking in Compose

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

推荐阅读更多精彩内容