MsgCenter
MsgCenter是本人自己实现的进程内的消息传递的框架。该框架是我在Github上的工程SxLibrary的一部分。
https://github.com/tangrb/SxLibrary
为什么要实现MsgCenter?
前几天去面试,被人问及如何在Android的各个组件之间传递消息,我当时给了很多中答案。例如,在Activity之间可以通过Intent来传递消息,在Fragment之间可以通过回调来进行通信,或者设置一个全局变量,然后一个组件去设置,一个组件去读取。然后面试官问我有没有使用过EventBus,使用EventBus可以方便在不同组件之间传递消息。我当时愣了一下,因为我只听说过有这个框架,但是没有使用过。
面试回来后很受挫,甚至怀疑自己是不是out了。过了大概一两天后,我就有了自己实现一个类EventBus的框架的想法。于是那天我花了半天实现实现了一个初步的可用的MsgCenter。当然这个前提是我没有看EventBus的源码,只看了EventBus的基本使用方法。如果看了EventBus源码的话,那就没什么意思了。
直到今天,我重构了MsgCenter并使得MsgCenter稳定起来。
MsgCenter的架构、设计
MsgCenter使用了生产者/消费者模型,生产者负责产生并发布消息,消费者负责订阅消息,连接生产者和消费者的是MsgCenter,MsgCenter负责缓存消息,并将消息传递到匹配的消费者手里。一个消息可以被多个消费者订阅。
初始化MsgCenter
MsgCenter.instance();
该方法用来实例化一个MsgCenter对象,MsgCenter目前采用的是单例模式。
该方法只能在主线程中调用,因为MsgCenter内部要实例化一个Handler对象,该Handler对象用来将消息回调到主线程中。
发布消息
MsgCenter.instance().publish(String msgName, int msgType, Object msgEntity);
该方法可以在任何线程中使用。
msgName用来表示该消息的名称,msgName不能为null和长度为0的字符串。
msgType表示该消息的类型,MsgType接口中定于了4种消息类型,消息解析请看MsgType的源码:
package com.trb.sxlibrary.msg;
public interface MsgType {
/**
* 实时消息,一旦发布就会被立即消耗。
* 如果有该消息的订阅者,则订阅者会收到该消息,该消息被消耗掉;
* 如果没有该消息的订阅者,该消息会被抛弃、销毁。
* <p>
* 该类消息的消息订阅者只能在非UI线程中接收到该消息。
*/
int RT = 1;
/**
* 粘性消息,发布后该消息缓存到消息列表中。
* 如果有该消息的订阅者,则订阅者会收到该消息,该消息被消耗掉;
* 如果没有该消息的订阅者,该消息会一直存在于消息列表中。
* <p>
* 该类消息的消息订阅者只能在非UI线程中接收到该消息。
*/
int STICKY = 2;
/**
* 作用同RT。
* <p>
* 该类消息的消息订阅者只能在UI线程中接收到该消息。
*/
int RT_UI = 11;
/**
* 作用同STICKY。
* <p>
* 该类消息的消息订阅者只能在UI线程中接收到该消息。
*/
int STICKY_UI = 12;
}
订阅消息
MsgCenter.instance().subscribe(String msgName, MsgListener l);
该方法用来订阅消息。
在这里,我认为消息只需要消息名就可以和订阅者产生关联,所以订阅的时候可以不需要消息的类型。
取消订阅消息
MsgCenter.instance().subscribe(String msgName, MsgListener l);
在第一版的时候,我考虑过使用WeakReference来包装MsgListener对象,但是最终版放弃了,我觉得还是要手动去注销,因为GC不能保证及时释放MsgListener对象。
销毁
MsgCenter.destroy();
该方法用来停止MsgCenter的工作,内部是停止了一个解析分发消息的线程,然后释放了MsgCenter对象。
使用示例
package com.trb.sxlibrary;
import android.os.Bundle;
import android.util.Log;
import com.trb.sxlibrary.app.SxActivity;
import com.trb.sxlibrary.msg.MsgCenter;
import com.trb.sxlibrary.msg.MsgListener;
import com.trb.sxlibrary.msg.MsgType;
import org.xutils.view.annotation.ContentView;
@ContentView(R.layout.activity_main)
public class MainActivity extends SxActivity implements MsgListener {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MsgCenter.instance();
testMsgCenter();
}
@Override
protected void onDestroy() {
MsgCenter.instance().unsubscribe("msg_test", MainActivity.this);
MsgCenter.instance().unsubscribe("msg_test_ui", MainActivity.this);
MsgCenter.destroy();
super.onDestroy();
}
private void testMsgCenter() {
Log.i(TAG, "testMsgCenter: ");
new Thread() {
@Override
public void run() {
MsgCenter.instance().subscribe("msg_test", MainActivity.this);
MsgCenter.instance().subscribe("msg_test_ui", MainActivity.this);
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new MsgSendThread().start();
}
}.start();
}
@Override
public void onMsgArrived(String nameName, Object msg) {
Log.i(TAG, "onRecvMsg: " + msg);
}
class MsgSendThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
MsgCenter.instance().publish("msg_test", MsgType.RT, "test msg: " + +i);
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
MsgCenter.instance().publish("msg_test_ui", MsgType.RT_UI, "test msg ui : " + +i);
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}