Android性能优化:UI卡顿帧率检测&优化

Posted Dusan_杜小菜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android性能优化:UI卡顿帧率检测&优化相关的知识,希望对你有一定的参考价值。

前言

本文主要分享:handler耗时检测、帧率、丢帧统计的方法。

统计方法与实现

我们知道,Handler有个成员变量mLooper,它通过loop()方法取出需要执行的Message,message非空时,会根据是否有printer来打印开始、结束的log,我们可以自定义一个Printer,根据回调统计耗时。

具体实现:

class HandlerLogger : Printer 
        companion object 
            private const val START = ">>>>> Dispatching to"
            private const val END = "<<<<< Finished to"
        

        //打印log,可以统计时长,超过xxxms认为卡顿
        private var start = 0L

        override fun println(x: String?) 
            val isStartHandle = x?.startsWith(START) == true
            if (isStartHandle) 
                //开始计时
                LogMonitor.instance.startMonitor()
                start = System.currentTimeMillis()
            
            if (x?.startsWith(END) == true) 
                //结束计时,并计算出方法执行时间
                LogMonitor.instance.removeMonitor()
                val end = System.currentTimeMillis()
                val diff = end - start
                if (diff > 100 && start > 0) 
                    Log.e(TAG, "dq-handle忙死了,Please check your task,time=$diff" + "ms")
                
            
        
    

帧率统计

系统每一帧的绘制都有回调,我们也是可以注册监听。通过Choreographer来统计帧率:

@JvmStatic
    fun frameMonitor() //帧率检测
        mFpsCount = 0
        mLastFrameTime = 0
        mLastFrameTimeNanos = 0
        mFrameTimeNanos = 0
        Choreographer.getInstance().postFrameCallback(object : FrameCallback 
            override fun doFrame(frameTimeNanos: Long) 
                val diff = (frameTimeNanos - mLastFrameTimeNanos) / 1_000_000
                if (diff > frameCountPerSecond && mLastFrameTimeNanos > 0) 
                    val droppedFrames = (diff / frameCountPerSecond).roundToInt()
                    if (droppedFrames > 3) 
                        Log.d(TAG, "dq-丢帧 droppedFrames=$droppedFrames")
                    
                
                mLastFrameTimeNanos = frameTimeNanos
                mFpsCount++
                mFrameTimeNanos = frameTimeNanos
                Choreographer.getInstance().postFrameCallback(this)
            
        )

        Rx2Utils.backgroundTaskDelayed(runnable, 1000)
    

打印耗时堆栈

handler任务开始(>>>>> Dispatching to)时,设置定时器,如果handle处理耗时超过100ms,打印主线程的堆栈。

/**
         * 自定义超时的阈值,如果handle处理耗时超过100ms,打印堆栈
         */
        private const val TIME_BLOCK = 100L
        private val mLogRunnable = Runnable 
            //打印出执行的耗时方法的栈消息
            val sb = StringBuilder()
            val stackTrace = Looper.getMainLooper().thread.stackTrace
            for (s in stackTrace) 
                sb.append(s.toString())
                sb.append("\\n")
            
            Log.e(TAG, "dq-main-ui stackTrace=$sb")
        

Janky Frames

官方衡量Janky frames的标准:一帧的时间超过16.67ms。可以通过adb命令获取当前的丢帧信息。

adb shell dumpsys gfxinfo your_package_name framestats

Matrix检测

使用Matrix框架,可以统计并打印每个方法的耗时,有对主要耗时的方法降序打印堆栈信息。

系统UI工具

开发者模式里面打开帧率统计工具(具体看手机,有些是性能监视器,显示FPS信息)

profile工具

as自带的profile工具,可以看方法耗时

Thanks

Welcome to contact me: duqian2010@gmail.com or Wechat:dusan2010

以上是关于Android性能优化:UI卡顿帧率检测&优化的主要内容,如果未能解决你的问题,请参考以下文章

Android性能优化:UI卡顿帧率检测&优化

iOS性能优化-UI卡顿检测

iOS性能优化-UI卡顿检测

android UI卡顿问题学习

Android UI性能优化原理

Android卡顿优化思路