Android 组件化探索与思考

前言

开发中,我习惯性会把一个模块的功能放在一个包下,便于查找,但烦于耦合性太高,后期维护太费劲,因此对项目进行组件化拆分势在必行。组件化好处:便于开发,团队成员只关注自己的开发的小模块,降低耦合性,后期维护方便等。相当于先有很多小组件,各自开发,最后组装,成一个 app。

关系图



app:壳工程;
module1:组件1;
module2:组件2;
common:第三方库,公用工具、自定义 View、主题等。

效果预览


组件化过程很容易想到一些问题,比如 module1 我想单独调试怎么做?module1 有页面需要跳转到module2怎么办等。接下来,我一一探索,提供解决方案。

全局设置 Gradle

如果有很多项目,可以设置全局来统一管理版本号或依赖库,这样就不用一个个去改了,根目录下 build.gradle 添加:

def androidSupportVersion = '25.3.1'

ext {
    //编译的 SDK 版本,如API20
    compileSdkVersion = 25
    //构建工具的版本,其中包括了打包工具aapt、dx等,如API20对应的build-tool的版本就是20.0.0
    buildToolsVersion = "26.0.0"
    //兼容的最低 SDK 版本
    minSdkVersion = 14
    //向前兼容,保存新旧两种逻辑,并通过 if-else 方法来判断执行哪种逻辑
    targetSdkVersion = 22
    appcompatV7 = "com.android.support:appcompat-v7:$androidSupportVersion"
    constraintLayout = 'com.android.support.constraint:constraint-layout:1.0.2'
}

其中module/build.gradle:

android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion
    //……
}

资源名重名

每个 module 都有 app_name,为了不让资源名重名,可以在每个组件的 build.gradle 中增加 resourcePrefix "xxx_",固定每个组件的资源前缀。但是 resourcePrefix 这个值只能限定 xml 里面的资源,并不能限定图片资源,所有图片资源仍然需要你手动去修改资源名。不过我更建议把图片、 strings、 colors、dimens 等资源放到 common 去,可以防止不同的资源名字却对应了同一资源值。

组件单独调试

application 与 library 切换

module1 在开发阶段应该 application,等 release 后才是 library,这里可以设置一个变量控制下,在根项目 gradle.properties 加入:

# 组件单独调试开关,true 可以,false 不可以,需要点击 "Sync Project"。
isDebug=false

module1/build.gradle:

if (isDebug.toBoolean()) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}

android {
    //……    
}

applicationId

开发阶段,module1 还必须有个 applicationId:

android {
     //……
    defaultConfig {
        // 作为library时不能有applicationId,只有作为一个独立应用时才能够如下设置
        if (isDebug.toBoolean()){
            applicationId "com.wuxiaolong.module1"
        }
        //……
        }
}

入口类

到这里还不行,还得有 AndroidManifest 设置入口类,release 后这个 AndroidManifest 不需要打包进去,新建文件 debug,然后在 build.gradle 指定路径:

android {
    //……  
    sourceSets {
        main {
            if (isDebug.toBoolean()) {
                manifest.srcFile 'src/main/debug/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/release/AndroidManifest.xml'
                java {
                    //release 时 debug 目录下文件不需要合并到主工程
                    exclude 'debug/**'
                }
            }
        }
    }
}

另外,module 可能会需要使用到自定义的 Application,release 同样也不需要打包进去,不然合并会有冲突。

组件间通信

组件间通信包括两个场景:(1)UI 跳转;(2)调用组件某个类的某个方法。
这里涉及路由,何为路由,就是页面请求,都交给它处理。网上有很多路由库,我这里选的是阿里的 ARouter,ARouter 能解决上面的问题,但是也遗留一个问题,我独立运行 module1 时,想访问 module2 页面就做不到了,Router 不支持跨进程访问,这个问题待定,也可能是我使用 ARouter 姿势不对,如果您能做到,望告知。

ARouter 使用

1、common

dependencies {
    //arouter
    compile rootProject.ext.arouterApi
}

2、组件
app 和 module 都需要加入:

android {
    defaultConfig {
        //arouter
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [moduleName: project.getName()]
            }
        }
    }

dependencies {
    //arouter
    annotationProcessor rootProject.ext.arouterCompiler
}

3、使用
sample 列出了组件跳转、组件跳转-带参数、获取 Frgment、调用组件某个类的使用方法,详见我的 GitHub 分享。
详细使用请阅读 ARouter,不得不吐槽,文档写的不是一般的烂。

library 重复依赖

module1 和 module2 分别都依赖了 common,会不会导致 library 重复依赖呢,想必大家也有这个疑问了,实际上在 release 构建 APP 的过程中 Gradle 会自动将重复的 aar 包排除,APP 中也就不会存在相同的代码了,可以打包反编译验证下,我试了,确实没有重复依赖。

ButterKnife

Attribute value must be constant

在 Android Studio 的 library 的 module 中无法使用 ButterKnife。
网上说用 R2 替代(为什么能用 R2?),但都没有说 R2 怎么生成的?这篇《butterknife在library中使用问题处理》文章说使用 android-apt,确实可行,但是带来一个新坑,发现 apply plugin: 'android-apt' 与 arouter 冲突,这时候 arouter 失效了。正确姿势,用 Android ButterKnife Zelezny 插件生成,手动改成 R2,clean 下就 OK,感谢群里的小伙伴提示。

OnClick 方法

ButterKnife 还有个坑,OnClick 方法中同样使用 R2,但是找 id 的时候使用 R,然而 library 中是不能使用 switch- case 找 id 的(原因:《在Android library中不能使用switch-case语句访问资源ID的原因分析及解决方案》),可以使用 if-else:

  @OnClick({R2.id.module1_button, R2.id.module1_button2})
    public void onViewClicked(View view) {
        int id = view.getId();
        Log.d("wxl","id="+id);
        if (id == R.id.module1_button) {
            toastShow("module1_button");
        } else if (id == R.id.module1_button2) {
            toastShow("module1_button2");
        }
    }

当你写 switch- case 时,Android Studio 也有提示,可以一键转换成 if-else。

源码

https://github.com/WuXiaolong/ModularSample

最后

1、撸了一次组件化,感觉自己好菜比,好多东西还需要学习,遗留:(1)、每个 module 的配置最好有个固定模版,这样新建 module 就不用一一配置了;(2)、关于注解与依赖注入,不明不白,导致组件间通信花费了太多时间,后续要系统学习下这块知识。
2、可能还有未知的坑,大家可以 Star ModularSample,我会持续更新。
3、网上组件化文章不少,但优秀的文章屈指可数,很多只是讲组件化思想,点到即止,最讨厌这种半藏着半掖式分享,感觉他们在耍流氓。对于那些无私愿意分享的人,我一直都是很钦佩的,因为有他们,让我们这些后人在开发的路上不孤单无助。
4、熟悉我的朋友,可能知道我在无锡,二线城市,总感觉技术很落后,所以我一直要保持学习,不知道组件化是不是在大城市在项目中运用很普遍?据说所知,无锡组件化用的很少,理论上在一线城市会处在技术前沿。
5、很多朋友说我文章总是会一个难点讲的通俗易懂,其实不知道我在易懂的背后做了多少实践做支撑,实践得真理,我是相信这句话的。

参考

Android组件化方案

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

推荐阅读更多精彩内容