robotium-5.0.1源码解析 --ActivityUtils

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;
    // 普通的 activity
    private Activity activity;
    // 用于做延时的,看了UIAutomator的代码,都用SystemClock.sleep()了,比这个看着优雅
    private final Sleeper sleeper;
    // 日志标签,log 日志输出会带上robotium的标签.标记框架是他们的
    private final String LOG_TAG = "Robotium";
    // 短等待时间100ms
    private final int MINISLEEP = 100;
    // 用于activitymonitor循环抓取当前activity的等待50ms
    private 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,定时时间就是上面定义的50ms
    private 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,那么假如堆栈最为当前最新的activity 
        if (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);
        }
        // 返回所有的当前存活activity
        return 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;
            // 获取一个activityMonitor
            activityMonitor = 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() {
            @Override
            public void run() {
                // 检查activitymonitor是否已创建,避免null异常
                if (activityMonitor != null){
                    // 获取当前最新的activity
                    Activity activity = activityMonitor.getLastActivity();
                    // 检查获取对象是否为null
                    if (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()){
            // 获取当前位置的activity
            Activity 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,直到获取到一个存活的activity
            if (activityMonitor != null) {
                Activity activity = activityMonitor.getLastActivity();
                // 此处可能导致无限循环
                // activityMonitor初始化是为得到当前activity.应用又没有新打开页面,调用该方法就死循环了
                // 传入一个null的activity对象,在 初始化之后,没打开新的 activity就不断null,死循环了
                while (activity == null){
                    // 等待300ms
                    sleeper.sleepMini();
                    // 获取当前activity
                    activity = activityMonitor.getLastActivity();
                }
                // 非空对象加入堆栈
                addActivityToStack(activity);
            }
            else{
                // 等待300ms
                sleeper.sleepMini();
                // 初始化activityMonitor
                setupActivityMonitor();
                // 继续获取最新的activity
                waitForActivityIfNotAvailable();
            }
        }
    }

    /**
     * 获取当前最新的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();
        }
        // 获取堆栈中的栈顶activity
        if(!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)
    {
        // 获取所有存活的activity
        ArrayList<Activity> activitiesOpened = getAllOpenedActivities();
        boolean found = false;    
        // 遍历所有存活的activity,如果不存在指定的activity,则为false,找到为 true
        for(int i = 0; i < activitiesOpened.size(); i++){
            if(activitiesOpened.get(i).getClass().getSimpleName().equals(name)){
                found = true;
                break;
            }
        }
        // 如果找对需要返回的activity在activity堆栈中.那么尝试货到该activity
        if(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.
     */  

    @Override
    public void finalize() throws Throwable {
        // 停止activity监控定时任务
        activitySyncTimer.cancel();
        try {
            // 清理activityMonitor对象
            // Remove the monitor added during startup
            if (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 listener
        activitySyncTimer.cancel();
        // 获取所有存活的activity
        ArrayList<Activity> activitiesOpened = getAllOpenedActivities();
        // 结束所有存活的activity
        // Finish all opened activities
        for (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 measure
        finishActivity(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();
            }
        }
    }

}

文章参考地址:http://blog.csdn.net/huifeng1/article/details/18261981


你可能感兴趣的:(robotium-5.0.1源码解析 --ActivityUtils)