阅读 2002

拿来吧你,Compose尝鲜初体验!

前言

Compose 正式版在七月份的尾巴如期而至,我也写了一份 Compose 版本的项目,Demo其实比较简单。

结构

地址:github.com/mCyp/Hoo

这已经是它的第三个版本:

  1. 第一版:Kotlin + Jetpack
  2. 第二版:Flutter
  3. 第三版:Compose + Jetpack

还记得去年 Compose 推出的时候,我就在团队内部分享了一次 Compose,当时为了展示一个 Preview 的功能,差点卡到下不了台。

麻了

其实写代码的时候速度还可以,但是投屏时属实有些尴尬。

一、技术栈使用

Hoo 功能虽小,但五脏俱全。

技术栈

整个项目的技术栈就是 Compose + Jetpack,由于 Google 大力推行 Android Jetpack,使得我们以后开发 Android 的技术栈越来越清晰,以后的趋势可能是掌握好 Jetpack 就可以帮助我们轻松的开发应用。

在使用 Compose 的时候,发现 Lottie 对 Compose 的支持速度还挺快,于是毫不犹豫的使用了 Lottie。

收藏效果

效果还不错~

二、入门必看

官方文档的地址: 官方入门

官方的Sample: Github Samples

官方页面

这是我在官网截的图,从图中来看,入门教程支持中文,目录结构也比较清晰,中文开发者入门还是比较轻松的。

‘渔’有了,很多人还有诸如以下的疑惑:

  • 为什么要用 Compose 代替 Android 原有的 View 结构?
  • 什么是声明式编程?
  • Compose开发有什么优缺点?

我来为大家一一解答。

1. xml构建UI之痛

首先,我们得明确一点,传统的 Android View 结构是基于面向对象

从我们开始写安卓开始,我就使用 xml 构建 UI,等进入 Activity 或者 Fragment 的生命周期,系统再帮我们解析 xml 文件,一层层的搭建 Android View 结构树,等到使用的时候,会有两个问题:

第一,findViewById 这种方式查询 View 比较低效,每次都需要通过遍历 Android View 树获取指定的View。

第二,对于自定义View来说,我们可能需要管理一大堆的 getset 方法,来管理 View 的各种状态,在一些场景下,手动管理各种 Viewaddremove 也比较麻烦。所以,一些初中级的 Android 开发谈起自定义View总是眉头紧皱。

既然苦于 Android 既有 View 结构久矣,那 Google 自然就做了顺水推舟的事,Compose 也就应运而生。

2. 什么是声明式编程?

过去几年,我们在 Android 领域总是听到关于 声明式UI 的动态,先有大哥 Flutter,后有 Compose 小弟,为什么整 Android 行业都开始向 声明式UI 转变了呢?

也许从代码中找到一些答案,比如我们要去构建一个如下界面,并要求,点击第一个 Button,移除第二个 Button

欢迎页

1.传统写法

构建xml布局:

<LinearLayout>
    <ImageView/>
    <TextView/>
    <Button/>
    <Button/>
</LinearLayout>
复制代码

之后在 Activity 中创建各种 View 对象,通过命令式写法操作这些对象去设置图片,文字和点击事件等。当点击第一个 Button,我们还需要获取外层的 LinearLayout 对象,动态的 remove 第二个子 Button

2.Compose写法

Compose 是一种声明式UI,你需要把界面描述出来,即使界面结构发生变化,你也不需要操纵原来的View,你需要做的是描述状态发生变化后的界面是什么样子的,以代码为例:

@Composable
fun WelcomePage(){
    val state = remember{ mutableStateOf(true)} // ... 获取数据
    Column(){
        Image(...)
        Text(...)
        Button(...) // 点击的时候设置state
        if(state.value){
            Button(...)
        }
    }
}
复制代码

上面的代码中,很清晰的告诉我们,这是一个 Column,对应着原来的 LinearLayout,里面有 ImageTextButton,当状态 state 的值是 true 的时候,会展示另外一个 Button。状态 state 的修改是通过第一个 Button 的点击事件设置的,这里我没有写出来。

Compose 中的重组意味着重建,当 State 发生变化时,描述UI的 @Compose 方法会发生重组。用一张图来描述添加 View 的情况:

添加子View

