调试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就不举例了。

重写控件

还有一种情况,我们甚至不知道这个方法会不会执行的时候,并且我们关注的重点其实是一个控件会不会被显示出来,那么我们可以以直接去重写这个控件,然后在重写这个控件的时候添加上打印堆栈的代码:

  1. 重写这个控件 比如我们现在需要查看一个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();
              }
          }
      }
    
  2. 使用这个控件的.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。