android studio上HierarchyViewer的使用实例
16lz
2021-01-23
使用方法:
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
new CopyOnWriteArrayList
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
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
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
更多相关文章
- Android 虚化图片的方法
- android 显示Gift图片
- [置顶] 我的Android进阶之旅------>Android电话窃听实例
- android imageview图片显示出来
- 2014.01.07 ——— android开发实例之QuickActionBar
- Android okHttp上传图片
- Mono for Android 显示远程图片
- Android 实现仿Window7图片预览窗格效果
- Android图片浏览之源码