Android組件化實戰三: 模塊之間的交互

前言

上一篇文章記錄了組件化開發中的項目部署需要注意的地方,而本文旨在實現模塊之間的交互,比如頁面的跳轉,數據的傳遞等等,而在集成化模式下,各個子模塊都是library,到底該如何實現呢?首先我們要知道傳統的組件間的通信方式,以及其適用場景和優缺點。

組件間通信的傳統方式

  • EventBus:不同的消息需要定義不同的EventBean(一對一),導致EventBean會非常多,而且一對多就會混亂、難以維護
  • 反射:反射技術可以實現,維護成本高且容易出現高版本@hide限制
  • 隱式意圖:維護成本還好,只是比較麻煩,需要維護Manifest中action
  • BroadcastReceiver:需要動態註冊(7.0之後),需求方發送廣播
  • 類加載:需要準確的全類名路徑,維護成本高且容易出現人爲失誤(包名路徑容易弄錯)

類加載技術交互實現

在personal模塊要跳轉到order模塊的Order_MainActivity,類加載技術實現主要邏輯如下:

// 類加載跳轉,可以成功,維護成本較高且容易出現人爲失誤
// 需要準確的全類名路徑
try{
	Class targetClass = Class.forName("xpf.moudlar.deploy.order.Order_MainActivity");
    Intent intent = new Intent(this, targetClass);
    intent.putExtra("params","xpf");
    startActivity(intnet);
}catch(ClassNotFoundException e) {
 	e.printStackTrace()
}

全局Map記錄信息實現

定義PathBean對象

  • path屬性:跳轉目標字符串縮寫
  • clazz屬性:跳轉目標Class對象
  • 保存到common公共基礎庫,所有子模塊都可以調用
/**
 * 路徑對象(公共基礎庫中,所有子模塊都可以調用)
 * path:"order/Order_MainActivity"
 * clazz: Order_MainActivity.class
 */
public class PathBean {

    private String path;
    private Class clazz;

    public PathBean(String path, Class clazz) {
        this.path = path;
        this.clazz = clazz;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public Class getClazz() {
        return clazz;
    }

    public void setClazz(Class clazz) {
        this.clazz = clazz;
    }
}

將需要跳轉的目標PathBean放在common公共基礎模塊的全局Map中,對外提供管理類,主要包含兩個方法,一個將對應模塊的Activity路徑信息分組保存到全局Map中。另一個方法就是根據組名和路徑信息獲取目標類的類對象,實現跳轉。

 * 全局路徑記錄器(根據子模塊分組)
 */
public class RecordPathManager {

    // key:組名"order" value: order子模塊下的所有Activity路徑信息
    private static Map<String, List<PathBean>> groupMap = new HashMap<>();

    /**
     * 將路徑信息加入全局Map
     *
     * @param groupName 組名,如:"personal"
     * @param pathName  路徑名,如:"Personal_MainActivity"
     * @param clazz     類對象,如:Personal_MainActivity.class
     */
    public static void joinGroup(String groupName, String pathName, Class<?> clazz) {
        List<PathBean> list = groupMap.get(groupName);
        if (list == null) {
            list = new ArrayList<>();
            list.add(new PathBean(pathName, clazz));
            groupMap.put(groupName, list);
        } else {
            for (PathBean pathBean : list) {
                if (!pathName.equals(pathBean.getPath())) {
                    list.add(new PathBean(pathName, clazz));
                    groupMap.put(groupName, list);
                }

            }
        }
    }


    /**
     * 根據組名和路徑名獲取類對象,達到跳轉目的
     * @param groupName
     * @param pathName
     * @return
     */
    public static Class<?> getTargetClass(String groupName, String pathName) {
        List<PathBean> list = groupMap.get(groupName);
        if (list == null) return null;
        for (PathBean pathBean : list) {
            // 比較路徑名時忽略大小寫
            if (pathName.equalsIgnoreCase(pathBean.getPath())) {
                return pathBean.getClazz();
            }
        }
        return null;
    }

}

試想一下,如果跳轉的時候,找不到類對象(比如Order_MainActivity.class), 就無法跳轉,也就是說在跳轉之前,要先將對應模塊的所有Activity路徑信息保存起來,可以在主模塊app的application裏面執行保存的操作,這樣所有的子模塊就都可以獲取到需要跳轉的目標PathBean進行跳轉了,避免了找不到對應目標信息的問題。

public class AppApplication extends BaseApplication {

    @Override
    public void onCreate() {
        super.onCreate();
        RecordPathManager.joinGroup("app", "MainActivity", MainActivity.class);
        RecordPathManager.joinGroup("order", "Order_MainActivity", Order_MainActivity.class);
        RecordPathManager.joinGroup("personal", "Personal_MainActivity", Personal_MainActivity.class);
    }
}

在集成模式下,order和personal之間是相互沒有依賴關係的,通過RecordPathManager的getTargetClass方法獲取跳轉目標Activity的類對象,進行跳轉。下面僅舉例在order模塊,跳轉至app模塊的MainActivity和personal模塊的Personal_MainActivity,在personal等其它子模塊跳轉邏輯一樣。

public class Order_MainActivity extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.order_activity_main);
        Log.d(Cons.TAG, "common/Order_MainActivity");

    }
	// 跳轉至app模塊的MainActivity
    public void jumpApp(View view) {
        // 全局Map記錄路徑信息方式實現跳轉
        Class<?> targetClass = RecordPathManager.getTargetClass("app", "MainActivity");
        if (targetClass == null) {
            Log.d(Cons.TAG, "獲取targetClass爲空");
        }
        Intent intent = new Intent(this, targetClass);
        intent.putExtra("name", "xpf");
        startActivity(intent);
    }
	
    // 跳轉至personal模塊的Personal_MainActivity
    public void jumpPersonal(View view) {
        // 全局Map記錄路徑信息方式實現跳轉
        Class<?> targetClass = RecordPathManager.getTargetClass("personal", "Personal_MainActivity");
        if (targetClass == null) {
            Log.d(Cons.TAG, "獲取targetClass爲空");
        }
        Intent intent = new Intent(this, targetClass);
        intent.putExtra("name", "xpf");
        startActivity(intent);
    }
}

大致思路如下圖:

在這裏插入圖片描述

總結

本文主要介紹了模塊之間交互的兩種方式,對於類加載實現方式,需要準確的全類名路徑。可以成功,維護成本較高且容易出現人爲失誤。而對於全局Map保存路徑和類對象信息實現方式,如果各個子模塊Activity較多比如200多個,也就是說在app模塊的application中對於保存信息的操作,要執行200次,這很不優雅,也不符合實際開發場景,能不能像個辦法生成一個類專門來處理application中對於的保存操作呢?答案是肯定的,我們可以通過apt生成一個類來專門處理這個任務,欲知詳情,且聽下回分解。
對於全局Map保存路徑和類對象信息實現方式,如果各個子模塊Activity較多比如200多個,也就是說在app模塊的application中對於保存信息的操作,要執行200次,這很不優雅,也不符合實際開發場景,能不能像個辦法生成一個類專門來處理application中對於的保存操作呢?答案是肯定的,我們可以通過apt生成一個類來專門處理這個任務,欲知詳情,且聽下回分解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章