一、概述
在做app性能优化的时候,大家都希望能够写出丝滑的UI界面,以前写过一篇博客,主要是基于Google当时发布的性能优化典范,主要提供一些UI优化性能示例:
实际上,由于各种机型的配置不同、代码迭代历史悠久,代码中可能会存在很多在UI线程耗时的操作,所以我们希望有一套简单检测机制,帮助我们定位耗时发生的位置。
本篇博客主要描述如何检测应用在UI线程的卡顿,目前已经有两种比较典型方式来检测了:
- 利用UI线程Looper打印的日志
- 利用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();
即可。
然后我们在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);
}
});
}
}
第一次的时候开始检测,如果大于阈值则输出相关堆栈信息,否则则移除。
使用方式和上述一致。
相关推荐
**ANR问题解析**是Android应用性能优化的核心部分。ANR(Application Not Responding)是指应用程序无响应,当用户界面无法及时响应用户的输入事件或者系统服务请求时,Android系统将提示ANR错误。主要分为四类:...
### Android应用性能优化 在移动开发领域,特别是针对Android平台的应用开发过程中,性能优化是确保应用流畅运行、提升用户体验的关键环节。本篇文章将围绕“Android应用性能优化”这一主题,详细探讨Android应用...
在Android应用开发中,UI卡顿是一个常见的性能问题,它会严重影响用户体验。为了优化和调试这类问题,开发者需要有一种高效的方式来监控和分析UI线程的行为。"Android-Ui卡顿监视工具高频采集堆栈信息方便定位问题...
在实际开发中,结合BlockCanary和其他性能分析工具(如TraceView、Systrace、LeakCanary等),开发者可以全面地监控和优化应用性能,确保应用流畅运行,提升用户体验。通过对卡顿日志的分析,开发者能够定位到导致...
通过这种方式,开发者可以定位性能瓶颈,找到导致UI卡顿或延迟的原因。 要使用Systrace进行UI性能分析,首先要开启Systrace。在Android Studio中,可以通过以下步骤来执行Systrace: 1. 打开Android Studio,选择`...
### Android应用性能优化的重要性 在当今移动互联网时代,Android应用已成为人们生活中不可或缺的一部分。随着市场竞争的日益激烈,用户对应用的体验要求也越来越高。因此,性能优化成为了提升用户体验的关键因素之...
根据提供的标题“Android应用性能优化【高清】”和描述“Android应用性能优化【高清】”,本文将深入探讨Android应用性能优化的关键技术与实践方法。由于提供的部分内容主要为重复的网站链接,这部分内容将不会被...
### Android应用性能优化 #### 一、引言 在当今移动互联网时代,Android作为全球最广泛使用的移动操作系统之一,其应用程序的数量与日俱增。随着市场竞争的加剧和技术的发展,用户对于应用的质量要求也越来越高,...
Android 性能调优是 Android 应用程序开发中非常重要的一方面。为了提高 Android 应用程序的性能,需要从多方面考虑,包括设计思想、代码质量优化、设计模式、数据结构等。下面我们就这些方面的知识点进行总结。 ...
在Android开发领域,性能优化是提升用户体验和应用质量的关键环节。这个"免费:Android性能优化视频百度云下载链接.rar"的压缩包文件提供了一个学习资源,可能是由一系列视频教程组成,帮助开发者深入理解和掌握...
此外,图片加载优化是提升应用性能的关键。Android提供了像Glide、Picasso等第三方库,它们能够高效地加载和缓存网络或本地图片,避免内存泄漏和卡顿问题。开发者应学会合理使用这些库,优化图片的加载速度和内存...
Android性能优化技术在某体重管理APP中的应用研究 Android性能优化技术是 Android 应用开发中一个非常重要的方面。随着 Android 操作系统的普及, Android 应用程序的数量也在不断增加。为了在众多应用程序中...
总结,Android性能优化是一个综合性的任务,涉及到UI、启动、崩溃、卡顿、安全、网络等多个方面。开发者需要结合系统提供的优化方案、第三方库以及各种工具,进行全方位的优化,以提供更优质、更稳定的应用体验。
通过以上知识点的学习,开发者能更好地理解Android UI线程的工作原理,避免阻塞并优化用户界面的响应速度,提升应用的性能和用户体验。视频教程“010_android 之UI线程阻塞及其优化”将更深入地通过实例来展示这些...
同时,利用Android提供的性能监控工具如TraceView和Systrace,可以定位和优化应用中的卡顿和延迟。 在应用数据处理方面,合理使用SQLite数据库和ContentProvider,可以有效地对数据进行存储和检索。同时,也要注意...
本文将围绕这三个方面,深入探讨Android应用性能优化的具体策略和技术细节。 #### 一、速度提升策略 在确保应用速度方面,开发人员需要关注代码效率。为了编写高效的Android代码,建议遵循以下原则: 1. **减少...
为了提升流畅度,开发者需要降低卡顿,优化界面绘制效率,使用如Android Profiler等工具检测UI线程的性能瓶颈,以及合理使用硬件加速。 4. 应用包大小优化:随着Android设备存储空间的增加,应用包大小虽不像早年...
Android性能优化是一个涵盖广泛的主题,涉及到系统层面的优化、内存管理、UI绘制、启动速度提升等多个方面。以下是对标题和描述中涉及的知识点的详细解释: 1. **基本概念**:了解Android性能优化,首先要掌握...
以上只是Android社交应用UI实现的一部分,实际开发中还需要考虑性能优化、用户体验、适配不同设备等因素。在ZYBmob这个项目中,可能包含了实现这些功能的源代码和示例,通过学习和实践,新手可以快速掌握Android社交...