LiveDataBus基础
LiveDataBus具有生命周期感知 | 和Lifecycle绑定,不需要注册和反注册,没有内存泄漏风险 |
LiveDataBus实现简单 | 相对EventBus的复杂实现,LiveDataBus只需要一个类 |
LiveDataBus减小APK包大小 | LiveDataBus只依赖Android官方组件LiveData |
LiveDataBus依赖方支持更好 | 相对RxBus依赖于RxJava,LiveDataBus只依赖于官方组件 |
观察者模式和发布订阅模式有什么区别?
- LiveData采用观察者模式,观察者和被观察者互相可见,被观察者通知观察者进行改变,例如长途汽车上乘务员通知指定乘客到站。
- LiveDataBus基于LiveData组件,采用发布订阅模式,观察者和被观察者互相不可见。被观察者会发出广播,观察者只会对自己订阅的广播做出反应。例如高铁动车上的广播到站。
数据结构
LiveDataBus采用一个map进行储存键值对,其中Key为String类型,决定了发布者发布到哪个消息通道、而订阅者通过这个key找到其订阅的通道。
with方法是从map里返回一个具体LiveData对象,即返回一个消息通道。
消息通道即为value,是一个LiveData<Object>的对象。本文使用LiveData的子类MutableLiveData简化发布订阅操作。Object就是消息的类型,在新建LiveData对象时设置。
使用双重校验的单例模式,保证只有一个map,即只有一条消息总线。
public final class LiveDataBus {
private static Map<String , MutableLiveData<Object>> map = null;
public LiveDataBus() {
map = getInstance();
}
private static class SingleHolder {
private static final LiveDataBus DATA_BUS = new LiveDataBus();
}
public static LiveDataBus get(){
return SingleHolder.DATA_BUS;
}
private static Map<String , MutableLiveData<Object>> getInstance(){
if (map == null){
synchronized (LiveDataBus.class){
if (map == null){
map = new HashMap<>();
return map;
}
};
}
return map;
}
public <T> MutableLiveData<T> with(String key, Class<T> type){
if (!map.containsKey(key)){
map.put(key, new MutableLiveData<Object> ());
}
return (MutableLiveData<T>)map.get(key);
}
public MutableLiveData<Object> with(String key){
return with(key, Object.class);
}
}
订阅方法
在map中通过key获取订阅对象的消息通道LiveData,并设置观察的消息类型,再实现observe接口,具体执行订阅到消息后的事件处理。
LiveDataBus.get().
with("Main A", String.class)
.observe(this,
(Observer<String>) s ->
Toast.makeText(MainActivity.this, s, Toast.LENGTH_SHORT).show());
发送消息方法
postValue()用于子线程中,setValue()用于主线程中,方法内容是向LiveData传递一个消息。
//子线程使用
LiveDataBus.get().with("Child B").postValue("Child B msg");
//主线程使用
LiveDataBus.get().with("Main A").setValue("Main B msg");
完整流程
LiveDataBus.get()
.with("Main A", String.class)
.observe(this, s -> Toast.makeText(MainActivity.this, s, Toast.LENGTH_SHORT).show());
btn2.setOnClickListener(view ->
LiveDataBus.get().with("Main B").setValue("Main A msg"));
activity启动后会自动订阅“Main A”的消息通道;用户点击按钮btn2后会发送消息”Main A ms“到“Main A”的消息通道中,之后订阅者收到消息后会在activity活跃时执行onchange方法(由lamda表达式简化)。
总结
用map可以模拟总线,每一个键值对即对应着一条支线。
追踪组件生命周期可以避免内存泄漏。
例如handler会持有外部类activity的引用,在activity结束后handler仍在处理自己的事件,即造成内存泄漏。