2021年5月21日星期五

Jetpack Compose What and Why, 6个问题

Jetpack Compose 7月就要发正式版了! Android UI未来的新写法, 赶紧了解一下.早学一步, 早卷起来.

Jetpack Compose What and Why, 6个问题

1.这个技术出现的背景, 初衷, 要达到什么样的目标或是要解决什么样的问题.

Jetpack Compose是什么?
它是一个声明式的UI工具包(declarative UI toolkit for Android).

它的主要目的就是改变之前命令式地(imperatively)写UI的方法, 改成声明式(declarative)的.

命令式

Android之前的写法就叫命令式: view hierarchy是一个UI widgets构成的tree, 当app的状态改变时, UI需要更新. 通常的做法是通过findViewById()等手段找到要更新的节点, 通过setText(), addChild(), setImageBitmap()等方法更新控件的内部状态. 每个控件都有自己的内部状态, 并且暴露getter/setter, 允许程序逻辑和控件交互.

命令式为什么不好呢:

  • 这样手动地更新view会增加犯错的可能性. 如果某一数据在多个地方被渲染, 那么很可能就忘了更新其中的某个view.
  • 很容易创建非法状态, 比如两个更新以不期望的方式冲突了. (比如: 一个要更新值, 另一个要移除节点.)
  • 维护的复杂度随着需要更新的view个数而增加.

声明式

所以, 在过去的几年里, 业界一直在探索并且开始转向一种声明式的UI模型. 目的就是简化构建和更新UI.

Jetpack Compose是一个声明式的UI framework. 该技术的原理是从头开始重新生成整个屏幕, 然后仅应用必要的更改. 这种方法避免了手动更新stateful view的复杂度.

在Compose的声明式解决方案里, widgets相对来说是stateless的, 不暴露getter/setter.
实际上, widgets根本不是以对象的形式来暴露的.
当更新UI的时候, 实际上是传不同的参数调用了composable方法. 当数据改变时, composable负责把当前的应用状态转化为UI.

2.这个技术的优势和劣势分别是什么, 或者说, 这个技术的trade-off是什么.

Compose的优势:

  • 目前Google投入了大量的资源(学习资源, 社区挑战赛, IDE和编译器支持, 推出desktop版本等)来推广Compose, 我们有理由相信Google官方会继续发力, Compose会成为Android未来的UI标准开发形式.
  • Compose的声明式写法和Flutter, SwiftUI, React契合, 在支持多个平台的团队里, 有利于架构思想的统一.
  • 声明式UI, 写起来更快, 不容易出错.
  • 因为所有的代码都是Kotlin写的(真100%kotlin), 利用了Kotlin的强类型安全, 编译器会提示很多错误.
  • 修复和更新了一些旧的API: (Buggy Android Views: Picker, Spinner, EditText, 有一些edge cases. 因为要更改旧的总是很难, 不如创建一个新的. )
  • 基于组合的Composable, 比基于继承的View体系, 更加灵活, 易于复用. 比如可以通过组合来达到复用多个源, 不再受单继承限制.
    以Button为例, 在传统的UI里, 它是单继承体系下的一个类: Button -> TextView -> View.
    而在Compose的世界里, 它只是一个@Composable的方法, 里面包含了其他composable, surface, row等.
    举例: list->detail两个界面, 可以通过提取方法参数来达到两个界面的composable复用.
  • 支持和View-based UI系统的互相调用. 这样有两个优点: 有利于已有项目app的混用和逐步迁移; 当Compose满足不了需求的时候可以用传统View作为第二选择.
  • 和Jetpack系列的其他库都能完美结合. (ViewModel, Kotlin Flow, Coroutines, Paging, Hilt, Navigation...)

