Android如何定位卡顿,Android检测卡顿方法

背景

在app开发过程中,经常会出现由于在主线程执行某些耗时操作(例如db,文件io操作等)导致页面显示会出现卡顿,影响用户体验。本文主要讲解一种基于Handler Message机制的卡顿检测方案,

原理 :Android系统在执行每个方法的时候,会在方法的开始和结束打印日志。

在方法开始执行的时候,会打印

07-01 13:06:25.139 13471-13471/"" D/BlockDetector: BlockDetector init println x = >>>>> Dispatching to Handler (android.app.ActivityThread$H) {34d05903} null: 102

07-01 13:06:25.168 13471-13471/"" D/BlockDetector: BlockDetector init println x = >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {3a8c2969} null: 6

07-01 13:06:25.219 13471-13471/"" D/BlockDetector: BlockDetector init println x = >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {3a8c2969} null: 8

在方法结束执行的时候,会打印

07-01 13:07:02.036 13471-13471/com.apache.fastandroid D/BlockDetector: BlockDetector init println x = <<<<< Finished to Handler (android.os.Handler) {29d2efdd} com.squareup.leakcanary.AndroidWatchExecutor$1@dae1898

07-01 13:07:02.275 13471-13471/com.apache.fastandroid D/BlockDetector: BlockDetector init println x = <<<<< Finished to Handler (android.os.Handler) {29d2efdd} com.squareup.leakcanary.AndroidWatchExecutor$1@3c2ef8f1

07-01 13:07:02.521 13471-13471/com.apache.fastandroid D/BlockDetector: BlockDetector init println x = <<<<< Finished to Handler (android.os.Handler) {29d2efdd} com.squareup.leakcanary.AndroidWatchExecutor$1@2b3f9cd6

07-01 13:07:02.758 13471-13471/com.apache.fastandroid D/BlockDetector: BlockDetector init println x = <<<<< Finished to Handler (android.os.Handler) {29d2efdd} com.squareup.leakcanary.AndroidWatchExecutor$1@2f632b57

07-01 13:07:03.003 13471-13471/com.apache.fastandroid D/BlockDetector: BlockDetector init println x = <<<<< Finished to Handler (android.os.Handler) {29d2efdd} com.squareup.leakcanary.AndroidWatchExecutor$1@b82644

07-01 13:07:03.247 13471-13471/com.apache.fastandroid D/BlockDetector: BlockDetector init println x = <<<<< Finished to Handler (android.os.Handler) {29d2efdd} com.squareup.leakcanary.AndroidWatchExecutor$1@6a9332d

07-01 13:07:03.505 13471-13471/com.apache.fastandroid D/BlockDetector: BlockDetector init println x = <<<<< Finished to Handler (android.os.Handler) {29d2efdd} com.squareup.leakcanary.AndroidWatchExecutor$1@2570b062

07-01 13:07:07.634 13471-13471/com.apache.fastandroid D/BlockDetector: BlockDetector init println x = <<<<< Finished to Handler (android.os.Handler) {29d2efdd} com.squareup.leakcanary.AndroidWatchExecutor$1@148525f3

利用这个特点,然后就可以拦截这些打印日志,在>>>>> Dispatching的时候,延时特定时间(例如500ms)开始监控耗时, 在<<<<< Finished的时候结束监控,取消延时执行代码逻辑。如果延时的代码逻辑有执行,说明当前方法耗时超过了500ms,则把对应的堆栈信息打印出来。

操作步骤

具体代码如下:

/**

*

* 检测主线程卡顿

*/

public class BlockDetector {

public static void init() {

if(DebugUtils.isDebug()) {

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

//分发和处理消息开始前的log

private static final String START = ">>>>> Dispatching";

//分发和处理消息结束后的log

private static final String END = "<<<<< Finished";

@Override

public void println(String x) {

NLog.d("BlockDetector init println x = %s",x);

if (x.startsWith(START)) {

//开始计时

BlockMonitor.getInstance().startMonitor();

}

if (x.startsWith(END)) {

//结束计时

BlockMonitor.getInstance().removeMonitor();

}

}

});

}

}

public class BlockMonitor {

private static final String TAG = "=============BlockMonitor============= \n %s";

private static BlockMonitor sInstance = new BlockMonitor();

private Handler mIoHandler;

//方法耗时的卡口,500毫秒

private static final long TIME_BLOCK = 500L;

//存放一个msg周期的卡顿堆栈信息,防止重复打印

private Set mBlockStackTrace;

private BlockMonitor() {

HandlerThread logThread = new HandlerThread("BlockMonitor");

logThread.start();

mIoHandler = new Handler(logThread.getLooper());

mBlockStackTrace = Collections.synchronizedSet(new HashSet());

}

private Runnable mLogRunnable = new Runnable() {

@Override

public void run() {

//继续检测

startMonitor();

//打印出执行的耗时方法的栈消息

StackTraceElement[] stackTrace = Looper.getMainLooper().getThread().getStackTrace();

StringBuilder sb = new StringBuilder();

for (StackTraceElement s : stackTrace) {

sb.append(s.toString());

sb.append("\n");

}

String s = sb.toString();

if (!mBlockStackTrace.contains(s)) {

mBlockStackTrace.add(s);

//BlockLogUtils.e(TAG, s);

NLog.e(TAG, s);

}

}

};

public static BlockMonitor getInstance() {

return sInstance;

}

/**

* 开始计时

*/

public void startMonitor() {

NLog.d("BlockDetector startMonitor");

mIoHandler.postDelayed(mLogRunnable, TIME_BLOCK);

}

/**

* 停止计时

*/

public void removeMonitor() {

NLog.d("BlockDetector removeMonitor");

mIoHandler.removeCallbacks(mLogRunnable);

mBlockStackTrace.clear();

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值