概述
使用UiautomatorViewer工具快照屏幕时,感觉速度有点慢,所以这边就想着修改下源码来提升下速度,准确来说,应该算是换一种方式来快照屏幕。
主要的想法:新增一个按钮,添加一些按钮事件(保留了原本的快照功能)
按钮事件思路:
-
1、创建两个线程,线程A进行dump当前界面的层级结构数据,线程B进行屏幕截图
-
2、从手机内导出线程生成的两个文件到电脑端
-
3、调用工程内UiAutomatorViewer类的.setModel(model,new File(saveDirString+mobileXml), img);方法传入两个文件参数,随后在PC端生成快照。
-
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源码(三):提升快照速度所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复