Android组件化示例代码github地址:https://github.com/respost/ModuleDemo
一、组件化初始模型
1、通过一个简单的android项目初始架构图来了解组件化,如下图:

打个生动的比喻,把我们的APP当成一个电脑主机,那么app外壳就是主机外壳,main组件就是主板,其他各个组件就类似于硬盘、网卡、显卡之类的东西,各个组件连接到主板上,然后再安装到主机壳中,对外展示为一个完整的电脑主机。
2、app外壳和main组件是我们app的必备组成部分,一起构成了可对外发布的完整app,其他组件可以集成进来,也可以不集成进来,只会增加或者减少我们app的功能,但不影响我们app的最终发布。
二、创建Module模块(组件)
在我们的实际项目中,组件展示出来的效果大概是这样的:

1、我们开始创建Module模块,项目的APP上右键 → New → Module

2、选择 Android Library  →  Next

3、 输入模块名称 → Finish

三、组件的build.gradle文件说明
1、通过以上Module模块的创建,包括main组件在内,一共有5个组件,所以对应的有5个组件build.gradle文件,如下图:

2、 main组件的gradle文件中,apply plugin使用的是com.android.application

3、其他业务模块(组件A、组件B、组件C、common组件等),apply plugin使用的是com.android.library

四、组件集成
各个组件都建立完成之后,接下来可以把组件集成到main组件中,集成非常简单,只需在main组件的gradle文件中添加dependencies{}配置,添加如下语句:
  
   - 
    
     
    
    
     
      dependencies {
     
    
- 
    
     
    
    
     
           ...
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      //集成组件A
     
    
- 
    
     
    
    
         
      implementation project(':modulea')
     
    
- 
    
     
    
    
         
      //集成组件B
     
    
- 
    
     
    
    
     
          implementation 
      project
      (':moduleb')
     
    
- 
    
     
    
    
         
      //集成组件C
     
    
- 
    
     
    
    
     
          implementation 
      project
      (':modulec')
     
    
- 
    
     
    
    
     
      }
     
    
如下图:

五、组件资源共享
1、在common组件的build.gradle文件中,添加android 配置,如下:
  
   - 
    
     
    
    
     
      android 
      {
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      //省略前面的代码...
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      repositories 
      {
     
    
- 
    
     
    
    
             
      flatDir 
      {
     
    
- 
    
     
    
    
                 
      dirs 
      'libs'
     
    
- 
    
     
    
    
             
      }
     
    
- 
    
     
    
    
         
      }
     
    
- 
    
     
    
    
     
      }
     
    
在各个需要调用公共common组件的组件build.gradle文件中,也添加android 配置,如下:
  
   - 
    
     
    
    
     
      android 
      {
     
    
- 
    
     
    
    
        
     
    
- 
    
     
    
    
          
      //省略前面的代码..
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      repositories 
      {
     
    
- 
    
     
    
    
             
      flatDir 
      {
     
    
- 
    
     
    
    
                 
      dirs 
      '../common/libs/', 'libs'
     
    
- 
    
     
    
    
             
      }
     
    
- 
    
     
    
    
         
      }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      }
     
    
2、common组件里引入各种类库的时候必须用api,而不是用implementation,原因:
implementation编译的依赖只作用于当前的module,即common组件模块中使用implementation编译的三方库只对common模块起作用,main组件模块中无法使用该三方库。
 
3、关于组件资源共享,举个简单示例:例如图片都是存放到公共的common组件的res里,那么如何在组件A、组件B、组件C里使用呢?

使用方法如下:
- 打开各组件的build.gradle文件,在dependencies{}里添加如下代码即可:
  
   - 
    
     
    
    
     
      dependencies {
     
    
- 
    
     
    
    
         
     
    
- 
    
     
    
    
     
          ...
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      implementation project(':common')
     
    
- 
    
     
    
    
     
      }
     
    
- 如此一来,就能在组件A里调用common组件的图片资源了

