美文网首页
记一次自定义View的优化

记一次自定义View的优化

作者: 勇敢地追 | 来源:发表于2021-02-01 15:13 被阅读0次

    项目中用到一个自定义View,功能类似于跑马灯。但是在低端机上有明显的卡顿,故拿出部分代码做优化。代码如下

        override fun onDraw(canvas: Canvas) {
            super.onDraw(canvas)
            if (!TextUtils.isEmpty(mText) && mValueAnimator?.isRunning == true && mStartY != -1) {
                val x = mWidth - (mWidth + mPaint.measureText(mText)) * mFraction
                val y = mStartY.toFloat()
                canvas.drawText(mText, x, y, mPaint)
            }
        }
    

    通过查看 Android Profiler,可以知道

    onDraw      total = 6.7     self = 2.3     children = 4.4
                        6.1            1.7                4.3
                        6.4            2.0                4.3
                        6.6            2                  4.6
    

    onDraw里面,很明显 self 里面的计算占了 2% 左右,其实可以优化. measureText 可以放到外面
    canvas.drawText 占了4.5%左右,这一部分也可以优化

        override fun onDraw(canvas: Canvas) {
            super.onDraw(canvas)
            if (mValueAnimator?.isRunning == true && mStartY != -1) {
                canvas.clipRect(0, mCLipTop, width, mCLipBottom)//限制在规定的区域内重绘
                val x = mWidth - (mWidth + mTxtWidth) * mFraction
                val y = mStartY.toFloat()
                canvas.drawText(mText, x, y, mPaint)
            }
        }
    

    如上修改以后, self 降到 1% 左右,.同时 children 也降到 3% 左右(可见 canvas.drawText 还是很占CPU的)
    从技术角度能做的优化其实已经差不多了,但是从需求的角度还是有优化的空间的
    这个自定义View的功能就是跑马灯,就是让文字随着时间走.那么就可以想到两种解决方案
    (1)画布移动 canvas.translate
    这个方案的问题就是 translate 之后还是要 drawText, 还是很占CPU
    (2)整体移动 View, 也就是在 TextView 的基础上修改, 用 scrollTo 来处理

    最终方案

        override fun onDraw(canvas: Canvas) {
            super.onDraw(canvas)
            if (mValueAnimator?.isRunning == true) {
                val x = mWidth - (mWidth + mTxtWidth) * mFraction
                scrollTo(-x.toInt(), 0)
            }
        }
    

    自定义View的优化最重要的就是一开始的时候选择相对好一点的实现方式,这样后期的优化工作可以少一些

    最初写这篇文章时2021.02.01。现在是06.02了,发现这种实现方式还是有问题。可能会引发主线程消息队列一直无法清空使得activity无法及时销毁。经过测试,发现可以使用SurfaceView来实现。
    简单说一下为什么可以吧。SurfaceView 是在当前窗口上再创建一个新窗口。它有独立的视图,同时刷新的时候不需要重绘应用程序的窗口,不会影响主线程,所以可以实现复杂而高效的UI。当然,也有一定的弊端。因为有自己独立的 Window,因此 SurfaceView 也不能放到 ListView 或者 ScrollView中,而且也无法做旋转等动画。为了解决“无法做旋转等动画”这个问题,还引入了TextureView。具体链接在下面
    Android 图形系统 -- SurfaceView 使用
    Android 图形系统 -- TextureView 使用

    相关文章

      网友评论

          本文标题:记一次自定义View的优化

          本文链接:https://www.haomeiwen.com/subject/cpgjtltx.html