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生成一个类来专门处理这个任务,欲知详情,且听下回分解。

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