前言

去年曾经写过一篇文章调研
Compose
的性能:相比 XML , Compose 性能到底怎么样?

不过这篇文章主要是从包体积,页面首次打开时间来分析
Compose
的性能,而
Compose
作为一个
UI
框架,相信大家更关注它的渲染性能比如
FPS
,本文主要就是从
FPS
的角度来分析
Compose
的性能
本文主要包括以下内容:
  1. 如何测量ComposeFPS
  2. Compose列表渲染性能分析
  3. Compose粒子动画渲染性能分析

如何测量ComposeFPS

所谓FPS也就是每秒显示的帧数,Android 设备的 FPS 一般是 60,也即每秒要刷新 60 帧,所以留给每一帧的绘制时间最多只有 1000/60 = 16.67ms 。一旦某一帧的绘制时间超过了限制,就会发生 掉帧,用户在连续两帧会看到同样的画面。
监测
Android
应用的
FPS
,其实已经是相当成熟了,主要就是利用
Choreographer.getInstance().postFrameCallback()
方法,在这里就不缀述了。

那么,我们该怎么监听
Compose
FPS
呢?利用
Choreographer
监测仍然适用于
Compose
吗?

其实
Choreographer
依然可以用来监测
Compose
FPS
,不过
Compose
提供了更加方便的
API
供我们使用:
withFrameMillis
withFrameMillis
本质上是对
Choreographer
代码的封装,它会在下一帧到来时回调,并且会返回下一帧开始绘制的时间

下面我们来看下如何利用
withFrameMillis
来监测
Compose
FPS
@Composable
funFpsMonitor(modifier: Modifier)
 {

var
 fpsCount 
by
 remember { mutableStateOf(
0
) }

var
 fps 
by
 remember { mutableStateOf(
0
) }

var
 lastUpdate 
by
 remember { mutableStateOf(
0L
) }

    Text(

        text = 
"Fps: $fps"
, modifier = modifier

            .size(
60
.dp), color = Color.Red, style = MaterialTheme.typography.body1

    )


    LaunchedEffect(
Unit
) {

while
 (
true
) {

            withFrameMillis { ms ->

                fpsCount++

if
 (fpsCount == 
5
) {

                    fps = (
5000
 / (ms - lastUpdate)).toInt()

                    lastUpdate = ms

                    fpsCount = 
0
                }

            }

        }

    }

}

代码逻辑很简单:
  1. withFrameMillis会返回每一帧开始绘制的时间,两帧开始绘制时间的差值就是一帧绘制的时间
  2. 1000/(ms-lastUpdate)就是1秒内可以绘制的帧数,也就是FPS
  3. 为了避免帧数抖动过快,我们每5帧计算一次平均FPS,也就是fps = (5000 / (ms - lastUpdate)).toInt()

Compose列表渲染性能分析

关于Compose的列表的性能问题也是老生常谈了,很多人都说ComposeLazyColumn在低端手机上会卡顿,那么我们就来分析比较一下同一个页面用LazyColumnRecyclerView分别实现,在性能上有什么差距?
首先来看下页面的样式

如上,这个页面整体是一个列表,共有4种类型
  1. 可左右滑动的Banner
  2. 包含文字与一张图片的item
  3. 包含3张图片的复杂item
  4. 作为视频封面的大图item
然后我们用LazyColumnRecyclerView分别实现以上页面,然后在不同手机上分别测量其快速滑动时的FPS,结果如下:
Compose vs ViewAndroid 5.1Android 7.1Android 11
LazyColumn21 FPS43 FPS60 FPS
RecyclerView60 FPS60 FPS60 FPS
同时在
debug
包与
release
包都进行了以上测试,结果基本一致。可以看出,
LazyColumn
RecyclerView
在性能上的确有一定差距,尤其在低端手机上,
LazyColumn
快速滑动时掉帧明显,而
RecyclerView
则都很流畅

只能说
RecyclerView
太强了~

Compose粒子动画渲染性能分析

除了列表,我们也可以通过粒子动画的方式来测量Compose的性能,通过粒子动画我们可以评估在极端情况下ComposeView的渲染性能
首先来看下粒子动画效果:

如上,我们可以在画布上生成随机粒子并且做动画,随着粒子数量的增长,观察应用的FPS,以此评估Compose的渲染性能,我们同时也实现了一个View版本以进行对比,结果如下:
Compose VS View1001000300010000
Android 5.1 Compose60 FPS23 FPS8 FPS2 FPS
Android 5.1 View60 FPS25 FPS8 FPS2 FPS
Android 7.1 Compose60 FPS49 FPS21 FPS8 FPS
Android 7.1 View60 FPS52 FPS22 FPS8 FPS
Android 11 Compose60 FPS60 FPS60 FPS60 FPS
Android 11 View60 FPS60 FPS60 FPS60 FPS
可以看出,随着粒子数从
100
增长到
10000
,应用的
FPS
逐渐降低,在低端手机上尤其明显

而与列表不同的是,
Compose
View
在粒子动画中的渲染性能几乎一致,可以说是几乎没有区别

总结

本文主要从
FPS
的角度分析介绍了
Compose
的渲染性能,可以看出在画布中随机生成粒子动画时,
Compose
View
的渲染性能几乎一致。

而对于复杂列表,
LazyColumn
RecyclerView
在性能上有一定差距,在低端手机上尤其明显,在快速滑动时会有明显卡顿。

结合两个实验,看起来应该是
LazyColumn
组件存在一定性能问题,而
Compose
本身的渲染性能已经基本与
View
一致了~

项目地址

本文所有代码可见:https://github.com/shenzhen2017/compose-fps
继续阅读
阅读原文