Android 浅解组件化-路由框架(1)

前言

之前学习组件化-路由的时候也是花费了不少的时间,其实学习技术都是这样,自己弄懂了大部分东西之后就会觉得这个知识好像并不是那么难。
这里的 “ 组件化-路由技术 ” 分成两篇文章讲解,确实内容略多一点,第一篇主要就是讲解组件化,而第二篇就主要讲解路由知识,这里是第二篇文章的链接
我尽力讲得更加仔细一点,希望刚接触这项技术的小伙伴能够看得懂。

组件化的作用

组件化技术主要是进行项目比较大的团队才会采用的,想必它的作用很多小伙伴是清楚的了,我就简单提几点就行了。

  1. 提高编译速度: 该技术可以实现单独一个组件作为一个Application进行编译运行,例如我只想测试一下“登录、注册”组件,而我不必编译、运行整个项目,这样就可以提高我的开发效率。
  2. 解耦程度大: 解耦程度大不多解释,因为毕竟一个组件都可以单独运行了,你想它的解耦程度大不大呢?特别是将common(公共层)抽出来之后,用起来是真的舒服~
  3. 利于团队开发:这一点上感触颇深,在任务分配完成之后,就是感觉跟其它人的代码就完全分割开来了,写代码的过程很舒服,而且在git管理代码的过程中失误率也会小很多。

组件化实现

组件化实现比较轻松,下面我会将完整步骤都描述出来。

1. 统一每个组件的配置文件
第一步就是新建几个组件,选中项目new module就可以了,结果如下图所示:

新建组件

在这里,我的想法是app作为应用壳组件,它负责APK的打包,管理其它组件,而没有业务逻辑;lib_common是公共层组件,是放置共用的网络请求、工具类的地方;而lib_home、lib_chat组件就是我们的业务逻辑组件。
如上图所示,每一个组件都有自己的build.gradle文件,我们肯定需要配置文件(.gradle)里信息的统一,防止私自修改gradle文件而影响整个项目的编译运行。我们需要创建一个config.gradle(上图所示)来统一gradle文件,config.gadle文件包含以下信息:


配置文件

这一个config.gradle文件需要导入到项目配置文件中去,我们需要在project的build.gradle文件下代码的顶部加上apply from: "config.gradle"来将我们的配置文件导入项目。接下来只需要在每个组件的build.gradle文件中这么使用:

单一组件bild.gradle文件

2. 设置组件单独运行时的AndroidManifests.xml文件
在讲之前,我们先做一件事,由于common组件作为共用层,它肯定不需要单独运行,所以我们先将它导入其它的组件,按照添加三方库的办法,在其它组件的build.gradle文件中添加代码implementation project(':lib_common'),以此导入本地库,然后,将app组件下的res文件全部导入common组件中去(layout目录就不用了,它就是app组件私有的),由于已经依赖了common组件,那么app中res的所有文件就可以删除了,不然就多了,而且重名。

我们可以打开某一个组件下的AndroidManifests.xml看一下,它没有<application></application>标签,因为它此时是作为一个来使用的,它不能够使用应用标签。同理,它也不能配置该标签下的信息,例如应用名、主题之类的。按照三方库形式导入其它组件后,这个manifests文件上的信息会被合并到另外一个组件的manifests文件上去。
为了使得我们的组件可以单独运行,我们需要单独为它创建一个manifests文件,我们在Project方式查看项目的方式下,在该组件下建立一个包,就叫alone包吧~,然后在该包下创建AndroidManifests.xml文件,我的建议是直接将app组件下的AndroidManifests.xml文件直接拷贝过来,然后稍微修改下,像下面这样:

lib_chat manifests文件

这里大概能够理解为什么需要将res文件全部移动到common组件中去了吧,不然的app组件和chat组件是没有相互依赖的,chat组件就不能够使用图片、文字等资源了。

3. 实现两种运行模式
我们需要使项目有两种模式,一种是集成模式,一种是单独运行模式。
首先,我们在project下的gradle.properties文件中添加代码isRunAlone=true,这个文件中可以放置项目需要使用的常量值,这句代码的意思就是定义了一个Boolean类型变量为true,就是“可单独运行”吧。
接下来在其它组件的build.gradle文件下,将顶部apply plugin: 'com.android.library'代码修改为

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

这段代码的意思就是,通过常量值判断以哪种形式运行代码,.library就是作为第三方库使用,不可单独运行,.application就是可以作为一个应用单独运行。
我们要求在单独运行的模式下,能够使用我们自定义的manifests文件。以此需要在buildTypes内添加以下代码:

