HierarchyViewer是Android SDK包中一个非常好用的工具,你在 android-sdks/tools目录下可以找到它。通过HierarchyViewer,即使没有应用的源代码,我们也可以非常直观地浏览Activity中控件的层次结构图,以及每个控件的属性和截图,这对于测试人员编写自动化测试用例是极有帮助的。这个系列的文章,我们将通过阅读和解析HierarchyViewer的代码,来了解HierarchyViewer是如何工作的,也可以加深Android提供给开发者的各种接口的了解。本系列文章代码基于android4.0的源代码,还没有下载源代码的同学快去下载吧,旅程这就开始了。
本文首先并不直接从源代码阅读开始,而是demo和解释HierarchyViewer的主要工作原理,这可是作者从源代码中抽取的精华啊:)。看完本文,你就可以写一个自己简单的HierarchyViewer了。我们主要讲解如下几个部分:
1,如何连接ViewServer
2,如何获取活动的Activities
3,如何获取Activity的控件树
4,如何获取截图
如何连接ViewServer
ViewServer是Android通过4939端口提供的服务,HierarchyViewer主要是通过它来获取获取Activity信息的, HierarchyViewer主要做下面3件事情来连接ViewServer。这需要用到Adb,HierarchyViewer中是直接通过api来调用Adb的,而这里我们先使用命令行adb来实现同样的功能。
(1)Forword端口。就是把Android设备上的4939端口映射到PC的某端口上,这样,向PC的该端口号发包都会转发到Android设备的4939端口上。
首先,输入命令列出所有Android设备
1 | |
假设我们有多台设备连接在PC上,该命令的输出为:
1 2 3 | |
以设备emulator-5556为例,接下来我们把它的4939端口映射到PC的4939端口上:
1 | |
如果连接了多台Android设备,HierarchyViewer将把下一台Android设备的4939端口映射到PC的4940端口,以此类推。
(2)打开ViewServer服务。
首先,需要判断ViewServer是否打开:
1 | |
如果返回值是"Result: Parcel(00000000 00000000 '........')",说明ViewServer没有打开,那么需要用下面的命令打开ViewServer:
1 | |
反之,关闭ViewServer的命令是:
1 | |
(3)连接ViewServer,既然ViewServer已经打开,那么下一步我们就需要连接它了。由于我们已经把设备emulator-5556的4939端口映射为PC的4939端口上,所以我们需要连接的是127.0.0.1:4939。这需要写一些java代码:
1 2 3 4 5 6 7 8 9 10 11 |
|
out和in用于发送命令和接受返回数据,需要注意的是,HierarchyViewer和ViewServer的通信采用短连接,所以每发送一次命令,需要重新建立一次连接,所以以上代码需要反复调用。
如何获取活动的Activity
在打开HierarchyViewer时,会显示每个设备当前活动的Activity列表,如下图:
这是怎么实现的呢? 这需要向ViewerServer发送"LIST"命令,看下面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
我们可以获取到类似如下的列表
1 2 3 4 5 6 7 8 9 10 11 | |
注意,每行前面的16进制数字,那是一个hashcode,我们在进一步请求该Activity对应的控件树时要用到该hashcode。
如何获取Activity的控件树
选中一个Activity后,HierarchyViewer将获取它的控件并显示为层次图:
获取控件树信息的命令是DUMP,后面要接对应的Activity的hash code,如果使用ffffffff作为参数,那么就是取最前端的Activity。我们以com.android.launcher2.Launcher为例,它的hash code是4507aa28,看代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
返回的控件树被保存文本context1中,一般文本的内容都非常大,这里我不把它全部打印出来,我们只取其中一行来看:
1 | |
返回的文本中的每一行是Activity中的一个控件,里面包含了该控件的所有信息,HierarchyViewer正是通过解析这些信息并把它们显示在属性列表中的。需要注意每行的开始处都包含一个“控件类型@hash code”的字段,如android.widget.FrameLayout@44edba90 ,这个字段在获取该控件的屏幕截图时将被用到。
HierarchyViewer是怎么把这个文本解析成层次图的呢? 原来,每行前面都有若干空格的缩进,比如缩进5个空格表示该控件在第六层,那么往上找,最近的缩进4个空格的控件就是它的父控件。在该系列后面的文章中,我们将具体阅读HierarchyViewer是怎么解析该文本,又是如何显示层次图的。
如何获取截图
在层次图上选中控件时,HierarchyViewer会显示该控件的截图:
获取截图的命令是CAPTURE,需要传递Activity的hashcode和控件的hashcode作为参数,看下面的代码:
1 2 3 4 5 6 7 8 |
|
到此为止,我相信大家已经对HierarchyViewer的主要实现机制有了基本的了解,接下来我们就要真正开始阅读HierarchyViewer的代码了,后面几章的内容大概是:
使用Eclipse阅读和调试HierarchyViewer
HierarchyViewer的后台代码导读
HierarchyViewer的前台代码导读