一个非常简单的组建间事件通信类

要实现组建件自由通信,Android似乎没有提供很完美的方法,但是我们知道有很多第三方的EventBus库可以实现这种功能。

不过我始终没有使用过任何一个EventBus库,因为如果代码不多就能实现这个简单的功能,我是不愿意用第三方库的。

我第一次接触到EventBus这个东西,是在研究谷歌4.0原生日历代码的时候,那个时候Android上似乎还没有人提出EventBus这个概念,但是它实现的思路对我启发很大,虽然不知道它该叫什么。也是在那个时候我开始认识到接口在Java中的重要性。相关的文章见:Android 4.0日历(calendar)源码分析之CalendarController(事件分发) 

我们先来看看EventBus要解决的问题

假如我在一个登录界面登录成功,想把这个消息发送给主界面的一个tab页(比如个人中心),而这个tab是一个Fragment,这个时候就会感觉有点麻烦了,最笨的方法是从上往下,传递这个Fragment的实例。如果这种事件有三个以上,并且发生在三组不同的类之间,你的代码就会很乱了。

所以我们需要一种在任何地点发送一个消息,能被任何类接收到此消息的机制。

该怎么设计呢?

我们定义一个专门发送消息的类EventBus,并在这个类中定义一个处理消息的接口。

要满足任何地点发送消息,那么这个EventBus类可能必须使用单例,任何地点实例化它的时候都是同一对象。要把消息发送给任何类,EventBus必须在自己内部定义一个处理事件的接口,并且在内部维护一个接口的列表,当事件发送的时候,遍历这些接口,通知它们事件发生了。这里的接口就是被通知的对象,如果你的某个类要接收事件通知,实现这个接口。

还是先上代码吧,代码基本上就是从Calendar中提炼出来的。

EventBus.java

package com.jcodecraeer.app4android;
/**
 * Created by jianghejie on 17/5/1.
 */
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
import android.content.Context;
import android.text.format.Time;
public class EventBus {
    private static EventBus mController;
    private LinkedHashMap<Integer,EventHandler> eventHandlers =
            new LinkedHashMap<Integer,EventHandler>();
    public interface EventType {
        final int CATEGORY = 0;
        final int TOGGLE = 1;
        final int DATA = 2;
        final int LOGIN = 3;
        final int LOGOUT = 4;
        final int THEME = 5;
    }
    private EventBus() {
    }
    public interface EventHandler {
        void onHandleEvent(int eventType, Object obj);
    }
    public static EventBus create() {
        if (mController == null) {
            mController = new EventBus();
        }
        return mController;
    }
    public void sendEvent(int eventType,  Object obj) {
        for (Iterator<Entry<Integer, EventHandler>> handlers =
             eventHandlers.entrySet().iterator(); handlers.hasNext();) {
            Entry<Integer, EventHandler> entry = handlers.next();
            EventHandler eventHandler = entry.getValue();
            if (eventHandler != null)
                eventHandler.onHandleEvent(eventType, obj);
        }
    }
    public void registerEventHandler(int key, EventHandler eventHandler) {
        synchronized (this) {
            eventHandlers.put(key, eventHandler);
        }
    }
}

其中,create()方法创建这个类的对象,它只会返回同一个对象。EventHandler就是处理事件的接口,我们定义了一个EventHandler的LinkedHashMap,registerEventHandler(int key, EventHandler eventHandler) 方法向这个LinkedHashMap中增加EventHandler。EventType定义了事件的类型,你可以根据自己的需要添加事件类型,它只是一个数字而已。sendEvent(int eventType,  Object obj)方法发送事件,eventType是事件类型,obj参数是事件携带的数据,可以在接收的时候强制转换成需要的类型。EventType是很重要的,因为EventBus会向所有注册了的EventHandler发送消息,EventType用于判断到底发来的是什么消息,从而只处理自己想要的消息。

如何使用?

以上面发送登录消息为例:

假设主界面是MainActivity,个人中心是UserFragment,登录界面是LoginActivity。

UserFragment是接收消息,LoginActivity是发送消息,因此这里UserFragment是事件处理类,所以先让它实现EventHandler接口:

public class UserFragment extends Fragment implements  EventBus.EventHandler{
....
@Override
public void onHandleEvent(int eventType,  Object obj) {
    if(eventType == EventBus.EventType.LOGIN){
        updateLoginInfo();
    }
}
....
}

在MainActivity中我们我们把这个UserFragment注册到EventBus中:

EventBus.create().registerEventHandler(1,mUserFragment);

注意这里的1为mUserFragment在LinkedHashMap中的key值。

然后在LoginActivity中当登录成功的时候,发送登录成功的消息:

@Override
public void onLoginSucess(String msg) {  
    EventBus.create().sendEvent(EventBus.EventType.LOGIN,"登录成功");
}

总结

其实EventBus就是一个观察者模式而已,跟setOnClickListener是同一个东西,只不过它的观察者有很多个。