场景:同进程下,出现同时运行的动效,特别是全屏大图,对GPU渲染造成巨大负担

明显看出,动效过程中,trace显示异常,两个draw出现,图片大小为3200x2000,都在同一个render跟ui thread下进行提交渲染,(由于图片比较大,而且不能压缩跟裁剪处理),处于串行工作造成掉帧
方案一
针对这种情况,首先尝试利用Glide中的set(Downsampler.ALLOW_HARDWARE_CONFIG, true)api来优化,看下效果

可以看到,trace中已经没有upload图片了,这个api的用处,是用来缓存图片数据到GPU存储中的,这里的缓存不是指内存
在图片绘制过程中,每次图片动效,比如全屏轮播,都会带来GPU的重新渲染,跟本地是否缓存图片没关系,普通位图会在应用内存和 GPU 显存中各存一份像素数据
每次绘制时从 CPU 内存,将图片数据打包好,然后上传到 GPU,GPU具体渲染,这样处理可以减少GPU的压力
但是也有限制,比如针对bitmap的 getPixel setPixel 将无法操作,对渲染绘制方面限制,高斯模糊,圆角等都会抛出异常,并且数量不能过多,每个进程都有一个FD上限(文件描述符),超过了1024会导致加载失败,而每个图片缓存都会消耗一个FD,所以需要谨慎使用
trace中看到,其实只是针对upload部分,但是buffer等操作不可避免,依然是在同线程处理,但也可以应付大部分场景了
当然,前提是在应用内,已经优化到极致,比如图片加载时使用override裁剪处理,图片对清晰度要求不高可以压缩处理等
方案二
多线程处理,将该部分绘制丢到子线程中操作

可以看到,渲染部分交给了单独线程中service去绘制,不过buffer部分依然实在主线程
通过上面验证,想要进一步优化,只能独立进程,才能彻底分离,否则只能在draw层次去优化
场景:动效卡顿掉帧

看出一帧内绘制了五张大图,导致GPU紧张
动效图片是自定义上下轮播View,初始化时add了五个imageview,因为一些可定制跳转需求,recyclerview等无法满足
优化:针对动效动态控制显示隐藏
override fun setTranslationX(translationX: Float) { super.setTranslationX(translationX) updateVisible() } override fun setTranslationY(translationY: Float) { super.setTranslationY(translationY) updateVisible() } override fun setAlpha(alpha: Float) { super.setAlpha(alpha) updateVisible() } override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { super.onLayout(changed, left, top, right, bottom) updateVisible() } private fun updateVisible() { visibility = if ( translationX >= measuredWidth || translationX <= -measuredWidth || translationY >= measuredHeight || translationY <= -measuredHeight || alpha == 0f ) { INVISIBLE } else { VISIBLE } }
动效过程中,一共只需要显示两张图片,动效结束后只需要显示一张图片,那么可以根据参数更新view状态,调整后在看新的trace

除了绘制,还需要关注measure

recyclerview中加载是否耗时

如果系统资源紧张,Runnable的时间会超过16ms,并且大量线程处于Runnable的状态,或者频繁触发GC

选中时间段,查看cpu占比率

浙公网安备 33010602011771号