众所周知,RxJava目前很火爆,既然RxJava是响应式的典型观察者模式体现,那么问题来了,我可不可以用RxJava实现页面事件的通知,进而实现代替EventBus。这当然是可以实现的,下面开撸:
最开始的写法:
RxBus
/**
* Author KINCAI
* .
* description TODO
* .
* Time 2016-12-07 12:54
*/
public class RxBus {
private final Subject
EventBase实体类
/**
* Author KINCAI
* .
* description TODO
* .
* Time 2016-12-07 16:11
*/
public class EventBase {
private String tag;
private String flag;
private Object data;
public EventBase(String tag, Object data) {
this.tag = tag;
this.data = data;
}
public EventBase(String tag, String flag, Object data) {
this.tag = tag;
this.flag = flag;
this.data = data;
}
public EventBase() {
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public String getFlag() {
return flag;
}
public void setFlag(String flag) {
this.flag = flag;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
@Override
public String toString() {
return "EventBase{" +
"tag='" + tag + '\'' +
", flag='" + flag + '\'' +
", data=" + data +
'}';
}
}
RxBus.getInstance().send(new EventBase(“new”,“new1”,"news"));
RxBuss.getInstance().register(this, new RxBuss.EventListener() {
@Override
public void onEvent(EventBase eventBase) {
LogUtils.e(eventBase.getTag());
}
});
新建RxBus类,声明Subjcet
说明一下Subject可以看做是一个桥梁或者代理,充当了Observer和Observable的角色,也就是观察者与被观察者。
SerializedSubject可以处理并发,并发时只允许一个线程调用onnext等方法!。
PublishSubject是Subject的一种,它仅会向Observer释放在订阅之后Observable释放的数据。
EventBase类是消息实体类,可以看到上面所写的就是通过send发消息调用onNext,接收到消息用订阅者所在类的接口回调过去,实现接收到消息。
体验了一把发现有问题,比如我在activity1 register了并跳转到activity2同也register监听,然后跳转到activity3,销毁activity2 并在activity3 send消息 这是很会发现activity1和activity2都会受到消息,明明activity被销毁了,这怎么回事?第二个问题就是,也不算问题 就是我想用类似EventBus注解方式接受消息。
解决办法:1、在activity 销毁时 RxBus进行反注册,这样就需要在RxBus定义 private Map
首先上代码:
Event注解
/**
* Author KINCAI
* .
* description TODO
* .
* Time 2016-12-08 10:21
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Event {
String value();
}
RxBus改进
**
* Author KINCAI
* .
* description TODO
* .
* Time 2016-12-07 12:54
*/
public class RxBus {
private final Subject
rxBus = new SerializedSubject<>(PublishSubject.create());
private Map mSubscriptions = new HashMap<>();
private RxBus() {
}
public static RxBus getInstance() {
return RxBusInstance.instance;
}
private static class RxBusInstance{
private static final RxBus instance = new RxBus();
}
public void send(EventBase eventBase){
rxBus.onNext(eventBase);
}
public void register(final Object obj){
if(obj == null)
return;
Subscription subscription = rxBus.observeOn(AndroidSchedulers.mainThread())
.map(new Func1() {
@Override
public EventBase call(Object s) {
return (EventBase) s;
}
}).subscribe(new Action1() {
@Override
public void call(EventBase eventBase) {
RxBus.this.call(obj, eventBase);
}
});
putSubscription(obj, subscription);
}
private void call(Object obj, EventBase eventBase){
Class> cls = obj.getClass();
Method[] methods = cls.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(Event.class)) {
Event event = method.getAnnotation(Event.class);
String value = event.value();
String tag = eventBase.getTag();
try {
if (TextUtils.isEmpty(tag) || TextUtils.isEmpty(value)) {
method.setAccessible(true);
method.invoke(obj, eventBase);
} else {
if (tag.equals(value)) {
method.setAccessible(true);
method.invoke(obj, eventBase);
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
public void unRegister(Object obj){
if(obj == null)
return;
Subscription subscription = getSubscription(obj);
if(subscription != null && !subscription.isUnsubscribed()){
subscription.unsubscribe();
}
}
private void putSubscription(Object obj,Subscription subscription){
String className = obj.getClass().getName();
for (Map.Entry entry : mSubscriptions.entrySet()) {
if(className.equals(entry.getKey())){
if(!entry.getValue().isUnsubscribed()){
entry.getValue().unsubscribe();
}
mSubscriptions.remove(className);
break;
}
}
mSubscriptions.put(className,subscription);
}
private Subscription getSubscription(Object obj){
String className = obj.getClass().getName();
for (Map.Entry entry : mSubscriptions.entrySet()) {
if(className.equals(entry.getKey())){
Subscription value = entry.getValue();
mSubscriptions.remove(entry.getKey());
return value;
}
}
return null;
}
/*public interface EventListener {
void onEvent(EventBase eventBase);
}*/
}
订阅者
@Event(EventNotify.MAIN_INIT)
public void onEvent(EventBase eventBase) {
LogUtils.e("event main "+eventBase.getTag());
if(EventNotify.MAIN_INIT_RE_LOAD.equals(eventBase.getFlag())){
clearRefreshUserInfo();
initLoad();
}
}
注册的时候传入object就是当前注册类实例 用类名作为键 Subscription作为值存入map集合,当然啦需要判断键是否存在防止多次注册,反注册的时候根据键找到Subscription并判断没有取消订阅的时候进行取消订阅。
在call方法中主要是根据当前注册类找到Event注解方法 并且判断EventBase的tag值和Event value值是否相同,相同就调用onEvent方法,起到筛选作用,当然发送的时候EventBaseTag为空的时候或者Event value为空就不筛选,直接回调,EventBase的flag参数是给订阅者onEvent方法接收到消息进一步筛选类型的。
好啦,这是我在activity1注册 并且onEvent的Event("mian"),activity2注册 并onEvent的Event("mian2")
这是我在activity3发送消息 RxBus.getInstance().send(new EventBase("main","test","data"));
毫无疑问,activity1才能收到消息。
别忘了在onDestory方法反注册哦;
仅供参考,有什么地方写的不好的 ,或者有错误,欢迎提出。