美文网首页
Router方案说明

Router方案说明

作者: 8bc18a303943 | 来源:发表于2017-06-12 17:14 被阅读86次

    前言

    该方案是阐述Android平台组件化方案设计中Router 组件的的设计思路。针对猫窝科技组件化开发工作,进行Router组件的业务设计,实现业务模块层级的全局统跳协议,通过协议完成组件注册和组件调用。

    组件化的历史
    > copy from 再谈组件化

    自从1948年6月21日,软件模式在曼切斯特大学诞生以来,软件体系结构经历了四个阶段:无结构、萌芽、初级和高级阶段。自上世纪 90 年代步入高级阶段以来,软件开发的目标是使软件具备较好的自适应性、互操作性、可扩展性和可重用性,软件开发强调采用构件化技术和体系结构技术。

    在项目的实施阶段,体系结构是建立开发人员的组织、分工、协调开发人员关系和配合的依据。在项目的维护升级阶段,对软件的任何扩充和修改都要在体系结构的指导下进行,以维护整体设计的合理性和正确性,并为维护升级的复杂性和代价分析提供依据。

    在日常开发中,程序员一直考虑的一个问题是如何让代码变的简单。抛开技术大牛和大神程序员这条路(毕竟开发人员是一种金字塔结构),最后自然而然形成的一套思路就是大团队的协同合作。经过长时间的积累,软件开发人员借鉴了硬件组成原理(如CPU从提升主频到多核的改变),基于组件式程序设计思想,提出了组件式软件体系结构,这一理论给软件开发工程注入了无限的活力。进而牵涉到的两个原则就是:内聚性和耦合性,也就是架构设计中所谓的高内聚、低耦合。通俗来讲就是:一个模块实现所需要的全部功能(内聚性),而不需要其他人辅助实现;并且代码不会影响到别的模块(低耦合性)。

    组件化一定程度上可以约等于模块化,调用者只需关注输入和输出,相互之间没有影响,组件化本质的一点就是封装。每个组件对应一个工程目录,组件所需的各种资源都在这个目录下就近维护;每个组件相对独立,界面只不过是组件的容器,组件自由组合形成功能完整的界面;当不需要某个组件,或者想要替换组件时,可以整个目录删除/替换。组件化只是所有GUI开发的一种思路,总思想就是分而治之、重复利用。

    组件化通常有以下几个要素:

    1)组件是对逻辑的封装,不限于UI元素。

    2)组件具备单个可移植性,即“随加载随用”,不需要为其准备复杂的基础条件。
    组件是一个广义上的概念,并不一定都是页面跳转,还可以是其他不具备UI属性的服务提供者,比如日志服务,VOIP服务,内存管理服务和其他帮助服务等,即在更高的维度去封装功能单元。组件化开发一个最重要的特点就是把图形、非图形的各种逻辑均抽象为一个统一的概念(组件)来实现开发的模式。对这些功能单元进行进一步的分类,才能在具体的业务场景下做更合理的设计。这些在MrPeakTeach的《iOS组件化方案》中也做了相应的讨论。

    组件可以分为以下几类:

    1)带UI属性的独立业务模块。

    这些组件有很具体的业务场景,如App的主页模块、登录注册模块、分享模块等。这类模块一般有个入口Controller,可以通过Push或Present的方式作为入口接入。Controller作为页面的基本单位和Web Page有很高的相似度,蘑菇街采取URL注册的实现方式或是天猫的统跳协议等,采用类URL的方式标记本地的每一个Controller,不仅方便本地的跳转,还能支持Server下发跳转指令,对于业务的兼容性有很大的帮助。
    从理论上来说,组件化和URL本身并没有什么联系,URL只是接入组件的方式之一。

    2)不具备UI属性的独立业务模块。

    这类模块不具备UI场景,但却和具体的业务相关,如日志上报模块、埋点统计等。组件被调用分为远程和本地,这种日志服务的调用是本地类型的调用,用URL来标这类记本地服务多有不便。

    3)不具备业务场景的功能模块。

    这类模块和具体的业务场景无关,如数据模块(提供数据的读写服务,包含多线程的处理等)、Network模块和图片处理类等。这些模块可以被任意模块使用,但不和任何业务相关。这种组件属于我们app的基础服务提供者,更像是一个个SDK,或是帮助类。通过Pods使用的很多著名第三方库都属于这一类,像FMDB,SDWebImage等。

    组件其实不是那么好进行抽象设计的,组件可以横向组件,但也要考虑纵向复用的问题,不得不牵涉的问题就是耦合问题。还有的就是组件的粒度问题,组件要细分到何种程度,都是在架构设计中需要考虑的,这些问题我们在具体使用时都需要考虑。

    组件化的优势

    组件化编程的关键目的是为了将程序模块化,使各个模块之间可以单独开发,单独测试。组件式体系结构把程序的功能分散在各个不同的组件中来完成,组件是可独立开发的程序模块,它能够动态地插入到系统中,并且可以被自由地删除和替换。

    组件化能够提高软件开发的并行性和开发效率,降低设计开发难度,缩短开发周期,增强应用程序的可运行性、可测试性和可维护性。归纳起来就是:

    组件化能够提高软件的复用度。

    降低整个系统的耦合度,在保持接口不变的情况下,我们可以替换不同的组件快速完成需求,以满足用户不断变化的需求,缩短项目交付周期。

    组件化因为强大的独立性,可以提高软件开发的并行性,为软件产业的大规模生产提供支持,便于协同开发。

    提高可维护性,由于整个系统是通过组件组合起来的,在出现问题的时候,可以用排除法直接移除组件,或者根据报错的组件快速定位问题,因为每个组件之间低耦合,职责单一,所以逻辑会比分析整个系统要简单。

    由于每个组件的职责单一,并且组件在系统中是被复用的,所以对代码进行优化可获得系统的整体升级。例如某个组件负责处理异步请求,与业务无关,我们添加缓存机制,序列化兼容,编码修正等功能,一来整个系统中的每个使用到这个组件的模块都会受惠;二来可以使这个组件更具健壮性。由于代码中的耦合度降低了,每个模块都可以分拆为一个组件,团队中每个人发挥所长维护各自组件,对整个应用来说是精细的打磨。

    功能目录说明

    Router方案工程目录
    • annotation

      注解工程,工程下的有组件注册时必须使用到的注解类。
      AAR地址:'com.maowo.remote:router-annotation:x.x.x'

    • compiler

      Apt工程,编译前自动寻找含有annotation注解的类文件,并注册生成表文件。
      AAR地址:'com.maowo.remote:router-compiler:x.x.x'

    • router

      路由API工程,负责注册、查找路由,分发路由事件
      AAR地址:'com.maowo.remote:router-api:x.x.x'

    工程依赖
    ~~ 需要向Router注册组件的模块,必须依赖Router模块。并在模块build.gradle文件下添加语句:
    apply plugin: 'com.common.router'(废弃,已经不需要依赖该插件)~~

    为工程注册Router的方式通过手动注册的方式:
    第一步、所有需要使用到router组件的module中的 xxx.gradle中加入如下代码

    android {
         ····
        defaultConfig {
            ···
            javaCompileOptions {
                annotationProcessorOptions {
                    arguments = ["moduleName": project.name]
                }
            }
        }
    }
    dependencies{
        ···
        implementation 'com.maowo.remote:router-api:0.0.1'
        annotationProcessor 'com.maowo.remote:router-compiler:0.0.1'
    }
    

    第二步、建议在Application初始化的时候,向Router注册需要使用Router组件的模块

       //初始化router
            Router.initialize(new Configuration.Builder().setDebuggable(true)
                    .registerModules("module1","module2","module3").build());
    
    

    Part1. 组件注册

    组件注册

    如图所示:

    1. 每个组件对应有一个具体的业务Handler,该业务Handler必须继承RouterHandler基类。
    2. 为目标业务Handler添加注解(Route),并注册唯一标识。

    Part2. 组件调用API

    Router.build(uri)

    是路由的入口,一切页面跳转皆是从此开始。

    1. Router.build(uri).callback(callback)

    为当前路由添加回调,不管成功失败都会通知,参见RouteCallback。

    1. Router.build(uri).requestCode(int)

    添加了requestCode即表示要调用startActivityForResult,requestCode >= 0。

    1. Router.build(uri).addFlags(flags)

    添加标记,类似intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)。

    1. Router.build(uri).anim(enter, exit)

    添加基础跳转动画。

    1. Router.build(uri).skipInterceptors()

    跳过拦截器,即绿色通道。

    1. Router.build(uri).go()

    Router链式调用的结束,无参

    1. Router.build(uri).go(Context context)

    Router链式调用的结束,参数Context的具体对象可以是,ApplicationContext,Activity,FragmentActivity。需要调用系统方法onActivityResult方法,需要通过具体实例启动对象,这里支持传入具体实例。

    1. Router.build(uri).extras(Bundle budle)

    传入bundle参数集合

    1. Router.build(uri).addParam(String key, Object value)

    快速添加参数,目前只支持:

    if (value instanceof Integer) {
        bundle.putInt(key, (Integer)value);
    } else if (value instanceof String) {
        bundle.putString(key, (String)value);
    } else if (value instanceof Long) {
        bundle.putLong(key, (Long)value);
    } else if (value instanceof Double) {
        bundle.putDouble(key, (Double)value);
    } else if (value instanceof Boolean) {
        bundle.putBoolean(key, (Boolean)value);
    } else if (value instanceof Parcelable) {
        bundle.putParcelable(key, (Parcelable)value);
    } else if (value instanceof Serializable) {
        bundle.putSerializable(key, (Serializable)value);
    } else if (value instanceof Float) {
        bundle.putFloat(key, (Float)value);
    }
    

    Part3. 组件调用间参数说明

    参数说明

    Part4. 注册&调用流程示意图

    注册组件示意图 调用组件示意图

    关于Router方案的参考:

    参考项目:https://github.com/chenenyu/Router/ 从1.3.0版本fork出来,进行了一定的改造。该项目的可以学习到许多Gradle知识,关于如何自定义插件,如何自定义编译时注解解析方案。

    相关文章

      网友评论

          本文标题:Router方案说明

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