Jetpack Compose 还是传统 View?一个安卓老兵的真实体验和迁移建议

🔑 关键词:Jetpack Compose,传统View,安卓开发,迁移对比,性能

📖 摘要:结合两年实际项目经验,从冷启动耗时、滑动帧率、代码量、生态兼容等角度对比Compose与View,给出不吹不黑的独立观点。

说实话,我一开始是拒绝用Compose的。2022年底公司启动新项目,Kotlin官方一直在推,加上技术leader说未来趋势,我只好单独拿一个商品列表模块试水。前两周那叫一个别扭,XML布局是一棵静态的树,Compose虽然也是一棵树,但它由状态驱动,每次刷新都像重新画一遍。我那会儿老想着findViewById,脑子里全是旧的View模型,写出来的Compose代码也一股View味。后来慢慢才适应,但这个过程远比文档里说的“三小时上手”要漫长得多。

图片

先聊聊性能,因为这是很多人忽略的坑。我用同一个商品列表页面做过对照测试,Redmi K40上,RecyclerView + ViewBinding冷启动到首帧大约420ms,Compose + LazyColumn大约500ms,多了80ms。滑动起来差距更明显,快速滚动时Compose的掉帧次数大概是View的两倍,尤其item里带了圆角图片和阴影的时候。后来我用ImageLoading的异步加载、在LazyColumn里加key、把阴影改成drawWithCache,掉帧才稍微好点。但每次优化都得多想一层,而View那边不需要管这些。所以你看网上说Compose性能好,那基本是指它重绘的粒度,实际机器上没感受到优势。

图片

但开发效率上,Compose确实是香的。以前写个item列表,要layout XML、ViewHolder、Adapter、点击回调、数据绑定,一套下来少说200行。现在一个@Composable函数搞定,我们那个简单列表页,原来Java写了300多行,换Kotlin Compose只有150多行,而且逻辑都在一块,不用来回跳文件。不过别高兴太早,Compose的坑也很隐蔽。remember和mutableStateOf的用法稍微理解不到位,UI就不刷新,或者莫名其妙重绘。我同事就在一个@Composable里直接传了一个普通普通Bean对象,改完数据UI死活不动,排查半天发现没转成State。这种问题在View时代根本不会发生,因为setText总是能调的。

图片

再说生态适配,如今主流三方库都支持Compose了,但老项目里那些东西还是让你头疼。我们项目用的百度地图SDK,它完全基于View,在Compose里只能拿AndroidView包一层。为了不让地图在重组时重绘,还得用mutableStateOf控制更新,搞得很别扭。还有WebView,也是包了一层。最崩溃的是复用旧的自定义View,比如之前花了两周写的那个图表控件,在Compose里要通过AndroidView塞进去,可它内部的触摸事件和绘制逻辑跟Compose的手势系统又不完全兼容,有时候滑动起来互相抢事件。这种问题没遇到的时候真想不到。

图片

还有一个容易被忽略的是构建效率。我的项目全量编译从35秒左右涨到55秒,多了20秒。Debug包体积从18MB涨到22MB。增量编译虽然影响不大,但每天全量构建的时候还是很烦躁。所以我的建议是:全新项目、团队本来就会Kotlin、没有复杂自定义View,那直接用Compose没问题,作为未来方向很合理。但老项目里有大量自定义View和地图、WebView这种,你就别强行迁移了,成本远大于收益。我现在就是新模块用Compose,老模块继续View,两头跑虽然有点精神分裂,但至少不会因为迁一个模块而失眠了。

图片

🏷️ 标签: