• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

技术漫谈之Jectpack-Compose

android 搞代码 3年前 (2022-04-09) 57次浏览 已收录 0个评论
文章目录[隐藏]

最近Jetpack Compose公布了Beta版本,抽时间理解了一下Compose带来的扭转和其中的一些原理。本文不会解说具体API,只是比拟随便的分享本人的一些疑难以及在探寻答案过程中的一些播种。

为什么要有Compose?

Android曾经十年多了,传统的Android UI ToolKit有很多历史遗留问题,而有些官网也很难批改。比方View.java有三万多行代码,比方Combo box居然叫Spinner,再比方Button继承自Textview。同时官网的一些widget修复依赖系统升级,达到用户周期过长。

通过在Jetpack中增加Compose,脱离了Android零碎,代码修复能够更快地达到用户。

而对国内开发者来说,更对立的代码,意味着没有厂商定制。这几天有位敌人和我埋怨『哪个大佬有工夫重写个editText吗,厂商/零碎的一堆问题』,我想他可能要梦想成真了。

同时,Compose通过引入申明式编程,依赖Kotlin个性,能够让代码编写更快更简略。

设想写一个搜寻通讯录的界面,传统的Android开发写这个界面须要多少代码?activity一个xml,item一个xml,封装一个recyclerview,再写一个Adapter,写了这么多,可能还费劲不讨好,xml转成view的过程中,IO和反射影响了性能,界面再简单一些,走异步layout还是x2c?而在compose中,可能只须要上面这段简短的代码,并且没有xml的性能问题。

如上图,在Compose中,一直的办法调办法,就实现了UI的组装。

什么是申明式编程?

提到Compose,就不得不理解什么是申明式编程。

咱们来看一下维基百科的解释,申明式编程是一种编程范式,表白逻辑但不形容具体管制流程。就是通知计算机我想要什么,而不是通知它怎么做。那对应到Android就是我想要一个什么样的UI,而不是这个UI应该如何扭转,当然UI的主动扭转须要框架的反对。

申明式编程在React、Flutter等框架中曾经有宽泛的利用,申明状态,状态变动,UI主动重绘。

有意思的是,Compose的发起人Jim Sproch之前是React的外围开发人员,他在Slack上聊到VDOM的一些问题,比方vdom分配内存空间在简单我的项目中成为性能瓶颈,compose采纳调用composable办法的形式,缩小内存调配。相比vdom,compose把node暗藏在背地以防滥用,同时能够更不便的应用if/for管制流程。

@Composable是什么原理?

下面这个简略的例子,当点击button,button中的文字主动加1,remember用来记录最新的count值。

@Composable是个注解,而要实现自动更新UI,必定是批改了Class文件,让咱们看看class文件变成了什么样?Kotlin编译后的class在build/tmp/kotlin-classes目录中,但在Android Studio中是无奈看到class反编译后的内容,能够用Jadx。而后Text()这些Composable办法编译成class后也有改变,为了不便浏览,最好是编译好APK后,再用Jadx浏览反编译源码。

下面就是编译后的CountInner办法,能够看到,办法参数都被扭转了,办法块中增加了很多start/end,调用Text()的Lambda变成了ComposableLamda,改变还是比拟多的。

这些改变是怎么实现的呢?如果我没记错的话,Kotlin的协程也做了有些扭转办法参数的操作,两个是不是差不多的实现?但协程是kotlin个性,应用层动静批改class文件,难道是在Gradle Transform里用ASM去操纵class的?

一番搜寻,发现Compose利用了Kotlin compiler的新个性,通过IR extension,能够在两头代码生成期间批改逻辑。IR又是什么?intermediate representation的缩写,翻译为两头语言。Kotlin为了Compose凋谢了扩大能力,并且对立了JVM/JS/Native的IR流水线,为跨平台提供反对。能够了解为Kotlin对协程做的那些事件,通过应用IR extension,你在应用层也能够去做了。

Talk is cheap, I will show you the code.

Compose Compiler的源码。ComposePlugin.kt中注册了ComposeIrGenerationextension。ComposeIrGenerationExtension中又有ComposableFunctionBodyTransformer实现下面形容的办法中增加start/end,ComposerLambdaMemoization实现下面形容的扭转成ComposerLambda。具体逻辑能够看源码,正文形容的比较清楚。

