返回

Small 插件化重复 id 的优雅解决之道

Android

前言

回顾年初针对公司一款多模块应用进行插件化实践时,在方案选择上花费了相当长的时间。综合调研了 atlas、replugin、small 等方案后,由于原有项目采用模块化架构,每个模块都需要实现动态更新,而核心的业务插件体积相对较小,更新时只需替换原有插件,最终我们选择了 small 方案。然而,在实践过程中,我们遇到了一个棘手的问题:插件化后,重复 id 的问题接踵而至。本文将详细阐述我们如何巧妙解决这一难题,为有类似需求的开发者提供参考。

问题

在插件化过程中,我们发现不同插件中存在重复的 id,这导致了严重的冲突和异常。具体表现如下:

  • 布局错乱: 不同插件中拥有相同 id 的控件会相互覆盖,导致布局混乱。
  • 事件冲突: 不同插件中拥有相同 id 的控件会响应相同的事件,造成事件处理混乱。
  • 数据错乱: 不同插件中拥有相同 id 的数据存储会相互覆盖,导致数据错乱。

这些问题严重影响了插件化的稳定性和可用性,必须尽快找到合适的解决方案。

解决方案探索

面对重复 id 问题,我们探索了多种解决方案,包括:

  • 使用命名空间: 为每个插件分配一个唯一的命名空间,在控件 id 前加上命名空间前缀,以避免冲突。
  • 使用随机 id: 为每个插件生成随机 id,确保唯一性。
  • 使用哈希算法: 对插件的唯一标识符进行哈希运算,生成哈希值作为 id,以避免冲突。

然而,这些方案都存在一定的缺陷。命名空间方案需要开发者手动维护,容易出错。随机 id 方案可能会产生过于冗长的 id,影响可读性。哈希算法方案虽然可以生成唯一 id,但由于哈希函数的碰撞特性,仍有可能出现冲突。

优雅的解决之道

经过深入思考和反复试验,我们最终找到了一个优雅且高效的解决方案:基于插件加载顺序的 id 偏移

具体来说,我们为每个插件分配了一个唯一的加载顺序。在加载插件时,我们根据加载顺序为插件中所有控件的 id 添加一个偏移量。偏移量的计算方式如下:

偏移量 = 加载顺序 * 最大 id 数

其中,最大 id 数是一个预先定义的值,代表插件中可能出现的最大 id 数量。

例如,假设我们有 3 个插件,最大 id 数为 100。第一个插件加载顺序为 1,偏移量为 0;第二个插件加载顺序为 2,偏移量为 100;第三个插件加载顺序为 3,偏移量为 200。

这样一来,不同插件中的控件即使拥有相同的原始 id,经过偏移后也会得到不同的实际 id。例如,三个插件中都有一个 id 为 1 的控件,经过偏移后,它们的实际 id 分别为 1、101 和 201,从而避免了冲突。

具体实现

在 small 插件化框架中,我们通过重写 ApplicationLoaders 类来实现基于加载顺序的 id 偏移。具体代码如下:

public class CustomApplicationLoaders extends ApplicationLoaders {

    private int loadOrder;

    public CustomApplicationLoaders(int loadOrder) {
        this.loadOrder = loadOrder;
    }

    @Override
    public void onStart(Context context) {
        super.onStart(context);

        // 计算偏移量
        int offset = loadOrder * MAX_ID_COUNT;

        // 遍历控件,添加偏移量
        for (View view : getLoadedClass().getViews()) {
            int id = view.getId();
            if (id != View.NO_ID) {
                view.setId(id + offset);
            }
        }
    }
}

在加载每个插件时,我们都会实例化一个 CustomApplicationLoaders 对象,并传入当前插件的加载顺序。这样一来,每个插件中控件的 id 都会自动添加相应的偏移量,从而避免冲突。

效果验证

经过实际测试,基于加载顺序的 id 偏移方案有效解决了插件化重复 id 问题。我们加载了多个插件,每个插件中都包含大量控件,但没有出现任何布局错乱、事件冲突或数据错乱的情况。

优势总结

与其他解决方案相比,基于加载顺序的 id 偏移方案具有以下优势:

  • 自动化: 整个过程完全自动化,无需开发者手动维护。
  • 高效: 计算偏移量的过程非常简单,不会对插件加载性能产生明显影响。
  • 通用: 该方案适用于所有类型的插件,无论插件大小或复杂程度如何。

适用场景

基于加载顺序的 id 偏移方案特别适用于以下场景:

  • 插件化应用: 需要动态加载和卸载插件,插件中可能存在重复 id。
  • 模块化应用: 需要将应用拆分为多个模块,每个模块作为一个独立的插件加载。
  • UI 组件库: 需要将 UI 组件打包成插件,并动态加载到不同的项目中。

结语

通过提出基于加载顺序的 id 偏移方案,我们优雅地解决了插件化重复 id 问题,为插件化开发实践提供了一种高效且通用的解决方案。希望本文能够对有类似需求的开发者有所帮助,推动插件化技术在更多场景下的应用。

相关资料