美文网首页
Android的简单Router实现

Android的简单Router实现

作者: 编程_书恨少 | 来源:发表于2019-03-18 17:57 被阅读0次

    1.为什么会想写Router

    1.a 最近准备开始正正经经的写android的应用了,所以最近在想一些架构和结构的东西。这里最先想到的就是统一处理页面的跳转方式,这样有什么好处呢?
    那我们先看一下传统的跳转传值方式

    a.A跳转B页面时,如果不需要下个页面回传数据,调用方法是这样婶的

            Intent intent = new Intent();
            intent.setClass(this, OneActivity.class);
            startActivity(intent);
    

    b.A跳转B页面时,如果需要下个页面回传数据,调用方法是这样婶的


    Snip20190318_3.png

    并且需要在B页面设置resultCode值

    Intent intent = new Intent();
    intent.setClass(OneActivity.this, MainActivity.class);
    intent.putExtra("price", 10);
    setResult(1, intent);
    finish();
    

    而且还需要在A页面进行方法的监听,才能实现回传数据,天哪

    @Override
        protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
    
            if (requestCode == 1 && resultCode == 1) {
                System.out.println(data);
            }
        }
    

    c.如果是A->B->C,然后C->A,进行反向传值的话,需要这样处理

    真的真的是好麻烦,并且这还是在不涉及到启动模式的情况下。如果涉及到不同的启动模式还需要实现不同的回调方法,才能监听到回传的数据。真的是感觉好麻烦。如果你对启动模式还不了解的话,请先移步到这里。https://www.cnblogs.com/claireyuancy/p/7387696.html

    这种处理方式,当页面会被几个页面跳回的话,处理起来就会很麻烦,只是记住每个页面的resultCode就很麻烦了,还要进行判断。想象一下,业务的判断
    竟然还要根据非业务的回传值判断

    好了,吐槽就到这里。那么我们来思考一个问题,如果是我们来做的话,想要以什么样的方式来进行参数的传递和参数回传的判断呢?
    基于传统方式的使用不便,调用方法偏多,并且碎片化的散落在不同的位置,使得代码的可读性下降,不易于后续维护。所以我提出了以下四点需求

    a.统一跳转方法
    b.统一跳转方法的传参方式
    c.统一回退方法
    d.统一回退方法的参数处理
    e.不用再关心不同启动模式下方法不同意的问题

    2.解决方案

    我的解决方案就是自己写一个路由,进行集中式的栈管理

    a 首先,我们要有一个集中管理栈

     /// 单例
        public static Router getInstance() {
            if (instance == null) {
                instance = new Router();
            }
    
            if (activityStack == null) {
                activityStack = new Stack<Activity>();
            }
            return instance;
        }
    

    b 统一跳转方式和回退方式

    /// 向前跳转方法
        public void routeForward(Class<?> cls, Map params) {
    
            instance.params = params;
    
            Intent intent = new Intent();
    
            Activity currentActivity = currentActivity();
    
            intent.setClass(currentActivity, cls);
    
            currentActivity.startActivity(intent);
        }
    
    
        /// 向后跳转到指定的控制器
        public void routeBack(Class<?> cls, Map params) {
    
            BaseActivity backActivity = (BaseActivity) getActivity(cls);
    
            if (backActivity == null) return;
    
            backActivity.backParams = params;
    
            for (int i = activityStack.size() - 1; i > 0; i--) {
    
                Activity activity = activityStack.get(i);
    
                if (activity.equals(backActivity) == false) {
                    finishActivity(activity);
                } else {
                    return;
                }
            }
        }
    
    /// 结束指定的Activity
        public void finishActivity(Activity activity) {
            if (activity != null && activityStack.contains(activity)) {
                activityStack.remove(activity);
                activity.finish();
                activity = null;
            } else  {
                Log.e("RouterError","移除控制器失败");
            }
        }
    

    c 统一传参方式

    压栈参数,和回退参数,统一在基类中进行管理

        public Map params;
    
        public Map backParams;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_base);
    
            Router.getInstance().addActivity(this);
    
            BaseActivity currentActivity = (BaseActivity) Router.getInstance().currentActivity();
    
            currentActivity.params = Router.getInstance().params;
        }
    

    在routeForward方法中,统一进行参数的赋值
    在routeBack方法中,统一进行回退页面参数的赋值

    3.解决方案演示Demo

    现在回到我们之前的问题,A页面跳转B页面,再从B页面跳回A页面时,传值的问题。

    1.现在基类中做好参数配置

     public Map params;
    
        public Map backParams;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_base);
    
            Router.getInstance().addActivity(this);
    
            BaseActivity currentActivity = (BaseActivity) Router.getInstance().currentActivity();
    
            currentActivity.params = Router.getInstance().params;
        }
    

    2.A页面跳转B页面,统一正向传值

    btn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                    Map params = new HashMap();
                    params.put("price", 11);
                    params.put("backClass", "A");
                    Router.getInstance().routeForward(B.class, params);
    
                }
            });
    

    在B页面获取A页面传来的值

            int price = (int) params.get("price");
    

    3.B页面跳转A页面,统一反向传值

    backBtn.setOnClickListener(new View.OnClickListener() {
    
                @Override
                public void onClick(View v) {
    
                    Map backParams = new HashMap();
                    backParams.put("price", 30);
                    Router.getInstance().routeBack(A.class, backParams);
                }
            });
    

    并且这个回退方法是根据Activity的类名识别的,即使是回退几个十几个页面也是同一个方法搞定。(这个回退方法可以改成让A页面传入参数String类型的类名,然后内部反射,指明会退到哪个页面,这样可以做到解耦,时间关系这里我就先不做修改了,使用的同学可以自行更改)

    这时页面就会回退到A,然后只需要在A页面的onResume方法中进行统一判断就可以了

    @Override
        protected void onResume() {
            super.onResume();
    
            if (backParams != null) {
                int price = (int) backParams.get("price");
            }
    
            System.out.println();
        }
    

    4.物理返回键处理

    在基类中添加了一个设置指定返回类型和回传参数的方法,设置了该方法,则认为物理返回键需要返回到Class类对应的activity,并回传相应参数,进行页面处理
    BaseActivity中添加方法

        public Class backPressedCls;
    
    /*物理返回键设置参数方法*/
        public void setPhysicalBack(Class<?> cls, Map par) {
            backPressedCls = cls;
            backParams = par;
        }
    

    在基类中重写onBackPressed方法

    @Override
        public void onBackPressed() {
            super.onBackPressed();
    
            System.out.println();
    
            if (backPressedCls != null) {
                Router.getInstance().routeBack(backPressedCls, backParams);
            }
        }
    

    外部使用时,提前设置好就可以了
    Demo中是在TwoActivity中进行了物理键返回设置

            Map params = new HashMap();
            params.put("price", 13);
            setPhysicalBack(OneActivity.class, params);
    

    最后,放出Demo的github地址https://github.com/majianghai/Router_android

    相关文章

      网友评论

          本文标题:Android的简单Router实现

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