Android组件化开发的意义何在?

安卓组件化开发的意义

当项目比较大需要多人协同开发的时候,组件化开发可以使大家分模块开发,并且不会互相影响。并且可以单独调试,不受其他模块制约。

项目结构解析

创建一个主应用,两个子应用(既可以做应用,也可以作为主应用的依赖),一个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

    
    

        
            
            
        

    

基础库设置

基础库设置接口,由子项目实现

以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 中已收录,里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中...

你可能感兴趣的:(Android组件化开发的意义何在?)