劣势:

  • 需要用Canary版本的Android Studio, 目前(2021.5)IDE还是存在一些问题的.
  • Gradle也要升级到最新版(7.0.0-alpha15), 不是很稳定, 还有一些问题.
  • 版本更新频繁. Compose alpha版本的一些API已经变了. -> 但是目前已经beta, 最新的Google I/0说7月就会有稳定版发布.
  • 相比Android View, 社区支持不够多. -> 但是Google已经投入了大量的资源来推广, 社区支持正在飞速增长.
  • 虽然Google封装了material的compose库, 但还是有一部分View控件没有办法提供, 比如WebView, MapView等.

3.这个技术使用的场景.

Jetpack Compose的使用场景是取代原来的Android View写法(Jetpack Compose用全新的方式来写UI, 即将成为Google Android标准写法.

注意这里的改变除了UI写法的改变, 还是一种状态管理思想的转变.
声明式, 单向数据流, 单个数据源.
Android内部的模式近年来一直追求的无外乎就是数据和View的分离, View的无知与自动更新, 清晰的逻辑管理和分离, 可测试性等等.

除了与View强相关的这一层(ViewModel)外, 其他的业务逻辑, 数据交互等被影响不大, 所以即便app决定逐渐迁移到Compose, 也只用管View绘制以及和View相邻的这一层.

4.技术的组成部分和关键点.

Jetpack compose的总体特点:

  • 声明式UI. f(state)=UI.
  • Built on Kotlin.
  • Unbundled: 不是和系统绑定的, 而是和Jetpack中的库一样, 版本独立, 可以自己更新维护版本, 也保证了多个系统上的行为一致.
  • Built for interop. 可以和已有View互相调用, 适用于现有项目的逐渐迁移.
  • 内置控件和theming, 支持material design.

Composable functions

Compose的使用方法:
定义一系列的composable functions: 接收数据, 发射UI元素.

@Composablefun Greeting(names: String) { Text("Hello $name")}

Composable方法的特点:

  • 所有的方法都必须有@Composable注解.
  • 方法参数是数据.
  • 通过调用其他composable方法来发射UI元素.
  • 方法不返回值, 因为它们在描述屏幕状态, 而不是构建UI widgets.
  • 方法要快, 具有幂等性(调用多少次结果都一样), 没有副作用. (fast, idempotent, and side-effect free.) 这就要求方法不会修改外部属性或者全局变量, 也没有Random的调用等.

还有一个小区别就是不同于普通的kotlin方法命名规范, composable方法名的首字母要大写, 因为它此时代表的是一种widget.

Recomposition

Compose framework会很机智地选出有变化, 需要重新绘制的部分.

在Compose中, 如果调用composable function, 传入了新数据, 会使得方法被recomposed: 这个方法发射的widgets会根据需要进行重新绘制.

因为重新绘制整个UI tree会花销比较大, 所以实际上composable function只有input改变的才会被重新绘制, 对于那些参数没有变化的方法和lambda, 其实是skip掉的, 这样才能提高recompose的效率.

所以, 永远不要依赖于执行composable function的side-effects, 因为recomposition有可能会被skip掉.

side-effects包括:

  • 更新共享对象.
  • 更新ViewModel中的observable.
  • 更新shared preferences.

由于composable functions有可能会被逐帧执行(比如动画期间), 所以它应该足够的快, 如果需要耗时的操作, 可以考虑后台的coroutine.

5.技术的底层原理和关键实现.

Compose的几个特点:

  • Composable functions可以以任何顺序执行.
  • Composable functions可以并行执行.
  • Recomposition会尽可能地skip多的composable functions. 如果真的需要side-effects, 考虑用callback.
  • Recomposition是乐观的, 它认为在本次重绘期间不会有新的状态改变, 如果有新的状态改变, 它可能会取消当前绘制, 以新的参数重新开始绘制.
  • Composable function有可能会被执行得很频繁(比如动画), 所以避免耗时操作.

关于Compose的底层原理, 目前还没找到一个官方的文档或者架构图.
因为可能大家都还在学习怎么使用, 这项技术的底层实现细节还没有被热烈讨论起来.
这里有个问题: https://stackoverflow.com/questions/58558163/how-does-jetpack-compose-work-under-the-hood

从使用者的角度揣测一下Compose的原理:
虽然Composable使用了注解@Composable, 但是却没有添加注解处理器(kapt), 所以并不是依靠注解在编译期生成代码.

在添加依赖的时候需要在build.gradle里添加:

 composeOptions {  kotlinCompilerExtensionVersion compose_version }

所以它和kotlin的编译器有关系.

这个视频: Understanding Compose (Android Dev Summit '19)在17:18开始讲实现原理.

@Composable更像是一个语言的关键字. 可以类比suspend, 有以下几个共同点:

  • 改变了方法的类型.
  • 强制了方法的调用上下文.

部分更新

用了定制化的Kotlin编译器插件, 数据改变时, 受数据影响的composable的方法会被重新调用.

6.已有的实现和它之间的对比.

Android View和Jetpack Compose的对比.

Android View和Jetpack Compose的相似点:

  • 都是Android UI的写法.

Jetpack Compose改进了View系统的哪些地方:

  • 不再需要担心深层嵌套. Compose UI不允许多遍的测量(multi-pass measurement), 改善了效率.

Flutter和Jetpack Compose的对比.

Jetpack Compose和Flutter的相似点:

  • 声明式UI, UI = f(state).
  • 都有web和desktop版本.
  • 官方都提供了一些material的控件和资源, 比如都有个Scaffold, 提供脚手架.
  • 都可以和原生混用, 虽然程度不一样, Compose的混用粒度更细一点.
  • 都可以一边改UI一边预览.

Jetpack Compose比Flutter好的地方:

  • 基于Kotlin, 相比于Flutter的dart来说, 对Android开发者更友好一些.
  • 接着上一点, 因为Compose只改了UI, 所以其他部分的代码库仍然是Android原生代码的逻辑, 趁手的第三方库比较多. 而Flutter, 就得利用其它package来做json解析, 数据库等等.
  • Flutter的stateful widget改状态必须要在setState里, 使用上不是很方便, 容易出错.
  • Jetpack Compose的Recomposition看上去更智能一些, 完全自动, 不像Flutter一样需要开发者自己设置一些flag来表明哪个部分不需要重绘.
  • 安装包体积应该有优势? 因为Flutter SDK包含了自己的图像引擎, 而Compose是没有native层面的东西的.

Flutter比Jetpack Compose好的地方:

  • Flutter还支持iOS.
  • Flutter相比Jetpack Compose稍微成熟一些(Flutter出来的早一些), 是经过一些app的实际上线验证的.
  • Flutter是有自己的图形引擎Skia的, 绘制会更有效率? (没有验证, 纯猜测)

Reference

  • Thinking in Compose
  • Using Jetpack libraries in Compose | Session -> 这个讲状态管理和其他Jetpack库结合的视频很棒.








原文转载:http://www.shaoqun.com/a/754785.html

跨境电商:https://www.ikjzd.com/

netporter:https://www.ikjzd.com/w/2132

出口易:https://www.ikjzd.com/w/1317


JetpackCompose7月就要发正式版了!AndroidUI未来的新写法,赶紧了解一下.早学一步,早卷起来.JetpackComposeWhatandWhy,6个问题1.这个技术出现的背景,初衷,要达到什么样的目标或是要解决什么样的问题.JetpackCompose是什么?它是一个声明式的UI工具包(declarativeUItoolkitforAndroid).它的主要目的就是改变之前命令
邮乐:https://www.ikjzd.com/w/1776
母婴团购网:https://www.ikjzd.com/w/716
blibli:https://www.ikjzd.com/w/1676
亚马逊全类目审核自助检测工具:https://www.ikjzd.com/tl/109403
亚马逊与Worldpay合作,推出新支付功能!:https://www.ikjzd.com/articles/19592
29岁剩女 我要如何初恋?:http://www.30bags.com/a/253733.html