我是靠谱客的博主 震动鸵鸟,最近开发中收集的这篇文章主要介绍UiautomatorViewer源码(三):提升快照速度,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

使用UiautomatorViewer工具快照屏幕时,感觉速度有点慢,所以这边就想着修改下源码来提升下速度,准确来说,应该算是换一种方式来快照屏幕。

主要的想法:新增一个按钮,添加一些按钮事件(保留了原本的快照功能)

按钮事件思路:

  1. 1、创建两个线程,线程A进行dump当前界面的层级结构数据,线程B进行屏幕截图

  2. 2、从手机内导出线程生成的两个文件到电脑端

  3. 3、调用工程内UiAutomatorViewer类的.setModel(model,new File(saveDirString+mobileXml), img);方法传入两个文件参数,随后在PC端生成快照。

  4. ps:每次打开uiautomatorViewer工具时,会去清空PC端指定目录下之前生成的数据。

OK,接下来,差不多到了上代码的环节。有部分代码是建立在UiautomatorViewer源码(一):浅析 和UiautomatorViewer源码(二):持久化 这两篇文章上的。

第一步:新增一个类,EasyScreenshotAction。

package com.android.uiautomator.actions;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

import com.android.ddmlib.IDevice;
import com.android.uiautomator.DebugBridge;
import com.android.uiautomator.UiAutomatorModel;
import com.android.uiautomator.UiAutomatorViewer;

public class EasyScreenshotAction extends Action {
	
	UiAutomatorViewer mViewer;
	
	
	public EasyScreenshotAction(UiAutomatorViewer viewer) {
		super("&SYNC");
		this.mViewer = viewer;
	}
	
	public ImageDescriptor getImageDescriptor() {
		return ImageHelper.loadImageDescriptorFromResource("images/screenshot.png");
	}
	
	public static String getCurrentTime(){
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");   
		return df.format(System.currentTimeMillis());   
	}
	
