Robotium学习笔记三

来源:互联网 发布:创度软件下载 编辑:程序博客网 时间:2024/05/20 17:27

上一篇说到Serach类的方法,本想把SOLO类里面几类的方法都做一个记录,结果发现有很多方法其实大同小异,在这里做一下补充说明

我们拿到了页面中的所有view并且可以从中搜索需要的view,那么solo类中的例如 waitFor,get,is还有assert类型的方法就都可以使用共同的方法来获取,在这些查找和判断类型的方法中几乎都会调用ViewFetcher类下的getCurrentViews方,而后调用getViews方法,最后不论是获取(get),还是判断(wait,is,assert)就都能做到了.

public <T extends View> ArrayList<T> getCurrentViews(Class<T> classToFilterBy, boolean includeSubclasses, View parent) {ArrayList<T> filteredViews = new ArrayList<T>();List<View> allViews = getViews(parent, true);for(View view : allViews){if (view == null) {continue;}Class<? extends View> classOfView = view.getClass();if (includeSubclasses && classToFilterBy.isAssignableFrom(classOfView) || !includeSubclasses && classToFilterBy == classOfView) {filteredViews.add(classToFilterBy.cast(view));}}allViews = null;return filteredViews;}

另外还有一个很重要的类 ActivityUtils 这个类主要借助Instrumentation类控制,监控activity,还有对acticity栈的管理,在有些方法中可以直接通过findViewByid的方法直接获取view,或者遍历栈返回到指定的页面,还有一些set类方法也直接依赖于这个ActivityUtils类

http://www.tuicool.com/articles/677Zvi 这篇文章的作者已经做了详细的备注


