Android性能:通过Choreographer检测UI丢帧和卡顿

简介:                                          Android性能:通过Choreographer检测UI丢帧和卡顿Android系统每隔16ms重绘UI界面,16ms是因为Android系统规定UI绘图的刷新频率60FPS。

                                         Android性能:通过Choreographer检测UI丢帧和卡顿

Android系统每隔16ms重绘UI界面,16ms是因为Android系统规定UI绘图的刷新频率60FPS。Android系统每隔16ms,发送一个系统级别信号VSYNC唤起重绘操作。1秒内绘制UI界面60次。每16ms为一个UI界面绘制周期。
平常所说的“丢帧”情况,并不是真的把绘图的帧给“丢失”了,也而是UI绘图的操作没有和系统16ms的绘图更新频率步调一致,开发者代码在绘图中绘制操作太多,导致操作的时间超过16ms,在Android系统需要在16ms时需要重绘的时刻由于UI线程被阻塞而绘制失败。如果丢的帧数量是一两帧,用户在视觉上没有明显感觉,但是如果超过3帧,用户就有视觉上的感知。丢帧数如果再持续增多,在视觉上就是所谓的“卡顿”。
丢帧是引起卡顿的重要原因。在Android中可以通过Choreographer检测Android系统的丢帧情况,以作为进一步分析卡顿的基础:

package zhangphil.test;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Choreographer;
import android.view.View;

public class ANRActivity extends AppCompatActivity {

    private MyFrameCallback mFrameCallback = new MyFrameCallback();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Choreographer.getInstance().postFrameCallback(mFrameCallback);

        setContentView(R.layout.activity_anr);
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                uiLongTimeWork();
            }
        });
    }

    public class MyFrameCallback implements Choreographer.FrameCallback {
        private String TAG = "性能检测";
        private long lastTime = 0;

        @Override
        public void doFrame(long frameTimeNanos) {
            if (lastTime == 0) {
                //代码第一次初始化。不做检测统计。
                lastTime = frameTimeNanos;
            } else {
                long times = (frameTimeNanos - lastTime) / 1000000;
                int frames = (int) (times / 16);

                if (times > 16) {
                    Log.w(TAG, "UI线程超时(超过16ms):" + times + "ms" + " , 丢帧:" + frames);
                }

                lastTime = frameTimeNanos;
            }

            Choreographer.getInstance().postFrameCallback(mFrameCallback);
        }
    }

    private void uiLongTimeWork() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

Choreographer周期性的在UI重绘时候触发,在代码中记录上一次和下一次绘制的时间间隔,如果超过16ms,就意味着一次UI线程重绘的“丢帧”。丢帧的数量为间隔时间除以16,如果超过3,就开始有卡顿的感知。

代码运行输出:

07-20 11:23:40.082 5654-5654/zhangphil.test W/性能检测: UI线程超时(超过16ms):17ms , 丢帧:1
07-20 11:23:40.099 5654-5654/zhangphil.test W/性能检测: UI线程超时(超过16ms):17ms , 丢帧:1
07-20 11:23:40.145 5654-5654/zhangphil.test W/性能检测: UI线程超时(超过16ms):28ms , 丢帧:1
07-20 11:23:40.165 5654-5654/zhangphil.test W/性能检测: UI线程超时(超过16ms):20ms , 丢帧:1
07-20 11:23:40.190 5654-5654/zhangphil.test W/性能检测: UI线程超时(超过16ms):24ms , 丢帧:1
07-20 11:23:40.208 5654-5654/zhangphil.test W/性能检测: UI线程超时(超过16ms):17ms , 丢帧:1
07-20 11:23:40.224 5654-5654/zhangphil.test W/性能检测: UI线程超时(超过16ms):17ms , 丢帧:1
07-20 11:23:40.257 5654-5654/zhangphil.test W/性能检测: UI线程超时(超过16ms):33ms , 丢帧:2
07-20 11:23:40.306 5654-5654/zhangphil.test W/性能检测: UI线程超时(超过16ms):24ms , 丢帧:1

 

