背景
一些问题
-
命令式UI痛点一
在android发展的长河中,android的视图层次结构一直是一种多叉树的结构,创建过程是一种命令方式呈现应用界面。其中xml布局的读取解析,不仅会造成io性能消耗和反射创建标签对于的view造成的性能消耗。不仅如此,这种命令形式下,会提高视图出错的可能性,体现在多视图更新上,会有遗漏操作或者更新命令冲突的情况。
-
MVVM+Databinding
当然,在使用MVVM+Databinding架构下能帮忙自动执行布局和数据绑定和更新,达成一致性。但是MVVM+Databinding架构的局限性也存在,一是通过AOP注解会大大增加编译时间、二是发生问题不好定位、三是不适合多变业务和协同开发。
-
命令式UI痛点二
除去命令形式下出错率高,还有一个难题:视图变化导致部分视图树或者整颗的重新绘制。例如,某项更新造成一个view组件从视图树中移除,就会造成视图树的重新绘制,成本昂贵啊。 -
flutter的出现
后来,Google推出了flutter语言,新一代跨平台UI组件的诞生。全新的声明式编程的组件,同时也是响应式框架的体现(声明式UI式让开发人员描述当前的UI状态,并将转移给框架执行)。同时,也能解决上面几个问题:io和反射的性能消耗、视图与数据的绑定、视图变化导致重绘的开销。(理解flutter的三颗树原理和组件的颗粒度 来看上面的难题是否解决)flutter的确是一个可行方案,我们的项目也是渐进方式引入Flutter,选了几个小组件来编写。目前局限性只是在社区不成熟(这个后面会好起来的)、混合开发脱离不了原生。混合开发的疼的是,对于大型项目已经有很多成熟的通用组件,导致flutter组件调用时,会有大量的通道代码和交互代码,还有就是一些原生的基础能力支持。目前还是将flutter当作一个UI组件使用了,高性能、高流畅度还是挺香的。
-
Compose的出现
现在,google有开发一个新能力,Jetpack Compose,是一个适用于 Android 的新式声明性界面工具包。Compose 提供声明性 API,让你可在不以命令方式改变前端视图的情况下呈现应用界面,从而使编写和维护应用界面变得更加容易。此术语需要一些解释说明,它的含义对应用设计非常重要。其实他跟flutter很像,其次kotlin和dart也有点类似。当然,它也解决上面那命令式的几个痛点问题,但是它没有flutter的性能好(flutter部分性能优势是来自架构层面的)。上面说的flutter的痛点问题,混合开发不够友好。其实flutter和Compose不在一个竞争纬度上,但是我个人理解的是,Compose能解决一些UI组件的问题,跟flutter一样,虽然性能不及flutter,但是本身就是原生代码,就不存在混合开发的难点了。
其他优势,可以先看下声明性范式转变理解重组这个概念
需求
我们的需求很简单,提升页面的绘制速度和解决布局变化的重绘问题。
测试
首先我的测量工具是用addOnFrameMetricsAvailableListener
方法实现的:可能不精准。测试环境:小米5手机。
window?.addOnFrameMetricsAvailableListener(Window.OnFrameMetricsAvailableListener {
window, frameMetrics, dropCountSinceLastInvocation ->
Log.v("test","measure + layout=${frameMetrics.getMetric(FrameMetrics.LAYOUT_MEASURE_DURATION)/1000000}, " +
" delay=${frameMetrics.getMetric(FrameMetrics.UNKNOWN_DELAY_DURATION)/1000000}, " +
" anim=${frameMetrics.getMetric(FrameMetrics.ANIMATION_DURATION)/1000000}," +
" touch=${frameMetrics.getMetric(FrameMetrics.INPUT_HANDLING_DURATION)/1000000}, " +
" draw=${frameMetrics.getMetric(FrameMetrics.DRAW_DURATION)/1000000}, " +
" total=${frameMetrics.getMetric(FrameMetrics.LAYOUT_MEASURE_DURATION)/1000000}")
}, Handler())
然后第二种测量方式是adb测量:adb shell am start -W packagename/packagename.MainActivity
第三种测量方式,最正常的打点:onCreate和onResume 时差
文本测试
先测试单组件的测试:
原生
代码如下:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:padding="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="现在,google有开发一个新能力,Jetpack Compose,是一个适用于 Android 的新式声明性界面工具包。*Compose 提供声明性 API,让你可在不以命令方式改变前端视图的情况下呈现应用界面,从而使编写和维护应用界面变得更加容易。此术语需要一些解释说明,它的含义对应用设计非常重要。*其实他跟flutter很像,其次kotlin和dart也有点类似。当然,它也解决上面那命令式的几个痛点问题,但是它没有flutter的性能好(flutter部分性能优势是来自架构层面的)。上面说的flutter的痛点问题,混合开发不够友好。其实flutter和Compose不在一个竞争纬度上,但是我个人理解的是,Compose能解决一些UI组件的问题,跟flutter一样,虽然性能不及flutter,但是本身就是原生代码,就不存在混合开发的难点了。"
android:textColor="#000"
android:textSize="20dp" />
多次测试原生的单组件下:
- addOnFrameMetricsAvailableListener 测量下measure + layout=0, delay=2, anim=0, touch=0, draw=5, total=0
- adb测试下:ThisTime: 470 TotalTime: 849 WaitTime: 876
- 打点测试下:执行间隔为:25ms
Compose
测试代码如下:
@Composable
fun Greeting(name: String) {
Text("现在,google有开发一个新能力,Jetpack Compose,是一个适用于 Android 的新式声明性界面工具包。*Compose 提供声明性 API,让你可在不以命令方式改变前端视图的情况下呈现应用界面,从而使编写和维护应用界面变得更加容易。此术语需要一些解释说明,它的含义对应用设计非常重要。* \n" +
"\n" +
"\t其实他跟flutter很像,其次kotlin和dart也有点类似。当然,它也解决上面那命令式的几个痛点问题,但是它没有flutter的性能好(flutter部分性能优势是来自架构层面的)。上面说的flutter的痛点问题,混合开发不够友好。其实flutter和Compose不在一个