Activity跳转实现“从哪儿来回哪去”

作者: Kisson | 来源:发表于2016-06-13 20:27 被阅读793次

    标题中引号的内容,相信各位Android程序员会碰到这样的需求。特别是当一个功能有多个入口的时候,更种跳转会让人抓狂。有时候我们会利用Activity的SingleTask模式来完成清栈操作,但当业务场景变的复杂的时候,就需要我们考虑其他方式了。

    情景一

    Activity的跳转路径为:
    A->B->C->D->E->A。
    最终要求存在栈里面的Activity只有A。

    实现

    通过设置Activity A为SingleTask模式可以完成该跳转操作(当然前提是要求所有Activity在同一个Task里面)。同时,我们也可以通过自定义一个Activity栈来完成该操作。代码如下:

    import android.app.Activity;
    
    import java.util.ArrayList;
    
    /**
     * help to manager activity stack
     * @author kisson
     */
    public class ActivityStackManager {
    
        private static ArrayList<Activity> sActivityList = new ArrayList<>();
    
        private static class ActivityStackManagerHolder {
            private static ActivityStackManager sInstance = new ActivityStackManager();
        }
    
        public static ActivityStackManager getInstance() {
            return ActivityStackManagerHolder.sInstance;
        }
    
        public void addActivity(Activity activity) {
            sActivityList.add(activity);
        }
    
        /**
         * back to target activity
         *
         * @param addTime the add time of target activity
         * @return true if back to target activity successfully
         */
        public boolean back2TargetActivity(String addTime) {
            if (isTargetActivityExist(addTime)) {
                for (int i = sActivityList.size() - 1; i >= 0; i--) {
                    String var = ((BaseActivity) sActivityList.get(i)).getAddTime();
                    if (!var.equals(addTime)) {
                        popActivityFromStack(sActivityList.get(i));
                    } else {
                        return true;
                    }
                }
            }
            return false;
        }
    
        /**
         * back to target activity
         *
         * @param indexActivityClass the class of target activity
         * @return true if back to target activity successfully
         */
        public boolean back2TargetActivity(Class<Activity> indexActivityClass) {
            if (isTargetActivityExist(indexActivityClass)) {
                for (int i = sActivityList.size() - 1; i >= 0; i--) {
                    if (sActivityList.get(i).getClass() != indexActivityClass) {
                        popActivityFromStack(sActivityList.get(i));
                    } else {
                        return true;
                    }
                }
            }
            return false;
        }
    
        private boolean isTargetActivityExist(String addTime) {
            for (Activity activity : sActivityList) {
                if(activity == null){
                    continue;
                }
                if (((BaseActivity) activity).getAddTime().equals(addTime)) {
                    return true;
                }
            }
            return false;
        }
    
        private boolean isTargetActivityExist(Class<Activity> targetActivityClass) {
            for (Activity activity : sActivityList) {
               if(activity == null){
                    continue;
                }
                if (activity.getClass() == targetActivityClass) {
                    return true;
                }
            }
            return false;
        }
    
        private void popActivityFromStack(Activity activity) {
            if (activity != null && !activity.isFinishing()) {
                activity.finish();
                sActivityList.remove(activity);
            }
        }
    
        public void removeActivity(Activity activity) {
            sActivityList.remove(activity);
        }
    
    }
    

    以上写的Activity栈管理器比较简单,我们可以根据需求进行拓展。接着定义一个BaseActivity类,来完成入栈和出栈等相关操作,代码如下。

    import android.app.Activity;
    import android.os.Bundle;
    import android.os.SystemClock;
    
    /**
     * Created by kisson on 16/6/7.
     */
    public class BaseActivity extends Activity {
    
        private String addTime;
    
        public String getAddTime() {
            return addTime;
        }
    
        public void setAddTime(String addTime) {
            this.addTime = addTime;
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setAddTime(String.valueOf(SystemClock.currentThreadTimeMillis()));
            ActivityStackManager.getInstance().addActivity(this);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            ActivityStackManager.getInstance().removeActivity(this);
        }
    }
    

    这里在BaseActivity中定义了addTime变量,那么它的作用什么?
    比如Activity的跳转路径为:
    A->B->C->D->B'->E。
    在该跳转路径上Activity B 出现两次(Activity B的启动模式为standard),虽然它们是同一个Activity,但是是不同的的实例,因此通过Class来区分就显得不够用了。所以,在这里添加addTime变量,用于保证Activity实例的唯一性。
    接着,我们需要实现一个辅助类用于完成“情景一”的跳转。

    package com.dighammer.kisson.goback;
    
    import android.app.Activity;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * Created by kisson on 16/6/8.
     */
    public class ActivityPathManager {
    
        /**
         * 这里用数组记录源Activity而不是单独用一个String,是因为:在某一个跳转路径上可能有多个注册源Activity行为
         * 比如A->B->C-D-A,在A中进行注册源Activity,
         * 同时另外一条链路M->N->B->C->D->M(当然这两条链路是不可能同时发生的),需要在B中注册源Activity。但是这两条链路有重合部分,
         * 如果仅仅用String来表示addTime,会存在覆盖的情况,因此用数组来保存addTime,但是只有第一条数据有效。
         **/
        private static List<String> sAddTimeList = new ArrayList<>();
    
        private static List<Class<Activity>> sActivityClassList = new ArrayList<>();
    
        private static class ActivityPathManagerHolder {
            private static ActivityPathManager sInstance = new ActivityPathManager();
        }
    
        public static ActivityPathManager getInstance() {
            return ActivityPathManagerHolder.sInstance;
        }
    
        /**
         * 注册源Activity
         *
         * @param addTime Activity的创建时间,可以唯一表示某一Activity
         */
        public void registerSourceActivity(String addTime) {
            sAddTimeList.add(addTime);
        }
    
        /**
         * 注册源Activity
         *
         * @param indexClass Activity的类名
         */
        public void registerSourceActivity(Class<Activity> indexClass) {
            sActivityClassList.add(indexClass);
        }
    
        /**
         * 当从源Activity通过任意跳转路径到达目标Activity时,调用此方法后可以返回到源Activity
         *
         * @return 如果是true,直接跳转到源Activity;如果是false,走原有逻辑
         */
        public boolean back2SourceActivity() {
            if (!sAddTimeList.isEmpty()) {
                ActivityStackManager.getInstance().back2TargetActivity(sAddTimeList.get(0));
                clearAddTime();
                return true;
            }
            return false;
        }
    
        /**
         * 当从源Activity通过任意跳转路径到达目标Activity时,调用此方法后可以返回到源Activity
         *
         * @return 如果是true,直接跳转到源Activity;如果是false,走原有逻辑
         */
        public boolean back2SourceActivity2() {
            if (!sActivityClassList.isEmpty()) {
                ActivityStackManager.getInstance().back2TargetActivity(sActivityClassList.get(0));
                clearClass();
                return true;
            }
            return false;
        }
    
        /**
         * 当从源Activity通过任意跳转路径到达目标Activity时,调用此方法后可以返回到源Activity,此方法不需要注册Activity
         *
         * @param addTime 源Activity的添加时间
         * @return 如果是true,直接跳转到源Activity;如果是false,走原有逻辑
         */
        public boolean back2SourceActivity(String addTime) {
            if (addTime != null) {
                ActivityStackManager.getInstance().back2TargetActivity(addTime);
                return true;
            }
            return false;
        }
    
        /**
         * 当从源Activity通过任意跳转路径到达目标Activity时,调用此方法后可以返回到源Activity,此方法不需要注册Activity
         *
         * @param indexClass 源Activity的类
         * @return 如果是true,直接跳转到源Activity;如果是false,走原有逻辑
         */
        public boolean back2SourceActivity(Class<Activity> indexClass) {
            if (indexClass != null) {
                ActivityStackManager.getInstance().back2TargetActivity(indexClass);
                return true;
            }
            return false;
        }
    
    
        private void clearAddTime() {
            sAddTimeList.clear();
        }
    
        private void clearClass() {
            sActivityClassList.clear();
        }
    
        /**
         * 清除所有已经注册Activity的addTime
         * notice:在你的源Activity的onCreate和onRestart方法调用该方法!
         */
        public void unregisterSourceActivity(String addTime) {
            sAddTimeList.remove(addTime);
        }
    
        /**
         * 清除所有已经注册Activity的Class
         * notice:在你的源Activity的onCreate和onRestart方法调用该方法!
         */
        public void unregisterSourceActivity(Class<Activity> indexClass) {
            sActivityClassList.remove(indexClass);
        }
    }
    

    用法

    在源Activity中通过调用ActivityPathManager的registerSourceActivity方法进行注册(注意在源Activity的onCreate和onRestart方法进行注销),比如。

        public void onClick(View view) {
            startActivity(new Intent(SourceActivity.this, AActivity.class));
            ActivityPathManager.getInstance().registerSourceActivity(getAddTime());
        }
    

    在最终跳转到的目标Activity通过调用ActivityPathManager的back2SourceActivity方法返回到源Activity,比如。

        public void onClick(View view){
            ActivityPathManager.getInstance().back2SourceActivity();
        }
    

    最终的结果可以成功返回到源Activity。

    情景二

    本文所实现的“从哪来回哪去”功能并不能顾及到所有跳转情况,但是我们可以根据需求在此基础上进行拓展。
    比如跳转路径为A->B->C->D->E->F。
    最终要求栈里只有A和F,并且F后退是返回到A的。
    这种跳转需求,Activity的四种启动模式就无法搞定了。
    但是我们可以增加ActivityPathManager和ActivityStackManager类中的方法,来完成相应的功能。
    在ActivityStackManager类中增加back2TargetActivityExceptTop方法,代码如下。

        /**
         * back to target activity but do not pop the top activity
         *
         * @param addTime the add time of target activity
         * @return true if back to target activity successfully
         */
        public boolean back2TargetActivityExceptTop(String addTime) {
            if (isTargetActivityExist(addTime)) {
                for (int i = sActivityList.size() - 2; i >= 0; i--) {
                    String var = ((BaseActivity) sActivityList.get(i)).getAddTime();
                    if (!var.equals(addTime)) {
                        popActivityFromStack(sActivityList.get(i));
                    } else {
                        return true;
                    }
                }
            }
            return false;
        }
    

    通用在ActivityPathManager类中增加back2SourceActivityExceptTop方法,代码如下:

        public boolean back2SourceActivityExceptTop() {
            if (!sAddTimeList.isEmpty()) {
                ActivityStackManager.getInstance().back2TargetActivityExceptTop(sAddTimeList.get(0));
                clearAddTime();
                return true;
            }
            return false;
        }
    

    最后

    欢迎大家来提出宝贵意见,或者某些情景下,本文功能无法实现的!

    相关文章

      网友评论

      本文标题:Activity跳转实现“从哪儿来回哪去”

      本文链接:https://www.haomeiwen.com/subject/meeprttx.html