`
wx1569484809
  • 浏览: 63883 次
文章分类
社区版块
存档分类
最新评论

Android UI性能优化 检测应用中的UI卡顿

 
阅读更多

一、概述

在做app性能优化的时候,大家都希望能够写出丝滑的UI界面,以前写过一篇博客,主要是基于Google当时发布的性能优化典范,主要提供一些UI优化性能示例:

实际上,由于各种机型的配置不同、代码迭代历史悠久,代码中可能会存在很多在UI线程耗时的操作,所以我们希望有一套简单检测机制,帮助我们定位耗时发生的位置。

本篇博客主要描述如何检测应用在UI线程的卡顿,目前已经有两种比较典型方式来检测了:

  1. 利用UI线程Looper打印的日志
  2. 利用Choreographer

两种方式都有一些开源项目,例如:

其实编写本篇文章,主要是因为发现一个还比较有意思的方案,该方法的灵感来源于一篇给我微信投稿的文章:

该项目主要用于捕获UI线程的crash,当我看完该项目原理的时候,也可以用来作为检测卡段方案,可能还可以做一些别的事情。

所以,本文出现了3种检测UI卡顿的方案,3种方案原理都比较简单,接下来将逐个介绍。

二、利用loop()中打印的日志

(1)原理

大家都知道在Android UI线程中有个Looper,在其loop方法中会不断取出Message,调用其绑定的Handler在UI线程进行执行。

大致代码如下:

public static void loop() {
    final Looper me = myLooper();

    final MessageQueue queue = me.mQueue;
    // ...
    for (;;) {
        Message msg = queue.next(); // might block
        // This must be in a local variable, in case a UI event sets the logger
        Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " +
                    msg.callback + ": " + msg.what);
        }
        // focus
        msg.target.dispatchMessage(msg);

        if (logging != null) {
            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
        }

        // ...
        }
        msg.recycleUnchecked();
    }
}

 

所以很多时候,我们只要有办法检测:

msg.target.dispatchMessage(msg);

此行代码的执行时间,就能够检测到部分UI线程是否有耗时操作了。可以看到在执行此代码前后,如果设置了logging,会分别打印出>>>>> Dispatching to<<<<< Finished to这样的log。

我们可以通过计算两次log之间的时间差值,大致代码如下:

public class BlockDetectByPrinter {

    public static void start() {

        Looper.getMainLooper().setMessageLogging(new Printer() {

            private static final String START = ">>>>> Dispatching";
            private static final String END = "<<<<< Finished";

            @Override
            public void println(String x) {
                if (x.startsWith(START)) {
                    LogMonitor.getInstance().startMonitor();
                }
                if (x.startsWith(END)) {
                    LogMonitor.getInstance().removeMonitor();
                }
            }
        });

    }
}

 

假设我们的阈值是1000ms,当我在匹配到>>>>> Dispatching时,我会在1000ms毫秒后执行一个任务(打印出UI线程的堆栈信息,会在非UI线程中进行);正常情况下,肯定是低于1000ms执行完成的,所以当我匹配到<<<<< Finished,会移除该任务。

大概代码如下:

public class LogMonitor {

    private static LogMonitor sInstance = new LogMonitor();
    private HandlerThread mLogThread = new HandlerThread("log");
    private Handler mIoHandler;
    private static final long TIME_BLOCK = 1000L;

    private LogMonitor() {
        mLogThread.start();
        mIoHandler = new Handler(mLogThread.getLooper());
    }

    private static Runnable mLogRunnable = new Runnable() {
        @Override
        public void run() {
            StringBuilder sb = new StringBuilder();
            StackTraceElement[] stackTrace = Looper.getMainLooper().getThread().getStackTrace();
            for (StackTraceElement s : stackTrace) {
                sb.append(s.toString() + "\n");
            }
            Log.e("TAG", sb.toString());
        }
    };

    public static LogMonitor getInstance() {
        return sInstance;
    }

    public boolean isMonitor() {
        return mIoHandler.hasCallbacks(mLogRunnable);
    }

    public void startMonitor() {
        mIoHandler.postDelayed(mLogRunnable, TIME_BLOCK);
    }

    public void removeMonitor() {
        mIoHandler.removeCallbacks(mLogRunnable);
    }

}

 

我们利用了HandlerThread这个类,同样利用了Looper机制,只不过在非UI线程中,如果执行耗时达到我们设置的阈值,则会执行mLogRunnable,打印出UI线程当前的堆栈信息;如果你阈值时间之内完成,则会remove掉该runnable。

(2)测试

用法很简单,在Application的onCreate中调用:

BlockDetectByPrinter.start();
  • 1

save_snippets_01.png

  • 1

即可。

然后我们在Activity里面,点击一个按钮,让睡眠2s,测试下:

findViewById(R.id.id_btn02)
    .setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
            }
        }    });

 

运行点击时,会打印出log:

02-21 00:26:26.408 2999-3014/com.zhy.testlp E/TAG: 
java.lang.VMThread.sleep(Native Method)
   java.lang.Thread.sleep(Thread.java:1013)
   java.lang.Thread.sleep(Thread.java:995)
   com.zhy.testlp.MainActivity$2.onClick(MainActivity.java:70)
   android.view.View.performClick(View.java:4438)
   android.view.View$PerformClick.run(View.java:18422)
   android.os.Handler.handleCallback(Handler.java:733)
   android.os.Handler.dispatchMessage(Handler.java:95)

 

会打印出耗时相关代码的信息,然后可以通过该log定位到耗时的地方。

三、 利用Choreographer

android系统每隔16ms发出VSYNC信号,触发对UI进行渲染。SDK中包含了一个相关类,以及相关回调。理论上来说两次回调的时间周期应该在16ms,如果超过了16ms我们则认为发生了卡顿,我们主要就是利用两次回调间的时间周期来判断:

大致代码如下:

public class BlockDetectByChoreographer {
    public static void start() {
        Choreographer.getInstance()
            .postFrameCallback(new Choreographer.FrameCallback() {
                @Override
                public void doFrame(long l) {
                    if (LogMonitor.getInstance().isMonitor()) {
                        LogMonitor.getInstance().removeMonitor();                    
                    } 
                    LogMonitor.getInstance().startMonitor();
                    Choreographer.getInstance().postFrameCallback(this);
                }
        });
    }
}

 

第一次的时候开始检测,如果大于阈值则输出相关堆栈信息,否则则移除。

使用方式和上述一致。

转载于:https://my.oschina.net/u/3637221/blog/1505911

分享到:
评论

相关推荐

    Android性能优化.pdf

    **ANR问题解析**是Android应用性能优化的核心部分。ANR(Application Not Responding)是指应用程序无响应,当用户界面无法及时响应用户的输入事件或者系统服务请求时,Android系统将提示ANR错误。主要分为四类:...

    Android应用性能优化

    ### Android应用性能优化 在移动开发领域,特别是针对Android平台的应用开发过程中,性能优化是确保应用流畅运行、提升用户体验的关键环节。本篇文章将围绕“Android应用性能优化”这一主题,详细探讨Android应用...

    Android-Ui卡顿监视工具高频采集堆栈信息方便定位问题代码

    在Android应用开发中,UI卡顿是一个常见的性能问题,它会严重影响用户体验。为了优化和调试这类问题,开发者需要有一种高效的方式来监控和分析UI线程的行为。"Android-Ui卡顿监视工具高频采集堆栈信息方便定位问题...

    Android-卡顿检测工具forandroid

    在实际开发中,结合BlockCanary和其他性能分析工具(如TraceView、Systrace、LeakCanary等),开发者可以全面地监控和优化应用性能,确保应用流畅运行,提升用户体验。通过对卡顿日志的分析,开发者能够定位到导致...

    android 性能优化-Systrace分析UI性能demo

    通过这种方式,开发者可以定位性能瓶颈,找到导致UI卡顿或延迟的原因。 要使用Systrace进行UI性能分析,首先要开启Systrace。在Android Studio中,可以通过以下步骤来执行Systrace: 1. 打开Android Studio,选择`...

    Android应用性能优化经验分享-张明云

    ### Android应用性能优化的重要性 在当今移动互联网时代,Android应用已成为人们生活中不可或缺的一部分。随着市场竞争的日益激烈,用户对应用的体验要求也越来越高。因此,性能优化成为了提升用户体验的关键因素之...

    Android应用性能优化【高清】

    根据提供的标题“Android应用性能优化【高清】”和描述“Android应用性能优化【高清】”,本文将深入探讨Android应用性能优化的关键技术与实践方法。由于提供的部分内容主要为重复的网站链接,这部分内容将不会被...

    《Android应用性能优化》.(埃尔韦).[PDF]

    ### Android应用性能优化 #### 一、引言 在当今移动互联网时代,Android作为全球最广泛使用的移动操作系统之一,其应用程序的数量与日俱增。随着市场竞争的加剧和技术的发展,用户对于应用的质量要求也越来越高,...

    Android 性能调优方面总结

    Android 性能调优是 Android 应用程序开发中非常重要的一方面。为了提高 Android 应用程序的性能,需要从多方面考虑,包括设计思想、代码质量优化、设计模式、数据结构等。下面我们就这些方面的知识点进行总结。 ...

    免费:Android性能优化视频百度云下载链接.rar

    在Android开发领域,性能优化是提升用户体验和应用质量的关键环节。这个"免费:Android性能优化视频百度云下载链接.rar"的压缩包文件提供了一个学习资源,可能是由一系列视频教程组成,帮助开发者深入理解和掌握...

    android UI界面开发图片

    此外,图片加载优化是提升应用性能的关键。Android提供了像Glide、Picasso等第三方库,它们能够高效地加载和缓存网络或本地图片,避免内存泄漏和卡顿问题。开发者应学会合理使用这些库,优化图片的加载速度和内存...

    Android性能优化技术在某体重管理APP中的应用研究.pdf

    Android性能优化技术在某体重管理APP中的应用研究 Android性能优化技术是 Android 应用开发中一个非常重要的方面。随着 Android 操作系统的普及, Android 应用程序的数量也在不断增加。为了在众多应用程序中...

    Android核心性能优化汇总

    总结,Android性能优化是一个综合性的任务,涉及到UI、启动、崩溃、卡顿、安全、网络等多个方面。开发者需要结合系统提供的优化方案、第三方库以及各种工具,进行全方位的优化,以提供更优质、更稳定的应用体验。

    010_android 之UI线程阻塞及其优化

    通过以上知识点的学习,开发者能更好地理解Android UI线程的工作原理,避免阻塞并优化用户界面的响应速度,提升应用的性能和用户体验。视频教程“010_android 之UI线程阻塞及其优化”将更深入地通过实例来展示这些...

    Android应用程序性能优化

    同时,利用Android提供的性能监控工具如TraceView和Systrace,可以定位和优化应用中的卡顿和延迟。 在应用数据处理方面,合理使用SQLite数据库和ContentProvider,可以有效地对数据进行存储和检索。同时,也要注意...

    Android性能优化

    本文将围绕这三个方面,深入探讨Android应用性能优化的具体策略和技术细节。 #### 一、速度提升策略 在确保应用速度方面,开发人员需要关注代码效率。为了编写高效的Android代码,建议遵循以下原则: 1. **减少...

    Android性能优化手记

    为了提升流畅度,开发者需要降低卡顿,优化界面绘制效率,使用如Android Profiler等工具检测UI线程的性能瓶颈,以及合理使用硬件加速。 4. 应用包大小优化:随着Android设备存储空间的增加,应用包大小虽不像早年...

    android 性能优化文章

    Android性能优化是一个涵盖广泛的主题,涉及到系统层面的优化、内存管理、UI绘制、启动速度提升等多个方面。以下是对标题和描述中涉及的知识点的详细解释: 1. **基本概念**:了解Android性能优化,首先要掌握...

    Android设交应用常见UI实现

    以上只是Android社交应用UI实现的一部分,实际开发中还需要考虑性能优化、用户体验、适配不同设备等因素。在ZYBmob这个项目中,可能包含了实现这些功能的源代码和示例,通过学习和实践,新手可以快速掌握Android社交...

Global site tag (gtag.js) - Google Analytics