Android模組化(二)——模組通訊和模組間服務呼叫
上一篇《我所理解的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中打包釋出。