一.组件化/模块化及插件化概念:
多module划分业务和基础功能,这概念作为组件化的基础。
- 组件:指的是单一的功能组件,如视频组件(VideoSDK)/支付组件(PaySDK)/路由组件(Router)等,每个组件都能单独抽出来制作成SDK。
- 模块:指的是独立的业务模块,如直播模块(LiveModule)/首页模块(HomeModule)/即时通讯模块(IMModule)等,模块相对于组件来说粒度更大,模块可能包含多种不同的组件。
组件化开发的好处:
- 避免重复造轮子,可以节省开发和维护的成本;
- 可以通过组件和模块为业务基准合理地安排人力,提高开发效率;
- 不同的项目可以共用一个组件或模块,确保整体技术方案的统一性;
- 为未来插件化共用同一套底层模型做准备。
模块化开发的好处:
- 业务模块解耦,业务移植更加简单;
- 多团队根据业务内容进行并行开发测试;
- 单个业务可以单独编译打包,加快编译速度;
- 多个app共用模块,降低了研发和维护成本。
组件化和模块化的本质思想是一致的,都是为了代码重用和业务解耦。区别在于模块化是业务导向,组件化湿功能导向。
项目体积越来越大后,必定会有超过方法数65535的时候,要么选择MultiDex的方式分包解决,要么使用插件化的方法是完成项目。
组件化和模块化的划分将更好地为项目插件化开路。插件化的模块发布和正常发布有着非常大的差异,已经脱离了组件化和模块化的构建机制,插件化拥有更高效的业务解耦。
二.依赖:
Android studio独有设计——module依赖,包括对第三方库的依赖,它包含对其他Module的依赖。通过依赖我们可以访问第三方和其他被依赖Module的代码和资源。
- Jar dependency:通过Gradle配置引入lib文件夹中的所有.jar后缀的文件,还能引用.aar后缀的文件;
- Base Module:相当于一个基础模块库(lib Module)来作为依赖,对应的是Module dependency,实质上是将其打包aar文件,方便其他苦进行依赖;
- 第三方依赖通过Library dependency完成仓库索引依赖,这里的仓库可以配置为网络库和本地库。
全部工具作用的配置最后还是会转化为代码的形式存在于我们配置的build.gradle中。
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
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'
}
一般情况下,Android studio定义使用dependencies包含全部资源引入,使用compile提示来引入库:
- 读入自身目录使用的是fileTree是;
- 读入其他资源module使用的“project”字段,而“:base”中的冒号的意思是文件目录内与自己相同层次的其他module;
- “annotationProcessor”字段作用与“compile”类似。
三.聚合和解耦:
- 依赖——关系:有依赖才能产生关系,Android Studio正是以依赖的方式给每个module之间提供了沟通和交流的渠道,从而形成聚合;
- 关系——解耦:需要解耦,就要设计更加适合交流沟通的系统。
聚合和解耦是项目架构的基础,架构的实质可以理解为人与人之间关系的连接。
四.AndroidManifest:
1.AndroidManifest其实就是Android项目的声明配置文件。
每个module都有一份配合的AndroidManifest文件来记载其信息,最终生成一个app的时候,其只有一份AndroidManifest来指导app应该如何配置。多个AndroidManifest记录独立配置信息,最终合成一个AndroidManifest。
最终合成一个AndroidManifest的地址,地址为:app/build/intermediates/manifests/full/debug/AndroidManifest.xml,intermediates文件夹包含的是app生成的“中间件”。
2.AndroidManifest属性汇总:
搭建工程的时候,首先得有创始人或架构师(Application module),人后招员工(lib module),员工努力工作(coding),完成自己的任务(生成aar),最后架构师将项目汇总起来并完成项目的发布(生成app)。
- 每个lib module(功能module)作业完成之后,编译器在build/output/aar目录中生成一个aar文件;
- Application module(主module) 依赖于多个lib module(功能module);
- 当编译主module时会将这些功能module重新编译,然后将成果(aar)放在module的intermediates文件夹中;
- 每个module完成编写后app/build/intermediates/expoded-aar中引用其最终生成aar文件中,exploded-aar还包含了其他第三方仓库引用到的库;
- 每个module中的引用文件,其aar文件解压缩得到的文件目录中包含一般Android工程的部分资源,如aidl/assests等,从classes.jar文件是每个module真正代码包,res包含的功能module的资源,而每个功能module都有它自己的AndroidManifest,aar的AndroidManifest中,即使没有四大组件,依然需要带有application的标识,还会帮组我们不全use-sdk的信息。
3.AndroidManifest属性变更:
- 注册Activity:在module中注册的activity会由编译器自动补全必要的属性(icon和theme),其name属性会补全文件所在的位置(包名+文件名)。name需要具体包名+属性名,这是因为AndroidManifest会引用多个module中的文件,需要知道具体路径,不然在编译器打包时会找不到每个文件的具体位置。
- 注册Application:在App中最终声明一个Application到AndroidManfiest中。
替换原则:
如果功能module有Application,主module没有自定义Application,这时会自然引用功能module的Application;
如果主module有自定义Application,其他module没有,则自动引入module的Application;
如功能module中有两个自定义Application,在解决冲突后,Application最终会载入后编译的module的Application;
如猪module中有自定义Application,其他功能module也有自定义Application,在解决冲突后,最后编译的猪module的Application会在AndroidManifest中。
- 权限申明:多个module声明的权限会最终在AndroidManifest合并重复的权限,所以相同的全乡只会被声明一次;
- 主题声明:Acivity的每个主题都是独立的,每个Activity的主题都会在引用自身module的AndroidManifest所声明的主题,没有声明的使用默认Android主题;
- Service声明:与Activity相同,四大组件都一样,如BroadcastReceiver和ContentProvider;
- shareUid声明:通过声明Shared User Id,拥有同一个User id的多个app可以配置成运行在同一个进程中,所以默认可以互相访问任意数据。只有在主module(Application module)中声明sharedUserId,才会最终打包到full AndroidManifest中,每个module打包aar时都会将versionCode和versionName两个属性补全。
4.Application:
Application的基础及作用:
当Android应用启动的时候,最先启动的系统组件并不是MainActivity,而是Application,每个app运行时仅创建一个唯一一个Application,用于存储系统的一些信息,那么可以将它理解为整个app的一个单例对象,并且其生命周期时最长的,相当于整个app的周期。主要方法:
- onCreate:在创建应用程序时回调的方法,比任何activity都要靠前;
- onTerminate:当终止应用程序对象时调用,不保证一定被调用,当程序被内核终止以便为其他应用程序释放资源时将不会提醒,并且不调用应用程序的 onTerminate方法而直接终止进程;
- onLowMemory:当后台程序已经终止且资源还匮乏时会调用这个方法。好的应用程序一般会在这个方法中释放一些不必要的资源来应对后台城西已经终止/前台应用程序内存还不够时的情况;
- onConfigurationChanged:配置改变时触发这个方法,如手机屏幕旋转时等。
- registerActivityLifecycleCallbacks()及unregisterActivityLifecycleCallbacks():这两个方法用于注册或者注销app内所有的Activity的声明周期监听,当app内Activity的生命周期发生变化时就会调用ActivityLifecycleCallbacks()中的方法。从ActivityLifecycleCallbacks这个方法中获取到在栈顶的Activity对象,而应为application单例对象时可以全局获取的,全局toast可以引用application的context对象。但是想做全局弹框,就需要理解弹窗特性,弹窗需要依赖当前的窗口对象,弹窗初始化的时候就必须要获取顶层activity的上下文。
组件化Application:
- 如功能module有Application,主module没有自定义Application,这时会自动引入功能module的Application;
- 如主module有自定义Application,其他module没有,自动引用主module的Application;
- 如功能module中有两个自定义Application,那么需要解决冲突,每个功能module都需要添加上tool:replace字段;
- 如主module有自定义Application,其他功能module也有自定义Application,在主module中添加tool:replace解决冲突后,会在编译的主module的Application在AndroidManfest中。