如果手动点击按钮故意阻塞1秒,丢弃的帧数更多。

相关文章
|
3天前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
3月前
|
移动开发 监控 前端开发
构建高效Android应用:从优化布局到提升性能
【7月更文挑战第60天】在移动开发领域,一个流畅且响应迅速的应用程序是用户留存的关键。针对Android平台,开发者面临的挑战包括多样化的设备兼容性和性能优化。本文将深入探讨如何通过改进布局设计、内存管理和多线程处理来构建高效的Android应用。我们将剖析布局优化的细节,并讨论最新的Android性能提升策略,以帮助开发者创建更快速、更流畅的用户体验。
65 10
|
12天前
|
算法 JavaScript Android开发
|
1月前
|
设计模式 Java Android开发
安卓应用开发中的内存泄漏检测与修复
【9月更文挑战第30天】在安卓应用开发过程中,内存泄漏是一个常见而又棘手的问题。它不仅会导致应用运行缓慢,还可能引发应用崩溃,严重影响用户体验。本文将深入探讨如何检测和修复内存泄漏,以提升应用性能和稳定性。我们将通过一个具体的代码示例,展示如何使用Android Studio的Memory Profiler工具来定位内存泄漏,并介绍几种常见的内存泄漏场景及其解决方案。无论你是初学者还是有经验的开发者,这篇文章都将为你提供实用的技巧和方法,帮助你打造更优质的安卓应用。
|
2月前
|
Android开发 开发者 索引
Android实战经验之如何使用DiffUtil提升RecyclerView的刷新性能
本文介绍如何使用 `DiffUtil` 实现 `RecyclerView` 数据集的高效更新,避免不必要的全局刷新,尤其适用于处理大量数据场景。通过定义 `DiffUtil.Callback`、计算差异并应用到适配器,可以显著提升性能。同时,文章还列举了常见错误及原因,帮助开发者避免陷阱。
173 9
|
2月前
|
XML Android开发 UED
💥Android UI设计新风尚!掌握Material Design精髓,让你的界面颜值爆表!🎨
随着移动应用市场的蓬勃发展,用户对界面设计的要求日益提高。为此,掌握由Google推出的Material Design设计语言成为提升应用颜值和用户体验的关键。本文将带你深入了解Material Design的核心原则,如真实感、统一性和创新性,并通过丰富的组件库及示例代码,助你轻松打造美观且一致的应用界面。无论是色彩搭配还是动画效果,Material Design都能为你的Android应用增添无限魅力。
64 1
|
2月前
|
安全 Android开发 数据安全/隐私保护
安卓与iOS的对决:移动操作系统的性能与创新
在当今智能手机市场,安卓和iOS两大操作系统一直处于竞争状态。本文将深入探讨它们在性能、安全性和用户体验方面的不同,并分析这些差异如何影响用户的选择。
55 3
|
3月前
|
存储 搜索推荐 Java
探索安卓开发中的自定义视图:打造个性化UI组件Java中的异常处理:从基础到高级
【8月更文挑战第29天】在安卓应用的海洋中,一个独特的用户界面(UI)能让应用脱颖而出。自定义视图是实现这一目标的强大工具。本文将通过一个简单的自定义计数器视图示例,展示如何从零开始创建一个具有独特风格和功能的安卓UI组件,并讨论在此过程中涉及的设计原则、性能优化和兼容性问题。准备好让你的应用与众不同了吗?让我们开始吧!
|
3月前
|
编解码 Android开发
【Android Studio】使用UI工具绘制,ConstraintLayout 限制性布局,快速上手
本文介绍了Android Studio中使用ConstraintLayout布局的方法,通过创建布局文件、设置控件约束等步骤,快速上手UI设计,并提供了一个TV Launcher界面布局的绘制示例。
55 1