原文地址: https://proandroiddev.com/compose-ui-beyond-the-ui-part-i-big-changes-bfe824ee8ed4
Jetpack Compose 是开发 Andorid UI 和应用的新工具。因为是以 UI 框架的形式问世的,已经有许多文章介绍它的内部原理和如何用来构建 UI。
但是构建一个应用不仅仅是 UI,在其他方面 Compose 也带来了改变。这个系列文章,我会关注一些未来构建 App 时可能会发生的变化。
我认为,它有许多优势,除此之外还会因为其他因素被广泛使用。有必要讨论它会如何改变我们的开发,找到适合我们需求的方式。
注意:本文提到的 Compose 都是指 Compose UI,而 Compose 并不是只有 UI 呦!
如今的 Android 开发有什么问题?
Android 有些方面很复杂。一部分是因为 bug,另外是缺少经验的开发者(甚至有些老 Android 开发也)常常遇到问题。
Fragment 和 Activity 的生命周期
生命周期是 Android 开发最复杂的点之一:是导致许多错误的根源,对开发者来说很难理解。
尤其是 Fragment,可以看这里,内部有两个生命周期,一个是 view,一个是 Fragment 自己。
还有复杂的返回栈。比如,你在 fragment 存活时监听了一个数据,想去更新 UI 时,却发现 view 已经销毁了;又或者新的 view 已经创建,而你持有了一个已经被销毁 view 的引用,导致内存泄漏。
随着文档改善,建议的增加,和 Lifecycle 相关组件的引入,处理生命周期相对来说有所改善。但它仍是一个问题源。
Configuration changes 回调
Android 生命周期开发非常复杂的另一个原因就是 configuration changes。谷歌建议我们让系统处理 configuration change,大部分应用都遵守了(UPD:这个建议是给老的 view 系统的,compose 不再需要)。举例来说,让系统处理 configuration change 的一个场景就是转屏,系统重新创建 activity(和 fragment 和 view)。有许多影响:整在执行的操作会被暂停,内存中的数据会重置。除此之外,状态和任务也会丢失,用户要等待。
解决这个问题有几种方案:首先忽略官方的建议,自己处理 configuration change。Activity 和 Fragment 没有被重建,转屏会快一点,但是我们要手动重载资源,更新 UI。
另一个方案就是让这些类被引用,也就是不被销毁。以前是用一个 headless 的 fragment,现在通常用 ViewModel 实现。ViewModel 与 MVVM 无关,只是一个可以在 fragment 和 activity 生命周期 recreate 后,不被销毁的类。
使用 ViewModel 也不简单,首先要由系统实例化,如果我们想给 ViewModel 的构造方法加个参数(几本是必然要加),就要提供工厂方法。并且 ViewModel 不能方便的访问绑定到 Fragment 或是 Activity 的对象,有一个更短的生命周期: resource,local 和 fragment 自己…想要访问这些对象,需要更复杂的逻辑避免内存泄漏。
Theming and material components
Android 的主题和 material components 就是难用。使用组件支持的功能很方便,一旦你稍微想对组件做一些定制,准备好个把钟头吧。
Compose 做了什么改变?
虽然 Compose UI 只是个 UI 工具,它的工作原理在 UI 之外改变我们应用的架构。可以让我们更好的处理前面的问题,改善 Android 开发体验。
和 Fragment 说再见,你不会想它的。
首先,Compose 不需要 Fragment。迁移现有 App 的过程中,使用 Fragment 包一层 Compose 或许情有可原;全新的项目里,就忘掉 Fragment 吧。
Compsoe 可以让我们访问 Context 和 Android framework, composable 函数可以承载 UI,大到整块屏幕,或是用来做到 navigation frameworks。所以,没有理由在一个 100% Compose 应用里使用 Fragment:何况它们没有提供任何价值还要处理生命周期。
终结 Configuration changes 带来的破坏
关于如何去做,我们会在后面的文章介绍,使用 Compose 比传统 view 的方式容易很多。不必担心 view 生命周期超出控制器(ViewModel,Presenter 等),或是任务被暂停(有些任务例外,不过那是另外一个话题了)。
可以避免重建重量级组件比如 Activity ,对 view 有了更多的控制权,创造更快的用户体验。
不需要 ViewModel
自己处理 Configuration changes 随之而来的就是不再需要 ViewModel 了, ViewModel 是为了在 recreate 期间持有数据和任务。
我们创建自己的 controller,不需要继承 ViewModel,更轻量,不需要 factory 而且是平台无关的。当然,其实也没有特别简单,后面文章会介绍。
给人类使用的 Theming 和 material components
在 Compose 自定义 widget 相较于之前的方式更简单,更容易。
不止于此!我们可以看到所有 material component 的实现,观察它如何工作,使用了什么主题,接收什么参数。总之主题和 material components 会更好用,
从代码就可以方便看出支持什么,添加不支持的功能。(译者注:作者这里就给 Compose 一顿夸,没有解释为什么。我想到一个点是 Compose 所有的参数都可以在函数上方便的看到,而不像之前 xml,支持哪些属性,和对应的行为完全靠猜)。
Compose 带来的其他变化
Databinding 棺材板上的最后一颗钉子
当前的趋势就是,架构越来越响应式,而响应式编程关键一步就是如何将数据绑定到 UI。没有问题不代表不能改善。
使用 databinding 插件可以少写很多模板代码,但是会影响编译速度,编译失败时的问题又很难排查 debug。
Compose 就没有这些问题,数据和 UI 自动绑定,框架帮我们做了,谢天谢地。
还有 LiveData,帮我们持有 UI 关心的数据,处理生命周期很有用。虽然在 kotlin 使用上有点小问题,即使声明为非空类型,也会有 null 传过来。
Databinding 插件只能配合 LiveData 使用,用了 DataBinding 就不能用 flow 替换 LiveData(UPD: Android Studio ArticFox 之后 databinding 支持 StateFlow)。
Compose 没有这个问题,用了 Flow,除了解决 null 问题之外,还有更多的操作符可供使用,很能将较重的任务放在其他线程执行(没错,就像 RxJava 那样)。
Welcome multiplatform
终于讲到 multiplatform 了。Kotlin multiplatform 推动进展显著,会改变整个行业。Compose 支持跨平台:Jetbrains 搞了 Compose for Desktop!(UPD: 还有 web!)
一份代码,跨平台想想都美(在做梦)。
结论
用 Compose 明天会更好。不久的将来,没有 Fragment,没有 ViewModel,view 和 controller 和 lifecycle 一一映射,开发体验会更愉快。需要学习很多新的内容。
(后悔了,我翻译了个广告,没啥有意思的东西…立个 flag,下家公司不用 Compose 不去)。