package com.robotium.solo;import java.lang.ref.WeakReference;import java.util.ArrayList;import java.util.Iterator;import java.util.Stack;import java.util.Timer;import java.util.TimerTask;import junit.framework.Assert;import android.app.Activity;import android.app.Instrumentation;import android.app.Instrumentation.ActivityMonitor;import android.content.IntentFilter;import android.util.Log;import android.view.KeyEvent;/** * 用于Activity操作的工具类 * Contains activity related methods. Examples are: * getCurrentActivity(), getActivityMonitor(), setActivityOrientation(int orientation). * * @author Renas Reda, renas.reda@robotium.com * */class ActivityUtils {// Instrument 各种事件发送强大利器private final Instrumentation inst;// activitymonitor 所有的activity变化都可以监控private ActivityMonitor activityMonitor;// 普通的 activityprivate Activity activity;// 用于做延时的,看了UIAutomator的代码,都用SystemClock.sleep()了,比这个看着优雅private final Sleeper sleeper;// 日志标签,log 日志输出会带上robotium的标签.标记框架是他们的private final String LOG_TAG = “Robotium”;// 短等待时间100msprivate final int MINISLEEP = 100;// 用于activitymonitor循环抓取当前activity的等待50msprivate static final int ACTIVITYSYNCTIME = 50;// activity堆栈,用于存放所有开启状态的activity,采用WeakReference,避免对GC产生影响private Stack<WeakReference<Activity>> activityStack;// Activity对象引用变量,使用WeakReference,避免对GC产生影响private WeakReference<Activity> weakActivityReference;// 堆栈存储activity的名字private Stack<String> activitiesStoredInActivityStack;// 定时器,用于定时获取最新的activity,定时时间就是上面定义的50msprivate Timer activitySyncTimer;/** * 构造函数 * Constructs this object. * * @param inst the {@code Instrumentation} instance. 获取instrument一般都是通过getIntrument()获取的传递给构造函数 * @param activity the start {@code Activity} 应用启动的activity,一般是传递mainActivity * @param sleeper the {@code Sleeper} instance Sleep工具类 */public ActivityUtils(Instrumentation inst, Activity activity, Sleeper sleeper) {this.inst = inst;this.activity = activity;this.sleeper = sleeper;createStackAndPushStartActivity();activitySyncTimer = new Timer();activitiesStoredInActivityStack = new Stack<String>();// 开启 activity监控setupActivityMonitor();setupActivityStackListener();}/** * 创建一个堆栈,用于存放创建的activity.因为 activity创建了新的老的就在后面了,所以使用堆栈的先进后出功能 * * Creates a new activity stack and pushes the start activity. */private void createStackAndPushStartActivity(){// 初始化一个堆栈activityStack = new Stack<WeakReference<Activity>>();// 如果构造函数传入的activity不为null,那么假如堆栈最为当前最新的activityif (activity != null){WeakReference<Activity> weakReference = new WeakReference<Activity>(activity);activity = null;activityStack.push(weakReference);}}/** * 返回所有处于打开或运行状态的activity,一般代码编写返回一个 List<Activity>较好 * Returns a {@code List} of all the opened/active activities. * * @return a {@code List} of all the opened/active activities */public ArrayList<Activity> getAllOpenedActivities(){// 构造一个 List 用于返回 activity数组ArrayList<Activity> activities = new ArrayList<Activity>();// 遍历activityStack堆栈中的所有activity 加如到List中Iterator<WeakReference<Activity>> activityStackIterator = activityStack.iterator();// 判断是否可以继续遍历while(activityStackIterator.hasNext()){// 获取当前activity,堆栈指针指向下个activity对象Activity activity = activityStackIterator.next().get();// 判断activity对象非空,才加入,可能由于gc导致对象已经被回收,导致null异常if(activity!=null)activities.add(activity);}// 返回所有的当前存活activityreturn activities;}/** * 通过instrument构造一个activityMonitor用于监控activity的创建 * This is were the activityMonitor is set up. The monitor will keep check * for the currently active activity. */private void setupActivityMonitor() {try {// 为了addMonitor方法需要,创建一个null对象IntentFilter filter = null;// 获取一个activityMonitoractivityMonitor = inst.addMonitor(filter, null, false);} catch (Exception e) {e.printStackTrace();}}/** * 通过定时任务不断刷新获取当前最新创建的activity,定时每50ms运行一次,因此存在一定的概率获取的不是最新的activity * This is were the activityStack listener is set up. The listener will keep track of the * opened activities and their positions. */private void setupActivityStackListener() {// 创建一个定时任务TimerTask activitySyncTimerTask = new TimerTask() {@Overridepublic void run() {// 检查activitymonitor是否已创建,避免null异常if (activityMonitor != null){// 获取当前最新的activityActivity activity = activityMonitor.getLastActivity();// 检查获取对象是否为nullif (activity != null){// 如果该activity已经存储在activity堆栈中,则不进行重复添加if(!activitiesStoredInActivityStack.isEmpty() && activitiesStoredInActivityStack.peek().equals(activity.toString())){return;}// 移除可能存在同名对象,避免堆栈加入脏数据if (activitiesStoredInActivityStack.remove(activity.toString())){removeActivityFromStack(activity);}// 确保activity还处于存活状态,并加入堆栈if (!activity.isFinishing()){addActivityToStack(activity);}}}}};// 开启定时任务,每50ms执行一次activitySyncTimer.schedule(activitySyncTimerTask, 0, ACTIVITYSYNCTIME);}/** * 从activity堆栈中移除一个activity * Removes a given activity from the activity stack * * @param activity the activity to remove */private void removeActivityFromStack(Activity activity){// 遍历整个堆栈Iterator<WeakReference<Activity>> activityStackIterator = activityStack.iterator();while(activityStackIterator.hasNext()){// 获取当前位置的activityActivity activityFromWeakReference = activityStackIterator.next().get();// 如果发现当前堆栈中存在 null对象,则移除之if(activityFromWeakReference == null){activityStackIterator.remove();}// 找对了对应的activity,则移除之if(activity!=null && activityFromWeakReference!=null && activityFromWeakReference.equals(activity)){activityStackIterator.remove();}}}/** * 获取ActivityMonitor对象,一般这个也没啥用 * Returns the ActivityMonitor used by Robotium. * * @return the ActivityMonitor used by Robotium */public ActivityMonitor getActivityMonitor(){return activityMonitor;}/** * 设置屏幕方向,横或者纵 * Sets the Orientation (Landscape/Portrait) for the current activity. * * @param orientation An orientation constant such as {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE} or {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_PORTRAIT} */public void setActivityOrientation(int orientation){Activity activity = getCurrentActivity();activity.setRequestedOrientation(orientation);}/** * 获取当前的activity,true标识需要等待500ms,false标识不需要等待500ms * Returns the current {@code Activity}, after sleeping a default pause length. * * @param shouldSleepFirst whether to sleep a default pause first * @return the current {@code Activity} */public Activity getCurrentActivity(boolean shouldSleepFirst) {return getCurrentActivity(shouldSleepFirst, true);}/** * 获取当前activity,并且等待500ms * Returns the current {@code Activity}, after sleeping a default pause length. * * @return the current {@code Activity} */public Activity getCurrentActivity() {return getCurrentActivity(true, true);}/** * 把activity加入堆栈中 * Adds an activity to the stack * * @param activity the activity to add */private void addActivityToStack(Activity activity){// activity名加入堆栈activitiesStoredInActivityStack.add(activity.toString());weakActivityReference = new WeakReference<Activity>(activity);activity = null;// activity弱引用对象加入堆栈activityStack.push(weakActivityReference);}/** * 一直等待,知道出现抓取到一个存活的activity,未找到存活activity则不断迭代循环,有概率导致无限死循环 * 可自行修改添加一个超时时间,避免引发无法循环 * Waits for an activity to be started if one is not provided * by the constructor. */private final void waitForActivityIfNotAvailable(){// 如果当前堆栈中的activity为空,当初始化时传入的activity为null,可导致该状态if(activityStack.isEmpty() || activityStack.peek().get() == null){// 不断尝试获取当前activity,直到获取到一个存活的activityif (activityMonitor != null) {Activity activity = activityMonitor.getLastActivity();// 此处可能导致无限循环// activityMonitor初始化是为得到当前activity.应用又没有新打开页面,调用该方法就死循环了// 传入一个null的activity对象,在 初始化之后,没打开新的 activity就不断null,死循环了while (activity == null){// 等待300mssleeper.sleepMini();// 获取当前activityactivity = activityMonitor.getLastActivity();}// 非空对象加入堆栈addActivityToStack(activity);}else{// 等待300mssleeper.sleepMini();// 初始化activityMonitorsetupActivityMonitor();// 继续获取最新的activitywaitForActivityIfNotAvailable();}}}/** * 获取当前最新的activity,shouldSleepFirst为true,那么等待500ms后在获取, * waitForActivity为true那么尝试获取最新的activity,为false则不尝试获取最新的,直接从activity堆栈中获取栈顶的activity返回 * * Returns the current {@code Activity}. * * @param shouldSleepFirst whether to sleep a default pause first * @param waitForActivity whether to wait for the activity * @return the current {@code Activity} */public Activity getCurrentActivity(boolean shouldSleepFirst, boolean waitForActivity) {// 是否需要等待if(shouldSleepFirst){sleeper.sleep();}// 是否需要获取最新的if(waitForActivity){waitForActivityIfNotAvailable();}// 获取堆栈中的栈顶activityif(!activityStack.isEmpty()){activity=activityStack.peek().get();}return activity;}/** * 检查 activity堆栈是否为空 * Check if activity stack is empty. * * @return true if activity stack is empty */public boolean isActivityStackEmpty() {return activityStack.isEmpty();}/** * 通过不断触发返回按钮尝试回到指定名字的activity * Returns to the given {@link Activity}. * * @param name the name of the {@code Activity} to return to, e.g. {@code “MyActivity”} */public void goBackToActivity(String name){// 获取所有存活的activityArrayList<Activity> activitiesOpened = getAllOpenedActivities();boolean found = false;// 遍历所有存活的activity,如果不存在指定的activity,则为false,找到为 truefor(int i = 0; i < activitiesOpened.size(); i++){if(activitiesOpened.get(i).getClass().getSimpleName().equals(name)){found = true;break;}}// 如果找对需要返回的activity在activity堆栈中.那么尝试货到该activityif(found){// 判断当前activity是否为需要返回的,不是是不断发送返回指令,直到找到while(!getCurrentActivity().getClass().getSimpleName().equals(name)){try{inst.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);// instrument 触发该指令可能导致的exception}catch(SecurityException ignored){}}}// 没有找到则打印先关日志.并且抛错else{for (int i = 0; i < activitiesOpened.size(); i++){Log.d(LOG_TAG, “Activity priorly opened: “+ activitiesOpened.get(i).getClass().getSimpleName());}Assert.fail(“No Activity named: ‘” + name + “‘ has been priorly opened”);}}/** * 在当前activity中按照id查询String * Returns a localized string. * * @param resId the resource ID for the string * @return the localized string */public String getString(int resId){Activity activity = getCurrentActivity(false);return activity.getString(resId);}/** * solo生命周期结束,释放相关资源 * Finalizes the solo object. */@Overridepublic void finalize() throws Throwable {// 停止activity监控定时任务activitySyncTimer.cancel();try {// 清理activityMonitor对象// Remove the monitor added during startupif (activityMonitor != null) {inst.removeMonitor(activityMonitor);activityMonitor = null;}} catch (Exception ignored) {}super.finalize();}/** * 关闭所有存活的activity * All activites that have been opened are finished. */public void finishOpenedActivities(){// 停止activity监听定时任务// Stops the activityStack listeneractivitySyncTimer.cancel();// 获取所有存活的activityArrayList<Activity> activitiesOpened = getAllOpenedActivities();// 结束所有存活的activity// Finish all opened activitiesfor (int i = activitiesOpened.size()-1; i >= 0; i–) {sleeper.sleep(MINISLEEP);finishActivity(activitiesOpened.get(i));}// 释放对象activitiesOpened = null;sleeper.sleep(MINISLEEP);// Finish the initial activity, pressing Back for good measurefinishActivity(getCurrentActivity(true, false));this.activity = null;sleeper.sleepMini();// 点击2次back按钮退出程序try {inst.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);sleeper.sleep(MINISLEEP);inst.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);} catch (Throwable ignored) {// Guard against lack of INJECT_EVENT permission}// 清空堆栈信息clearActivityStack();}/** *清空堆栈信息 * Clears the activity stack. */private void clearActivityStack(){activityStack.clear();activitiesStoredInActivityStack.clear();}/** * 调用activity的清理方法结束activity生命周期 * Finishes an activity. * * @param activity the activity to finish */private void finishActivity(Activity activity){if(activity != null) {try{activity.finish();}catch(Throwable e){e.printStackTrace();}}}}

0 0
原创粉丝点击