重组是怎么实现的?

看Compose的文档,始终有重组(Recomposition)这个词,就是状态变动的时候,自动更新UI。那重组是怎么实现的呢?

每次调用count.getValue()的时候,最终会回调到Composer,Composer中维持着一个Map,这时就把state和以后的scope进行了关联,scope能够了解为一段能够重组的范畴。那以后的scope哪里来呢?还记得编译的class里多了很多start和end吗,在调用start办法的时候,会生成一个scope,放在栈顶。所以调用count.getValue()的时候,间接拿栈顶scope就能够了。当调用end的时候,会调用updateScope更新scope的block属性,而这个block是一个lambda,执行这个lambda会调用对应的composable办法重绘,这样state和block就关联起来了,前面state变动的时候,拿到block执行就能够了。在这个例子中,count state对应的block是一个调用Button办法的lambda。

再来看下更新state的流程。每次调用count.SetValue()的时候,最终会调到Composer中的recordModificationsOf办法,而后从上段说的Map中获取state对应的scope, 并把它增加到invalidations中,通过编舞者监听,下次vsync时,会调用invalidations中lambda的invoke办法,从而更新UI。

请留神,『在调用start办法的时候,会生成一个scope』,但其实只有第一次增加的时候生成就够了,前面更新UI的时候间接用旧的就能够了,太多相似的货色须要存储,Compose中有一个十分重要的数据结构叫插槽表SlotTable,刚说的这个scope复用以及例子中的remember都是利用了SlotTable,具体能够看深刻详解 Jetpack Compose | 实现原理。

Text对应的是TextView吗?

Text对应的是TextView吗?不是的。

debug看了一下,所有的composable UI最初被包在一个AndroidComposeView中,放在ContentView上面,所以最上层的货色是没有变动的。传统的Android UI中的view树,变成了node树,view的那些性能被node代替了。

和旧有体系兼容,能够间接把AndroidComposeView增加在xml中,这样就能够混用了。

自定义Layout怎么写?

简略的看了一下,measure/layout走的是measurePolicy,在一个办法中去写measure和layout。measure中有个Constraints最大最小限度,相似MeasureSpec那一套,match\_parent变成了Modifier.fillMaxWidth(),这个Modifier会在measure之前批改Constraints,measure的时候会把批改后的Constraints传递进去。

draw是通过Modifier实现的,还是走canvas那一套。

Touch事件怎么解决?

自认为对Android的touch事件还算比拟理解,之前在看Android源码的时候也发现了一些有意思的中央,比方down事件在native底层解决,不是作为message在java层looper解决,所以setMessageLogging的形式检测不到down里的耗时。那编舞者不是散发Input/animation/layout的callback吗?那个次要是用来解决move事件。你认为move事件里只有一个坐标点吗,看看MotionEvent.getHistorySize办法吧,那这个size和屏幕采样率以及触控采样率又是什么关系呢?

言归正传,看到Compose的呈现,必定也好奇对Touch事件处理形式的扭转。

dispatchTouchEvent/onInterceptTouchEvent/onTouchEvent这些办法不见了,拦挡事件须要实现PointerInputFilter,次要逻辑写在onPointerEvent办法,这个办法甚至连boolean都没返回,那怎么判断是否生产了呢?传递进来包装好的event中有个是否生产的属性,每个filter本人判断是否有未生产的事件,去批改曾经生产。感觉这一块还有优化空间,如同没有生产之前的事件,后续事件还会回调到。

当初定义了Initial、Main、Final三个阶段,在你关怀的阶段中去解决,前两个阶段和以前差不多,Final阶段相似用来解决之前的cancel事件。

结尾

Compose还在继续优化中,比方composable函数最近要反对并发执行了。

两年磨一剑,谷歌推广Compose的信心是毋庸置疑的。Compose为了不便开发者,也是思考到了很多事实的货色,比方像kotlin反对和java互调一样,反对Compose和传统UI互调。尽管投入微小,确实更快更简略,但在社区中的遍及还有待工夫验证,毕竟Jetpack中的库很多大家都还没有用过,而Compose的征程也注定要比Kotlin艰巨。

工夫无限,本文只能夸夸其谈、管中窥豹、抛砖引玉了,如有舛误,还望不吝赐教。


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:技术漫谈之Jectpack-Compose

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址