Android彻底组件化—UI跳转升级改造

作者: 格竹子 | 来源:发表于2017-12-22 18:16 被阅读5574次

    得到Android组件化方案已经开源,参见Android组件化方案开源。方案的解读文章是一个小的系列,这是系列的第四篇文章:
    1、Android彻底组件化方案实践
    2、Android彻底组件化demo发布
    3、Android彻底组件化-代码和资源隔离
    4、Android彻底组件化—UI跳转升级改造
    5、Android彻底组件化—如何使用Arouter

    JIMU开源以后,收到了很多朋友的评论或者私信,提出了很多有价值的意见和建议,一个比较集中的点就在于组件之间的UI跳转不够优雅。当时由于业务比较紧张,没有时间来完善这块,最近终于抽出时间把UI跳转的功能进行了升级改造,期间也得到@leobert等大牛的鼎力支持以及ARouter等优秀方案的启发,现在JIMU新的UI跳转功能已经发布了,欢迎大家使用。

    已实现功能

    (1)按组件区分host,增加URL的可读性
    (2)自动注册路由,不再需要手动编写代码进行路由分发
    (3)按需加载,只有实际跳转到某个组件是,该组件的路由表才会加载
    (4)自动生成路由表文件,方便组件开发团队之间调用
    (5)参数支持依赖注入,不需要编写参数的解析代码

    URL结构

    组件之间的UI跳转是基于标准的URL来实现的,先简单看一下URL的基本构成:

    <scheme>://<host>/<path>?<query>
    

    这个是最简单的一个模型,不过用于我们UI跳转协议已经足够了。下面是一个跳转到分享页面的实例:

    DDComp://share/shareBook?bookName=Gone with the Wind
    

    结合我们的组件化框架,我们简单讲一下各部分的含义

    (1)scheme对应的是DDComp,这个在JIMU没有限制,使用时可以自己自由设置,一般为了从应用外跳转进来,会在manifest的入口Activity添加以下配置

    <intent-filter>
        <data android:scheme="DDComp" />
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
    </intent-filter>
    

    (2)host对应的是share。在组件化框架中,每个组件对应一个唯一的host,例如分享组件的host就是share,读书组件的host是reader等等。
    ● host是路由分发的第一级,根据host可以定位到每个组件。
    ● host还可以对所有的路由URL进行一个分组,只有调用到该分组的路由的时候,组内的路由才会被加载进内存

    (3)path对应的是shareBook。它对应的是具体的每个具体的页面,例如shareBook对应就是ShareActivity。在一个组件之内,path是不能重复的

    (4)query对应的是bookName=Gone with the Wind。它表示要跳转到ShareActivity,需要传入的参数,例如这里需要传入书的名字等。

    下面我们就讲一下如何使用JIMU的UI跳转新功能!

    组件添加必要的依赖

    在组件的build.gradle中添加依赖

    annotationProcessor 'com.luojilab.ddcomponent:router-anno-compiler:1.0.0'
    

    同时添加

    defaultConfig {
        javaCompileOptions {
            annotationProcessorOptions {
                 arguments = [host: "share"]
            }
        }
    }
    

    此处的"share"是跳转URI中的host,每个组件需要设置不同的host。

    注册组件到UIRouter中

    在组件的声明周期类ApplicationLike中,添加注册和反注册代码

    public class ShareApplike implements IApplicationLike {
        UIRouter uiRouter = UIRouter.getInstance();
        @Override
        public void onCreate() {
            uiRouter.registerUI("share");
        }
        @Override
        public void onStop() {
            uiRouter.unregisterUI("share");
        }
    }
    

    目标页面添加注解

    首先在跳转的目的Activity上添加RouteNode注解

    @RouteNode(path = "/shareBook", desc = "分享书籍页面")
    public class ShareActivity extends AppCompatActivity {
    

    如果需要传入参数,在具体的参数定义上增加Autowired注解:

    @Autowired
    String bookName;
    @Autowired
    Author author;
    

    注意此处的参数不能是private的,否则编译会直接报错。这里的原因在于依赖注入的时候没有使用反射,而是直接调用了该参数,所以需要参数至少是包可见的。

    依赖注入

    如果想使用自动装载功能,需要在Activity的onCreate中调用方法

    AutowiredService.Factory.getInstance().create().autowire(this);
    

    建议该方法在基类Activity中调用

    build项目

    项目执行build,会生成apt文件,具体可在build目录下面查看
    同时还会在根目录生成UIRouterTable文件夹,里面会列出每个组件向外提供的路由表

    auto generated, do not change !!!! 
    
    HOST : share
    
    分享杂志页面
    /shareMagazine
    author:com.luojilab.componentservice.share.bean.Author
    bookName:String
    
    分享书籍页面
    /shareBook
    author:com.luojilab.componentservice.share.bean.Author
    bookName:String
    

    跳转

    在发起跳转页面,有三种方式可以跳转到目的页面

    Bundle方式
        // UI transfer with Bundle
        private void goToShareActivityWithBundle() {
            Author author = new Author();
            author.setName("Margaret Mitchell");
            author.setCounty("USA");
            Bundle bundle = new Bundle();
            bundle.putString("bookName", "Gone with the Wind");
            bundle.putString("author", JsonService.Factory.getInstance()
                    .create().toJsonString(author));
            UIRouter.getInstance().openUri(getActivity(), "DDComp://share/shareBook", bundle);
        }
    
    URI方式
        // UI transfer with URI
        private void goToShareActivityWithUri() {
            Author author = new Author();
            author.setName("Barack Obama");
            author.setCounty("New York");
            final String URI_LEGAL = "DDComp://share/shareMagazine?bookName=NYTIME&amp;author=";
            legal and illegal data delivering*/
            UIRouter.getInstance().openUri(getActivity(),
                    URI_LEGAL
                            + JsonService.Factory.getInstance().create().toJsonString(author), null);
        }
    
    startActivityForResult
        //startActivityForResult
        private void goToShareActivityForResult() {
            Author author = new Author();
            author.setName("Margaret Mitchell");
            author.setCounty("USA");
            UIRouter.getInstance().openUri(getActivity(),
                    "DDComp://share/shareBook?bookName=Gone with the Wind&amp;author="
                            + JsonService.Factory.getInstance().create().toJsonString(author), null, 7777);
        }
    

    具体使用请参见github源码 https://github.com/mqzhangw/AndroidComponent。如果对方案有不理解的地方,欢迎阅读解析文章Android彻底组件化方案实践Android彻底组件化demo发布

    目前很多app已经使用ARouter来进行UI跳转,JIMU也是支持ARouter的,只是为了更契合现在的组件化框架,所以自己实现了一套。鉴于已使用ARouter的app迁移成本有点高,后面会专门写一篇如何在组件化框架中使用ARouter的文章,敬请期待!

    JIMU的讨论群,群号693097923,欢迎大家加入:


    进群请扫码

    相关文章

      网友评论

      • laughingkid:你UI,以及组件的定义是什么样的?一个UI就是一个组件么?一个组件是不是可以包含多个UI?
        格竹子:@laughingkid 组件是根据业务来定义的,可能含有多个UI
      • 33af5afb733e:大佬 请教一下。在本地广播不同的组件跳不了 为什么 同一个组件的activity可以跳
      • 4eb9fbedf20c:Didn't find class "com.luojilab.gen.router.AppUiRouter" 这个错误是少了什么配置吗
      • 3de5c7f96de3:请问子项目的AppLike中怎么获取Context呢,一些初始化的方法不好处理
        格竹子:@轨迹_f00b 请看源码,里面有示例
      • Yanqilong:跳转URL的 Scheme DDComp 支持自定义吗?怎么修改。
        搞Android的文艺青年:同样的问题,在App壳工程的manifest文件中修改吗?
        格竹子:@Yanqilong Scheme可以改成自己的,UIRouter不检验Scheme。
      • 大空ts翼:请问这个和Dagger2里的DispatchingAndroidInjector该如何配合?(这玩意有点难描述,大概就是这个项目那样,https://github.com/googlesamples/android-architecture-components/tree/master/GithubBrowserSample)Component里必须有所有需要注入的Activity的相关Module,这个Module又没法动态添加,而Activity又是在不同模块的。
        大空ts翼:@格竹子 呃,暂时给每个module都分配了一个component,还没时间去验证(感觉activity里有别的module的fragment时就会有问题),另外想问下,有办法知道activity或者fragment是来自哪个module的吗?
        格竹子:@大空ts翼 这个没仔细研究过,不可以在每个组件中设置吗?必须要求全局设置?
      • 飞起来的大雨:最新代码readercomponent 单个module运行点击里面的按钮直接崩掉
        格竹子:@飞起来的小糖豆 你用的是最新的代码吗。我试了没有问题啊,你可以拉最新的试一下,如果还有问题,麻烦贴一下崩溃日志
      • 白点黑羽:大神你好!我将您的框架用在项目中,遇到一个问题:主Application(主项目普通MVC)和子Application(子项目Dragger2+MVP+kotlin)实现的方式不同,里面注册的东西也不同,子项目单独运行没问题,但运行主项目就出现Application依赖问题,还有子项目会依赖Application做一些操作,分别运行时候 依赖的包路径也不一样了。这里没有好的思路解决:joy:
        白点黑羽:@格竹子 就是一个电商类的项目,子项目是一个外卖类的,所有子项目有高德地图相关的注册,而电商类的没有。大神的意思是吧IApplicationLike当作是主应用的代理吗?那我如何判断当前是应该用IApplicationLike还是用子项目的Application呢?
        格竹子:@白点黑羽 还有,可以透漏一下你们的项目是什么app吗?
        格竹子:@白点黑羽 子项目(组件)如果集成到app里面,是不会调用子Application的逻辑的,组件化框架里面提供了一个IApplicationLike来充当Application的作用,你把子项目的初始化逻辑移到这里就可以了。“子项目依赖主项目做一些操作”,不要明白是什么意思,这些操作放在主项目的Application中不可以吗?
      • fa47c82221a6:Error:(14, 1) A problem occurred evaluating project ':router-anno-compiler'.
        > Could not read script 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle'.
        > Operation timed out (Connection timed out)

        这个是什么连接超时?
        fa47c82221a6:@格竹子 哦哦,好了,可能是网络问题。
        格竹子:这里就是去获取一段脚本,https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle
        ,你网络有问题吗

      本文标题:Android彻底组件化—UI跳转升级改造

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