传统的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