使用方法:
1无法再真机运行,需要在模拟机运行
2app在manifest要添加
(1)<uses-permission android:name="android.permission.INTERNET"/>
(2)<application android:debugable=" true"
3在测试的activity中使用:
(1)添加三行代码:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewServer.get(this).addWindow(this);
}
public void onDestroy() {
super.onDestroy();
ViewServer.get(this).removeWindow(this);
}
public void onResume() {
super.onResume();
ViewServer.get(this).setFocusedWindow(this);
}
(2)点击运行as项目,然后模拟器运行程序,
(3)tools--android--androiddevice monitor
(4)界面打开后,没有找到,搜索hierarachy view即可,本人亲测,没有问题
直接上使用的源码:
创建ViewServer.java类(拷贝过去就可以):
package
com.linzhi.receiver
(替换)
;
import
android.app.Activity;
import
android.content.Context;
import
android.content.pm.ApplicationInfo;
import
android.os.Build;
import
android.text.TextUtils;
import
android.util.Log;
import
android.view.View;
import
android.view.ViewDebug;
import
java.io.BufferedReader;
import
java.io.BufferedWriter;
import
java.io.IOException;
import
java.io.InputStreamReader;
import
java.io.OutputStream;
import
java.io.OutputStreamWriter;
import
java.lang.reflect.Method;
import
java.net.InetAddress;
import
java.net.ServerSocket;
import
java.net.Socket;
import
java.util.HashMap;
import
java.util.List;
import
java.util.Map;
import
java.util.concurrent.CopyOnWriteArrayList;
import
java.util.concurrent.ExecutorService;
import
java.util.concurrent.Executors;
import
java.util.concurrent.locks.ReentrantReadWriteLock;
/**
*布局优化HierarchyViewer的类
*
* Created by sjy on 2017/5/2.
*/
public class
ViewServer
implements
Runnable {
/**
* The default port used to startview servers.
*/
private static final int VIEW_SERVER_DEFAULT_PORT
=
4939
;
private static final int VIEW_SERVER_MAX_CONNECTIONS
=
10
;
private static final
String
BUILD_TYPE_USER
=
"user"
;
// Debug facility
private static final
String
LOG_TAG
=
"ViewServer"
;
private static final
String
VALUE_PROTOCOL_VERSION
=
"4"
;
private static final
String
VALUE_SERVER_VERSION
=
"4"
;
// Protocol commands
// Returns the protocol version
private static final
String
COMMAND_PROTOCOL_VERSION
=
"PROTOCOL"
;
// Returns the server version
private static final
String
COMMAND_SERVER_VERSION
=
"SERVER"
;
// Lists all of the available windows in thesystem
private static final
String
COMMAND_WINDOW_MANAGER_LIST
=
"LIST"
;
// Keeps a connection open and notifies when thelist of windows changes
private static final
String
COMMAND_WINDOW_MANAGER_AUTOLIST
=
"AUTOLIST"
;
// Returns the focused window
private static final
String
COMMAND_WINDOW_MANAGER_GET_FOCUS
=
"GET_FOCUS"
;
private
ServerSocket
mServer
;
private final int mPort
;
private
Thread
mThread
;
private
ExecutorService
mThreadPool
;
private final
List
mListeners
=
new
CopyOnWriteArrayList();
private final
HashMap
mWindows
=
new
HashMap();
private final
ReentrantReadWriteLock
mWindowsLock
=
new
ReentrantReadWriteLock();
private
View
mFocusedWindow
;
private final
ReentrantReadWriteLock
mFocusLock
=
new
ReentrantReadWriteLock();
private static
ViewServer
sServer
;
/**
* Returns a unique instance of theViewServer. This method should only be
* called from the main thread ofyour application. The server will have
* the same lifetime as your process.
*
* If your application does not havethe
android:debuggable
* flag set in its manifest, the server returned by this method will
* be a dummy object that does not doanything. This allows you to use
* the same code in debug and releaseversions of your application.
*
* @param context A Context used to check whether the applicationis
* debuggable, this can be theapplication context
*/
public static
ViewServer get(Context context) {
ApplicationInfo info =context.getApplicationInfo();
if
(
BUILD_TYPE_USER
.equals(Build.
TYPE
) &&
(info.
flags
& ApplicationInfo.
FLAG_DEBUGGABLE
) !=
0
) {
if
(
sServer
==
null
) {
sServer
=
new
ViewServer(ViewServer.
VIEW_SERVER_DEFAULT_PORT
);
}
if
(!
sServer
.isRunning()) {
try
{
sServer
.start();
}
catch
(IOException e) {
Log.
d(
LOG_TAG
,
"Error:"
, e);
}
}
}
else
{
sServer
=
new
NoopViewServer();
}
return
sServer
;
}
private
ViewServer() {
mPort
= -
1
;
}
/**
* Creates a new ViewServerassociated with the specified window manager on the
* specified local port. The serveris not started by default.
*
* @param port The port for the server to listen to.
* @see #start()
*/
private
ViewServer(
int
port) {
mPort
= port;
}
/**
* Starts the server.
*
* @return True if the serverwas successfully created, or false if it already exists.
* @throws java.io.IOExceptionIf the server cannot be created.
* @see #stop()
* @see #isRunning()
*/
public boolean
start()
throws
IOException {
if
(
mThread
!=
null
) {
return false
;
}
mThread
=
new
Thread(
this
,
"LocalView Server [port="
+
mPort
+
"]"
);
mThreadPool
= Executors.newFixedThreadPool(
VIEW_SERVER_MAX_CONNECTIONS
);
mThread
.start();
return true
;
}
/**
* Stops the server.
*
* @return True if the serverwas stopped, false if an error occurred or if the
* server wasn't started.
* @see #start()
* @see #isRunning()
*/
public boolean
stop() {
if
(
mThread
!=
null
) {
mThread
.interrupt();
if
(
mThreadPool
!=
null
) {
try
{
mThreadPool
.shutdownNow();
}
catch
(SecurityException e) {
Log.
w(
LOG_TAG
,
"Couldnot stop all view server threads"
);
}
}
mThreadPool
=
null
;
mThread
=
null
;
try
{
mServer
.close();
mServer
=
null
;
return true
;
}
catch
(IOException e) {
Log.
w(
LOG_TAG
,
"Couldnot close the view server"
);
}
}
mWindowsLock
.writeLock().lock();
try
{
mWindows
.clear();
}
finally
{
mWindowsLock
.writeLock().unlock();
}
mFocusLock
.writeLock().lock();
try
{
mFocusedWindow
=
null
;
}
finally
{
mFocusLock
.writeLock().unlock();
}
return false
;
}
/**
* Indicates whether the server iscurrently running.
*
* @return True if the serveris running, false otherwise.
* @see #start()
* @see #stop()
*/
public boolean
isRunning() {
return mThread
!=
null
&&
mThread
.isAlive();
}
/**
* Invoke this method to register anew view hierarchy.
*
* @param activity The activity whose view hierarchy/window toregister
* @see #addWindow(android.view.View,String)
* @see #removeWindow(android.app.Activity)
*/
public void
addWindow(Activity activity) {
String name =activity.getTitle().toString();
if
(TextUtils.isEmpty(name)){
name =activity.getClass().getCanonicalName() +
"/0x"
+ System.identityHashCode(activity);
}
else
{
name +=
"("
+ activity.getClass().getCanonicalName() +
")"
;
}
addWindow(activity.getWindow().getDecorView(), name);
}
/**
* Invoke this method to unregister aview hierarchy.
*
* @param activity The activity whose view hierarchy/window tounregister
* @see #addWindow(android.app.Activity)
* @see #removeWindow(android.view.View)
*/
public void
removeWindow(Activity activity) {
removeWindow(activity.getWindow().getDecorView());
}
/**
* Invoke this method to register anew view hierarchy.
*
* @param view A view that belongs to the view hierarchy/windowto register
* @name name The name of theview hierarchy/window to register
* @see #removeWindow(android.view.View)
*/
public void
addWindow(View view, String name) {
mWindowsLock
.writeLock().lock();
try
{
mWindows
.put(view.getRootView(), name);
}
finally
{
mWindowsLock
.writeLock().unlock();
}
fireWindowsChangedEvent();
}
/**
* Invoke this method to unregister aview hierarchy.
*
* @param view A view that belongs to the view hierarchy/windowto unregister
* @see #addWindow(android.view.View,String)
*/
public void
removeWindow(View view) {
mWindowsLock
.writeLock().lock();
try
{
mWindows
.remove(view.getRootView());
}
finally
{
mWindowsLock
.writeLock().unlock();
}
fireWindowsChangedEvent();
}
/**
* Invoke this method to change thecurrently focused window.
*
* @param activity The activity whose view hierarchy/windowhasfocus,
* or null to remove focus
*/
public void
setFocusedWindow(Activity activity) {
setFocusedWindow(activity.getWindow().getDecorView());
}
/**
* Invoke this method to change thecurrently focused window.
*
* @param view A view that belongs to the view hierarchy/windowthat has focus,
* or null to remove focus
*/
public void
setFocusedWindow(View view) {
mFocusLock
.writeLock().lock();
try
{
mFocusedWindow
= view ==
null
?
null
: view.getRootView();
}
finally
{
mFocusLock
.writeLock().unlock();
}
fireFocusChangedEvent();
}
/**
* Main server loop.
*/
public void
run() {
try
{
InetAddress address =InetAddress.
getLocalHost();
mServer
=
new
ServerSocket(
mPort
,
VIEW_SERVER_MAX_CONNECTIONS
, address);
}
catch
(Exception e) {
Log.
w(
LOG_TAG
,
"StartingServerSocket error: "
,e);
}
while
(
mServer
!=
null
&& Thread.currentThread() ==
mThread
) {
// Any uncaught exception will crash the systemprocess
try
{
Socket client =
mServer
.accept();
if
(
mThreadPool
!=
null
) {
mThreadPool
.submit(
new
ViewServerWorker(client));
}
else
{
try
{
client.close();
}
catch
(IOException e) {
e.printStackTrace();
}
}
}
catch
(Exception e) {
Log.
w(
LOG_TAG
,
"Connectionerror: "
,e);
}
}
}
private static boolean
writeValue(Socket client, String value) {
boolean
result;
BufferedWriter out =
null
;
try
{
OutputStream clientStream =client.getOutputStream();
out =
new
BufferedWriter(
new
OutputStreamWriter(clientStream),
8
*
1024
);
out.write(value);
out.write(
"\n"
);
out.flush();
result =
true
;
}
catch
(Exception e) {
result =
false
;
}
finally
{
if
(out!=
null
) {
try
{
out.close();
}
catch
(IOException e) {
result =
false
;
}
}
}
return
result;
}
privatevoid
fireWindowsChangedEvent(){
for
(WindowListener listener :
mListeners
) {
listener.windowsChanged();
}
}
private void
fireFocusChangedEvent() {
for
(WindowListener listener :
mListeners
) {
listener.focusChanged();
}
}
private void
addWindowListener(WindowListener listener) {
if
(!
mListeners
.contains(listener)) {
mListeners
.add(listener);
}
}
private void
removeWindowListener(WindowListener listener) {
mListeners
.remove(listener);
}
private interface
WindowListener {
void
windowsChanged();
void
focusChanged();
}
private class
ViewServerWorker
implements
Runnable, WindowListener {
private
Socket
mClient
;
private boolean mNeedWindowListUpdate
;
private boolean mNeedFocusedWindowUpdate
;
private final
Object[]
mLock
=
new
Object[
0
];
public
ViewServerWorker(Socket client) {
mClient
= client;
mNeedWindowListUpdate
=
false
;
mNeedFocusedWindowUpdate
=
false
;
}
public void
run() {
BufferedReader in =
null
;
try
{
in =
new
BufferedReader(
new
InputStreamReader(
mClient
.getInputStream()),
1024
);
final
String request = in.readLine();
Log.
i(
"Command"
,
"===>"
+ request);
String command;
String parameters;
int
index = request.indexOf(
' '
);
if
(index== -
1
) {
command = request;
parameters =
""
;
}
else
{
command =request.substring(
0
, index);
parameters =request.substring(index +
1
);
}
boolean
result;
if
(
COMMAND_PROTOCOL_VERSION
.equalsIgnoreCase(command)) {
result =
writeValue(
mClient
,
VALUE_PROTOCOL_VERSION
);
}
else if
(
COMMAND_SERVER_VERSION
.equalsIgnoreCase(command)) {
result =
writeValue(
mClient
,
VALUE_SERVER_VERSION
);
}
else if
(
COMMAND_WINDOW_MANAGER_LIST
.equalsIgnoreCase(command)) {
result = listWindows(
mClient
);
}
else if
(
COMMAND_WINDOW_MANAGER_GET_FOCUS
.equalsIgnoreCase(command)) {
result =getFocusedWindow(
mClient
);
}
else if
(
COMMAND_WINDOW_MANAGER_AUTOLIST
.equalsIgnoreCase(command)) {
result =windowManagerAutolistLoop();
}
else
{
result =windowCommand(
mClient
, command, parameters);
}
if
(!result){
Log.
w(
LOG_TAG
,
"Anerror occurred with the command: "
+ command);
}
}
catch
(IOException e) {
Log.
w(
LOG_TAG
,
"Connectionerror: "
,e);
}
finally
{
if
(in!=
null
) {
try
{
in.close();
}
catch
(IOException e) {
e.printStackTrace();
}
}
if
(
mClient
!=
null
) {
try
{
mClient
.close();
}
catch
(IOException e) {
e.printStackTrace();
}
}
}
}
private boolean
windowCommand(Socket client, String command,String parameters) {
boolean
success =
true
;
BufferedWriter out =
null
;
try
{
// Find the hash code of the window
int
index = parameters.indexOf(
' '
);
if
(index== -
1
) {
index =parameters.length();
}
final
String code = parameters.substring(
0
,index);
int
hashCode = (
int
)Long.parseLong(code,
16
);
// Extract the command's parameter after thewindow description
if
(index< parameters.length()) {
parameters =parameters.substring(index +
1
);
}
else
{
parameters =
""
;
}
final
View window = findWindow(hashCode);
if
(window==
null
) {
returnfalse
;
}
// call stuff
final
Method dispatch = ViewDebug.
class
.getDeclaredMethod(
"dispatchCommand"
,
View.
class
, String.
class
, String.
class
, OutputStream.
class
);
dispatch.setAccessible(
true
);
dispatch.invoke(
null
, window, command, parameters,
new
UncloseableOutputStream(client.getOutputStream()));
if
(!client.isOutputShutdown()){
out =
new
BufferedWriter(
new
OutputStreamWriter(client.getOutputStream()));
out.write(
"DONE\n"
);
out.flush();
}
}
catch
(Exception e) {
Log.
w(
LOG_TAG
,
"Couldnot send command "
+command +
" with parameters "
+ parameters, e);
success =
false
;
}
finally
{
if
(out!=
null
) {
try
{
out.close();
}
catch
(IOException e) {
success =
false
;
}
}
}
return
success;
}
private
View findWindow(
int
hashCode) {
if
(hashCode== -
1
) {
View window =
null
;
mWindowsLock
.readLock().lock();
try
{
window =
mFocusedWindow
;
}
finally
{
mWindowsLock
.readLock().unlock();
}
return
window;
}
mWindowsLock
.readLock().lock();
try
{
for
(Map.Entry entry :
mWindows
.entrySet()) {
if
(System.identityHashCode(entry.getKey())== hashCode) {
return
entry.getKey();
}
}
}
finally
{
mWindowsLock
.readLock().unlock();
}
return null
;
}
private boolean
listWindows(Socket client) {
boolean
result =
true
;
BufferedWriter out =
null
;
try
{
mWindowsLock
.readLock().lock();
OutputStream clientStream= client.getOutputStream();
out =
new
BufferedWriter(
new
OutputStreamWriter(clientStream),
8
*
1024
);
for
(Map.Entry entry :
mWindows
.entrySet()) {
out.write(Integer.
toHexString(System.
identityHashCode(entry.getKey())));
out.write(
' '
);
out.append(entry.getValue());
out.write(
'\n'
);
}
out.write(
"DONE.\n"
);
out.flush();
}
catch
(Exception e) {
result =
false
;
}
finally
{
mWindowsLock
.readLock().unlock();
if
(out!=
null
) {
try
{
out.close();
}
catch
(IOException e) {
result =
false
;
}
}
}
return
result;
}
private boolean
getFocusedWindow(Socket client) {
boolean
result =
true
;
String focusName =
null
;
BufferedWriter out =
null
;
try
{
OutputStream clientStream= client.getOutputStream();
out =
new
BufferedWriter(
new
OutputStreamWriter(clientStream),
8
*
1024
);
View focusedWindow =
null
;
mFocusLock
.readLock().lock();
try
{
focusedWindow =
mFocusedWindow
;
}
finally
{
mFocusLock
.readLock().unlock();
}
if
(focusedWindow!=
null
) {
mWindowsLock
.readLock().lock();
try
{
focusName =
mWindows
.get(
mFocusedWindow
);
}
finally
{
mWindowsLock
.readLock().unlock();
}
out.write(Integer.
toHexString(System.
identityHashCode(focusedWindow)));
out.write(
' '
);
out.append(focusName);
}
out.write(
'\n'
);
out.flush();
}
catch
(Exception e) {
result =
false
;
}
finally
{
if
(out!=
null
) {
try
{
out.close();
}
catch
(IOException e) {
result =
false
;
}
}
}
return
result;
}
public void
windowsChanged() {
synchronized
(
mLock
){
mNeedWindowListUpdate
=
true
;
mLock
.notifyAll();
}
}
publicvoid
focusChanged() {
synchronized
(
mLock
){
mNeedFocusedWindowUpdate
=
true
;
mLock
.notifyAll();
}
}
private boolean
windowManagerAutolistLoop() {
addWindowListener(
this
);
BufferedWriter out =
null
;
try
{
out =
new
BufferedWriter(
new
OutputStreamWriter(
mClient
.getOutputStream()));
while
(!Thread.interrupted()) {
boolean
needWindowListUpdate =
false
;
boolean
needFocusedWindowUpdate =
false
;
synchronized
(
mLock
){
while
(!
mNeedWindowListUpdate
&& !
mNeedFocusedWindowUpdate
) {
mLock
.wait();
}
if
(
mNeedWindowListUpdate
) {
mNeedWindowListUpdate
=
false
;
needWindowListUpdate =
true
;
}
if
(
mNeedFocusedWindowUpdate
) {
mNeedFocusedWindowUpdate
=
false
;
needFocusedWindowUpdate =
true
;
}
}
if
(needWindowListUpdate){
out.write(
"LIST UPDATE\n"
);
out.flush();
}
if
(needFocusedWindowUpdate){
out.write(
"FOCUS UPDATE\n"
);
out.flush();
}
}
}
catch
(Exception e) {
Log.
w(
LOG_TAG
,
"Connectionerror: "
,e);
}
finally
{
if
(out!=
null
) {
try
{
out.close();
}
catch
(IOException e) {
// Ignore
}
}
removeWindowListener(
this
);
}
return true
;
}
}
private static class
UncloseableOutputStream
extends
OutputStream {
private final
OutputStream
mStream
;
UncloseableOutputStream(OutputStream stream) {
mStream
= stream;
}
public void
close()
throws
IOException {
// Don't close the stream
}
public boolean
equals(Object o) {
return mStream
.equals(o);
}
public void
flush()
throws
IOException {
mStream
.flush();
}
public int
hashCode() {
return mStream
.hashCode();
}
public
String toString() {
return mStream
.toString();
}
public void
write(
byte
[] buffer,
int
offset,
int
count)
throws
IOException {
mStream
.write(buffer, offset, count);
}
public void
write(
byte
[] buffer)
throws
IOException {
mStream
.write(buffer);
}
public void
write(
int
oneByte)
throws
IOException {
mStream
.write(oneByte);
}
}
/**
* 一个空的ViewServer类
*/
private static class
NoopViewServer
extends
ViewServer {
private
NoopViewServer() {
}
@Override
public boolean
start()
throws
IOException {
return false
;
}
@Override
public boolean
stop() {
returnfalse
;
}
@Override
public boolean
isRunning() {
return false
;
}
@Override
public void
addWindow(Activity activity) {
}
@Override
public void
removeWindow(Activity activity) {
}
@Override
public void
addWindow(View view, String name) {
}
@Override
public void
removeWindow(View view) {
}
@Override
public void
setFocusedWindow(Activity activity) {
}
@Override
public void
setFocusedWindow(View view) {
}
@Override
public void
run() {
}
}
}
参考:http://blog.csdn.net/kdsde/article/details/52984444