1、模块化
在Android Studio中,新建工程默认有一个App module,然后还可以通过File->New->New Module 新建module。那么这里的“module” 和实际说的“模块”基本是一个概念了。也就是说,原本一个 App模块承载了所有的功能,而模块化就是拆分成多个模块放在不同的Module里面,每个功能的代码都在自己所属的module中添加。
1、模块划分
已京东为例,大致可以分为 “首页”、“分类”、“发现”、“购物车”、“我的”、“商品详情” 六个模块。
这是一般项目都会采用的结构。另外通常还会有一个通用基础模块module_common,提供BaseActivity/BaseFragment、图片加载、网络请求等基础能力,然后每个业务模块都会依赖这个基础模块。
然后业务模块之间很显然是有相互依赖的。例如 “首页”、“分类”、“发现”、“购物车”、“我的”,都是需要跳转到“商品详情” 的,必然是依赖“商品详情” ;而“商品详情”是需要能添加到“购物车”能力的;而“首页”点击搜索显然是“分类”中的搜索功能。所以这些模块之间存在复杂的依赖关系。
模块化缺点:在各个业务功能比较独立的情况下是比较合理的,但多个模块中肯定会有页面跳转、数据传递、方法调用 等情况,所以必然存在以上这种依赖关系,即模块间有着高耦合度。高耦合度加上代码量大,就极易出现上面提到的那些问题了,严重影响了团队的开发效率及质量。
2、组件化介绍
业务组件:去除模块间的耦合,使得每个业务模块可以独立当做App存在,对于其他模块没有直接的依赖关系。
业务基础组件:是提供给业务组件使用,但不是独立的业务,例如分享组件、广告组件;
基础组件:即单独的基础功能,与业务无关,例如 图片加载、网络请求等。
1、组件化好处:
A、加快编译速度:每个业务组件都是一个单独的工程,可独立编译运行,拆分后代码量较少,编译自然变快。
B、提高协作效率:解耦使得组件之间彼此互不打扰,组件内部代码相关性极高。团队中每个人有自己的责任组件,不会影响其他组件;降低团队成员熟悉项目的成本,只需熟悉责任组件即可。
C、功能重用:组件类似引用的第三方库,只需维护好每个组件。业务组件可上可下,灵活多变;而基础组件,为新业务随时集成提供了基础,减少重复开发和维护工作量。
2、组件化架构
A、组件依赖关系是上层依赖下层,修改频率是上层高于下层;
B、基础组件是通用基础能力,修改频率极低,作为SDK可供公司所有项目集成使用。
C、common组件:作为支撑业务组件、业务基础组件的基础(BaseActivity/BaseFragment等基础能力),同时依赖所有的基础组件,提供多数业务组件需要的基本功能。所以业务组件、业务基础组件所需的基础能力只需要依赖common组件即可获得。
D、业务组件、业务基础组件:都依赖common组件。但业务组件之间不存在依赖关系,业务基础组件之间不存在依赖关系。而业务组件是依赖所需的业务基础组件的,例如几乎所有业务组件都会依赖广告组件来展示Banner广告、弹窗广告等。
E、最上层则是主工程,即所谓的“壳工程”,主要是集成所有的业务组件、提供Application唯一实现、gradle、manifest配置,整合成完备的App。
3、组件化开发的问题点
A、业务组件,如何实现单独运行调试?
B、业务组件间没有依赖,如何实现页面的跳转?
C、业务组件间没有依赖,如何实现组件间通信/方法调用?
D、业务组件间没有依赖,如何获取fragment实例?
E、业务组件不能反向依赖壳工程,如何获取Application实例、如何获取Application onCreate()回调(用于任务初始化)?
3、组件独立调试
每个业务组件都是一个完整的整体,可以当做独立的App,需要满足单独运行及调试的要求,这样可以提升编译速度提高效率。
做到组件独立调试,有两种方案:
A、单工程方案,组件以module形式存在,动态配置组件的工程类型;
B、多工程方案,业务组件以library module形式存在于独立的工程,且只有这一个library module(不讲)。
1、动态配置组件工程类型
单工程模式,整个项目只有一个工程,它包含:App module加上各个业务组件module,就是所有的代码,这就是单工程模式。
在 AndroidStudio开发Android项目时,使用的是Gradle来构建。Android Gradle中提供了两种插件,在开发中可以通过配置不同的插件来配置不同的module类型。
A、Application插件,id: com.android.application B、Library插件,id: com.android.library
区别比较简单,Application插件来配置一个Android App工程,项目构建后输出一个 APK 安装包;Library插件来配置一个Android Library工程,构建后输出ARR包。
显然App module配置的就是Application插件,业务组件module配置的是Library插件。想要实现业务组件的独立调试,这就需要把配置改为Application插件;而独立开发调试完成后,又需要变回Library 插件进行集成调试。
AndroidStudio创建一个Android项目后,会在根目录中生成一个gradle.properties文件。在这个文件定义的常量,可以被任何一个build.gradle读取。所以可以在gradle.properties中定义一个常量值isModule,true为即独立调试;false为集成调试。然后在业务组件的build.gradle中读取isModule,设置成对应的插件即可。
2、动态配置ApplicationId和AndroidManifest
A、一个App是需要一个ApplicationId,而组件在独立调试时也是一个App,所以也需要一个 ApplicationId,集成调试时组件是不需要ApplicationId;
B、一个 APP也只有一个启动页, 而组件在独立调试时也需要一个启动页,在集成调试时就不需要了。
//build.gradle(业务组件)
android {
、、、、、、
defaultConfig {
、、、、、、
if (isModule.toBoolean()) {
//独立调试时添加 applicationId ,集成调试时移除
applicationId "com.hfy.componentlearning.cart"
}
}
sourceSets {
main {
//独立调试与集成调试时使用不同的AndroidManifest.xml文件
if (isModule.toBoolean()) {
manifest.srcFile 'src/main/moduleManifest/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/AndroidManifest.xml'
}
}
}
、、、、、、
}
所以ApplicationId、AndroidManifest也是需要isModule来进行配置的。其中独立调试的AndroidManifest是新建于目录moduleManifest,使用manifest.srcFile即可指定两种调试模式的AndroidManifest文件路径。
(1) moduleManifest中新建的manifest文件指定了Application、启动activity(单独调试)
//moduleManifest/AndroidManifest.xml
<manifest xmlns:android="schemas.android.com/apk/res/and…"
package="com.hfy.module_cart" >
<application android:name=".CartApplication"
android:allowBackup="true"
android:label="Cart"
android:theme="@style/Theme.AppCompat">
(2) 原本自动生成的manifest,未指定Application、启动activity(集成调试)
<manifest xmlns:android="schemas.android.com/apk/res/and…"
package="com.hfy.module_cart">
4、页面跳转
所有的业务组件都依赖了Common组件,所以在Common组件中使用关键字**“api”**添加的依赖,业务组件都能访问。要使用 ARouter进行界面跳转,需要Common组件添加Arouter的依赖(另外其它组件共同依赖的库也要都放到 Common 中统一依赖)
因为ARouter比较特殊,“arouter-compiler ”的annotationProcessor依赖需要所有使用到ARouter的组件中都单独添加,不然无法在apt中生成索引文件,就无法跳转成功。
并且在每个使用到ARouter的组件的build.gradle中,其android{}中的 javaCompileOptions中也需要添加特定配置。然后壳工程需要依赖业务组件。
1、common组件的build.gradle
//common组件的build.gradle
dependencies {
、、、、、、、、
//ARouter的依赖
api 'com.alibaba:arouter-api:1.4.0’
annotationProcessor 'com.alibaba:arouter-compiler:1.2.1'
//业务组件、业务基础组件 共同依赖的库(网络库、图片库等)都写在这里~
}
2、业务组件的build.gradle
//业务组件的build.gradle
android {
、、、、、、、、
defaultConfig {
、、、、、、、、
javaCompileOptions{
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
}
}
}
}
dependencies {
、、、、、、
//ARouter注解处理器的依赖
annotationProcessor 'com.alibaba:arouter-compiler:1.2.1’
//业务组件依赖common组件
implementation 'com.github.hufeiyang:Common:1.0.0'
}
3、壳工程app module的build.gradle
//壳工程app module的build.gradle
dependencies {
、、、、、、、、
//这里没有使用私有maven仓,而是发到JitPack仓,一样的意思~
implementation 'com.github.hufeiyang:Cart:1.0.1' //依赖购物车组件
implementation 'com.github.hufeiyang:HomePage:1.0.2' //依赖首页组件
//壳工程内 也需要依赖Common组件,因为需要初始化ARouter
implementation 'com.github.hufeiyang:Common:1.0.0'
}
4、ARouter初始化
ARouter依赖完了,先要对ARouter初始化,需要在Application内完成:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//这两行必须写在init之前,否则这些配置在init过程中将无效
if (BuildConfig.DEBUG) {
//打印日志
ARouter.openLog();
//开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
ARouter.openDebug();
}
//尽可能早,推荐在Application中初始化
ARouter.init(this);
}
}
5、组件间通信
例如,首页需要展示购物车中商品的数量,而查询购物车中商品数量,这个能力是购物车组件内部的。可以通过组件拆分出可暴露服务来实现。
A、暴露组件:只存放服务接口、服务接口相关的实体类、路由信息、便于服务调用的util类等;
B、业务组件:需要依赖自己的暴露组件,并实现服务接口,如module_cart依赖export_cart 并实现其中的服务接口;
C、服务调用方:只依赖服务提供方的暴露组件,如module_home依赖export_cart,而不依赖module_cart;
D、接口的实现注入:依然是由ARouter完成,和页面跳转一样使用路由信息。即暴露组件通过路由调用业务组件实现的真正的服务。
1、新建export_cart
在购物车工程中新建module即export_cart,在其中新建接口ICartService并定义获取购物车商品数量方法,注意接口必须继承IProvider,是为了使用ARouter的实现注入:
A、ICartService服务接口
//购物车组件对外暴露的服务,必须继承IProvider
public interface ICartService extends IProvider {
//获取购物车中商品数量的方法
CartInfo getProductCountInCart();
}
B、CartInfo是购物车信息(包含商品数量)
//购物车信息
public class CartInfo {
//商品数量
public int productCount;
}
C、创建路由表信息,存放购物车组件对外提供跳转的页面、服务的路由地址
//购物车组件路由表
public interface CartRouterTable {
//购物车页面
String PATH_PAGE_CART = "/cart/cartActivity";
//购物车服务
String PATH_SERVICE_CART = "/cart/service";
}
D、外部组件调用CartServiceUtil
//购物车组件服务工具类,其他组件直接使用此类即可:页面跳转、获取服务。
public class CartServiceUtil {
//跳转到购物车页面
public static void navigateCartPage(String param1, String param2){
ARouter.getInstance()
.build(CartRouterTable.PATH_PAGE_CART)
.withString("key1",param1)
.withString("key2",param2)
.navigation();
}
//获取服务实现类
public static ICartService getService(){
return (ICartService) ARouter.getInstance().build(CartRouterTable.PATH_SERVICE_CART).navigation();
}
//获取购物车中商品数量
public static CartInfo getCartProductCount(){
return getService().getProductCountInCart();
}
}
这里使用静态方法分别提供了页面跳转、服务获取、服务具体方法获取。 其中服务获取和页面跳转同样是使用路由,并且服务接口实现类也是需要添加@Route注解指定路径的。
2、module_cart的实现
A、module_cart需要依赖export_cart(module_cart需要依赖export_cart)
//module_cart的Build.gradle
dependencies {
、、、、、、、
annotationProcessor 'com.alibaba:arouter-compiler:1.2.1'
implementation 'com.github.hufeiyang:Common:1.0.0'
//依赖export_cart
implementation 'com.github.hufeiyang.Cart:export_cart:1.0.5'
}
B、CartActivity的path改为路由表提供(为CartActivity添加页面路由注解)
@Route(path = CartRouterTable.PATH_PAGE_CART)
public class CartActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cart);
}
}
C、实现ICartService(添加@Route注解指定CartRouterTable中定义的服务路由)
@Route(path = CartRouterTable.PATH_SERVICE_CART)
public class CartServiceImpl implements ICartService {
@Override
public CartInfo getProductCountInCart() {
//这里实际项目中应该是请求接口或查询数据库
CartInfo cartInfo = new CartInfo();
cartInfo.productCount = 666;
return cartInfo;
}
@Override
public void init(Context context) {
//初始化工作,服务注入时会调用,可忽略
}
}
3、module_home中的使用和调试(module_home需要依赖export_cart)
//module_home的Build.gradle
dependencies {
、、、、、、
annotationProcessor 'com.alibaba:arouter-compiler:1.2.1'
implementation 'com.github.hufeiyang:Common:1.0.0'
//注意这里只依赖export_cart(module_cart由壳工程引入)
implementation 'com.github.hufeiyang.Cart:export_cart:1.0.5'
}
1、HomeActivity调用CartServiceUtil打开购物车页面或者或者购物车商品数量
@Route(path = "/homepage/homeActivity")
public class HomeActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
//通过路由跳转到 购物车组件的购物车页面(但没有依赖购物车组件)
findViewById(R.id.btn_go_cart).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CartServiceUtil.navigateCartPage("param1", "param1");
}
});
//调用购物车组件服务:获取购物车商品数量
TextView tvCartProductCount = findViewById(R.id.tv_cart_product_count);
tvCartProductCount.setText("购物车商品数量:"+ CartServiceUtil.getCartProductCount().productCount);
}
}
看到使用CartServiceUtil.getCartProductCount()获取购物车信息并展示,跳转页面也改为了CartServiceUtil.navigateCartPage()方法。
6、fragment实例获取
通常直接访问具体Fragment类来new一个Fragment实例。但这里组件间没有直接依赖,依然是ARouter来实现不同组件间获取Fragment。
1、先在module_cart中创建CartFragment(并添加注解@Route,指定路径)
//添加注解@Route,指定路径
@Route(path = CartRouterTable.PATH_FRAGMENT_CART)
public class CartFragment extends Fragment {
、、、、、、、、
public CartFragment() {}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
、、、、、、、、
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_cart, container, false);
}
}
2、获取Fragment
路由还是定义在export_cart的CartRouterTable中,然后再module_home中依赖export_cart,使用ARouter获取Fragment实例。
@Route(path = "/homepage/homeActivity")
public class HomeActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
、、、、、、、、、
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction= manager.beginTransaction();
//使用ARouter获取Fragment实例,并添加
Fragment userFragment = (Fragment) ARouter.getInstance().build(CartRouterTable.PATH_FRAGMENT_CART).navigation();
transaction.add(R.id.fl_test_fragment, userFragment, "tag");
transaction.commit();
}
}
7、Application生命周期分发
通常会在Application的onCreate中做一些初始化任务,例如前面提到的ARouter初始化。而业务组件有时也需要获取应用的Application,也要在应用启动时进行一些初始化任务。
直接在壳工程Application的onCreate操作,这样做会带来问题:因为希望壳工程和业务组件代码隔离(虽然有依赖),并且希望内部的任务要在业务组件内部完成。 那么如何做到各业务组件无侵入地获取Application生命周期呢?
使用AppLifeCycle插件,它专门用于在Android组件化开发中,Application生命周期主动分发到组件。具体使用如下:
1、common组件依赖applifecycle-api
//common组件build.gradle
dependencies {
、、、、、、、、
//AppLifecycle的依赖
api 'com.github.hufeiyang.Android-AppLifecycleMgr:applifecycle-api:1.0.4'
}
2、业务组件依赖applifecycle-compiler和common组件
//业务组件build.gradle
dependencies {
、、、、、、、
//common组件的依赖
implementation 'com.github.hufeiyang:Common:1.0.2’
//applifecycle-compiler的依赖,注解处理相关
annotationProcessor 'com.github.hufeiyang.Android-AppLifecycleMgr:applifecycle-compiler:1.0.4'
}
3、实现接口IApplicationLifecycleCallbacks用于接收Application生命周期,且添加@AppLifecycle注解
//业务组件的AppLifecycle
@AppLifecycle
public class CartApplication implements IApplicationLifecycleCallbacks {
public Context context;
//用于设置优先级,即多个组件onCreate方法调用的优先顺序
@Override
public int getPriority() {
return NORM_PRIORITY;
}
@Override
public void onCreate(Context context) {
//可在此处做初始化任务,相当于Application的onCreate方法
this.context = context;
}
@Override
public void onTerminate() {}
@Override
public void onLowMemory() {}
@Override
public void onTrimMemory(int level) {}
}
实现的方法有onCreate、onTerminate、onLowMemory、onTrimMemory。最重要的就是onCreate方法了,相当于Application的onCreate方法,可在此处做初始化任务。并且还可以通过getPriority()方法设置回调,多个组件onCreate方法调用的优先顺序,无特殊要求设置NORM_PRIORITY即可。
4、壳工程引入AppLifecycle插件、触发回调
A、壳工程根目录的build.gradle
//壳工程根目录的build.gradle
buildscript {
repositories {
google()
jcenter()
//applifecycle插件仓也是jitpack
maven { url 'jitpack.io' }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.1'
//加载插件applifecycle
classpath 'com.github.hufeiyang.Android-AppLifecycleMgr:applifecycle-plugin:1.0.3'
}
}
B、app module的build.gradle
//app module的build.gradle
apply plugin: 'com.android.application'
//使用插件applifecycle
apply plugin: 'com.hm.plugin.lifecycle'
、、、、、、、
dependencies {
、、、、、、、、
//依赖所有的业务模块
implementation 'com.github.hufeiyang.Cart:module_cart:1.0.11'
implementation 'com.github.hufeiyang:HomePage:1.0.5’
//壳工程内也需要依赖Common组件,因为要触发生命周期分发
implementation 'com.github.hufeiyang:Common:1.0.2'
}
C、在Application中触发生命周期的分发
//壳工程 MyApplication
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
、、、、、、
ApplicationLifecycleManager.init();
ApplicationLifecycleManager.onCreate(this);
}
@Override
public void onTerminate() {
super.onTerminate();
ApplicationLifecycleManager.onTerminate();
}
@Override
public void onLowMemory() {
super.onLowMemory();
ApplicationLifecycleManager.onLowMemory();
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
ApplicationLifecycleManager.onTrimMemory(level);
}
}
android {
、、、、、、
defaultConfig {
、、、、、、
if (isModule.toBoolean()) {
//独立调试时添加 applicationId ,集成调试时移除
applicationId "com.hfy.componentlearning.cart"
}
}
sourceSets {
main {
//独立调试与集成调试时使用不同的AndroidManifest.xml文件
if (isModule.toBoolean()) {
manifest.srcFile 'src/main/moduleManifest/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/AndroidManifest.xml'
}
}
}
、、、、、、
}
//moduleManifest/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hfy.module_cart" >
<application android:name=".CartApplication"
android:allowBackup="true"
android:label="Cart"
android:theme="@style/Theme.AppCompat">
<activity android:name=".CartActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
(2) 原本自动生成的manifest,未指定Application、启动activity(集成调试)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hfy.module_cart">
<application>
<activity android:name=".CartActivity"></activity>
</application>
</manifest>
//common组件的build.gradle
dependencies {
、、、、、、、、
//ARouter的依赖
api 'com.alibaba:arouter-api:1.4.0’
annotationProcessor 'com.alibaba:arouter-compiler:1.2.1'
//业务组件、业务基础组件 共同依赖的库(网络库、图片库等)都写在这里~
}
2、业务组件的build.gradle
//业务组件的build.gradle
android {
、、、、、、、、
defaultConfig {
、、、、、、、、
javaCompileOptions{
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
}
}
}
}
dependencies {
、、、、、、
//ARouter注解处理器的依赖
annotationProcessor 'com.alibaba:arouter-compiler:1.2.1’
//业务组件依赖common组件
implementation 'com.github.hufeiyang:Common:1.0.0'
}
3、壳工程app module的build.gradle
//壳工程app module的build.gradle
dependencies {
、、、、、、、、
//这里没有使用私有maven仓,而是发到JitPack仓,一样的意思~
implementation 'com.github.hufeiyang:Cart:1.0.1' //依赖购物车组件
implementation 'com.github.hufeiyang:HomePage:1.0.2' //依赖首页组件
//壳工程内 也需要依赖Common组件,因为需要初始化ARouter
implementation 'com.github.hufeiyang:Common:1.0.0'
}
4、ARouter初始化
ARouter依赖完了,先要对ARouter初始化,需要在Application内完成:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//这两行必须写在init之前,否则这些配置在init过程中将无效
if (BuildConfig.DEBUG) {
//打印日志
ARouter.openLog();
//开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
ARouter.openDebug();
}
//尽可能早,推荐在Application中初始化
ARouter.init(this);
}
}
A、暴露组件:只存放服务接口、服务接口相关的实体类、路由信息、便于服务调用的util类等;
B、业务组件:需要依赖自己的暴露组件,并实现服务接口,如module_cart依赖export_cart 并实现其中的服务接口;
C、服务调用方:只依赖服务提供方的暴露组件,如module_home依赖export_cart,而不依赖module_cart;
D、接口的实现注入:依然是由ARouter完成,和页面跳转一样使用路由信息。即暴露组件通过路由调用业务组件实现的真正的服务。
1、新建export_cart
在购物车工程中新建module即export_cart,在其中新建接口ICartService并定义获取购物车商品数量方法,注意接口必须继承IProvider,是为了使用ARouter的实现注入:
A、ICartService服务接口
//购物车组件对外暴露的服务,必须继承IProvider
public interface ICartService extends IProvider {
//获取购物车中商品数量的方法
CartInfo getProductCountInCart();
}
B、CartInfo是购物车信息(包含商品数量)
//购物车信息
public class CartInfo {
//商品数量
public int productCount;
}
C、创建路由表信息,存放购物车组件对外提供跳转的页面、服务的路由地址
//购物车组件路由表
public interface CartRouterTable {
//购物车页面
String PATH_PAGE_CART = "/cart/cartActivity";
//购物车服务
String PATH_SERVICE_CART = "/cart/service";
}
D、外部组件调用CartServiceUtil
//购物车组件服务工具类,其他组件直接使用此类即可:页面跳转、获取服务。
public class CartServiceUtil {
//跳转到购物车页面
public static void navigateCartPage(String param1, String param2){
ARouter.getInstance()
.build(CartRouterTable.PATH_PAGE_CART)
.withString("key1",param1)
.withString("key2",param2)
.navigation();
}
//获取服务实现类
public static ICartService getService(){
return (ICartService) ARouter.getInstance().build(CartRouterTable.PATH_SERVICE_CART).navigation();
}
//获取购物车中商品数量
public static CartInfo getCartProductCount(){
return getService().getProductCountInCart();
}
}
这里使用静态方法分别提供了页面跳转、服务获取、服务具体方法获取。 其中服务获取和页面跳转同样是使用路由,并且服务接口实现类也是需要添加@Route注解指定路径的。
2、module_cart的实现
A、module_cart需要依赖export_cart(module_cart需要依赖export_cart)
//module_cart的Build.gradle
dependencies {
、、、、、、、
annotationProcessor 'com.alibaba:arouter-compiler:1.2.1'
implementation 'com.github.hufeiyang:Common:1.0.0'
//依赖export_cart
implementation 'com.github.hufeiyang.Cart:export_cart:1.0.5'
}
B、CartActivity的path改为路由表提供(为CartActivity添加页面路由注解)
@Route(path = CartRouterTable.PATH_PAGE_CART)
public class CartActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cart);
}
}
C、实现ICartService(添加@Route注解指定CartRouterTable中定义的服务路由)
@Route(path = CartRouterTable.PATH_SERVICE_CART)
public class CartServiceImpl implements ICartService {
@Override
public CartInfo getProductCountInCart() {
//这里实际项目中应该是请求接口或查询数据库
CartInfo cartInfo = new CartInfo();
cartInfo.productCount = 666;
return cartInfo;
}
@Override
public void init(Context context) {
//初始化工作,服务注入时会调用,可忽略
}
}
3、module_home中的使用和调试(module_home需要依赖export_cart)
//module_home的Build.gradle
dependencies {
、、、、、、
annotationProcessor 'com.alibaba:arouter-compiler:1.2.1'
implementation 'com.github.hufeiyang:Common:1.0.0'
//注意这里只依赖export_cart(module_cart由壳工程引入)
implementation 'com.github.hufeiyang.Cart:export_cart:1.0.5'
}
1、HomeActivity调用CartServiceUtil打开购物车页面或者或者购物车商品数量
@Route(path = "/homepage/homeActivity")
public class HomeActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
//通过路由跳转到 购物车组件的购物车页面(但没有依赖购物车组件)
findViewById(R.id.btn_go_cart).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CartServiceUtil.navigateCartPage("param1", "param1");
}
});
//调用购物车组件服务:获取购物车商品数量
TextView tvCartProductCount = findViewById(R.id.tv_cart_product_count);
tvCartProductCount.setText("购物车商品数量:"+ CartServiceUtil.getCartProductCount().productCount);
}
}
看到使用CartServiceUtil.getCartProductCount()获取购物车信息并展示,跳转页面也改为了CartServiceUtil.navigateCartPage()方法。
6、fragment实例获取
通常直接访问具体Fragment类来new一个Fragment实例。但这里组件间没有直接依赖,依然是ARouter来实现不同组件间获取Fragment。
1、先在module_cart中创建CartFragment(并添加注解@Route,指定路径)
//添加注解@Route,指定路径
@Route(path = CartRouterTable.PATH_FRAGMENT_CART)
public class CartFragment extends Fragment {
、、、、、、、、
public CartFragment() {}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
、、、、、、、、
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_cart, container, false);
}
}
2、获取Fragment
路由还是定义在export_cart的CartRouterTable中,然后再module_home中依赖export_cart,使用ARouter获取Fragment实例。
@Route(path = "/homepage/homeActivity")
public class HomeActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
、、、、、、、、、
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction= manager.beginTransaction();
//使用ARouter获取Fragment实例,并添加
Fragment userFragment = (Fragment) ARouter.getInstance().build(CartRouterTable.PATH_FRAGMENT_CART).navigation();
transaction.add(R.id.fl_test_fragment, userFragment, "tag");
transaction.commit();
}
}
7、Application生命周期分发
通常会在Application的onCreate中做一些初始化任务,例如前面提到的ARouter初始化。而业务组件有时也需要获取应用的Application,也要在应用启动时进行一些初始化任务。
直接在壳工程Application的onCreate操作,这样做会带来问题:因为希望壳工程和业务组件代码隔离(虽然有依赖),并且希望内部的任务要在业务组件内部完成。 那么如何做到各业务组件无侵入地获取Application生命周期呢?
使用AppLifeCycle插件,它专门用于在Android组件化开发中,Application生命周期主动分发到组件。具体使用如下:
1、common组件依赖applifecycle-api
//common组件build.gradle
dependencies {
、、、、、、、、
//AppLifecycle的依赖
api 'com.github.hufeiyang.Android-AppLifecycleMgr:applifecycle-api:1.0.4'
}
2、业务组件依赖applifecycle-compiler和common组件
//业务组件build.gradle
dependencies {
、、、、、、、
//common组件的依赖
implementation 'com.github.hufeiyang:Common:1.0.2’
//applifecycle-compiler的依赖,注解处理相关
annotationProcessor 'com.github.hufeiyang.Android-AppLifecycleMgr:applifecycle-compiler:1.0.4'
}
3、实现接口IApplicationLifecycleCallbacks用于接收Application生命周期,且添加@AppLifecycle注解
//业务组件的AppLifecycle
@AppLifecycle
public class CartApplication implements IApplicationLifecycleCallbacks {
public Context context;
//用于设置优先级,即多个组件onCreate方法调用的优先顺序
@Override
public int getPriority() {
return NORM_PRIORITY;
}
@Override
public void onCreate(Context context) {
//可在此处做初始化任务,相当于Application的onCreate方法
this.context = context;
}
@Override
public void onTerminate() {}
@Override
public void onLowMemory() {}
@Override
public void onTrimMemory(int level) {}
}
实现的方法有onCreate、onTerminate、onLowMemory、onTrimMemory。最重要的就是onCreate方法了,相当于Application的onCreate方法,可在此处做初始化任务。并且还可以通过getPriority()方法设置回调,多个组件onCreate方法调用的优先顺序,无特殊要求设置NORM_PRIORITY即可。
4、壳工程引入AppLifecycle插件、触发回调
A、壳工程根目录的build.gradle
//壳工程根目录的build.gradle
buildscript {
repositories {
google()
jcenter()
//applifecycle插件仓也是jitpack
maven { url 'https://jitpack.io' }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.1'
//加载插件applifecycle
classpath 'com.github.hufeiyang.Android-AppLifecycleMgr:applifecycle-plugin:1.0.3'
}
}
B、app module的build.gradle
//app module的build.gradle
apply plugin: 'com.android.application'
//使用插件applifecycle
apply plugin: 'com.hm.plugin.lifecycle'
、、、、、、、
dependencies {
、、、、、、、、
//依赖所有的业务模块
implementation 'com.github.hufeiyang.Cart:module_cart:1.0.11'
implementation 'com.github.hufeiyang:HomePage:1.0.5’
//壳工程内也需要依赖Common组件,因为要触发生命周期分发
implementation 'com.github.hufeiyang:Common:1.0.2'
}
C、在Application中触发生命周期的分发
//壳工程 MyApplication
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
、、、、、、
ApplicationLifecycleManager.init();
ApplicationLifecycleManager.onCreate(this);
}
@Override
public void onTerminate() {
super.onTerminate();
ApplicationLifecycleManager.onTerminate();
}
@Override
public void onLowMemory() {
super.onLowMemory();
ApplicationLifecycleManager.onLowMemory();
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
ApplicationLifecycleManager.onTrimMemory(level);
}
}
首先在onCreate方法中调用ApplicationLifecycleManager的init()方法,用于收集组件内实现了IApplicationLifecycleCallbacks且添加了@AppLifecycle注解的类。然后在各生命周期方法内调用对应的ApplicationLifecycleManager的方法,来分发到所有组件。