sourceSets {
            main {
                if (isRunAlone.toBoolean()) {
                    manifest.srcFile 'src/main/alone/AndroidManifest.xml'
                } else {
                    manifest.srcFile 'src/main/AndroidManifest.xml'
                    java {
                        //清除alone目录下的文件
                        exclude 'run_alone/**'
                    }
                }
            }
        }

最后贴出home组件的完整build.gradle文件代码:

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

android {
    compileSdkVersion rootProject.ext.android.compileSdkVersion
    defaultConfig {
        minSdkVersion rootProject.ext.android.minSdkVersion
        targetSdkVersion rootProject.ext.android.targetSdkVersion
        versionCode rootProject.ext.android.versionCode
        versionName rootProject.ext.android.versionName
        testInstrumentationRunner rootProject.ext.android.testInstrumentationRunner

    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }

        sourceSets {
            main {
                if (isRunAlone.toBoolean()) {
                    manifest.srcFile 'src/main/alone/AndroidManifest.xml'
                } else {
                    manifest.srcFile 'src/main/AndroidManifest.xml'
                    java {
                        //清除run_alone目录下的文件
                        exclude 'run_alone/**'
                    }
                }
            }
        }
    }

}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation rootProject.ext.dependencies.appcompat
    implementation rootProject.ext.dependencies.constraint_layout
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation rootProject.ext.dependencies.junit
    androidTestImplementation rootProject.ext.dependencies.runner
    androidTestImplementation rootProject.ext.dependencies.espresso_core
    
    //导入共用层组件
    implementation project(':lib_common')
}

我们可以单独运行了吗?不可以,因为我们还没有启动活动
我们在每一个组建下创建一个活动,并在alone目录下的manifests文件中将它设置为启动活动。接下来就可以单独运行了。

注意事项

1. 资源名冲突
当我们切换成集成运行模式下的时候,两个组件中资源命名相同的话,就会导致资源名冲突,系统怎么会知道你想采用哪一个xml文件呢?
解决这个冲突也很简单,每一个组件都加上一个前缀就行了。添加代码resourcePrefix "前缀_"在该组件的build.gradle文件中的buildTypes内就行了,在你创建xml文件的时候,系统就会强制要求你给该xml文件添加前缀,否则就会编译报错。记住,不是编译器自动添加前缀,而是手动添加前缀,不添加则编译报错。

2. 导库问题
通过implementation 形式导入的库具有相互依赖性,举个栗子,我们在app组件下导入home、chat的组件后,在chat组件中就可以使用home组件的文件,同理在home组件中就可以使用chat组件的文件。
但是,这个方法在导入第三方库的时候就行不通了。 在某个组件中使用implementation导入第三方库,那么就只有该组件能够使用该第三方库。那么我们就应该使用api的方式来实现第三方库导入,例如在common层gradle中加上代码api 'com.github.bumptech.glide:glide:3.7.0'导入Glide库,可以实现在其它组件中也调用Glide第三方库。
仅仅在app组件下导入一次即可,单独将其导入其它业务组件代码贴出来:

 if (!isRunAlone.toBoolean()) {
        api project(":lib_chat")
        api project(":lib_home")
    }

3. manifests注册、权限问题
除了app、common组件,其它业务逻辑组件我们都应该具有两张表。但是每一次我们生成一个活动的时候,编译器只会在一张表上面去注册活动,因此一定要记住,我们需要手动在另外一张表上面注册活动。还有就是权限问题,一般我们只需要在common层的manifests文件中将所有权限都申明就可以了,不然的话,你还需要在业务组件上去申明两次权限(两张表)。

4. 签名配置
由于需要第三方平台的使用,需要我们提供应用的签名,我们要统一我们APK的签名。这里说一种最常用的自动签名的方式。在我们手动打包一次APK之后,生成了.key文件,接下来直接代码啦:

//在build.gradle的android 内
signingConfigs {
        //签名配置要在buildtypes之前
        //签名文件放在build.gradle同级目录
        config {
            //填写自己的key文件的相对路径
            storeFile file("./key.jks")
            storePassword "123456"
            keyAlias "123456"
            keyPassword "123456"
        }
    }
    buildTypes {
        release {
            //使用签名
            signingConfig signingConfigs.config
            //混淆
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        debug {
            signingConfig signingConfigs.config
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

我们需要在其它的组件下也添加这段代码,当然有快捷方式,就是在Android Studio的Project Structure中的signing去设置,它会自动在build.gradle中生成相应代码。
Project Structure

组件化的介绍暂时就到这儿了,肯定是有许多地方是没有讲到的,就靠自己慢慢摸索啦~
下一篇文章讲路由,Android 讲解组件化-路由框架(2)

笔者水平有限,有写得不好的地方,请大胆指出~
转载请注明出处~

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

推荐阅读更多精彩内容