当然,整个界面重组毕竟是个很高昂的操作,对应着时间、计算能力和电池的消耗,Compose 当然做了优化,只会对必要 @Compose 方法进行重组。比如,上述的 state 发生变化的时候,只会重建 ViewGroupText2

三、为什么要选择Compose?

声明式 UI 的大哥 Flutter 已经出道很久了,再学习 Compose 还有意义吗,Flutter 还是 Compose

我先抛出我的结论:

  • 如果你想运用到实际的生产环境中,Flutter 肯定是更好的选择,因为更多的人帮你踩过了坑。
  • 如果你想 Kotlin 一把梭,只是学习尝鲜,结合 Android JetpackCompose 可以很好的作为你的技术储备。

简单的聊聊 Compose 中还不错的地方。

1. Android开发习惯的继承

相信很多同学都有这样的习惯:

  • 使用 Kotlin 开发
  • 必须协程
  • 复杂的布局会使用 ConstraintLayout
  • ...

是的,这些东西我们依然在 Compose 中运用,从而降低我们的上手难度。

2. Android Jetpack 的支持

在 Compose 刚刚发布的时候,Android Jetpack 中的很多其他库都第一时间给予了 Compose 支持,从而丰富了 Compose 的开发生态。

目前,能够直接在 Compose 上使用的 Jetpack 库有:

  1. Navigation
  2. Paging
  3. ViewModel
  4. LiveData
  5. hilt
  6. lifecycle

理论上来讲,Android Jetpack 上跟 UI 不相关的库 Compose 应该都是支持的,在我写的 Hoo 中,就使用了Paging、Navigation、ViewModel 和 LiveData等 Android Jetpack 库,再有协程和 Kotlin 的加持,整个开发过程中轻松不少!

3. 更少的代码

Compose 可以使我们更加专注于 UI 的开发,声明式UI 可以显著的减少方法数和包体积。在谷歌官方的 《Jetpack Compose 使用前后对比》 一文说道:

Tivi应用在使用了 Compose 后,我们发现 APK 大小缩减了 41%,方法数减少了 17%

其实这些都是可以预见的,比如更加简单的动画和触摸事件的 Api。

4. Preview

Compose支持代码的Preview,如图:

Preview

Compose 代码写完后,可以直接在右边预览,但是更新速度差点意思,不如 Flutter 的热重载方便。

5. 其他

其他的一些点可能就跟 Flutter 有点像了。

  • Compose 的主题原生支持黑夜模式,开发者定制主题的时候提供两套颜色即可,想起之前,起点读书支持黑夜模式可是花了很大的功夫。

  • 通过 Scaffold,可以轻松集成很多 Material 组件,比如 TopbarFloatingActionButtonBottomNavigationBar 等,这些都可以帮助我们节省出不少的时间。

  • 另外,在 Compose 中不能轻松实现效果的时候,借助于 AndroidView,可以去调用Android原生View。

四、吐槽

当然了,Compose 目前还有一些槽点。

1. 生态不丰富

Compose 作为刚出来的 UI 框架,虽然 Android Jetpack 第一时间给予了支持,但生态不丰富这一点是毋庸置疑的。

一些非基础的常用UI,Google 给出了一些解决方案,比如 【accompanist】,它可以帮助你解决部分常用的库。

如果没有你想要的轮子,你只能选择自己造或者引用 Android 原生控件。不过这从侧面也说明了一些机会,当你觉得缺少什么的时候,写出好的开源库的机会来临了~

2. 学习资源少

在学习 Flutter 的时候,遇到某种效果,可能谷歌一下,就有答案了。

但在现阶段的 Compose 中,大概率要自己动手~

3. 导航

作为官方指定的导航 - Navigation,在非 Compose 代码中集成是支持页面之间的过渡动画的,在 Compose 中目前还是不支持的(现在看了一下,有支持的库了)。

Navigation 文档中说明是可以记录页面状态的,但就实际使用而言,有的页面记录状态还是有问题的,比如,纯粹使用 Paging + LazyColumn,当页面切换时,会记录当前页面位置,当加上 Header 就不行了。

当然了,也有可能是我的使用姿势问题。

最后

第一次写 Compose 项目,难免会有小问题,欢迎指正,感谢~

参考文章:

《从函数式编程到声明式UI》
《声明式 UI?Android 官方怒推的 Jetpack Compose 到底是什么》
官方文档

文章分类
Android