从零开始搭建Android组件化框架

作者: 8ba406212441 | 来源:发表于2018-06-06 20:55 被阅读4177次

    问题

    在已经开发过几个项目的童鞋,如果这时需要重新开发一个新项目,是否需要自己重新搭建框架呢,还是从老项目中拷贝粘贴? 我们是否可以封装一个底层的lib库,这个底层的公共基础库 包括了一些第三方库(如: okhttp, retrofit2, glide 等)的初始化及简单的封装和一些公共的base类.这样我们重新开发一个新项目只要依赖这个库就马上可以进行业务逻辑的开发了.

    什么是组件化

    组件化简单概括就是把一个功能完整的 App 或模块拆分成多个子模块, 每个子模块可以独立编译和运行, 也可以任意组合成另一个新的 App 或模块, 每个模块即不相互依赖但又可以相互交互, 遇到某些特殊情况甚至可以升级或者降级.
    大家可以点击该文章查看 [组件化框架简介] (https://www.jianshu.com/p/40e745038471)

    前言

    从今年开始接触组件化项目,刚开始感觉组件化非常的高大上,经过一段时间的了解,现在对组件化终于有了一定的了解,为了能更熟悉运用于实际的项目中,决定自己写一个demo框架,也想解决上述的问题,这章文档主要是对我所学习的内容做一个总结,巩固Android的一些基础知识,非常适合初学者,并且架构简单,学习成本低,对于一个急需快速组件化拆分的项目是很适合的. 望高手们多指教!
    附上 Demo地址 Github : 您的 Star 是我坚持的动力 ✊

    请使用 Android studio 3.0 以上版本


    老规则,先上效果图

    项目效果图.gif
    备注:该Demo只完成十分之一,有时间会一直更新

    一,demo 架构图详解

    系统架构设计.png

    上图是组件化工程模型,下面会列举一些组件化工程中用到的名词的含义:

    集成模式: 所有的业务组件被“app壳工程”依赖,组成一个完整的APP;
    组件模式: 可以独立开发业务组件,每一个业务组件就是一个APP;
    app壳工程: 负责管理各个业务组件,和打包apk,没有具体的业务功能;
    业务组件: 根据公司具体业务而独立形成一个的工程;
    Main组件:属于业务组件,指定APP启动页面、主界面 ;
    Common组件: 也就是功能组件(component_base 模块),支撑业务组件的基础,提供多数业务组件需要的功能,例如提供网络请求功能;
    component_data组件: 这里我存放了与项目相关的公共数据,例如bean的基类,IntentKV存数据的键值对等.
    SDK组件: 集成微信,支付宝支付,分享,推送等常用的第三方框架.


    组件化的优点

    Android APP组件化架构的目标是告别结构臃肿,让各个业务变得相对独立,业务组件在组件模式下可以独立开发,而在集成模式下又可以变为arr包集成到“app壳工程”中,组成一个完整功能的APP;
    从组件化工程模型中可以看到,业务组件之间是独立的,没有关联的,这些业务组件在集成模式下是一个个library,被app壳工程所依赖,组成一个具有完整业务功能的APP应用,但是在组件开发模式下,业务组件又变成了一个个application,它们可以独立开发和调试,由于在组件开发模式下,业务组件们的代码量相比于完整的项目差了很远,因此在运行时可以显著减少编译时间。


    Arouter路由.png

    这是组件化工程模型下的业务关系,业务之间将不再直接引用和依赖,而是通过“路由”这样一个中转站间接产生联系,而Android中的路由实际就是对URL Scheme的封装;
    对阿里巴巴的Arouter不熟悉的可以点击了解:https://github.com/alibaba/ARouter


    二, 项目中base基类和Libraries的简介

    项目目录.png component_base基础库.png 第三方依赖.png

    对于Android中常用的基类库,主要包括开发常用的一些框架。

    • 该项目基于目前比较流行的框架:Material Design + MVP + Rxjava2 + Retrofit2 + GreenDao + Glide

    • 部分的代码及API接口来自 Awesome WanAndroid 项目,以学习为目的,可以查看原著:https://github.com/JsonChao/Awesome-WanAndroid

    • 部分 Base基类,Libraries 简介

    1、Base 基类(BaseMVPActivity, BaseMVPFragment, BasePermissionActivity,
    BaseListFragment, BaseTabListFragment, BaseObserver...)
    2、MVP 基类(BaseView, BasePresenter ...)
    3、Retrofit2 + RxJava2 的封装 https://github.com/square/retrofit
    4、Autolayout 鸿洋大神的Android全尺寸适配框架.
    5、安卓调试神器-Stetho(Facebook出品 建议使用) https://github.com/facebook/stetho
    6、LocaleHelper 的封装,多语言包括阿拉伯语,从右到左布局,参考:https://juejin.im/entry/599397c5f265da2480332362
    7、Logger 网络日志的简单封装 https://github.com/orhanobut/logger
    8、通用的工具类
    9、自定义view(包括对话框,ToolBar布局,圆形图片等view的自定义)
    11、其他等等

    三,组件化搭建流程

    好了,前面废话了很多,下面才开始我们真正的组件化搭建过程,首先我们来看看组件模式和集成模式切换的实现:

    config.gradle主要来管理统一的SDK版本,避免版本冲突 (详细代码请下载项目查看 https://github.com/tome34/frameDemoMo2 )

    app壳的config.gradle部分代码

    ext是自定义属性,把所有关于版本的信息都利用ext放在另一个自己新建的gradle文件中集中管理

    1)组件模式和集成模式的转换最终使用方式

        isModule = false
        moduleShopMall = false
        moduleShopCart = false
        moduleWelfare = false
    
        isModule false;  表示整个app运行, true: 表示单独运行某一个module
        moduleShopMall;  false:作为Lib组件存在,true:作为application存在(其他  
        module同理)
    
    集成模式

    1, 首先需要在 config.gradle 文件中设置 appDebug = false
    2, 然后 Sync 下
    3, 最后选择 app 运行即可

    组件模式

    1, 首先需要在 config.gradle 文件中设置 appDebug = true
    2, 然后 Sync 下
    3, 最后相应的模块(moduleShopMall 、moduleShopCart 、moduleWelfare )进行运行即可

    2)组件化的配置流程

    Android Studio中的Module主要有两种属性,分别为:

    application属性,可以独立运行的Android程序,也就是我们的APP;    
    apply plugin: ‘com.android.application’
    
    library属性,不可以独立运行,一般是Android程序依赖的库文件;
    apply plugin: ‘com.android.library’
    

    Module的属性是在每个组件的 build.gradle 文件中配置的,当我们在组件模式开发时,业务组件应处于application属性,这时的业务组件就是一个 Android App,可以独立开发和调试;而当我们转换到集成模式开发时,业务组件应该处于 library 属性,这样才能被我们的“app壳工程”所依赖,组成一个具有完整功能的APP;

    1: 组件模式和集成模式的转换

    我们在AndroidStudio创建一个Android项目后,新建了config.gradle文件,并配置ext 管理整个项目的常量,那么在Android项目中的任何一个build.gradle文件中都可以把config.gradle中的常量读取出来, 如下代码:

    app壳的build.gradle

    注意:每次改变isModule的值后,都要同步项目才能生效;

    2: 组件之间AndroidManifest合并

    在 AndroidStudio 中每一个组件都会有对应的 AndroidManifest.xml,用于声明需要的权限、Application、Activity、Service、Broadcast等,当项目处于组件模式时,业务组件的 AndroidManifest.xml 应该具有一个 Android APP 所具有的的所有属性,尤其是声明 Application 和要 launch的Activity,但是当项目处于集成模式的时候, 我们要为组件开发模式下的业务组件再创建一个AndroidManifest.xml,然后根据isModule指定AndroidManifest.xml的文件路径,让业务组件在集成模式和组件模式下使用不同的AndroidManifest.xml,这样表单冲突的问题就可以规避了.如下module目录结构及:

    module目录结构

    上图是组件化项目中一个标准的业务组件目录结构,首先我们在main文件夹下创建一个module文件夹用于存放组件开发模式下业务组件的 AndroidManifest.xml,而 AndroidStudio 生成的 AndroidManifest.xml 则依然保留,并用于集成开发模式下业务组件的表单;然后我们需要在业务组件的 build.gradle 中指定表单的路径,代码如下:

       /*java插件引入了一个概念叫做SourceSets,通过修改SourceSets中的属性,可以指定哪些源文件
        (或文件夹下的源文件)要被编译,哪些源文件要被排除。*/
        sourceSets {
            main {
                if (rootProject.ext.moduleShopMall) {
                    manifest.srcFile 'src/main/module/AndroidManifest.xml'
                } else {
                    manifest.srcFile 'src/main/AndroidManifest.xml'
                    java {
                        //排除java/debug文件夹下的所有文件
                        exclude '*module'
                    }
                }
            }
        }
    

    这样在不同的开发模式下就会读取到不同的 AndroidManifest.xml ,然后我们需要修改这两个表单的内容以为我们不同的开发模式服务。

    3: 全局Context的获取及组件数据初始化

    当Android程序启动时,Android系统会为每个程序创建一个 Application 类的对象,并且只创建一个,application对象的生命周期是整个程序中最长的,它的生命周期就等于这个程序的生命周期。在默认情况下应用系统会自动生成 Application 对象,但是如果我们自定义了 Application,那就需要在 AndroidManifest.xml 中声明告知系统,实例化的时候,是实例化我们自定义的,而非默认的,如下图:

    组件化的AndroidManifest.xml

    android:name属性——是用来设置所有activity属于哪个application的,默认是android.app.Application,那么当我们是组件化项目我们就指定我们创建的module下的MyApp,该MyApp继承于基类的BaseApplication.

    组件化的appliction

    BaseApplication 主要用于各个业务组件和app壳工程中声明的 Application 类继承用的,只要各个业务组件和app壳工程中声明的Application类继承了 BaseApplication,当应用启动时 BaseApplication 就会被动实例化,这样从 BaseApplication 获取的 Context 就会生效,也就从根本上解决了我们不能直接从各个组件获取全局 Context 的问题;

    4: library依赖问题

    在组件化工程模型图中,我是把所有公共的功能组件全部放在component_base里面,我是想后期其他项目需要用到只依赖这个module就可以了,不需要依赖多个,这也有致命的缺点,就是有过多的依赖,不够单一,目前为了方便先这样做了.

    上面我们有介绍了自定义 config.gradle 配置来统一管理我们的版本, 所有在每个组件化项目中都依赖这个基础库component_base,如下代码

    //公用依赖包
        implementation project(':component_base')
        implementation project(':component_data')
    

    而我们的component_base 的build.gradle的代码如下:

    apply plugin: 'com.android.library'
    apply plugin: 'me.tatarka.retrolambda'  //lambda配置
    apply plugin: 'com.jakewharton.butterknife'
    
    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
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    
            //MultiDex分包方法
            multiDexEnabled true
    
            //Arouter路由配置
            javaCompileOptions {
                annotationProcessorOptions {
                    arguments = [moduleName: project.getName()]
                }
            }
    
        }
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }
    
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
        //防止编译的时候oom、GC
        dexOptions {
            javaMaxHeapSize "4g"
        }
    
        //解决.9图问题
        aaptOptions {
            cruncherEnabled = false
            useNewCruncher = false
        }
    
    }
        dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        api rootProject.ext.dependencies["appcompat_v7"]
        api rootProject.ext.dependencies["constraint_layout"]
        api rootProject.ext.dependencies["cardview-v7"]
        api rootProject.ext.dependencies["design"]
        testApi rootProject.ext.dependencies["junit"]
        androidTestApi rootProject.ext.dependencies["runner"]
        androidTestApi rootProject.ext.dependencies["espresso_core"]
    
        //MultiDex分包方法
        api rootProject.ext.dependencies["multidex"]
        //Arouter路由
        annotationProcessor rootProject.ext.dependencies["arouter_compiler"]
        api rootProject.ext.dependencies["arouter_api"]
        api rootProject.ext.dependencies["arouter_annotation"]
        //网络
        api rootProject.ext.dependencies["retrofit2"]
        api rootProject.ext.dependencies["converter-gson"]
        api rootProject.ext.dependencies["adapter-rxjava2"]
        api rootProject.ext.dependencies["rxjava2:rxandroid"]
        api rootProject.ext.dependencies["rxjava2"]
        api rootProject.ext.dependencies["logging-interceptor"]
        //黄油刀
        annotationProcessor rootProject.ext.dependencies["butterknife_compiler"]
        api rootProject.ext.dependencies["butterknife"]
        //日志
        api rootProject.ext.dependencies["logger"]
        //仿ios进度条
        api rootProject.ext.dependencies["kprogresshud"]
        //6.0权限
        api rootProject.ext.dependencies["permissionsdispatcher"]
        api rootProject.ext.dependencies["baseRecyclerViewAdapterHelper"]
        //图片
        api rootProject.ext.dependencies["glide"]
        //图片缩放,View Pager中浏览库
        api rootProject.ext.dependencies["photoview"]
        //仿ios 的PickerView时间选择器和条件选择器
        api rootProject.ext.dependencies["pickerView"]
        //上拉加载
        api rootProject.ext.dependencies["smartRefreshLayout"]
        api rootProject.ext.dependencies["SmartRefreshHeader"]
        //eventbus 发布/订阅事件总线
        api rootProject.ext.dependencies["eventbus"]
        //banner轮播图
        api rootProject.ext.dependencies["banner"]
        //RecyclerView万能适配器
        api rootProject.ext.dependencies["baseRecyclerViewAdapterHelper"]
        //Android屏幕适配
        api rootProject.ext.dependencies["autolayout"]
        //安卓调试神器-Stetho
        api rootProject.ext.dependencies["stetho"]
        api rootProject.ext.dependencies["stetho-okhttp3"]
    
        //公共数据
        implementation project(':component_data')
        }
    

    我们还是要考虑另一个情况,我们在build.gradle中compile的第三方库,例如AndroidSupport库经常会被一些开源的控件所依赖,而我们自己一定也会compile AndroidSupport库 ,这就会造成第三方包和我们自己的包存在重复加载,解决办法就是找出那个多出来的库,并将多出来的库给排除掉,而且Gradle也是支持这样做的,分别有两种方式:根据组件名排除或者根据包名排除,下面以排除support-v4库为例:

    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        compile("com.jude:easyrecyclerview:$rootProject.easyRecyclerVersion") {
            exclude module: 'support-v4'//根据组件名排除
            exclude group: 'android.support.v4'//根据包名排除
        }
    }
    
    5 Android Studio 3.0开始Gradle的配置
    • 这里介绍一下:android gradle tools 3.X 中依赖,implement、api 和compile区别

    2017 年google 后,Android studio 版本更新至3.0,更新中,连带着com.android.tools.build:gradle 工具也升级到了3.0.0,在3.0.0中使用了最新的Gralde 4.0 里程碑版本作为gradle 的编译版本,该版本gradle编译速度有所加速,更加欣喜的是,完全支持Java8。当然,对于Kotlin的支持,在这个版本也有所体现,Kotlin插件默认是安装的。

    在com.android.tools.build:gradle 3.0 以下版本依赖在gradle 中的声明写法

    compile fileTree(dir: 'libs', include: ['*.jar'])
    

    但在3.0后的写法为

    implementation fileTree(dir: 'libs', include: ['*.jar'])
    或
    api fileTree(dir: 'libs', include: ['*.jar'])
    

    在3.0版本中,compile 指令被标注为过时方法,而新增了两个依赖指令,一个是implement 和api,这两个都可以进行依赖添加,他们的区别是:

    • api 指令: 完全等同于compile指令,没区别,你将所有的compile改成api,完全没有错,它是对外部公开的。
    • implement指令: 这个指令的特点就是,对于使用了该命令编译的依赖,对该项目有依赖的项目将无法访问到使用该命令编译的依赖中的任何程序,也就是将该依赖隐藏在内部,而不对外部公开。
    • 从Android Studio 3.0开始,使用annotationProcessor代替apt。不可再使用apt,否则会编译报错。
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        //把implementation 用api代替,它是对外部公开的, 所有其他的module就不需要    
        //添加该依赖
        api rootProject.ext.dependencies["appcompat_v7"]
        api rootProject.ext.dependencies["constraint_layout"]
        api rootProject.ext.dependencies["cardview-v7"]
        api rootProject.ext.dependencies["design"]
        testApi rootProject.ext.dependencies["junit"]
        androidTestApi rootProject.ext.dependencies["runner"]
        androidTestApi rootProject.ext.dependencies["espresso_core"]
    }
    

    如果你想了解更多的Gradle知识,请点击查看:https://www.jianshu.com/p/8b8a550246bd

    6 组件之间调用和通信

    在组件化开发的时候,组件之间是没有依赖关系,我们不能在使用显示调用来跳转页面了,因为我们组件化的目的之一就是解决模块间的强依赖问题,假如现在要从A业务组件跳转到业务B组件,并且要携带参数跳转,这时候就需要引入“路由”的概念了.目前项目使用了阿里巴巴的Arouter路由,有兴趣的童鞋也可以去了解其他的"路由"框架,比如开源库的ActivityRouter, LiteRouter 路由框架 , AndRouter 路由框架 等.

    阿里巴巴的Arouter我就不在这里介绍了,请点击了解使用方式: https://blog.csdn.net/zhaoyanjun6/article/details/76165252

    7 组件化中的butterKnife的坑
    • 特别注意不要使用最新的8.8.1版本,而应该使用8.4.0 ,因为最新的版本好像不兼容组件化模式.按照8.4.0版本的方式依赖.
      第一步:
      在项目的buid.gradle中添加这两个依赖.
    buildscript {
      dependencies {
            classpath 'com.jakewharton:butterknife-gradle-plugin:8.4.0'
       classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
      }
    }
    
    

    第二步:
    在module的build.gredle 文件中的dependencies标签中添加

     annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0',
     implementation 'com.jakewharton:butterknife:8.4.0',
    
    

    第三步:
    在module的build.gredle 文件中添加

    apply plugin: 'com.jakewharton.butterknife'
    

    这三步就完成了butterKnife的接入了,如果你的Android studio 3.x 还没安装butterKnife的插件的,就先安装一下插件.

    • 组件化中的butterKnife的使用

    1、用R2代替R findviewid

      @BindView(R2.id.view_pager)
        ViewPager mViewPager;
        @BindView(R2.id.bottom_navigation_view)
        BottomNavigationView mBottomNavigationView;
        @BindView(R2.id.nav_view)
        NavigationView mNavView;
    
    

    每次都要syn一下,才会生效的.

    2、在click方法中同样使用R2,但是找id的时候使用R。

    @OnClick({R2.id.textView, R2.id.button1})
        public void onViewClicked(View view) {
            switch (view.getId()) {
                case R.id.textView:
                    break;
                case R.id.button1:
                    break;
            }
        }
    
    

    3、特别注意library中switch-case的使用,在library中是不能使用switch- case 找id的,解决方法就是用if-else代替。

    @OnClick({R2.id.textView, R2.id.button1, R2.id.button2})
        public void onViewClicked(View view) {
            int i = view.getId();
            if (i == R.id.textView) {
            
            } else if (i == R.id.button1) {
    
            } else if (i == R.id.button2) {
    
            } 
    

    就这样通过几个简单的步骤基本就完成了组件化的配置了. 具体可以运行项目查看.

    组件化项目的混淆方案

    组件化项目的Java代码混淆方案采用在集成模式下集中在app壳工程中混淆,各个业务组件不配置混淆文件。集成开发模式下在app壳工程中build.gradle文件的release构建类型中开启混淆属性,其他buildTypes配置方案跟普通项目保持一致,Java混淆配置文件也放置在app壳工程中,各个业务组件的混淆配置规则都应该在app壳工程中的混淆配置文件中添加和修改。

    之所以不采用在每个业务组件中开启混淆的方案,是因为 组件在集成模式下都被 Gradle 构建成了 release 类型的arr包,一旦业务组件的代码被混淆,而这时候代码中又出现了bug,将很难根据日志找出导致bug的原因;另外每个业务组件中都保留一份混淆配置文件非常不便于修改和管理,这也是不推荐在业务组件的 build.gradle 文件中配置 buildTypes (构建类型)的原因。

    四,知识点汇总

    1) Retrofit2 的封装

    2) Greendao 的使用

    ...



    该demo会持续优化更新,把知识点及工具类都汇总于该demo中,便于学习及日后查找.

    最后贴出Android组件化Demo地址:https://github.com/tome34/frameDemoMo2

    ** 如果你觉得这篇文章对你有帮助或启发,请点下关注,谢谢 _ **


    感谢以下文章提供的帮助:

    1, https://www.jianshu.com/p/8b8a550246bd
    2, https://www.jianshu.com/p/f671dd76868f
    3, https://blog.csdn.net/guiying712/article/details/55213884
    4, https://mp.weixin.qq.com/s/8PRbtmr2TNBH1MkqdFNiyg

    相关文章

      网友评论

      • 小小程序员jh:楼主写的很不错,学习了
      • jesse920524:按照你的butterKnife填坑指南配置了butterKnife,依然报错
        Could not get unknown property 'packageForR' for task ':app:processDebugResources' of type com.android.build.gradle.internal.res.LinkApplicationAndroidResourcesTask.

        你的项目下载下来也是报一样的错误.
        两个小时一直调这个,最终还是没有搞定.
        butterKnife似乎从9.0.0才开始支持组件化,参考https://github.com/JakeWharton/butterknife/issues/1310

        只好放弃在当前项目中使用ButterKnife了.
      • Master_Yang:问个问题,我怎么根据项目的业务来创建组件,比如,每个项目基本都会有登录和登出,是不是应该有个组件叫做module_login?,那我在其他组件里怎么调用这个login组件的登出接口呢
        8ba406212441:@Master_Yang 这个分模块你想怎么发都可以的,你可以把首页,列表,我的各分成一个组,视频和聊天分成一个组,如果觉得组太多,就把首页,列表和我的分成一个组,视频聊天和其他的也分成一个组都可以,反正就是随你喜欢
        Master_Yang:@tome869535144 比如,我现在项目是需要3个tab 比如首页,列表,我的,我是需要将3个frgamnet分别弄一个组件?module_login, module_home, module_xxx, module_me?,然后我的fragmeny里面还有视频功能,聊天功能,这又怎么分。。。
        8ba406212441:这个组件模块你自己喜欢就可以了,比如购物类的APP,你可以分订单,商品,登录等组件,你说调公共的接口可以放在基类里面,这样所有的组件都可以调得到,或者可以放在组件里面,供该组件内部调用,可以下载demo看看.
      • 我家小梅最可爱:IView 可以不用继承LifecycleOwner吗?
        activity和fragment都实现了LifecycleOwner。
        我家小梅最可爱:@tome869535144 谢谢
        8ba406212441:@我家小梅最可爱 可以的
      • CoderLiuPu:用gradle3.1.3报这个错误:
        找不到符号
        符号: 类 BaseEmptyVcFragment
        博主是不是忘传了:joy:
        8ba406212441:@梦是装梦 嗯嗯,是忘记上传了,我已经重新上传,你可以下载看看
      • 写代码的解先生:我有一个疑问,如果我需要在 module组件中进行一些三方的初始化,例如 IM 初始化,这样的代码原先是放在 application 中的,那么在集成模式下,这些代码应该放在那里呢
        HopeMan:@写代码的解先生 说一种思路:在壳工程的application中,根据config.gradle中的配置,通过反射加载组件中的某个类似组件中Application的功能的一个类。例如壳工程中有这么一个专门用来完成各个组件预初始化工作预加载的类RegisterComponent,其中有这样一个方法:
        /**
        * 注册组件
        *
        * @param classname 组件名
        */
        public static void registerComponent(@Nullable String classname) {
        if (TextUtils.isEmpty(classname)) {
        return;
        }
        if (components.keySet().contains(classname)) {
        return;
        }
        try {
        Class clazz = Class.forName(classname);
        IApplicationLike applicationLike = (IApplicationLike) clazz.newInstance();
        applicationLike.onCreate();
        components.put(classname, applicationLike);
        } catch (Exception e) {
        e.printStackTrace();
        }
        }
        调用方式:RegisterComponent.registerComponent("com.luojilab.share.applike.ShareApplike");
        com.luojilab.share.applike.ShareApplike就是上面说的类似application的类。
        写代码的解先生:@tome869535144 我觉得能不能把这些初始化放在组件当中,组件负责完成这些初始化操作
        8ba406212441:@写代码的解先生 如果要module单独运行,就需要在module中的myApplication中初始化,然后在APP下的myApplication下也同样做初始化,myApplication是继承application的,跟普通项目一样。
      • 我家小梅最可爱:你好我有一个问题。
        isModule = false
        moduleShopMall = false
        moduleShopCart = false
        moduleWelfare = false
        这样的情况下,我怎么控制打开的第一个activity不是SplashActivity(com.example.tome.module_shop_mall.activity)
        8ba406212441:@我家小梅最可爱 :+1:
        我家小梅最可爱:@tome869535144 你说的这个我明白了
        我之前是想知道集成模式下,第一个打开的activity怎么设置的,就是demo里面的splashactivity,发现是在module中manifest文件设置的。谢谢解答!
        8ba406212441:@我家小梅最可爱 你需要打开哪个module 就把isModule 设置为true,然后比如像单独运行moduleWelfare 这个module,就把moduleWelfare设置为true,然后同步一下就可以单独运行这个module了.你可以查看module下面另一个AndroidManifest.xml.这个文件就是来控制不同module单独运行的的启动页.
      • 乐雨252:我有个疑问,比如组件A和组件B是独立的,但是组件A需要启动组件B的界面,这个时候可以用路由,但是编译的时候只编译了组件A,还是启动不了组件B的界面。 这种问题如何解决?
        HopeMan:@bauerbao 这和组件化相违背了
        bauerbao:可以参考CC库,支持多个独立运行的组件app之间相互通信(前提必须有安装整体的主app)
        8ba406212441:@乐雨252 这就是组件化开发特点呀,各运行各组件,单独运行一个组件A,就没必要启动组件B啦,如果你查看多个组件就运行整个APP.如果按照你说的只编译组件A,又想启动组件B,那你可以把组件B当成一个lib依赖到组件A中.
      • 70574761680c:不太理解【就从根本上解决了我们不能直接从各个组件获取全局 Context 的问题】,不使用BaseApplication,组件会获取不到Context?假如所有组件都不需要在Application初始化的时候做一些初始化工作,那么不使用BaseApplication会有什么问题呢
        HopeMan:@tome869535144 当时这句话也是读了几遍没明白,看了代码才知道,所有处于library状态编译的组件是不能直接使用壳工程中BaseApplication中的对象的。作者的意思是在壳工程的BaseApplication中完成一些初始化。
        8ba406212441:@Andev 当然可以啦,你新建一个项目,就是没有BaseApplication呀,不是照样可以运行.用BaseApplication就是用来做一些全局的初始化,例如Context等等.
      • 向上_d821:学习一下!关注一下。赞一下
      • countryKing:把自己的工程改造完了,挺不错的。
        8ba406212441:@countryKing :+1::+1::+1:
      • 我赌一包辣条:config中改为moduleShopMall = true后会报错,错误日志Unable to resolve dependency for ':app@debug/compileClasspath': Could not resolve project :module_shop_mall.
        Open File
        Show Details
        HopeMan:@sunlight_1024 我在壳工程的build.gradle中这样改了下:
        if (!rootProject.ext.isModule) {
        if (!rootProject.ext.moduleShopMall) {
        implementation project(':module_shop_mall')
        }
        if (!rootProject.ext.moduleShopCart) {
        implementation project(':module_shop_cart')
        }
        if (!rootProject.ext.moduleWelfare) {
        implementation project(':module_welfare')
        }
        if (!rootProject.ext.moduleCommonUi) {
        implementation project(':module_common_ui')
        }
        }
        这样的话编译时就不会编译moduleShopMall对应的依赖库了
        我赌一包辣条:可以的,需要把config中的四个变量全都改为true才可以
      • 大lan猫:配置了config.gradle里的参数后,怎么单独运行moudle?
        8ba406212441:请看文档中的组件模式和集成模式的转换最终使用方式,设置参数后同步一下就可以运行了
      • ChrisSen:您好,想咨询您一个问题。
        看了您的项目,自己也跑了一下,发现您app包下面只是定义了一个application。为什么没有launcher Activity,如果使用了组件化,是不是只要最终引入的module中有launche的Activity就可以了。还有就是如果app只是作为一个壳的话,我觉得是不是不太合适,毕竟app作为软件的入口。您在开发的时候不知道您是一个什么样的想法和考虑。
        希望能收到您的回复!
        8ba406212441:@ChrisSen :+1:
        ChrisSen:@tome869535144 感谢您得回复,目前正在打算把自己手中得一个项目进行组件化,目前正在学习。
        8ba406212441:其实APP你也可以当成一个业务组件来看待,当我觉得把APP作为一个壳,同时也管理所有的module,把不同的业务组件放在不同的module中,这样就一目了然了。哪个页面配置了launcher 那他就是APP的启动页,其实组件化跟我们平时APP开发没多大区别,你可以模仿的新建一个组件化项目,或许就都明白了:blush:
      • 5e2dba156ed6:我在studio3.1.2上报错了
        Gradle DSL method not found: 'apply()'
        Possible causes:<ul><li>The project 'frameDemoMo2-master' may be using a version of the Android Gradle plug-in that does not contain the method (e.g. 'testCompile' was added in 1.1.0).
        Upgrade plugin to version 3.1.2 and sync project</li><li>The project 'frameDemoMo2-master' may be using a version of Gradle that does not contain the method.
        Open Gradle wrapper file</li><li>The build file may be missing a Gradle plugin.
        Apply Gradle plugin</li>
        8ba406212441:@小O雨 我刚刚也升级到3.1.3版本,目前没发现报错,你百度看看,或者我现在在推送一下项目,你在下载看看
      • 是小生孟浪了:Caused by: groovy.lang.MissingPropertyException: Could not get unknown property 'packageForR' for task ':app:processDebugResources' of type com.android.build.gradle.internal.res.LinkApplicationAndroidResourcesTask.
        at org.gradle.internal.metaobject.AbstractDynamicObject.getMissingProperty(AbstractDynamicObject.java:83)
        at org.gradle.internal.metaobject.AbstractDynamicObject.getProperty(AbstractDynamicObject.java:61)
        以上是我在studio3.13上报的错,跟你的butterknife配置有关????
        8ba406212441:@tome869535144 你把Gradle版本改成gradle:3.0.1 估计就可以运行了
        8ba406212441:@是小生孟浪了 应该是没关的,你百度看看
      • 未聞椛洺:学习学习
      • Julian_z:demo上传不完整,module_ui没有上传buildgradule
        8ba406212441:@同事叫我来巡山 不好意思,已经重新上传.麻烦再试试.
      • gton:我的也 报错啊
        Unable to resolve dependency for ':app@debug/compileClasspath': Could not resolve project
        8ba406212441:@gton 不好意思,已经重新上传.麻烦再试试.
      • 我不想说:为啥我下的demo跑不起来啊!!!!!
        我不想说:@tome869535144 阔以了 ,就是看不懂代码:joy: :joy: :joy:
        8ba406212441:@我不想说_cf2e 不好意思,已经重新上传.麻烦再试试.
      • JerryloveEmily::stuck_out_tongue_winking_eye: 我看到我的文章了:人工智能数学基础----导数,哈哈哈,欢迎关注我啊,陆续会上更多数学和机器学习的内容。 鸿洋站点都会有。
      • Android平头哥:不错
        HopeMan:@我家小梅最可爱 想把哪个module当做入口,把splashactivity放到对应组件就可以了,写法可以按照module_shop_mall main目录中清单文件中那样写
        我家小梅最可爱:你好,我有一个疑问,望解答
        moduleShopMall
        moduleShopCart
        moduleWelfare
        这3个module 我发现是 moduleShopMall 是入口 ,我需要在哪里更改入口呐
        8ba406212441:@梨子哥 互相学习😄😄😄

      本文标题:从零开始搭建Android组件化框架

      本文链接:https://www.haomeiwen.com/subject/hayisftx.html