安卓组件化开发的意义
当项目比较大需要多人协同开发的时候,组件化开发可以使大家分模块开发,并且不会互相影响。并且可以单独调试,不受其他模块制约。
项目结构解析
创建一个主应用,两个子应用(既可以做应用,也可以作为主应用的依赖),一个base库实现主应用和子应用的通讯。创建后项目结构如下
统一项目编译版本
- gradle.properties文件设置统一版本
# 统一编译版本等信息
compile_Sdk_Version=28
min_Sdk_Version=15
target_Sdk_Version=28
- 修改app、loginmodule、memodule、mudulelibrary的编译版本,以app为例
apply plugin: 'com.android.application'
android {
compileSdkVersion compile_Sdk_Version.toInteger()
defaultConfig {
applicationId "com.syw.modulesdemo"
minSdkVersion min_Sdk_Version.toInteger()
targetSdkVersion target_Sdk_Version.toInteger()
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
设置application和library切换开关
- gradle.properties文件设置切换开关
# application和library切换开关
isLoginApplication=true
isMeApplication=true
- 主应用动态添加依赖
//不要忘记toBoolean()
if (!isLoginApplication.toBoolean()) {
implementation project(':loginmodule')
}
if (!isMeApplication.toBoolean()) {
implementation project(':memodule')
}
implementation project(':modulelibrary')
- 子应用切换application和library、动态设置applicationId、动态设置AndroidManifest.xml、添加基础依赖。以login模块为例
//1.动态设置application或library
if (isLoginApplication.toBoolean()){
apply plugin: 'com.android.application'
}else{
apply plugin: 'com.android.library'
}
android {
compileSdkVersion compile_Sdk_Version.toInteger()
defaultConfig {
//2.library不存在applicationId
if (isLoginApplication.toBoolean()){
applicationId "com.syw.loginmodule"
}
minSdkVersion min_Sdk_Version.toInteger()
targetSdkVersion target_Sdk_Version.toInteger()
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
// 3.library状态下AndroidManifest.xml没有application信息,不设置启动activity
sourceSets{
main{
if (isLoginApplication.toBoolean()){
manifest.srcFile 'src/main/AndroidManifest.xml'
}else{
manifest.srcFile 'src/main/manifests/AndroidManifest.xml'
}
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:2.0.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation project(':modulelibrary')
}
依赖库的manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.syw.loginmodule">
<application>
<activity android:name=".LoginActivity">
</activity>
</application>
</manifest>
基础库设置
基础库设置接口,由子项目实现
以login模块为例,编写ILoginService
public interface ILoginService {
void launch(Context context);
Fragment getFragment(FragmentManager fragmentManager, int containerId, Bundle bundle);
}
编写接口管理类
public class ServiceFactory {
// 单例模式
private static final ServiceFactory instance=new ServiceFactory();
public ServiceFactory(){}
public static ServiceFactory getInstance() {
return instance;
}
private ILoginService iLoginService;
private IMeService iMeService;
public ILoginService getLoginService() {
return iLoginService;
}
public void setLoginService(ILoginService iLoginService) {
this.iLoginService = iLoginService;
}
public IMeService getMeService() {
return iMeService;
}
public void setMeService(IMeService iMeService) {
this.iMeService = iMeService;
}
}
子项目完成具体实现
public class LoginBridge implements ILoginService {
@Override
public void launch(Context context) {
Intent intent = new Intent(context, LoginActivity.class);
context.startActivity(intent);
}
@Override
public Fragment getFragment(FragmentManager fragmentManager, int containerId, Bundle bundle) {
LoginFragment loginFragment=new LoginFragment();
loginFragment.setFragmentData(bundle);
fragmentManager.beginTransaction().add(containerId,loginFragment).commit();
return loginFragment;
}
}
跳转方法的调用
跳转的具体实现已经完成,现在的问题是怎么调用,我们想要实现的是在MainActivity中通过如下代码调用
ServiceFactory.getInstance().getLoginService().launch(MainActivity.this);
那么现在的问题是,什么时候将LoginService设置到ServiceFactory,刚开始的时候还在想,既然已经依赖了loginmodule,为啥不直接跳转。仔细想想,这就违背了组件化的本意了,我们应该减少子项目和主项目之间的耦合,通过中间库的方式。
为了调用getLoginService,我们首先需要setLoginService,将实现类设置到ServiceFactory。于是就有了下面的方法
在子项目中创建一个方法,在主项目初始化的时候,通过主项目调用,子项目将实现类设置给ServiceManager
- 我们首先需要在基础库创建一个接口,通过主项目调用,实现全部子应用设置Service
public interface Appcompat {
void initializa();
}
- 我们首先创建一个类,实现该接口,设置LoginService
public class LoginApplication extends Application implements Appcompat {
@Override
public void initializa() {
ServiceManager.getInstance().setLoginService(new LoginBridge());
}
}
- 我们创建一个类,管理所有子项目设置Service的类。主项目通过反射的方法调用,实现全部子应用设置Service
public class AppConfig {
public static final String[] COMPONENT={
"com.syw.loginmodule.LoginApplication",
"com.syw.memodule.MeApplication"
};
}
- 现在我们需要在主项目中调用方法了,首先在主项目初始化的时候,通过initializa方法调用,已经让所有子项目setXxxService。
public class MainApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
for (String component : AppConfig.COMPONENT) {
try {
Class<?> clazz=Class.forName(component);
Object obj = clazz.newInstance();
if (obj instanceof Appcompat){
((Appcompat) obj).initializa();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
- 在需要使用的地方,即可直接getXxxService,然后调用方法
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.gologin).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ServiceManager.getInstance().getLoginService().launch(MainActivity.this);
}
});
findViewById(R.id.gome).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ServiceManager.getInstance().getMeService().launch(MainActivity.this);
}
});
findViewById(R.id.gofragment).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Bundle bundle=new Bundle();
bundle.putString("name","张三");
ServiceManager.getInstance().getLoginService().invokeLoginFragment(getSupportFragmentManager(),R.id.container,bundle);
}
});
}
}
应该还可以参考阿里的aroute框架,目前先暂时记录到这里
demo下载链接https://download.csdn.net/download/ForMuHan/13067005
本文在开源项目:https://github.com/Android-Alvin/Android-LearningNotes 中已收录,里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中...
网友评论