Android组件化开发的实现(一)如何统一管理编译运行环境

本文所对应的示例代码,已经上传到这里:
https://download.csdn.net/download/fenggering/10876548

前言

现在稍微有点规模的App项目,都会采用组件化的开发方式。
组件化通俗来说就是把app分成多个部件,各个部件职责较为单一,可以单独修改调试,也可以集成到一起发挥作用,这样就能很方便进行团队协作和版本更新。

组件化开发需要解决的几个问题(点击可跳转到对应小节):
一.如何统一管理编译环境
二.如何实现各个组件既能单独调试运行,又能集成到整体里
三.如何避免组件之间资源引用
四.组件之间如何跳转,传递数据

先建好项目里的各个组件,为开发做准备:
首先,我们新建一个项目。这个项目中默认会包含一个module,名为app,我们就称之为app组件,做为项目的主组件。其他组件最终都要集成进来。
接着,为实现组件化,需要建立一个基础通用组件,我们暂且称为lib组件。这个lib组件作用是实现一些共通的接口,方便其他组件之间数据通信和跳转等。也就是说lib组件应该被其他所有组件所依赖。如何新建lib组件呢?
Android studio的File -> new -> new moudle -> Android Library,点击下一步就新建了lib组件。在lib组件的build.gradle文件第一行,可以看到它的属性是library:

apply plugin: 'com.android.library'

同时我们再新建一个组件,假设这个组件是用来实现登录相关功能的,称为login组件,而且我们想让它可以单独运行和调试。如何新建呢?跟新建lib组件类型,但最后要选的不是Android Library,而是Phone & Tablet module。
这样完成后,在login组件的build.gradle里,可以看到login组件的属性是Application,这样它就可以单独运行和调试:

apply plugin: 'com.android.application'

那么login组件和lib组件还有什么区别呢?
lib组件没有生成默认的activity,Manifest文件内容也比login组件的简单得多。而且在lib组件的Build.gradle里,没有applicationId这一项。

在app组件和login组件的build.gradle里,添加对lib组件的依赖:

    implementation project(':componentlib')

有了这三个组件,就可以开始进行组件化的举例开发了。

一.如何统一管理编译环境

我们看到,上面两个组件的gradle文件里,各种版本号都是数字的形式存在的,比如这两处:

各个组件如果用的gradle版本,第三方库的版本等不一致的话,很容易出现问题,那怎么来统一管理这些版本号呢?

一个简单的解决方案就是,在配置文件里,用变量来定义这些版本号,然后进行引用。我们可以在项目的gradle.properties文件里添加定义:

compile_sdk_version = 26
support_version = 26.1.0

然后,就可以把各个组件gradle文件里的版本号做替代了,结果如下;

compileSdkVersion compile_sdk_version.toInteger()	// 用toInteger()转为数字
api "com.android.support:appcompat-v7:$support_version"	// 需要用到$符号表示引用,同时使用双引号 

注意,这里lib组件依赖support库,换成了api关键字,而没有用implementation,因为api的意思是,如果login组件依赖了lib组件,那么也就依赖了support库。所以login组件里对support库的依赖就可以去掉了。
这样,就实现了各个版本号的统一管理。

二.如何实现各个组件既能单独调试运行,又能集成到整体里

要满足这个要求,我们可以定义一个开关来控制,开关仍然可以放到gradle.properties内容里。比如控制login组件是否能单独运行的开关:

loginRunAlone = false

如何使用这个开关呢?因为login组件如果要集成,那么1,它必须转换成library,2.它的applicationId也要去掉,3.manifest文件要换。
第1个和第2个,我们这么改写login组件的build.gradle文件:

if (loginRunAlone.toBoolean()) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}
        if (loginRunAlone.toBoolean()) {
            applicationId "example.hp.componentlogin"
        }

这样就实现了application和library的转换。

第3点,我们可以把lib组件的AndroidManifest.xml文件复制到login组件里,新建一个manifest文件夹来存放,用于作为library集成。原先的用于作为application单独运行。这两个manifest文件如何指定呢?仍然是修改login组件的build.gradle文件,在“Android”那一段里加上这些:

    sourceSets{
        main {
            if (loginRunAlone.toBoolean()) {
                // 指定这个作为单独运行时的manifest
                manifest.srcFile "src/main/AndroidManifest.xml"
            } else {
                // 指定这个作为集成时的manifest
                manifest.srcFile "src/main/manifest/AndroidManifest.xml"
            }
        }
    }

这样第二个问题也就解决了。通过修改loginRunAlone为true或false来转换login组件是否能单独运行。

三、如何避免组件之间资源引用

1.设计组件化的一个初衷就是要避免组件间互相依赖。但是我们在写代码时,通过R.xxx.xxx之类很容易就会引用到其它组件的资源。比如login组件和app组件里都有布局文件叫activity_login.xml,那就很容易混淆。怎么解决呢?

一个方案,可以在组件的build.gradle里,加上resourcePrefix,如下是对login组件的修改:


这个意思是,所有的xml文件及xml里的资源命名,都要求带上"login_"前缀,否则就会出现警告:


其他组件也可以带上其他自定义的前缀。按这样命名,资源文件就不会重名了。
但是drawable文件不会有提示。所以图片的命名,就要靠我们自己制定和执行规范了。

2.另外,我们在app组件里,可能一不小心就通过R.layout.activity_login对login组件的布局文件进行了引用,就算能正常使用,也其实是违背了我们的设计初衷的。那么怎么避免呢?

为避免组件间失误的引用,可以把依赖关系改成runtimeOnly
比如login组件如果集成的话,是要被app组件依赖的。app组件的build.gradle里原本这么写:

implementation project(':componentlogin')

如果要避免app组件对login组件的引用,可以在app组件的build.gradle里,改成这样:

runtimeOnly project(':componentlogin')

这样改后,在app组件里,就没法引用login组件的类和资源了。

四.组件之间如何跳转,传递数据

这一节要讲的比较多,请看下一篇文章。
Android组件化开发的实现(二)Android组件之间页面如何跳转和传递数据

本文所对应的示例代码,已经上传到这里:
https://download.csdn.net/download/fenggering/10876548

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值