传统的Android项目开发是将所有的代码全部放到一个module工程中,为了代码的复用,最多也就将各种通用库的代码,比如音视频播放库、网络库、二维码扫描库等等放到单独的module下,以library形式作为主工程的依赖。
使用传统的开发模式会使我们的主工程变得越来越庞大复杂,越来越难以维护,而且如果是比较大型的项目也不利于多人协作开发。
为了解决传统开发模式带来的问题,组件化的开发思路就诞生了。组件化的思路很简单,就是将我们项目中的业务进行拆分,各业务模块间不相互依赖。
这么说可能有些抽象,举个例子。比如项目有登录、首页、音乐播放三个业务模块,登录完成后我们会跳转到首页,首页点击音乐列表进入音乐播放页面。使用传统的开发思路是,登录页面依赖首页,首页依赖播放列表页。而采用组件化的开发思路是,这三个模块互相都不知道对方的存在,只需要调用暴露的接口就能够实现各模块间的通讯。
接下来,我将带着大家一步步的去搭建我们的组件化的项目。
首先看下demo工程的目录结构。

其中ft_login和ft_main为业务模块,lib_base为业务基础组件,app为我们的主工程。lib_base工程下我们一般放置业务相关的接口,lib_base的目录结构如下:

先看下登录模块,先定义LoginService接口:
package com.example.lib_base.ft_login.service;
import android.content.Context;
import com.alibaba.android.arouter.facade.template.IProvider;
public interface LoginService extends IProvider {
void loginActivity(Context context);
boolean hasLogin();
}
然后看下lib_base的build.gradle配置:
apply plugin: 'com.android.library'
apply plugin: 'com.alibaba.arouter'
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
minSdkVersion 16
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName(), AROUTER_GENERATE_DOC: "enable"]
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.appcompat:appcompat:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
//arouter库
compileOnly('com.alibaba:arouter-api:1.5.1') {
exclude group: 'com.android.support'
}
annotationProcessor 'com.alibaba:arouter-compiler:1.5.1'
}
接下来我们在ft_login工程中实现LoginService接口

package com.example.ft_login.service;
import android.content.Context;
import android.util.Log;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.example.ft_login.LoginActivity;
import com.example.lib_base.ft_login.service.LoginService;
@Route(path = "/login/login_service")
public class LoginServiceImpl implements LoginService {
@Override
public void loginActivity(Context context) {
LoginActivity.start(context);
}
@Override
public boolean hasLogin() {
return false;
}
@Override
public void init(Context context) {
Log.i(LoginServiceImpl.class.getSimpleName(), "init()");
}
}
package com.example.ft_login;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
import com.example.lib_base.ft_main.service.impl.MainImpl;
public class LoginActivity extends FragmentActivity {
public static void start(Context context) {
Intent intent = new Intent(context, LoginActivity.class);
context.startActivity(intent);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login_layout);
}
public void login(View view) {
MainImpl.getInstance().startMainActivity(this);
}
}
ft_login模块的build.gradle配置跟lib_base的配置差不多,这里就不放代码了。
为了其他模块方便调用ft_login模块,需要另外新建一个包装类,LoginImpl
package com.example.lib_base.ft_login.service.impl;
import android.content.Context;
import com.alibaba.android.arouter.facade.annotation.Autowired;
import com.alibaba.android.arouter.launcher.ARouter;
import com.example.lib_base.ft_login.service.LoginService;
public class LoginImpl {
@Autowired(name = "/login/login_service")
protected LoginService mLoginService;
private static LoginImpl mLoginImpl;
public static LoginImpl getInstance() {
if (mLoginImpl == null) {
synchronized (LoginImpl.class) {
if (mLoginImpl == null) {
mLoginImpl = new LoginImpl();
}
return mLoginImpl;
}
}
return mLoginImpl;
}
private LoginImpl() {
ARouter.getInstance().inject(this);
}
public void loginActivity(Context context) {
mLoginService.loginActivity(context);
}
public boolean hasLogin() {
return mLoginService.hasLogin();
}
}
接下来看下app工程如下:

package com.example.test;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import com.example.lib_base.ft_login.service.impl.LoginImpl;
public class LoadingActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_loading_layout);
handler.sendEmptyMessageDelayed(1, 2000);
}
Handler handler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
LoginImpl.getInstance().loginActivity(LoadingActivity.this);
finish();
}
};
@Override
public void onBackPressed() {
}
}
package com.example.test;
import android.app.Application;
import com.alibaba.android.arouter.launcher.ARouter;
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
ARouter.init(this);
}
}
app工程的build.gradle配置跟ft_login差不多,主要区别在于dependencies中
dependencies {
......
//业务基础库
implementation project(':lib_base')
implementation project(':ft_main')
implementation project(':ft_login')
//arouter库
implementation('com.alibaba:arouter-api:1.5.1') {
exclude group: 'com.android.support'
}
annotationProcessor 'com.alibaba:arouter-compiler:1.5.1'
}
接下来启动工程就能看到从loading页面跳转到登录页面了。ft_main的写法同ft_login,这里不做展开了。
下面这张图是整个demo的工程结构图,大家可以更直观的感受组件化的整体结构。

组件化的核心思路就是将业务模块拆分,然后通过ARouter库来进行业务模块间的解耦。这样能避免业务模块间互相引用,能将复杂的业务模块拆分成多个小的组件,便于维护。
github上已经上传了demo。
关于组件化大家也可以看下这两篇文章,写得非常详细,非常好。
组件化:
https://blog.csdn.net/guiying712/article/details/55213884
多人协作gradle配置:
https://blog.csdn.net/guiying712/article/details/72629948