4、同样的道理, 组件A、 组件B、 组件C的颜色代码也可以直接调用公共common组件里colors.xml的代码

5、我们可以把其他第三方库、自定义view、工具类、公用资源都放进公共common组件里,也就是说组件A、组件B、组件C里build.gradle所引入的类库,都可以放到common组件里的dependencies{}里

6、所以各个业务组件里面的build.gradle文件的dependencies{}配置简化后,就变成了下面这样:

7、通过以上解说,大家应该都明白了吧,图片、xml这些(value目录下的各种xml文件),都可以放到公共common组件里,然后再被其他组件引用。对于全局共用的style.xml文件,我们更应该把它放在common组件中,例如我们的项目theme,本来是放在main组件的style里面,我们可以把它移到common中,这样其他组件调试时,作为一个单独的项目,也能和主项目有一样的主题。总而言之,所有你认为可以被各个组件共享的资源,都可以放在common组件中。
六、往组件里添加Fragment
1、以组件A为例,在组件A里添加一个包fragment

2、在fragment包右键 → New → Fragment →Fragment(Blank)

3、 填写Fragment碎片名称,勾选创建xml文件,如下:

4、对应的fragment_module_a.xml文件代码:
  
   - 
    
     
    
    
     
      <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     
    
- 
    
     
    
    
         
      android:layout_width=
      "match_parent"
     
    
- 
    
     
    
    
         
      android:layout_height=
      "match_parent">
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      <ImageView
     
    
- 
    
     
    
    
             
      android:layout_width=
      "match_parent"
     
    
- 
    
     
    
    
             
      android:layout_height=
      "match_parent"
     
    
- 
    
     
    
    
             
      android:scaleType=
      "centerCrop"
     
    
- 
    
     
    
    
             
      android:src=
      "@drawable/a" />
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      <TextView
     
    
- 
    
     
    
    
             
      android:layout_width=
      "match_parent"
     
    
- 
    
     
    
    
             
      android:layout_height=
      "wrap_content"
     
    
- 
    
     
    
    
             
      android:gravity=
      "center"
     
    
- 
    
     
    
    
             
      android:padding=
      "5dp"
     
    
- 
    
     
    
    
             
      android:text=
      "组件A"
     
    
- 
    
     
    
    
             
      android:background=
      "@color/green"
     
    
- 
    
     
    
    
             
      android:textColor=
      "@android:color/white"
     
    
- 
    
     
    
    
             
      android:textSize=
      "24dp" />
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      </FrameLayout>
     
    

5、其他组件也类似组件A一样,创建一个Fragment碎片,然后添加不同的背景图片即可。
6、main组件里添加导航和Fragment容器,main组件里activity_main.xml的代码如下:
  
   - 
    
     
    
    
     
      <?xml version="1.0" encoding="utf-8"?>
     
    
- 
    
     
    
    
     
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     
    
- 
    
     
    
    
         
      xmlns:app=
      "http://schemas.android.com/apk/res-auto"
     
    
- 
    
     
    
    
         
      android:layout_width=
      "match_parent"
     
    
- 
    
     
    
    
         
      android:layout_height=
      "match_parent"
     
    
- 
    
     
    
    
         
      android:id=
      "@+id/container"
     
    
- 
    
     
    
    
         
      android:orientation=
      "vertical">
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      <FrameLayout
     
    
- 
    
     
    
    
             
      android:id=
      "@+id/content"
     
    
- 
    
     
    
    
             
      android:layout_width=
      "match_parent"
     
    
- 
    
     
    
    
             
      android:layout_height=
      "0dp"
     
    
- 
    
     
    
    
             
      android:layout_weight=
      "1">
     
    
- 
    
     
    
    
         
      </FrameLayout>
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      <com.google.android.material.bottomnavigation.BottomNavigationView
     
    
- 
    
     
    
    
             
      android:id=
      "@+id/navigation"
     
    
- 
    
     
    
    
             
      android:layout_width=
      "match_parent"
     
    
- 
    
     
    
    
             
      android:layout_height=
      "wrap_content"
     
    
- 
    
     
    
    
             
      android:layout_gravity=
      "bottom"
     
    
- 
    
     
    
    
             
      android:background=
      "?android:attr/windowBackground"
     
    
- 
    
     
    
    
             
      app:menu=
      "@menu/navigation" />
     
    
- 
    
     
    
    
     
      </LinearLayout>
     
    
7、res下创建一个menu目录,里面添加一个navigation.xml文件,代码如下:
  
   - 
    
     
    
    
     
      <?xml version="1.0" encoding="utf-8"?>
     
    
- 
    
     
    
    
     
      <menu xmlns:android="http://schemas.android.com/apk/res/android">
     
    
- 
    
     
    
    
         
      <item
     
    
- 
    
     
    
    
             
      android:id=
      "@+id/navigation_a"
     
    
- 
    
     
    
    
             
      android:icon=
      "@drawable/home"
     
    
- 
    
     
    
    
             
      android:title=
      "组件A" />
     
    
- 
    
     
    
    
         
      <item
     
    
- 
    
     
    
    
             
      android:id=
      "@+id/navigation_b"
     
    
- 
    
     
    
    
             
      android:icon=
      "@drawable/video"
     
    
- 
    
     
    
    
             
      android:title=
      "组件B" />
     
    
- 
    
     
    
    
         
      <item
     
    
- 
    
     
    
    
             
      android:id=
      "@+id/navigation_c"
     
    
- 
    
     
    
    
             
      android:icon=
      "@drawable/me"
     
    
- 
    
     
    
    
             
      android:title=
      "组件C" />
     
    
- 
    
     
    
    
     
      </menu>
     
    
navigation.xml里调用的icon图片分别放到drawable和drawable-24目录里,最终主APP的MainActivity界面如下图:

8、MainActivity.java的代码如下:
  
   - 
    
     
    
    
     
      package net.zy13.
      module.demo;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      import androidx.annotation.NonNull;
     
    
- 
    
     
    
    
     
      import androidx.appcompat.app.AppCompatActivity;
     
    
- 
    
     
    
    
     
      import androidx.fragment.app.Fragment;
     
    
- 
    
     
    
    
     
      import androidx.fragment.app.FragmentTransaction;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      import android.os.Bundle;
     
    
- 
    
     
    
    
     
      import android.view.MenuItem;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      import com.google.android.material.bottomnavigation.BottomNavigationView;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      import net.zy13.
      module.modulea.fragment.ModuleAFragment;
     
    
- 
    
     
    
    
     
      import net.zy13.
      module.moduleb.fragment.ModuleBFragment;
     
    
