Android 多模块多组件开发 - 打造属于自己的路由

一.基本介绍

1. 借此机会分享一下自己从刚入门到现在,在开发架构方面的一些心路历程。最终我会把这部分代码进行开源,以后也会对其进行维护。但目前尚在测试中所以并未发布正式版本。我们可以先把代码下载下来进行了解,如果有什么问题可以随时 Issues,这也将是我的第一个开源库,希望能帮到大家。

2. 该库所涉及到的类大概在 30 个左右,源码并不多相信我们都能读懂里面的内容,这里罗列一下源码中所涉及到的一些知识点:
(1) 编译时注解自动生成 Module、Action 和 Intercepter
(2) 线程、线程池、线程同步异步和 Handler
(3) 责任链模式、享元模式、策略模式、模板模式 ...

3. 作为一个多模块的路由通信库,相信它已支持了所有跨模块通信的使用场景,功能介绍如下:
(1) 支持依赖注入,可单独作为依赖注入框架使用
(2) 支持线程切换和调度(原始线程,主线程,同步,异步)
(3) 支持多模块工程下的所有跨模块通信使用场景
(4) 支持添加多个拦截器,可根据优先级自定义拦截顺序
(5) 支持权限和网络检测、登录拦截跳转和数据埋点等功能

4. 笔者阅读了大量的开源库源码,本库的所有代码思想都来自其中,很感激这些大牛的开源和分享精神:
(1) ARouter
(2) butterknife
(3) okhttp
(4) EventBus
(5) RxJava
(6) retrofit

二.架构的演变之路

首先分享一下自己从刚入门到现在,在开发架构方面的一些心路历程,从刚开始踏上程序这条不归路(人生就是一条不归路),想想已经是好几个年头,中间经历过提升、迷茫和进阶,也经历过从不自信到自信、自满到自负。刚开始一个人在小公司小打小闹,是这个样子的:

那个时候所有的类都是写在一个包下面的,所有的 Activity 都是继承自系统下的 android.app.Activity,网络框架都是直接用的 android-async-http 所以加班挺严重, 一方面是自己能力经验还不够,另一方面是没有架构的情况下很多代码都是反复冗余的。毕业后去了一家上市公司,多人团队协作开发所以就改变了一些:

这个时候已经有所提升了,所有的 Activity 也不是直接继承自 android.app.Activity 了,也不再是直接使用 android-async-http 所以开发的日子自然舒坦了一些。一方面是经验能力上去了遇到问题能马上解决,另一方面基于架构开发很多代码不用反复写后期也便于维护,最主要的是大公司人多一些,之前是一个人干四个人的活,现在四个人干一个人的活。随着开发人员的越来越多,还有就是基本每逢过节都要做一些活动,等活动过后这些代码和资源就要删除,而且每两个月就得迭代一个新的版本,所以变得越来越复杂起来。后来就衍生出了很多像热更新、插件化、多模块多组件开发等等。当然刚开始的多模块多组件并未基于路由,是蜘蛛网的状态。

会有这么乱吗?随着业务逻辑更加复杂的情况下应该会更乱,因为功能模块都是各自存在于自己的 Module 中,但是可能在开发的过程中 Module1 得调用 Module2 的代码,这个时候如果是直接添加依赖那么肯定就会有这么乱了。接下来看下基于路由情况下的多模块多组件开发:

三. DRouter 基本使用

  1. 在需要跨模块通信的Module中添加依赖和配置
    defaultConfig {
        ......
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [moduleName: project.getName()]
            }
        }
    }

    dependencies {
        .......
        annotationProcessor project(':drouter-compiler')
    }
  1. 在 Module 中创建需要执行的 Action
// path 必须是以在 gradle 中配置的 moduleName + "/" 开头,否则编译通不过。
// threadMode 支持 POSTING 、MAIN、BACKGROUND、ASYNC 默认情况下是 POSTING(原始线程)
@Action(path = "login/action", threadMode = ThreadMode.MAIN)
public class LoginAction implements IRouterAction {

    @Override
    public RouterResult invokeAction(Context context, Map<String, Object> requestData) {
        // 通信执行方法支持所有场景,启动 Activity,Service,Provider,弹框,缓存数据,获取 Fragment 等等等等
        Intent intent = new Intent(context, LoginActivity.class);
        intent.putExtra("key", (String) requestData.get("key"));
        context.startActivity(intent);
        return new RouterResult.Builder().success().object(100).build();
    }
}
  1. 初始化 SDK
public class BaseApplication extends Application{
    @Override
    public void onCreate() {
        super.onCreate();
        // 开启 debug
        DRouter.openDebug();
        // 初始化且只能初始化一次,参数必须是 Application
        DRouter.getInstance().init(this);
    }
}
  1. 可在任意 Module 中执行跳转
// 根据 action 查询只执行对应方法,不处理返回回调,参数携带随意
DRouter.getInstance()
                .action("login/action")
                .context(this)
                .param("key", "value")
                .invokeAction();

// 根据 action 查询执行对应方法,并处理返回回调
DRouter.getInstance()
                .action("circlemodule/test")
                .context(this)
                .invokeAction(new ActionCallback() {
                    @Override
                    public void onInterrupt() {
                        Log.e("TAG", "被拦截了");
                    }

                    @Override
                    public void onResult(RouterResult result) {
                        // 注意该方法的执行线程是由 Action 的 threadMode 决定的,也就是说和 Action 在同一个线程
                        Log.e("TAG", "result = " + result.toString());
                    }
                });
  1. 在任意模块下都可添加拦截
// priority 优先级越高,拦截器执行越优先
@Interceptor(priority = 18)
public class CircleInterceptor implements ActionInterceptor {

    @Override
    public void intercept(ActionChain chain) {
        ActionPost actionPost = chain.action();
        // 圈子详情页必须是要登录,如果没有登录即可拦截跳转到登录页面,否则继续往下执行。
        if (chain.actionPath().equals("circlemodule/test")) {
            Toast.makeText(actionPost.context, "拦截圈子,跳转到登录", Toast.LENGTH_LONG).show();
            // 跳转到登录页面
            DRouter.getInstance()
                    .action("login/action")
                    .context(actionPost.context)
                    .invokeAction();

            // 这个方法调用后便会拦截整条链
            chain.onInterrupt();
        }
        // 继续向下转发
        chain.proceed(actionPost);
    }
}

6.混淆配置

-keep public class com.drouter.assist.**{*;}

源码地址:https://github.com/HCDarren/DRouter
视频讲解:https://pan.baidu.com/s/1kWoIA95

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350