前言
学习UiDevice对象,就需要看它的构造方法,构造方法中有UiDevice对象持有一些对象,每个对象都是我们分析程序的重点,毕竟UiDevice对象的功能,依赖这些组合的对象
备注:当前对象持有的对象,初始化的位置一般在实例变量创建时或者构造方法中,以下是UiDevice构造方法中正在做初始化对象的代码!
UiDevice(Instrumentation instrumentation) { mInstrumentation = instrumentation; mQueryController = new QueryController(instrumentation); mInteractionController = new InteractionController(instrumentation); // Enable multi-window support for API level 21 and up if (UiDevice.API_LEVEL_ACTUAL >= Build.VERSION_CODES.LOLLIPOP) { // Subscribe to window information AccessibilityServiceInfo info = getUiAutomation().getServiceInfo(); info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS; getUiAutomation().setServiceInfo(info); } }
UiAutomation对象很重要
我们看到getUiAutomation()方法在UiDevice构造方法中的调用
AccessibilityServiceInfo info = getUiAutomation().getServiceInfo(); info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS; getUiAutomation().setServiceInfo(info);
getUiAutomatrion()方法分析
位于UiDevice类中的getUiAutomation()方法,返回值是UiAutomation对象
UiAutomation getUiAutomation() {
return getUiAutomation(getInstrumentation());
}
1、先调用一个getInstrumentation()方法
该方法返回的Instrumentation对象会再被传入到接受一个参数的getUiAutomation重载方法中
2、再次调用重载的getUiAutomation()方法
3、此重载方法的返回值将作为当前getUiAutomation()方法的返回值
我们先学习一下Instrumentation对象是如何获取到的,即getInstrumentation()的调用!
getInstrumentation()方法分析
位于UiDevice中的getInstrumentation方法,返回值为Instrumentation对象
Instrumentation getInstrumentation() {
return mInstrumentation;
}
通过该方法就可以得到UiDevice对象持有的Instrumentation对象mInstrumentation,方法内部通过return语句返回mInstrumentation,说明Instrumentation对象已经初始化结束,这里只是返回
Instrumentation对象在哪初始化的
通过代码得知,是创建UiDevice的时候,传入的一个Instrumentation对象
创建UiDevice对象
public static final UiDevice mDevice = UiDevice.getInstance(getInstrumentation());
这时候传入的其实是InstrumentationRegistry下的静态方法getInstrumentation()返回的Instrumenation对象。
public static Instrumentation getInstrumentation() { Instrumentation instance = instrumentationRef.get(); if (null == instance) { throw new IllegalStateException( "No instrumentation registered! " + "Must run under a registering instrumentation."); } return instance; }
一个原子对象负责持有Instrumentation对象
找到了原子对象赋值的地方
我们需要找到registerInstance这个静态方法在哪里被调用即可
在MonitoringInstrumentation对象中的oncreate()方法中调用了
MonitoringInstrumentation对象,从名字上,果然是Instrumentation的子类,它是具体的对象,代码追踪到这里,只要再找到这个oncreate()方法在哪里调用即可!
很快找到了,追踪了整个Unit框架了都要
AndroidJUnitRunner是MonitoringInstrumentation的子类,看来AndroidJUnitRunner也是个Instrumentation!!
AndroidUnitRunner作为入口类
我们是在am instrument 指定的该类,这一切明白了,这个用到的Instrumentation对象,其实就是AndroidUnitRunner对象
$ADB shell am instrument -w -e class com.xxx.camauto.Common#unlockScreen com.xiaomi.camauto.test/androidx.test.runner.AndroidJUnitRunner
重载的静态方法getUiAutomation(Instrumentation)方法分析
位于UiDevice类中的静态方法getUiAutomation(),它接受一个Instrumentation对象,最后会返回一个UiAutomation对象
static UiAutomation getUiAutomation(final Instrumentation instrumentation) {
int flags = Configurator.getInstance().getUiAutomationFlags();
if (UiDevice.API_LEVEL_ACTUAL > Build.VERSION_CODES.M) {
return instrumentation.getUiAutomation(flags);
} else {
// Custom flags not supported prior to N.
if (flags != Configurator.DEFAULT_UIAUTOMATION_FLAGS) {
Log.w(LOG_TAG, "UiAutomation flags not supported prior to N - ignoring.");
}
return instrumentation.getUiAutomation();
}
}
1、获取配置对象中的UiAutomation的标志位
首先通过Configurator对象的getUiAutomationFlags方法,得到一个int值,该值的初始值是0,然后再将该int值赋值给局部变量flags存储,flags存储的是关于UiAutomatrion对象的标志位(说明:Configurator对象存储着UI Automator测试框架用到的各种配置信息,此时局部变量flags存储的值正是从Configurator对象中获得,后面单独文章总结)
2、系统版本大于API 23获取UiAutomation对象的方式
接着做API版本判断,UiDevice类持有的API_LEVEL_ACTUAL代表API版本,根据API版本执行不同的逻辑
当API版本大于M(API==23)时,使用的传入的Instrumentation对象的接受一个整型参数的getUiAutomation()方法,此时会将局部变量flags传入进去,getUiAutomation(int)方法返回的是一个UiAutomation对象(看这个flags决定了获取对象的不同)
3、系统版本小于等于API 23获取UiAutomation对象的方式
当API版本小于等于M(API==23)时,使用的是传入的Instrumentation对象的无参数的getUiAutomation()方法,该方法也会返回一个UiAutomation对象
说明:最终getUiAutomation()方法中依赖Instrumentaion对象获取到的UiAutomation对象
找到具体的UiAutomation对象
从前面的步骤得知这个Instumentation对象其实是AndroidJUnitRunner,而调用的getUiAutomation()获取到的UiAutomation()对象,由于java是单继承,我们只要沿着AndroidJunitRunner的继承树, 找到getUiAutomation()方法,就能知道具体的UiAutomation对象在哪里创建的!!
1、先从AndroidJunitRunner中找getUiAutomation()方法,发现该类没有该方法
2、只能继续从它的父类MonitoringInstrumentation中找getUiAutomation()方法,这是面向对象程序的特点,记住了各位,结果还是没有这个方法
3、继续从它的父类ExposedInstumentationApi中查找,发现还是没有
4、继续从父类Instrumentation中查找,总算找到了
原来是UiAutomation对象,必须创建的时候才会创建,必须创建是指:没创建与已经销毁
可以看到把当前App上下文的主线程Looper对象传递进去了
总结
1、追踪了一圈,也知道UiAutomation对象是在哪里创建!
2、面向对象程序,子类找不到的方法,按照继承结构,继续向上找就对了。。