	public void run() {
		if(!DebugBridge.isInitialized()) {
			MessageDialog.openError(this.mViewer.getShell(), "Error obtaining Device Screenshot", "Unable to connect to adb. Check if adb is installed correctly.");
		} else {
			File saveDir=new File("C:\TempForUiautomatorView") ;
			if (!saveDir.exists()) {
				saveDir.mkdirs();
			}
			final String saveDirString = saveDir.getAbsolutePath()+File.separator;
			final IDevice device = this.pickDevice();
			if(device != null) {
				ProgressMonitorDialog dialog = new ProgressMonitorDialog(this.mViewer.getShell());
				try {
					dialog.run(true, false, new IRunnableWithProgress() {
						public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
							String adbHead = "adb ";
							try {
								if (EasyScreenshotAction.DevicePickerDialog.serial ==null || EasyScreenshotAction.DevicePickerDialog.serial.length()<1) {
								}else {
									adbHead="adb -s "+EasyScreenshotAction.DevicePickerDialog.serial+" ";
								}
								String  mobileScreenshot=getCurrentTime()+"_screenshot.png";
								String  mobileXml=getCurrentTime()+"_xml.uix";
								//使用多线程,来达到更快的同步速度
								MyThread screenThread=new MyThread(adbHead+"shell "/system/bin/screencap -p /data/local/tmp/"+mobileScreenshot+""");
								MyThread xmlThread=new MyThread(adbHead+"shell "uiautomator dump /data/local/tmp/"+mobileXml+""");
								monitor.setTaskName("Obtaining device screenshot");
								monitor.subTask("Taking UI XML snapshot...");
								ThreadPoolExecutor executor = new ThreadPoolExecutor(5,5, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());  
								executor.execute(screenThread);
								executor.execute(xmlThread);
								//等待线程池中所有线程执行完毕后,再开始pull操作
								executor.shutdown();
								try {  
									boolean loop = true;  
									do {    //等待所有任务完成  
										loop = !executor.awaitTermination(200, TimeUnit.MILLISECONDS);  //阻塞,直到线程池里所有任务结束
									} while(loop);  
								} catch (InterruptedException e) {  
									e.printStackTrace();  
								}  
								Runtime.getRuntime().exec(adbHead+"pull /data/local/tmp/"+mobileScreenshot+" "+saveDirString+mobileScreenshot).waitFor();
								monitor.subTask("Obtaining UI hierarchy");
								Runtime.getRuntime().exec(adbHead+"pull /data/local/tmp/"+mobileXml+" "+saveDirString+mobileXml).waitFor();
								UiAutomatorModel model = new UiAutomatorModel(new File(saveDirString+mobileXml));
								Image img = null;
								File screenshot = new File(saveDirString+mobileScreenshot);
								if(screenshot != null) {
									ImageData[] e = (new ImageLoader()).load(screenshot.getAbsolutePath());
									if(e.length < 1) {
										throw new RuntimeException("Unable to load image: " + screenshot.getAbsolutePath());
									}
									img = new Image(Display.getDefault(), e[0]);
								}
								mViewer.setModel(model,new File(saveDirString+mobileXml), img);
								//下次工具重启后删除目录下之前生成的所有文件
//								final String finalMobileScreenshot = mobileScreenshot;
//								final String finalMobileXml = mobileXml;
//								new Thread(new Runnable() {
//									public void run() {
//										if(new File(saveDirString+finalMobileScreenshot).exists()){
//											new File(saveDirString+finalMobileScreenshot).delete();
//										}
//										if(new File(saveDirString+finalMobileXml).exists()){
//											new File(saveDirString+finalMobileXml).delete();
//										}
//									}
//								}).start();
							} catch (Exception var4) {
								monitor.done();
								EasyScreenshotAction.this.showError(var4.getMessage(), var4);
								return;
							}
							monitor.done();
						}
					});
				} catch (Exception var4) {
					this.showError("Unexpected error while obtaining UI hierarchy", var4);
				}
				
			}
		}
	}
	
	private void showError(final String msg, final Throwable t) {
		this.mViewer.getShell().getDisplay().syncExec(new Runnable() {
			public void run() {
				Status s = new Status(4, "Screenshot", msg, t);
				ErrorDialog.openError(EasyScreenshotAction.this.mViewer.getShell(), "Error", "Error obtaining UI hierarchy", s);
			}
		});
	}
	
	private IDevice pickDevice() {
		List<?> devices = DebugBridge.getDevices();
		if(devices.size() == 0) {
			MessageDialog.openError(this.mViewer.getShell(), "Error obtaining Device Screenshot", "No Android devices were detected by adb.");
			return null;
		} else if(devices.size() == 1) {
			return (IDevice)devices.get(0);
		} else {
			EasyScreenshotAction.DevicePickerDialog dlg = new EasyScreenshotAction.DevicePickerDialog(this.mViewer.getShell(), devices);
			return dlg.open() != 0?null:dlg.getSelectedDevice();
		}
	}
	
	private static class DevicePickerDialog extends Dialog {
		
		private final List<?> mDevices;
		private final String[] mDeviceNames;
		private static int sSelectedDeviceIndex;
		private static String serial="";
		
		
		public DevicePickerDialog(Shell parentShell, List<?> devices) {
			super(parentShell);
			this.mDevices = devices;
			this.mDeviceNames = new String[this.mDevices.size()];
			
			for(int i = 0; i < devices.size(); ++i) {
				this.mDeviceNames[i] = ((IDevice)devices.get(i)).getName();
			}
			
		}
		
		protected Control createDialogArea(Composite parentShell) {
			Composite parent = (Composite)super.createDialogArea(parentShell);
			Composite c = new Composite(parent, 0);
			c.setLayout(new GridLayout(2, false));
			Label l = new Label(c, 0);
			l.setText("Select device: ");
			final Combo combo = new Combo(c, 2056);
			combo.setItems(this.mDeviceNames);
			int defaultSelection = sSelectedDeviceIndex < this.mDevices.size()?sSelectedDeviceIndex:0;
			combo.select(defaultSelection);
			sSelectedDeviceIndex = defaultSelection;
			serial = combo.getItem(combo.getSelectionIndex());
			combo.addSelectionListener(new SelectionAdapter() {
				public void widgetSelected(SelectionEvent arg0) {
					EasyScreenshotAction.DevicePickerDialog.sSelectedDeviceIndex = combo.getSelectionIndex();
					serial = combo.getItem(combo.getSelectionIndex());
//               System.out.println(serial);
				}
			});
			
//         System.out.println(serial);
			return parent;
		}
		
		public IDevice getSelectedDevice() {
			return (IDevice)this.mDevices.get(sSelectedDeviceIndex);
		}
	}
}

class MyThread extends Thread {
	public String cmd="";
	public MyThread(String cmdString) {
		this.cmd=cmdString;
	}
	
	public void run() {
		try {
			Runtime.getRuntime().exec(cmd);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}  
		
		
	}
}

第二步:在UiAutomatorViewer类的createContents()方法中添加按钮

protected Control createContents(Composite parent) {
      Composite c = new Composite(parent, 2048);
      GridLayout gridLayout = new GridLayout(1, false);
      gridLayout.marginWidth = 0;
      gridLayout.marginHeight = 0;
      gridLayout.horizontalSpacing = 0;
      gridLayout.verticalSpacing = 0;
      c.setLayout(gridLayout);
      GridData gd = new GridData(768);
      c.setLayoutData(gd);
      ToolBarManager toolBarManager = new ToolBarManager(8388608);
      toolBarManager.add(new OpenFilesAction(this));
      toolBarManager.add(new ScreenshotAction(this));
      //添加一个按钮
      toolBarManager.add(new EasyScreenshotAction(this));
      ToolBar tb = toolBarManager.createControl(c);
      tb.setLayoutData(new GridData(768));
      this.mUiAutomatorView = new UiAutomatorView(c, 2048);
      this.mUiAutomatorView.setLayoutData(new GridData(1808));
      return parent;
   }

