调试android源码之打堆栈加重写控件
调试android源码之打堆栈加重写控件
在跟一大神同事一起解bug的时候学到的。现在这个同事已经离职,祝他有更好的发展,也感谢他在带我解bug的时候教会我这么多知识。
通常我们在看android系统源码的时候需要查看一些方法的调用方,这时候在Android Studio中按快捷键Ctrl+Alt+H就好了(如何将Android系统源码导入到AS中请看我的前置文章)。但是很多时候一个方法会被很多地方调用,而我们又无法确定我们需要追的流程走的是哪一条路线的时候就,打印堆栈就是一个很好的方法。 一个简单的使用方法如下:
打堆栈
比我们知道这个方法会被执行,但是我们不知道这个方法是被谁调用执行的,那我们可以在这个方法里添加下面几行代码:
try {
throw new Exception("debug: enabled" + enabled/*可以加上你需要的参数信息*/);
} catch (Exception e) {
e.printStackTrace();
}
一般这个时候从log中就可以看到调用的流程。我这里没有现成的log就不举例了。
重写控件
还有一种情况,我们甚至不知道这个方法会不会执行的时候,并且我们关注的重点其实是一个控件会不会被显示出来,那么我们可以以直接去重写这个控件,然后在重写这个控件的时候添加上打印堆栈的代码:
- 重写这个控件
比如我们现在需要查看一个ImageButton是什么时候显示出来的,被谁调用显示出来的,那么可以先写一个MyImageButton.java类,在其中重写相应的方法,并天机打堆栈的代码。
java代码中:
public class MyImageButton extends ImageButton { public MyImageButton(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void setVisibility(int visibility) { super.setVisibility(visibility); try { throw new Exception("cktdebug: enabled" + visibility); } catch (Exception e) { e.printStackTrace(); } } }
- 使用这个控件的.xml文件中 使用我们重写的这个控件
将原先使用到ImageButton的地方
<ImageButton android:id="@+id/eggplant" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
改写成
<com.example.hcz.smartmenu.MyImageButton android:id="@+id/eggplant" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
搞定。 这样在需要显示这个ImageButton的时候,就会使用我们的重写的MyImageButton,并且在显示的时候执行了重写的setVisibility方法,自然机会打印堆栈,从堆栈中得到了我们想要的信息,即在哪里调用方法显示出了这个ImageButton。