在我们谈到这个问题时,我们不得不用的例子就是Robotium,这是当前最流行的除了Google的就属Robotium,很多其他的工具都基于Robotium修改而成。
针对Robotium怎么获得应用的windowmanager对象,然后再获取屏幕上的WindorDecorViews。
因为测试应用和被测应用是同一个进程中,所以夸应用是不可能的事情,所以不要试图去获取不属于该被测应用的Activity。
下面是怎么获取windowmanager对象的code
private static Class<?> windowManager;
static{
try {
String windowManagerClassName;
if (android.os.Build.VERSION.SDK_INT >= 17) {
windowManagerClassName = "android.view.WindowManagerGlobal";
} else {
windowManagerClassName = "android.view.WindowManagerImpl";
}
windowManager = Class.forName(windowManagerClassName);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (SecurityException e) {
e.printStackTrace();
}
}
我们可以看到,当sdk>=17时候,WindowManagerGlobal获取窗口ViewGroup的
那么我们再看看它是怎么获取里面的方法和属性呢?
/**
* Returns the WindorDecorViews shown on the screen.
*
* @return the WindorDecorViews shown on the screen
*/
public View[] getWindowDecorViews()
{
Field viewsField;
Field instanceField;
try {
viewsField = windowManager.getDeclaredField("mViews");
instanceField = windowManager.getDeclaredField(windowManagerString);
viewsField.setAccessible(true);
instanceField.setAccessible(true);
Object instance = instanceField.get(null);
return (View[]) viewsField.get(instance);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
/**
* Sets the window manager string.
*/
private void setWindowManagerString(){
if (android.os.Build.VERSION.SDK_INT >= 17) {
windowManagerString = "sDefaultWindowManager";
} else if(android.os.Build.VERSION.SDK_INT >= 13) {
windowManagerString = "sWindowManager";
} else {
windowManagerString = "mWindowManager";
}
}
我们来温故一下java反射吧:
反射常用的类和函数:Class,Constructor,Field, Method, 其中Class是类的对象,Constructor是类的构造函数对象,Field是类的属性对象实例,Method是方法对象实例。
Class:
1)Class clazz = Class.forName("com.android.settings.SettingsActivity")
2)基本类型:Class inter = Interger.TYPE
3) Class clz = MyClass.class
Constructor:
Constructor getConstructor(Class[] params) 用来获取特殊参数的公共构造函数
Constructor[] getConstructors()用来获取所有公共构造函数
getDeclaredConstructors()获取所有构造函数
getDeclaredConstructors(Class[] params) 获取所有带参数构造函数
获取属性的方法:
Field getField(String name)获取公共属性
Field[] getFields()获取所有公共属性
Fiel[] getDeclaredFields()获取所有属性
Field getDeclaredFields(String name)获取name属性
Method:
Method getMethod(String name, Class[] params)获取公共method
Method[] getMethods()获取所有公共methods
Fiel[] getDeclaredMethods()获取所有method
Field getDeclaredMethods(String name, Class[] params)获取name, methods
Robotium 其他的反射还有在获取ActionMenuItem的时候,这里用到的反射比较齐全,有方法,有属性
/**
* Clicks on an ActionBar Home/Up button.
*/
public void clickOnActionBarHomeButton() {
Activity activity = activityUtils.getCurrentActivity();
MenuItem homeMenuItem = null;
try {
Class<?> cls = Class.forName("com.android.internal.view.menu.ActionMenuItem");
Class<?> partypes[] = new Class[6];
partypes[0] = Context.class;
partypes[1] = Integer.TYPE;
partypes[2] = Integer.TYPE;
partypes[3] = Integer.TYPE;
partypes[4] = Integer.TYPE;
partypes[5] = CharSequence.class;
Constructor<?> ct = cls.getConstructor(partypes);
Object argList[] = new Object[6];
argList[0] = activity;
argList[1] = 0;
argList[2] = android.R.id.home;
argList[3] = 0;
argList[4] = 0;
argList[5] = "";
homeMenuItem = (MenuItem) ct.newInstance(argList);
} catch (Exception ex) {
Log.d(LOG_TAG, "Can not find methods to invoke Home button!");
}
if (homeMenuItem != null) {
activity.getWindow().getCallback().onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, homeMenuItem);
}
}
另外一个,使用反射方法的一个例子
/**
* Parse a timeout value set using adb shell.
*
* There are two options to set the timeout. Set it using adb shell:
* <br><br>
* 'adb shell setprop solo_large_timeout milliseconds'
* <br>
* 'adb shell setprop solo_small_timeout milliseconds'
* <br><br>
* Set the values directly using setLargeTimeout() and setSmallTimeout
*
* @param property name of the property to read the timeout from
* @param defaultValue default value for the timeout
* @return timeout in milliseconds
*
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private static int initializeTimeout(String property, int defaultValue) {
try {
Class clazz = Class.forName("android.os.SystemProperties");
Method method = clazz.getDeclaredMethod("get", String.class);
String value = (String) method.invoke(null, property);
return Integer.parseInt(value);
} catch (Exception e) {
return defaultValue;
}
}
所以在我们在做我们的自动化框架的时候,在必要的时候可以使用反射机制获取我们想要的东西,不过我们要注意进程安全行不要跨越Android规定的,不然会是徒劳无功的。