android log输出参数,Android之输出Handler日志

今天看到一篇文章提到了给Looper加日志以观察GC,发现这个Looper打日志这个小技巧有助于调试UI卡顿问题,我们学学这个技巧吧。

通过统计主线程Looper中每个Message的耗时,很容易找出主线程耗时过多的操作。这些操作往往是导致UI卡顿的罪魁祸首。

你可能会说,我在Handler.handMessage()中也可以添加计时代码呀,在Looper中统计有什么好处?如果是你自己写的Handler的确也很容易统计,但如果是别人写的呢,如果是第三方库中的呢?另一方面,即便自己写的,如何保证新加的Handler不会遗漏计时代码?所以这种做法并不可取。看看更好的做法是怎样的。

setMessageLogging()

注释文档中说,setMessageLogging()用于当前Looper处理Message时打印日志。

传null参数关闭日志功能,传非null的printer开启日志功能

开启日志功能后,会在每个Message分发的开始以及结束时输出日志信息到printer,具体的日志信息包括区分Message的目标Hander以及Message内容

对照loop()方法源码(省略无关部分),跟上面描述一致。所以这里不再赘述。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37// android.os.Looper.java

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

final Printer logging = me.mLogging;

if (logging != null) {

logging.println(">>>>> Dispatching to " + msg.target + " " +

msg.callback + ": " + msg.what);

}

...

msg.target.dispatchMessage(msg);

...

if (logging != null) {

logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);

}

...

}

}

/**

* Control logging of messages as they are processed by this Looper. If

* enabled, a log message will be written to printer

* at the beginning and ending of each message dispatch, identifying the

* target Handler and message contents.

*

* @param printer A Printer object that will receive log messages, or

* null to disable message logging.

*/

public void setMessageLogging(@Nullable Printer printer){

mLogging = printer;

}

输出Handler日志

界面上有一个使用Handler实现的轮播图,每隔5秒发消息切换到下一张图片。我们给它加上日志功能,代码如下:

1

2

3

4

5

6

7

8

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

@Override

public void println(String x){

// 为了便于logcat中观察, 我们只输出当前页面的日志

if (x != null && x.contains("EventCenterFragment")) {

Log.i(CmPerf.TAG, x);

}

}

});

1cae87640a5d953c7aee5b70ae764005.gif

每次切换图片时会输出如下格式的日志:

1

2

3

412-12 10:35:38.614 9542-9542 I: >>>>> Dispatching to Handler (com.tc.igame.view.common.fragment.EventCenterFragment$1) {101c258} null: 1

12-12 10:35:38.615 9542-9542 I: <<<<< Finished to Handler (com.tc.igame.view.common.fragment.EventCenterFragment$1) {101c258} null

12-12 10:35:43.617 9542-9542 I: >>>>> Dispatching to Handler (com.tc.igame.view.common.fragment.EventCenterFragment$1) {101c258} null: 1

12-12 10:35:43.618 9542-9542 I: <<<<< Finished to Handler (com.tc.igame.view.common.fragment.EventCenterFragment$1) {101c258} null

Dispatching to Handler和Finished to Handler对应首一次Message处理过程。我们可以根据这种特定的日志格式为每个Message处理加上耗时统计。具体做这可参考《为你的android程序加上gc监控吧!》,这里不展开。

补充

《为你的android程序加上gc监控吧!》中提到的gc监控做法太过复杂,并不可取。实际上,Android 6.0(API 23)之后art虚拟机支持如下方式获取gc次数和gc耗时:

1

2Debug.getRuntimeStat("art.gc.gc-count");

Debug.getRuntimeStat("art.gc.gc-time");

我们直接调用系统API即可很方便地获取到gc次数和gc耗时。

添加如下代码并在Android Monitor中强制gc,观察输出的日志。

1

2

3

4

5

6

7

8

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

@Override

public void println(String x){

if (x != null && x.contains("EventCenter") && x.contains("Finished to Handler")) {

Log.i(CmPerf.TAG, "looper println: count=" + Debug.getRuntimeStat("art.gc.gc-count"));

//Log.i(CmPerf.TAG, "looper println: time=" + Debug.getRuntimeStat("art.gc.gc-time"));

}

}

});

GC日志参考

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值