什么是组件化?

一个大型APP版本一定会不断的迭代,APP里的功能也会随之增加,项目的业务也会变的越来越复杂,这样导致项目代码也变的越来越多,开发效率也会随之下降。并且单一工程下代码耦合严重,每修改一处代码后都要重新编译,非常耗时,单独修改的一个模块无法单独测试。

组件化架构的目的是让各个业务变得相对独立,各个组件在组件模式下可以独立开发调试,集成模式下又可以集成到“app壳工程”中,从而得到一个具有完整功能的APP。

组件化每一个组件都可以是一个APP可以单独修改调试,而不影响总项目。

Android 组件化共享数据结构_Android开发

为什么使用组件化?

编译速度: 可以但需测试单一模块,极大提高了开发速度 超级解耦: 极度降低了模块间的耦合,便于后期的维护和更新 功能重用: 某一块的功能在另外的组件化项目中使用只需要单独依赖这一模块即可 便于团队开发: 组件化架构是团队开发必然会选择的一种开发方式,它能有效的使团队更好的协作

组件化实现

一、建立项目

我们新建一个moduleLearn的项目,这里面我们再新建几个module。module的建立是 file- > new module。

这里说明一下,我们建立了chat、contract、home这三个module,它们三个在建立的时候选择Phone & Tablet module模式。这三个模块, 就是我们要独立进行开发的。

commonlib在建立的时候,选择Android Library,它是做为公共组件存在

二、添加变量

让各组件可以根据变量值的变化来确定是否可以独立开发

在项目的根目录下,找到gradel.properties文件,在里面写下

#是否需要单独编译 true表示不需要 false表示需要

isNeedHomeModule = true
isNeedChatModule = true
isNeedContractModule = true

三、在各个子组件的build.gradle中进行修改

1,在头部进行修改

//根据是否独立运行,来改变module
if(!isNeedHomeModule.toBoolean())
{
    apply plugin: 'com.android.application'
}else{
    apply plugin: 'com.android.library'
}

2, android-> defaultConfig中的内容

android {
    compileSdkVersion 28
    defaultConfig {
   		//独立运行时,添加applicaton
        if(!isNeedHomeModule.toBoolean()) {
            applicationId "com.cg.home"
        }
        minSdkVersion 21
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
    }

三、修改各子组件的androidmanifest.xml文件

在src -> main 下面建立manifest文件夹,在里面再建立一个androidmanifest.xml文件,把外面的androidmanifest.xml的内容复制一份进来,并修改外面的androidmanifest.xml内容,修改什么呢,就是把默认的启动页去掉。

<?xml version="1.0" encoding="utf-8"?>


<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">


    </activity>
</application>

下面是正常的androidmanifest.xml

<?xml version="1.0" encoding="utf-8"?>


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.cg.home">


    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />


                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>


</manifest>

现在看到区别了吧,为什么要改这里呢,这里你不改的话,可以试一下,在不进行独立开发的时候,你一安装app,会有多个启动页面,这样就会在手上出现多个app的进入图标。

添加完androidmanifest.xml后,我们要去修改build.gradle文件,在android中添加

sourceSets{
        main{
			//这里我只是用home做的例子,每个module都要进行改,要判断相应的判断
            if(!isNeedHomeModule)
            {
                manifest.srcFile 'src/main/manifest/AndroidManifest.xml'
            }else{
                manifest.srcFile 'src/main/AndroidManifest.xml'
            }
        }
    }

四,去主app的build.gradle中添加引用

if(isNeedChatModule.toBoolean())
    {
        implementation project(':chat')
    }


    if(isNeedContractModule.toBoolean())
    {
        implementation project(':contract')
    }


    if(isNeedHomeModule.toBoolean())
    {
        implementation project(':home')
    }


    implementation project(':commonlib')

当进行独立开发的时候,就需要进行引用。

好,到这里,组件化就算处理完成了,运行一下,就可以看到,只要修改gradle.properties里面我们自定义的变量值,就可以实现是否独立开发了。

下面我们来看一下,ARouter的引用与使用。

我们定义了commonlib的作用就是为了能做共用的代码提取出来,但是ARouter里面的一些代码,却无法放到这里,不然总是会提示你错误。这算是一个坑吧。

现在我们把ARouter怎么引入做一个说明

一、所有module都引用一个commonlib。

二、在commonlib的buile.gradle中引入

compile "com.alibaba:arouter-api:1.5.0"

当然了,你可以不放在dommlib中,在每个module中独立加也行

三、在每个module中引入

annotationProcessor 'com.alibaba:arouter-compiler:1.2.2'

同时,在android -> defaultConfig中添加

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.cg.modulelearn"
        minSdkVersion 21
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"


		//这里就是ARouter的引用
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [AROUTER_MODULE_NAME: project.getName()]
            }
        }
    }

这里要注意主app中也要添加

四、初始化ARouter是在主app中,定义一个我们自己的myAppllication.

public class myApplication extends Application {


    @Override
    public void onCreate() {
        super.onCreate();


        initRouter();
    }


    private void initRouter() {
        if(BuildConfig.DEBUG)
        {
            ARouter.openLog();
            ARouter.openDebug();
        }
        ARouter.init(this);
    }
}

这样就集成完了,现在看一下,如何跳转与传值。

一、在子module中我们要进行注解

//这里注意,这时必须是二级目录,这里写的path就是在主app中要调用的跳转路径
@Route(path="/home/main")
public class MainActivity extends AppCompatActivity {


    private TextView txt_homeTitle;


	//这里的title值,就是要传入的值,前面必须加上@Autowired
    @Autowired
    public String title;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_homemain);
        //将页面注入到ARouter中
        ARouter.getInstance().inject(this);
        Log.e("MainActivity.java(onCreate)", "行数: 25  title:" + title);
        initControls();
    }


    /**
     * 初始化控件
     */
    private void initControls() {
        txt_homeTitle = (TextView)findViewById(R.id.txt_homeTitle);
        txt_homeTitle.setText(title);
    }




}

主app中的代码

public class MainActivity extends AppCompatActivity {


    private Button btn_home;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //ARouter.getInstance().inject(this);
        initControls();
    }


    /**
     * 初始化控件
     */
    private void initControls() {
        btn_home = (Button)findViewById(R.id.btn_home);
        btn_home.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ARouter.getInstance().build("/home/main")
                        .withString("title","主app传过来的HOME名字")
                        .navigation();
            }
        });
    }
}