昨天写了一篇关于DataProvider的文档,我们知道其作用是组件与Action之间解耦的。这是它的优点,恰好也是它的局限,因为在IDEA的插件SDK中,也只有AnActionEvent的getData方法可以使用DataProvider。那么组件与组件之间该如何解耦呢?
答案就是使用UserDataHolder!
public interface UserDataHolder {
@Nullable T getUserData(@NotNull Key key);
void putUserData(@NotNull Key key, @Nullable T value);
}
为什么说UserDataHolder可以用于组件之间进行数据解耦?主要是Application和Project都实现了该接口,而且恰恰一个插件中组件中必然能获取到Application对象,如果是Project级别的组件,那么还能获取到Project对象,这两个在对象在对应的Scope内都是单例唯一的。
从UserDataHolder的源码可以看出,它其实就是一个类似Map的KV存储。用户在想要将数据传递给另一个组件的时候,只需要将数据存储到合适的Scope对象中,然后在另一个组件中获取Scope对象,然后调用getUserData即可。
使用方法很简单,在产生数据的地方使用Application或者Project对象的putuserData存入数据,在使用的数据的地方调用对应的getUserData即可,Key类是一个泛型类,可以在通过key来确定对应数据类型,示例如下:
public class ComponentA {
// 定义一个Key,用于存储当前用户的名称
public static final Key USER_NAME_KEY = Key.create("username");
public ComponentA() {
// 在Application级别中保存数据
Application application = ApplicationManager.getInstance();
application.putUserData(USER_NAME_KEY, "Tom");
}
}
public class ComponentB {
public void display(){
Application application = ApplicationManager.getInstance();
application.getUserData(ComponentA.USER_NAME_KEY)
}
}
将上述代码中的application换成project依然可行,使用方法大致如此。
但是注意,由于其不会自动清除数据,因此生命后期等同于对应的Scope对象,因此如果过度依赖这种方法可能会导致内存溢出。
其次,由于写和读可能发生在任意位置,所以在使用的时候,尽可能遵循某种规则,一边后期排查问题。比如可以将Key定义在存数据的地方;只在一个地方写入等等。