- 
    
     
    
    
     
      import net.zy13.
      module.modulec.fragment.ModuleCFragment;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      public 
      class MainActivity extends AppCompatActivity implements BottomNavigationView.OnNavigationItemSelectedListener {
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      //定义碎片集合
     
    
- 
    
     
    
    
         
      private Fragment[] fragments = 
      new Fragment[
      3];
     
    
- 
    
     
    
    
         
      //当前显示的fragment的索引位置
     
    
- 
    
     
    
    
         
      private 
      int currentIndex = 
      0;
     
    
- 
    
     
    
    
         
      @Override
     
    
- 
    
     
    
    
         
      protected void onCreate(Bundle savedInstanceState) {
     
    
- 
    
     
    
    
             
      super.onCreate(savedInstanceState);
     
    
- 
    
     
    
    
     
              setContentView(R.layout.activity_main);
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
              initFragment();
     
    
- 
    
     
    
    
     
              BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
     
    
- 
    
     
    
    
     
              navigation.setOnNavigationItemSelectedListener(
      this);
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      /**
     
    
- 
    
     
    
    
     
       * 初始化Fragment碎片
     
    
- 
    
     
    
    
     
       */
     
    
- 
    
     
    
    
         
      private void initFragment() {
     
    
- 
    
     
    
    
             
      if (fragments[
      0] == 
      null) {
     
    
- 
    
     
    
    
     
                  fragments[
      0] = 
      new ModuleAFragment();
     
    
- 
    
     
    
    
     
                  getSupportFragmentManager().beginTransaction().add(R.id.content, fragments[
      0], 
      "moduleA").commit();
     
    
- 
    
     
    
    
     
              } 
      else {
     
    
- 
    
     
    
    
     
                  getSupportFragmentManager().beginTransaction().show(fragments[
      0]);
     
    
- 
    
     
    
    
     
              }
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      /**
     
    
- 
    
     
    
    
     
       * 导航选择事件
     
    
- 
    
     
    
    
     
       * @param item
     
    
- 
    
     
    
    
     
       * @return
     
    
- 
    
     
    
    
     
       */
     
    
- 
    
     
    
    
         
      @Override
     
    
- 
    
     
    
    
         
      public boolean onNavigationItemSelected(@NonNull MenuItem item) {
     
    
- 
    
     
    
    
             
      switch (item.getItemId()) {
     
    
- 
    
     
    
    
                 
      case R.id.navigation_a:
     
    
- 
    
     
    
    
                     
      if (currentIndex == 
      0) 
      return 
      true;
      //如果已经是当前的fragment,不用切换
     
    
- 
    
     
    
    
     
                      FragmentTransaction transition0 = getSupportFragmentManager().beginTransaction();
     
    
- 
    
     
    
    
     
                      hideAndShow(
      0,transition0);
     
    
- 
    
     
    
    
                     
      return 
      true;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
                 
      case R.id.navigation_b:
     
    
- 
    
     
    
    
                     
      if (currentIndex == 
      1) 
      return 
      true;
      //如果已经是当前的fragment,不用切换
     
    
- 
    
     
    
    
     
                      FragmentTransaction transition1 = getSupportFragmentManager().beginTransaction();
     
    
- 
    
     
    
    
                     
      if (fragments[
      1] == 
      null) {
     
    
- 
    
     
    
    
     
                          fragments[
      1] = 
      new ModuleBFragment();
     
    
- 
    
     
    
    
     
                          transition1.add(R.id.content, fragments[
      1], 
      "moduleB");
     
    
- 
    
     
    
    
     
                      }
     
    
- 
    
     
    
    
     
                      hideAndShow(
      1,transition1);
     
    
- 
    
     
    
    
                     
      return 
      true;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
                 
      case R.id.navigation_c:
     
    
- 
    
     
    
    
                     
      if (currentIndex == 
      2) 
      return 
      true;
      //如果已经是当前的fragment,不用切换
     
    
- 
    
     
    
    
     
                      FragmentTransaction transition2 = getSupportFragmentManager().beginTransaction();
     
    
- 
    
     
    
    
                     
      if (fragments[
      2] == 
      null) {
     
    
- 
    
     
    
    
     
                          fragments[
      2] = 
      new ModuleCFragment();
     
    
- 
    
     
    
    
     
                          transition2.add(R.id.content, fragments[
      2], 
      "modulec");
     
    
- 
    
     
    
    
     
                      }
     
    
- 
    
     
    
    
     
                      hideAndShow(
      2,transition2);
     
    
- 
    
     
    
    
                     
      return 
      true;
     
    
- 
    
     
    
    
     
              }
     
    
- 
    
     
    
    
             
      return 
      false;
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      /**
     
    
- 
    
     
    
    
     
       * 除了指定的fragment不hide,其他fragment全hide
     
    
- 
    
     
    
    
     
       * @param expectIndex 指定的fragment在fragments中的位置
     
    
- 
    
     
    
    
     
       * @param transition
     
    
- 
    
     
    
    
     
       */
     
    
- 
    
     
    
    
         
      private void hideAndShow(int expectIndex,FragmentTransaction transition) {
     
    
- 
    
     
    
    
             
      for (
      int i = 
      0; i < fragments.length; i++) {
     
    
- 
    
     
    
    
                 
      if (i != expectIndex && fragments[i] != 
      null) {
     
    
- 
    
     
    
    
     
                      transition.hide(fragments[i]);
     
    
- 
    
     
    
    
     
                  }
     
    
- 
    
     
    
    
     
              }
     
    
- 
    
     
    
    
     
              transition.show(fragments[expectIndex]);
     
    
- 
    
     
    
    
     
              transition.commit();
     
    
- 
    
     
    
    
     
              currentIndex = expectIndex;
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      }
     
    
9、Run运行项目,最终效果如下图,点击导航,可以切换到对应的组件上:

七、各个组件单独开发(测试)
前面我们把各个组件集成到main组件中,现在我们把组件拆分出来,单独开发,开发测试完成后,再把组件集成到main组件中,最后发布。组件单独出来开发的方法就是:在build.gradle文件中,把apply plugin: 'com.android.library',改成apply plugin: 'com.android.application',也就是把其library模式改为application模式,因为只有application才可以单独运行,library必须依靠application才能运行。
那么问题来了?
组件单独开发时,我们需要改build.gradle的apply plugin模式,等要集成到main组件时,又得改回来,如果这样子手工去改,组件一多,修改起来比较麻烦,也不优雅。优雅的解决办法就是设置一个开关,打开时,就是application模式,可以单独开发;关闭时,就是library模式,可以集成到main组件中。现在按我下面的步骤来实现:
1、在项目根目录下,有一个build.gradle文件,在这个文件最末尾添加一个ext {}配置,然后在ext配置里设定一个常量isDebug,值设为true
  
   - 
    
     
    
    
     
      ext {
     
    
- 
    
     
    
    
         
      /**
     
    
- 
    
     
    
    
          
      * 
      组件调试模式
     
    
- 
    
     
    
    
          
      * 
      isDebug 
      = 
      true 
      是组件模块,
      说明是单独的App
     
    
- 
    
     
    
    
          
      * 
      isDebug 
      = 
      false
      是集成模式,
      说明是依赖Lib
     
    
- 
    
     
    
    
          
      * 
      每次更改“isDebug”的值后,需要点击 
      "Sync Project" 
      按钮
     
    
- 
    
     
    
    
          
      *
     
    
- 
    
     
    
    
          
      */
     
    
- 
    
     
    
    
         
      isDebug 
      = 
      true
     
    
- 
    
     
    
    
     
      }
     
    

2、build.gradle里设置了isDebug常量后,我们项目中的其他build.gradle文件都可以把这个常量读取出来,所以我们可以在其他组件的build.gradle文件中,读取该常量的值,动态设置apply plugin,代码如下:
  
   - 
    
     
    
    
     
      if(isDebug){
     
    
- 
    
     
    
    
     
          apply plugin: 
      'com.android.application'
     
    
- 
    
     
    
    
     
      }
      else{
     
    
- 
    
     
    
    
     
          apply plugin: 
      'com.android.library'
     
    
- 
    
     
    
    
     
      }
     
    
3、这样子设置之后,当我们需要切换模式时,只需要修改项目根目录下build.gradle文件中isDebug常量的值,修改完成之后,点击Project sync按钮同步一下即可。如果有报错,那么还有个地方需要修改一下,就是main组件的build.gradle文件,我们把module的模式改成了application,main组件就不能引入application,引入的话就会报错,所以当是debug调试模式时,这里就不引入该组件,以免报错。所以在集成组件前,要先判断是什么模式,如下图:

4、接下来还得修改 AndroidManifest.xml,当把一个module设置为application时,AndroidManifest.xml需要包含一个app所需要的属性,例如app的icon、theme、launch Activity这些属性设置,而当module为library时,这些属性就都不需要用到,所以当我们处于不同模式时,AndroidManifest.xml文件的配置也得不同。方法如下:
(1)、Android目录模式切换到Project目录模式

(2)、 在各个组件的src文件夹中新创建一个debug目录,再把我们用于debug调试的AndroidManifest.xml文件放进去

(3)、调试用的AndroidManifest.xml文件可以直接复制manifests目录里的,然后添加application的基本信息,如下:
  
   - 
    
     
    
    
     
      <?xml version="1.0" encoding="utf-8"?>
     
    
- 
    
     
    
    
     
      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     
    
- 
    
     
    
    
         
      package=
      "net.zy13.module.modulea">
     
    
- 
    
     
    
    
         
      <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">
     
    
- 
    
     
    
    
         
      </application>
     
    
- 
    
     
    
    
     
      </manifest>
     
    
以上内容会有很多错误提示,其实提示的无非就是资源找不到,既然前面我们已经创建了公共的common组件,那么我们只需要把main组件中相应的资源移动到common组件中就可以了。
5、接下来在各个组件的build.gradle文件中,指定不同模式下使用的AndroidManifest.xml文件,在android {}里添加如下代码:
  
   - 
    
     
    
    
     
      sourceSets {
     
    
- 
    
     
    
    
     
              main {
     
    
- 
    
     
    
    
                 
      if (isDebug) {
     
    
- 
    
     
    
    
     
                      manifest.srcFile 
      'src/debug/AndroidManifest.xml'
     
    
- 
    
     
    
    
     
                  }
      else{
     
    
- 
    
     
    
    
     
                      manifest.srcFile 
      'src/main/AndroidManifest.xml'
     
    
- 
    
     
    
    
                     
      //集成开发模式下排除debug文件夹中的所有Java文件
     
    
- 
    
     
    
    
     
                      java {
     
    
- 
    
     
    
    
     
                          exclude 
      'debug/**'
     
    
- 
    
     
    
    
     
                      }
     
    
- 
    
     
    
    
     
                  }
     
    
- 
    
     
    
    
     
              }
     
    
- 
    
     
    
    
     
      }
     
    

6、以上设置完成,并且sync project(同步项目)之后,各个组件会是这样的目录结构:

7、在各个组件里创建一个用于调试启动的MainActivity活动,然后把fragment加载到activity_main.xml里,所对应的activity_main.xml布局文件如下:
  
   - 
    
     
    
    
     
      <?xml version="1.0" encoding="utf-8"?>
     
    
- 
    
     
    
    
     
      <fragment xmlns:android="http://schemas.android.com/apk/res/android"
     
    
- 
    
     
    
    
     
      android:name=
      "net.zy13.module.modulea.fragment.ModuleAFragment"
     
    
- 
    
     
    
    
     
      android:layout_width=
      "match_parent"
     
    
- 
    
     
    
    
     
      android:layout_height=
      "match_parent">
     
    
- 
    
     
    
    
     
      </fragment>
     
    
8、添加MainActivity活动后,我们还需要手动设置该活动为入口,打开src/debug/目录下的AndroidManifest.xml文件,修改MainActivity的配置如下:
  
   - 
    
     
    
    
     
      <activity
     
    
- 
    
     
    
    
         
      android:name=
      ".MainActivity">
     
    
- 
    
     
    
    
         
      <intent-filter>
     
    
- 
    
     
    
    
             
      <action android:name="android.intent.action.MAIN" />
     
    
- 
    
     
    
    
             
      <category android:name="android.intent.category.LAUNCHER" />
     
    
- 
    
     
    
    
         
      </intent-filter>
     
    
- 
    
     
    
    
     
      </activity>
     
    
9、以上步骤完成之后,组件就可以单独作为一个app来开发测试了,android studio的运行app里面,同时多了几个可运行的项目,如下图:

八、统一项目版本号
各个组件的build.gradle文件中,有很多版本号。为了避免每次修改都得同时修改多份build.gradle文件,也避免不同的组件使用的版本不一样,导致冲突,所以我们可以把这些版本号统一管理起来,方法如下:
1、在项目根目录下的build.gradle文件中,定义版本号常量
  
   - 
    
     
    
    
     
      ext {
     
    
- 
    
     
    
    
         
      /**
     
    
- 
    
     
    
    
     
       * 组件调试模式
     
    
- 
    
     
    
    
     
       * isDebug = true 是组件模块,说明是单独的App
     
    
- 
    
     
    
    
     
       * isDebug = false是集成模式,说明是依赖Lib
     
    
- 
    
     
    
    
     
       * 每次更改“isDebug”的值后,需要点击 "Sync Project" 按钮
     
    
- 
    
     
    
    
     
       *
     
    
- 
    
     
    
    
     
       */
     
    
- 
    
     
    
    
     
          isDebug = 
      true
     
    
- 
    
     
    
    
         
      //版本号
     
    
- 
    
     
    
    
     
          android = [
     
    
- 
    
     
    
    
     
                  compileSdkVersion: 
      30,
     
    
- 
    
     
    
    
     
                  buildToolsVersion: 
      "30.0.0",
     
    
- 
    
     
    
    
     
                  minSdkVersion    : 
      15,
     
    
- 
    
     
    
    
     
                  targetSdkVersion : 
      30,
     
    
- 
    
     
    
    
     
                  versionCode      : 
      1,
     
    
- 
    
     
    
    
     
                  versionName      : 
      "1.0"
     
    
- 
    
     
    
    
     
          ]
     
    
- 
    
     
    
    
     
      }
     
    

2、然后在各个组件的build.gradle文件中,做这样的修改:
  
   - 
    
     
    
    
     
      android {
     
    
- 
    
     
    
    
     
          compileSdkVersion rootProject.ext.android.compileSdkVersion
     
    
- 
    
     
    
    
     
          buildToolsVersion rootProject.ext.android.buildToolsVersion
     
    
- 
    
     
    
    
     
          defaultConfig {
     
    
- 
    
     
    
    
     
              minSdkVersion rootProject.ext.android.minSdkVersion
     
    
- 
    
     
    
    
     
              targetSdkVersion rootProject.ext.android.targetSdkVersion
     
    
- 
    
     
    
    
     
              versionCode rootProject.ext.android.versionCode
     
    
- 
    
     
    
    
     
              versionName rootProject.ext.android.versionName
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      }
     
    

九、使用路由实现组件之间的通信
通过前面的学习,我们已经知道组件可以拆分了,但是当他们集成到main组件中时,还是需要一定的通信,例如业务A需要调用到业务B的一个页面,甚至进行传参。但是在“组件化”模式下,业务A和业务B是完全分开的,在业务A的认知里,根本就不存在业务B,也就没办法直接调用。当然,如果要业务A与业务B可以直接通信,互相引入就可以,但是这样的话,项目耦合性太高,架构也混乱,会把“组件化”的所有优点都一一撇掉,所以我们应该用另外一种方式来处理。
这里需要引入一个概念:路由”,就如我们实际访问网络一样,我们电脑发送的请求都经过路由器转发,在“组件化”中,我们也可以设置这么一个中转站,来统一处理不同组件之间的调用关系。关于路由的用法,后面会补充,这里先用最简单的方法,来实现组件之间的调用(页面跳转),代码如下:
  
   - 
    
     
    
    
     
      try {
     
    
- 
    
     
    
    
     
          Class c= Class.forName(
      "net.zy13.module.modulea.MainActivity");
     
    
- 
    
     
    
    
     
          Intent intent = 
      new Intent(context,c);
     
    
- 
    
     
    
    
     
          startActivity(intent);
     
    
- 
    
     
    
    
     
      } 
      catch (ClassNotFoundException e) {
     
    
- 
    
     
    
    
     
          Log.e(
      "组件",
      "组件未集成,无法跳转");
     
    
- 
    
     
    
    
     
      }
     
    
以上代码是通过完整的类名来进行跳转,在debug模式下,调用其他组件时,找不到对应组件,不会直接报错,只是提示“未集成,无法跳转”。我们可以把这个方法写成一个工具类,放在common组件中,方法如下:
1、在common组件里创建一个工具类PageUtils.java,代码如下:
  
   - 
    
     
    
    
     
      import android.content.Context;
     
    
- 
    
     
    
    
     
      import android.content.Intent;
     
    
- 
    
     
    
    
     
      import android.util.Log;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      /**
     
    
- 
    
     
    
    
     
       * @author 安阳 QQ:15577969
     
    
- 
    
     
    
    
     
       * @version 1.0
     
    
- 
    
     
    
    
     
       * @team 美奇软件开发工作室
     
    
- 
    
     
    
    
     
       * @date 2020/11/12 11:55
     
    
- 
    
     
    
    
     
       */
     
    
- 
    
     
    
    
     
      public 
      class PageUtils {
     
    
- 
    
     
    
    
         
      /**
     
    
- 
    
     
    
    
     
       * 页面跳转
     
    
- 
    
     
    
    
     
       * @param context
     
    
- 
    
     
    
    
     
       * @param className
     
    
- 
    
     
    
    
     
       */
     
    
- 
    
     
    
    
         
      public static void jump(Context context, String className){
     
    
- 
    
     
    
    
             
      try {
     
    
- 
    
     
    
    
     
                  Class c = Class.forName(className);
     
    
- 
    
     
    
    
     
                  Intent intent = 
      new Intent(context,c);
     
    
- 
    
     
    
    
     
                  context.startActivity(intent);
     
    
- 
    
     
    
    
     
              } 
      catch (ClassNotFoundException e) {
     
    
- 
    
     
    
    
     
                  Log.e(
      "组件",
      "未集成,无法跳转");
     
    
- 
    
     
    
    
     
              }
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      /**
     
    
- 
    
     
    
    
     
       * 页面跳转,可以传参,参数放在intent中,所以需要传入一个intent
     
    
- 
    
     
    
    
     
       * @param context
     
    
- 
    
     
    
    
     
       * @param className
     
    
- 
    
     
    
    
     
       * @param intent
     
    
- 
    
     
    
    
     
       */
     
    
- 
    
     
    
    
         
      public static void jump(Context context,String className,Intent intent){
     
    
- 
    
     
    
    
             
      try {
     
    
- 
    
     
    
    
     
                  Class c = Class.forName(className);
     
    
- 
    
     
    
    
     
                  intent.setClass(context,c);
     
    
- 
    
     
    
    
     
                  context.startActivity(intent);
     
    
- 
    
     
    
    
     
              } 
      catch (ClassNotFoundException e) {
     
    
- 
    
     
    
    
     
                  Log.e(
      "组件",
      "未集成,无法跳转");
     
    
- 
    
     
    
    
     
              }
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      }
     
    
2、在需要跳转的地方,直接用以下方法调用:
PageUtils.jump(context,"net.zy13.module.modulea.MainActivity");还有一种通信情况,就是其中某个组件的改变会影响到其他组件的改变。例如用户的登陆情况(是否登录),会影响到其他组件中一些控件的显示情况,这个时候我们可以用android的广播机制,或者用EventBus来解决。实际开发中,如果是像这种会影响全局的改变,应该放在公共的common组件之中。用户的登陆情况,是影响全局的存在,那么就可以在common中,定义一个用户单例,其他组件分别拿这个单例去控制其界面的显示,特别是引入databingding之后,操作起来更为方便,具体的实现方式大家可以百度参考其他教程,这里我就不实现了。
十、android路由框架
关于路由框架的具体用法,我单独整理成了一篇文章,示例代码也是写在了组件化项目里。
Android的路由框架用法:https://blog.csdn.net/qq15577969/article/details/109690111
转载:https://blog.csdn.net/qq15577969/article/details/109596071
