转自:此文属于finddreams的原创博客,转载请注明出处:http://blog.csdn.net/finddreams/article/details/78349267
上一篇《我所理解的Android模块化(一)》笔者讲到了Android模块化的基本知识和模块化跳转路由的基本用法,解决了模块化中跳转的问题,下面就来讲讲如何实现模块化之间的通信和跨模块方法调用。
模块通信
有这样一个场景,就是APP中的登录成功事件,需要在多个模块中都要监听到,登录页面是在用户中心的模块中,而购物车这个模块也关心用户是否登录成功这个事件,如何让登录成功这个事件,让所有除用户中心的其他模块都能收到这个事件呢?
方法其实有两个:
1.广播的形式,属于Android系统原生就支持的;
2.EventBus,这个在Android界几乎无人不知吧,发布/订阅事件的神器;
因为广播BroadcastReceiver虽然是Android系统原生支持的,但使用起来略显繁琐,而EventBus 3.0又非常的简单好用,所以我们项目选择的这个库来做模块间的事件通信。
想要实现各模块都接受某一个事件,按照EventBus的用法,发送事件首先得有一个Event Bean,在示例项目中在module_base中定义了一个LoginStateEvent,因为各子模块都依赖module_base模块,所以子模块都能够接收这个事件。
这样就可以在登录页面LoginActivity中发送一个LoginStateEvent登录成功事件:
EventBus.getDefault().post(new LoginStateEvent(true));
然后购物车模块如果关心这个登录成功事件,就只要在这个购物车页面ShoppingCartMainFragment注册EventBus 接收LoginStateEvent的事件即可:
@Subscribe(threadMode = ThreadMode.MAIN)
public void onLoginSuccess(LoginStateEvent event) {
if (event.isSuccess) {
tv_loginstate.setText("已登录");
}
}
如果其他模块也想关心这个事件也是同样的做法,EventBus来实现模块间的通信非常的简单方便。
模块间服务调用
模块间服务调用是什么意思呢?比如说有这样的一个场景,一般当我们打开商城APP的商品详情页面的时候,下面往往显示一个用户所在的配送地址,如果获取配送地址的这个接口是写在用户中心模块里面的,由用户中心模块来维护,我们知道如果是共有的module_base里的方法,不同模块可以都可以调用。但如果属于两个模块的独有方法,其他模块是不能调用的,那如何实现商品详情模块调用用户中心模块里面的方法呢?
答案还是借助上一篇文章讲到的ARouter框架来实现。
首先,为了所有子类模块都能共享这个方法,我们在module_base中定义一个服务接口:
package com.finddreams.module_base.utils;
import com.alibaba.android.arouter.facade.template.IProvider;
public interface IUserModuleService extends IProvider {
String getUserAddress(String userId);
}
该接口有个未实现的方法叫getUserAddress,获取用户所在的地址,接口写好了由谁来实现呢?获取用户所在的地址只有用户中心模块才有这个方法,所以就需要在用户中心模块中来实现这个接口了,我们把它叫做UserModuleService:
package com.finddreams.module_user;
import android.content.Context;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.finddreams.module_base.utils.IUserModuleService;
import com.finddreams.module_base.utils.RouteUtils;
/**
* Created by lx on 17-10-25.
* 跨模块的服务调用
*/
@Route(path = RouteUtils.Service_User)
public class UserModuleService implements IUserModuleService {
@Override
public String getUserAddress(String userId) {
return UserService.getUserAddress(userId);
}
@Override
public void init(Context context) {
}
}
UserService类中简单的写了一个getUserAddress方法,返回用户的配送地址是深圳
package com.finddreams.module_user;
public class UserService {
public static String getUserAddress(String userId) {
return "深圳";
}
}
和Activity和Fragment一样,我们也需要在实现的Service上加上path路由注解,这样ARouter框架才能发现这个服务,而且不同模块的Service的path前的组“/user/”一定要是不一样的,不然会出现找不到的情况:
@Route(path = RouteUtils.Service_User)
public static final String Service_User = "/user/service";
接下来就是服务的发现,调用方法:
package com.finddreams.module_base.utils;
import com.alibaba.android.arouter.launcher.ARouter;
public class ModuleRouteService {
public static String getUserAddress(String userId) {
IUserModuleService userModuleService = ARouter.getInstance().navigation(IUserModuleService.class);
if (userModuleService != null) {
return userModuleService.getUserAddress(userId);
}
return "";
}
}
这种面向接口编程的思想非常优秀,只和接口打交道,子类怎么实现不关心,所以通过ARouter的发现服务功能就可以自动找到实现了IUserModuleService接口的子类UserModuleService,调用getUserAddress方法获取到用户的配送地址。所以当我们在商品详情模块中调用这个方法的时候就能轻松的实现获取到用户收货地址的功能:
tv_address.setText("用户所在地址:"+ ModuleRouteService.getUserAddress("123"));
实现效果图
到此本文就解决了模块化中的两个问题,模块间通信和模块间的服务调用,具体详细用法请看:https://github.com/finddreams/AndModulePractice。
下一篇将会说一说Android模块化过程中遇到的一些问题和要注意的细节以及如何实现可插拔式的单独编译运行开发某一个模块,同时又能很方便的集成到主APP中打包发布。