网上关于组件化的文章有很多了,大部分都知道实现的思路,不过还是要自己去实践一下才会发现问题。文章的项目地址,项目用到CleanArchitecture框架,本文会介绍CleanArchitecture框架和dagger2在组件化的使用。
1:项目关系图
sdk: 一些公用库,各种辅助类,和第三方view
basic: (依赖sdk) 网络访问初始化,本地缓存和第三方包等。
commonbusiness: (依赖basic) 这里为什么我会多出这一层,因为有很多公共的业务,好比公司的app是强登录的,我会把登录模块写在这里,里面也包含了一些baseActivity和BaseApplication和各个组件的一些公共方法还有组件各种的服务接口的定义。
module_archives和module_knowledge: 就是两个组件,可以单独运行。
2:application和library切换
想必大家都知道了,定义一个isBuildModule=false,在组件的build.gradle中加入
if (isBuildModule.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
apply from: 'maven-release-kline-aar.gradle'
}
sourceSets {
main {
if (isBuildModule.toBoolean()) {
manifest.srcFile 'src/main/debug/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/release/AndroidManifest.xml'
java {
exclude '**/debug/**'
}
}
}
}
maven-release-kline-aar.gradle是一个打包aar的文件,在切换的时候也会使用不同的AndroidManifest.xml,因为在组件是debug的时候它是单独单独运行的,还有就是代码可以在建立一个debug包,可以在单独运行的时候做些初始化app的,打包的时候回剔除这部分代码。
3:library依赖和资源问题
我把所以的library都依赖在basic,每个组件都会依赖这个包,这样就不会存在library的版本问题,资源的问题就是
defaultConfig {
if (isBuildModule.toBoolean()) {
applicationId "com.wkw.archives"
}
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode rootProject.ext.versionCode
versionName rootProject.ext.versionName
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
resourcePrefix "archives"
}
4:组件之间的通信
你可以选择阿里的ARouter库,但是我的项目没有那么复杂,组件也就4个左右,所以没有使用阿里的库,我采用的是以下就是核心代码,
Object result = null;
Class> c = Class.forName(className);
if (c != null) {
result = c.newInstance();
}
return result;
但是采用Class.forName会有个问题那就是在混淆的时候,className是指定的,所以要在类上加@Keep 。
5:CleanArchitecture框架和dagger在组件化的使用
CleanArchitecture框架的github地址,这里再介绍分享一篇文章小鄧子的Easy Clean architecture on Android,我把data和domain会写在各自的业务模块中,自己的模块只要定义自己的就可以了,有个ApplicationModule会定义一些每个模块都需要的,
public class ApplicationModule {
@Provides
@Singleton
Context provideContext(Application application) {
return application;
}
@Provides
@Singleton
UserSystem provideUserSystem() {
return new UserSystem();
}
@Provides
@Singleton
ThreadExecutor provideThreadExecutor(JobExecutor jobExecutor) {
return jobExecutor;
}
@Provides
@Singleton
PostExecutionThread providePostExecutionThread(UIThread uiThread) {
return uiThread;
}
@Provides
@Singleton
MrService provideMrService() {
return new MrService();
}
@Provides
@Singleton
UserCache provideUserCache(UserCacheImpl userCache) {
return userCache;
}
}
然后在module_archives模块中会有ArchivesDataRepositoryModule和ArchivesActivityModule
其中KnowledgeDataRepositoryModule用于提供如下:
@Module
public class ArchivesDataRepositoryModule {
@Provides
@Singleton
ArchivesApi providesArchivesApi(MrService mrService) {
return mrService.createApi(ArchivesApi.class);
}
@Provides
@Singleton
ArchivesRepository prvidesArchivesRepository(ArchivesDataRepository archivesDataRepository) {
return archivesDataRepository;
}
}
ArchivesActivityModule的代码如下:
@Module
public abstract class ArchivesActivityModule {
@PerActivity
@ContributesAndroidInjector()
abstract ArchivesActivity contributeArchivesActivity();
}
这样在主app的AppComponent类中加入:
@Singleton
@Component(modules = {
AndroidInjectionModule.class, ApplicationModule.class,
ArchivesDataRepositoryModule.class, ArchivesActivityModule.class,
KnowledgeDataRepositoryModule.class, KnowledgeActivityModule.class
})
public interface AppComponent {
@Component.Builder
interface Builder {
@BindsInstance
Builder application(Application application);
AppComponent build();
}
void inject(MrApplication mrApplication);
}
在module_archives为debug模式下也会有个AppComponent
@Singleton
@Component(modules = {
AndroidInjectionModule.class, ApplicationModule.class,
ArchivesDataRepositoryModule.class, ArchivesActivityModule.class
})
public interface AppComponent {
@Component.Builder
interface Builder {
@BindsInstance
Builder application(Application application);
AppComponent build();
}
void inject(ArchivesApplication mrApplication);
}
各种模块初始化api和Repository,你要是嫌弃每个模块都要引入两个.class文件,你可以使用一个然后采用include的方式好比dagger中的AndroidSupportInjectionModule类方式
@Beta
@Module(includes = AndroidInjectionModule.class)
public abstract class AndroidSupportInjectionModule {
@Multibinds
abstract Map, AndroidInjector.Factory extends Fragment>>
supportFragmentInjectorFactories();
private AndroidSupportInjectionModule() {}
}
这样就会很清楚的知道自己模块需要初始化什么和使用什么,也不用考虑其它模块的初始化的数据,之后只需要在主app加入就行,也是比较方便的。
6:打包
各种模块当为library是要打包成aar的,maven-release-kline-aar.gradle文件代码如下:
apply plugin: 'maven'
ext {// ext is a gradle closure allowing the declaration of global properties
PUBLISH_GROUP_ID = 'com.wkw'
PUBLISH_ARTIFACT_ID = 'archives'
PUBLISH_VERSION = rootProject.ext.versionName
}
uploadArchives {
repositories.mavenDeployer {
//这里就是最后输出地址,在自己电脑上新建个文件夹,把文件夹路径粘贴在此
//注意”file://“ + 路径,有三个斜杠,别漏了
repository(url: "file:///Users/wukewei/Documents/android/ModularizationExample/repo")
pom.project {
groupId project.PUBLISH_GROUP_ID
artifactId project.PUBLISH_ARTIFACT_ID
version project.PUBLISH_VERSION
}
}
}
//以下代码会生成jar包源文件,如果是不开源码,请不要输入这段
//aar包内包含注释
task androidSourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.sourceFiles
}
artifacts {
archives androidSourcesJar
}
我只是打包到本地,你可以自己建立一个本地maven库。
7:如要改进的地方
1:每次建立一个模块还是要做很多初始化的工作
2:maven-release-kline-aar.gradle每个模块都会有,希望后期能改进。
3: debug模式下各个模块登录之后跳转问题
4:等等。。。。。
参考
从零开始的Android新项目11 - 组件化实践(1) -
大帅