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设备
假设我们有多台设备连接在PC上,该命令的输出为:
1
2
3
|
List of devices attached
emulator-5554 device
emulator-5556 device
|
以设备emulator-5556为例,接下来我们把它的4939端口映射到PC的4939端口上:
1
|
adb -s emulator-5556 forward tcp:4939 tcp:4939
|
如果连接了多台Android设备,HierarchyViewer将把下一台Android设备的4939端口映射到PC的4940端口,以此类推。
(2)打开ViewServer服务。
首先,需要判断ViewServer是否打开:
1
|
adb -s emulator-5556 shell service call window 3
|
如果返回值是"Result: Parcel(00000000 00000000 '........')",说明ViewServer没有打开,那么需要用下面的命令打开ViewServer:
1
|
adb -s emulator-5556 shell service call window 1 i32 4939
|
反之,关闭ViewServer的命令是:
1
|
adb -s emulator-5556 shell service call window 2 i32 4939
|
(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
|
import
java.net.*;
try {
Socket socket =
new Socket();
socket.connect( new
InetSocketAddress( "127.0.0.1" ,
4939 ), 40000 );
BufferedWriter out =
new BufferedWriter( new
OutputStreamWriter(socket.getOutputStream()));
BufferedReader in =
new BufferedReader( new
InputStreamReader(socket.getInputStream(), "utf-8" ));
}
} catch
( Exception e ) {
e.printStackTrace();
}
|
out和in用于发送命令和接受返回数据,需要注意的是,HierarchyViewer和ViewServer的通信采用短连接,所以每发送一次命令,需要重新建立一次连接,所以以上代码需要反复调用。
如何获取活动的Activity
在打开HierarchyViewer时,会显示每个设备当前活动的Activity列表,如下图:
这是怎么实现的呢? 这需要向ViewerServer发送"LIST"命令,看下面的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
out.write( "LIST" );
out.newLine();
out.flush();
String context= "" ;
String line;
while
((line = in.readLine()) != null ) {
if
( "DONE." .equalsIgnoreCase(line)) {
break ;
}
context+=line+ "\r\n" ;
}
|
我们可以获取到类似如下的列表
1
2
3
4
5
6
7
8
9
10
11
|
44fd1b78 com.android.internal.service.wallpaper.ImageWallpaper
4507aa28 com.android.launcher/com.android.launcher2.Launcher
45047328 com.tencent.mobileqq/com.tencent.mobileqq.activity.HomeActivity
450b8d18 com.tencent.mobileqq/com.tencent.mobileqq.activity.NotificationActivity
451049c0 com.tencent.mobileqq/com.tencent.mobileqq.activity.NotificationActivity
451167a8 com.tencent.mobileqq/com.tencent.mobileqq.activity.UpgradeActivity
450efef0 com.tencent.mobileqq/com.tencent.mobileqq.activity.UpgradeActivity
4502f2e0 TrackingView
4503f560 StatusBarExpanded
44fe0bb0 StatusBar
44f09250 Keyguard
|
注意,每行前面的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
|
//out.write("DUMP ffffffff");
out.write("DUMP 4507aa28");
out.newLine();
out.flush();
String context1="";
line="";
while ((line = in.readLine()) != null) {
if ("DONE.".equalsIgnoreCase(line)) { //$NON-NLS-1$
break;
}
context1+=line+"\r\n";
}
|
返回的控件树被保存文本context1中,一般文本的内容都非常大,这里我不把它全部打印出来,我们只取其中一行来看:
1
|
android.widget.FrameLayout@44edba90 mForeground=52,android.graphics.drawable.NinePatchDrawable@44edc1e0 mForegroundInPadding=5,false mForegroundPaddingBottom=1,0 mForegroundPaddingLeft=1,0 mForegroundPaddingRight=1,0
mForegroundPaddingTop=1,0 mMeasureAllChildren=5,false mForegroundGravity=2,55 getDescendantFocusability()=24,FOCUS_BEFORE_DESCENDANTS getPersistentDrawingCache()=9,SCROLLING isAlwaysDrawnWithCacheEnabled()=4,true isAnimationCacheEnabled()=4,true isChildrenDrawingOrderEnabled()=5,false
isChildrenDrawnWithCacheEnabled()=5,false mMinWidth=1,0 mPaddingBottom=1,0 mPaddingLeft=1,0 mPaddingRight=1,0 mPaddingTop=2,38 mMinHeight=1,0 mMeasuredWidth=3,480 mMeasuredHeight=3,800 mLeft=1,0 mPrivateFlags_DRAWING_CACHE_INVALID=3,0x0 mPrivateFlags_DRAWN=4,0x20
mPrivateFlags=8,16911408 mID=10,id/content mRight=3,480 mScrollX=1,0 mScrollY=1,0 mTop=1,0 mBottom=3,800 mUserPaddingBottom=1,0 mUserPaddingRight=1,0 mViewFlags=9,402653186 getBaseline()=2,-1 getHeight()=3,800 layout_bottomMargin=1,0 layout_leftMargin=1,0
layout_rightMargin=1,0 layout_topMargin=1,0 layout_height=12,MATCH_PARENT layout_width=12,MATCH_PARENT getTag()=4,null getVisibility()=7,VISIBLE getWidth()=3,480 hasFocus()=5,false isClickable()=5,false isDrawingCacheEnabled()=5,false isEnabled()=4,true isFocusable()=5,false
isFocusableInTouchMode()=5,false isFocused()=5,false isHapticFeedbackEnabled()=4,true isInTouchMode()=4,true isOpaque()=5,false isSelected()=5,false isSoundEffectsEnabled()=4,true willNotCacheDrawing()=5,false willNotDraw()=5,false
|
返回的文本中的每一行是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
|
import
org.eclipse.swt.graphics.Image;
import
org.eclipse.swt.widgets.Display;
out.write( "CAPTURE 4507aa28 android.widget.FrameLayout@44edba90" );
out.newLine();
out.flush();
Image image =
new Image(Display.getDefault(), socket.getInputStream());
|
到此为止,我相信大家已经对HierarchyViewer的主要实现机制有了基本的了解,接下来我们就要真正开始阅读HierarchyViewer的代码了,后面几章的内容大概是:
使用Eclipse阅读和调试HierarchyViewer
HierarchyViewer的后台代码导读
HierarchyViewer的前台代码导读
分享到:
相关推荐
android工具Hierarchy_Viewer命令详解
教你如何使用HierarchyViewer工具!
该文档详细讲解了Android开发当中的UI分析工具Hierarchy Viewer的使用方法
hierarchyviewer不能连接android真机问题
NULL 博文链接:https://byandby.iteye.com/blog/822526
android hierarchyviewer 代码
Hierarchy viewer的运行原 的介绍
解决这个启动 View Hierarchy时的这个bug: hierarchy viewer unable to debug device
然后用Hierarchy Viewer看了View的层级,这才有了一点点的思路。 在代码撰写的过程中,我也踩了不少坑。细看代码深处,或许你会有一丝丝的收获吧。 当然,在最初的最初,我搜了不少的draggable gridview的仓库,可惜...
Hierarchy Viewer是一个可以让您在Gooogle Chrome浏览器上以简单的方式显示App视图树的库
Hierarchy Viewer工具可以用来查看视图树(View Tree)并分析视图树中各个视图在测量、布局、绘制阶段所消耗的时间。通过该工具提供的信息,开发者可以找出视图树中那些不必要的视图以及性能瓶颈。在这个demo中,...
HierarchyViewer for iOS ,我们知道,Hierarchy Viewer 是Android SDK包中非常好用的工具。开发及测试人...
GnuCash Android is a companion expense-tracker application for GnuCash (desktop) designed for Android. It allows you to record transactions on-the-go and later import the data into GnuCash for the ...
ViewServer是一个简单的类,您可以在Android应用程序中使用它来使用HierarchyViewer检查工具。 ViewServer需要Android SDK r12或更高版本。 快速开始 确认您需要此库(不需要 ) 如果您确实需要此库,请按照以下...
A Material design back port of Android's CalendarView. The goal is to have a Material look and feel, rather than 100% parity with the platform's implementation. Usage Add compile '...
13-性能分析之hierarchyviewer使用 14-性能分析之Lint规范代码 15-性能分析之突破内存不足 16-性能分析之内存检测工具介绍 与XMPP相关试题 17-什么是XMPP和XMPP的数据格式 18-及时聊天的展示形式 19-TCP和UDP...
With the rapid improvement of computation capability in high performance supercomputer system, the imbalance of performance between computation subsystem and storage subsystem has become more and ...
总共8份,这是第一个 eclipse indigo Version: ... Android Hierarchy Viewer 18.0.0.v201203301601-306762 Android Traceview 18.0.0.v201203301601-306762。 另外还装好了CDT,可以编写c,c++本地代码。一步到位。
随机森林图像matlab代码神智:摹拍摄和大号收入库我的法师一nalysis 什么? 一个用于高效分层图像分割的C ++ 11库。 如果使用此代码,请相应地引用以下论文: T. Liu,C。Jones,M。Seyedhosseini,T。Tasdizen。 一...