Android之UI Automator框架源码分析(第九篇:UiDevice获取UiAutomation对象的过程分析)

本文主要是介绍Android之UI Automator框架源码分析(第九篇:UiDevice获取UiAutomation对象的过程分析),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

    通过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 upif (UiDevice.API_LEVEL_ACTUAL >= Build.VERSION_CODES.LOLLIPOP) {// Subscribe to window informationAccessibilityServiceInfo info = getUiAutomation().getServiceInfo();info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;getUiAutomation().setServiceInfo(info);}
}

 UiAutomation对象很重要

    

 AccessibilityServiceInfo info = getUiAutomation().getServiceInfo(); info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS; getUiAutomation().setServiceInfo(info);

    我们看到getUiAutomation()方法的调用 

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、面向对象程序,子类找不到的方法,按照继承结构,继续向上找就对了。。 

这篇关于Android之UI Automator框架源码分析(第九篇:UiDevice获取UiAutomation对象的过程分析)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/752137

相关文章

SpringBoot整合liteflow的详细过程

《SpringBoot整合liteflow的详细过程》:本文主要介绍SpringBoot整合liteflow的详细过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋...  liteflow 是什么? 能做什么?总之一句话:能帮你规范写代码逻辑 ,编排并解耦业务逻辑,代码

Java中调用数据库存储过程的示例代码

《Java中调用数据库存储过程的示例代码》本文介绍Java通过JDBC调用数据库存储过程的方法,涵盖参数类型、执行步骤及数据库差异,需注意异常处理与资源管理,以优化性能并实现复杂业务逻辑,感兴趣的朋友... 目录一、存储过程概述二、Java调用存储过程的基本javascript步骤三、Java调用存储过程示

MySQL中的InnoDB单表访问过程

《MySQL中的InnoDB单表访问过程》:本文主要介绍MySQL中的InnoDB单表访问过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、环境3、访问类型【1】const【2】ref【3】ref_or_null【4】range【5】index【6】

MySQL中的表连接原理分析

《MySQL中的表连接原理分析》:本文主要介绍MySQL中的表连接原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、环境3、表连接原理【1】驱动表和被驱动表【2】内连接【3】外连接【4编程】嵌套循环连接【5】join buffer4、总结1、背景

Spring 框架之Springfox使用详解

《Spring框架之Springfox使用详解》Springfox是Spring框架的API文档工具,集成Swagger规范,自动生成文档并支持多语言/版本,模块化设计便于扩展,但存在版本兼容性、性... 目录核心功能工作原理模块化设计使用示例注意事项优缺点优点缺点总结适用场景建议总结Springfox 是

浏览器插件cursor实现自动注册、续杯的详细过程

《浏览器插件cursor实现自动注册、续杯的详细过程》Cursor简易注册助手脚本通过自动化邮箱填写和验证码获取流程,大大简化了Cursor的注册过程,它不仅提高了注册效率,还通过友好的用户界面和详细... 目录前言功能概述使用方法安装脚本使用流程邮箱输入页面验证码页面实战演示技术实现核心功能实现1. 随机

MySQL 获取字符串长度及注意事项

《MySQL获取字符串长度及注意事项》本文通过实例代码给大家介绍MySQL获取字符串长度及注意事项,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录mysql 获取字符串长度详解 核心长度函数对比⚠️ 六大关键注意事项1. 字符编码决定字节长度2

Navicat数据表的数据添加,删除及使用sql完成数据的添加过程

《Navicat数据表的数据添加,删除及使用sql完成数据的添加过程》:本文主要介绍Navicat数据表的数据添加,删除及使用sql完成数据的添加过程,具有很好的参考价值,希望对大家有所帮助,如有... 目录Navicat数据表数据添加,删除及使用sql完成数据添加选中操作的表则出现如下界面,查看左下角从左

python中Hash使用场景分析

《python中Hash使用场景分析》Python的hash()函数用于获取对象哈希值,常用于字典和集合,不可变类型可哈希,可变类型不可,常见算法包括除法、乘法、平方取中和随机数哈希,各有优缺点,需根... 目录python中的 Hash除法哈希算法乘法哈希算法平方取中法随机数哈希算法小结在Python中,

Java Stream的distinct去重原理分析

《JavaStream的distinct去重原理分析》Javastream中的distinct方法用于去除流中的重复元素,它返回一个包含过滤后唯一元素的新流,该方法会根据元素的hashcode和eq... 目录一、distinct 的基础用法与核心特性二、distinct 的底层实现原理1. 顺序流中的去重