第三步:编写按钮事件

public void run() {
	if(!DebugBridge.isInitialized()) {
		MessageDialog.openError(this.mViewer.getShell(), "Error obtaining Device Screenshot", "Unable to connect to adb. Check if adb is installed correctly.");
	} else {
		File saveDir=new File("C:\TempForUiautomatorView") ;
		if (!saveDir.exists()) {
			saveDir.mkdirs();
		}
		final String saveDirString = saveDir.getAbsolutePath()+File.separator;
		final IDevice device = this.pickDevice();
		if(device != null) {
			ProgressMonitorDialog dialog = new ProgressMonitorDialog(this.mViewer.getShell());
			try {
				dialog.run(true, false, new IRunnableWithProgress() {
					public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
						String adbHead = "adb ";
						try {
							if (EasyScreenshotAction.DevicePickerDialog.serial ==null || EasyScreenshotAction.DevicePickerDialog.serial.length()<1) {
							}else {
								adbHead="adb -s "+EasyScreenshotAction.DevicePickerDialog.serial+" ";
							}
							String  mobileScreenshot=getCurrentTime()+"_screenshot.png";
							String  mobileXml=getCurrentTime()+"_xml.uix";
							//使用多线程,来达到更快的同步速度
							MyThread screenThread=new MyThread(adbHead+"shell "/system/bin/screencap -p /data/local/tmp/"+mobileScreenshot+""");
							MyThread xmlThread=new MyThread(adbHead+"shell "uiautomator dump /data/local/tmp/"+mobileXml+""");
							monitor.setTaskName("Obtaining device screenshot");
							monitor.subTask("Taking UI XML snapshot...");
							ThreadPoolExecutor executor = new ThreadPoolExecutor(5,5, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());  
							executor.execute(screenThread);
							executor.execute(xmlThread);
							//等待线程池中所有线程执行完毕后,再开始pull操作
							executor.shutdown();
							try {  
								boolean loop = true;  
								do {    //等待所有任务完成  
									loop = !executor.awaitTermination(200, TimeUnit.MILLISECONDS);  //阻塞,直到线程池里所有任务结束
								} while(loop);  
							} catch (InterruptedException e) {  
								e.printStackTrace();  
							}  
							Runtime.getRuntime().exec(adbHead+"pull /data/local/tmp/"+mobileScreenshot+" "+saveDirString+mobileScreenshot).waitFor();
							monitor.subTask("Obtaining UI hierarchy");
							Runtime.getRuntime().exec(adbHead+"pull /data/local/tmp/"+mobileXml+" "+saveDirString+mobileXml).waitFor();
							UiAutomatorModel model = new UiAutomatorModel(new File(saveDirString+mobileXml));
							Image img = null;
							File screenshot = new File(saveDirString+mobileScreenshot);
							if(screenshot != null) {
								ImageData[] e = (new ImageLoader()).load(screenshot.getAbsolutePath());
								if(e.length < 1) {
									throw new RuntimeException("Unable to load image: " + screenshot.getAbsolutePath());
								}
								img = new Image(Display.getDefault(), e[0]);
							}

                            //调用setModel方法,在工具中生成快照
							mViewer.setModel(model,new File(saveDirString+mobileXml), img);
						} catch (Exception var4) {
							monitor.done();
							EasyScreenshotAction.this.showError(var4.getMessage(), var4);
							return;
						}
						monitor.done();
					}
				});
			} catch (Exception var4) {
				this.showError("Unexpected error while obtaining UI hierarchy", var4);
			}
			
		}
	}
}

第四步:每次启动时删除指定文件夹下的旧文件,在UiAutomatorViewer类的Main方法中添加

public static void main(String[] args) {
	   DebugBridge.init();
	   //每次启动时,都要去检查是否有旧文件如果有的话,就删除旧文件
	   File saveDir=new File("C:\TempForUiautomatorView") ;
	   if (saveDir.exists()) {
		   File TrxFiles[] = saveDir.listFiles();
		   for(File curFile:TrxFiles ){
			   curFile.delete();  
		   }
	   }
	   try {
         UiAutomatorViewer e = new UiAutomatorViewer();
         e.setBlockOnOpen(true);
         e.open();
      } catch (Exception var5) {
         var5.printStackTrace();
      } finally {
         DebugBridge.terminate();
      }
   }

最终效果:

有益效果:

1、快照速度还是有提升的。

2、有部分Android版本这个工具会报java.lang.reflect.InvocationTargetException,使用这种方法后,可以完美规避。

最后

以上就是震动鸵鸟为你收集整理的UiautomatorViewer源码(三):提升快照速度的全部内容,希望文章能够帮你解决UiautomatorViewer源码(三):提升快照速度所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(58)

评论列表共有 0 条评论

立即
投稿
返回
顶部