EventBus设计模式剖析(一)单例模式
下一篇 EventBus设计模式剖析(二)建造者模式
EventBus:
由开源组织greenrobot开发的事件发布-订阅总线库。
设计模式:
软件开发中问题的解决套路。
单例模式简介
定义:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
很多时候我们搭建整个系统需要而且只需要一个全局对象,这么个对象就好比小说的线索,把整个流程穿插起来。这时候单例设计模式就派上了用场。另外,创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等,合理使用单例可以大大节省资源。
EventBus类中的单例模式
EventBus是Android的中央发布/订阅事件系统。事件被发布post(object)到总线。它将它传递给具有与事件类型匹配的处理程序方法的订阅服务器。要接收事件,订户必须使用register(object)注册到总线。注册后,订阅服务器将接收事件,直到调用unregister(object)。按照惯例,事件处理方法必须命名为“onEvent()”,该方法是公共的,不返回任何内容(void),并且只有一个参数(事件)。但是3.0版本后,事件处理方法名字可以任意取。常见使用套路源码如下:
首先:在接收消息的Activity中注册广播EventBus.getDefault().register(EventBusActivity.this); 其次对应的解注册EventBus.getDefault().unregister(EventBusActivity.this);写在这个Activity的onDestroy()函数中。在@Subscribe注解下写好onEvent()函数,即事件响应。
// eventbus 接受消息的Activity
public class EventBusActivity extends Activity {
private TextView tv_title;
private Button bt_eventbus_send;
private TextView tv_eventbus_result;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event_bus);
initView();
initData();
initListener();
}
private void initListener() {
// 跳转到发送页面
bt_eventbus_send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(EventBusActivity.this, EventBusSendActivity.class);
startActivity(intent);
}
});
}
private void initData() {
tv_title.setText("EventBus");
// 1注册广播
EventBus.getDefault().register(EventBusActivity.this);
}
private void initView() {
tv_title = (TextView)findViewById(R.id.tv_title);
bt_eventbus_send = (Button)findViewById(R.id.bt_eventbus_send);
tv_eventbus_result = (TextView)findViewById(R.id.tv_eventbus_result);
}
// 5接收消息
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event){
// 显示接收的消息
tv_eventbus_result.setText(event.name);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 2 解注册
EventBus.getDefault().unregister(EventBusActivity.this);
}
}
对于使用eventbus发送数据页面,我们在某个事件监听器下写好该事件的响应EventBus.getDefault().post(new MessageEvent("主线程发送过来的数据"));
// eventbus的发送数据页面
public class EventBusSendActivity extends Activity {
private TextView tv_title;
private Button bt_eventbus_send_main;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event_bus_send);
initView();
initData();
initListener();
}
private void initListener() {
// 主线程发送数据按钮点击事件处理
bt_eventbus_send_main.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 4 发送消息
EventBus.getDefault().post(new MessageEvent("主线程发送过来的数据"));
// 结束当前页面
finish();
}
});
}
private void initData() {
tv_title.setText("EventBus发送数据页面");
}
private void initView() {
tv_title = (TextView)findViewById(R.id.tv_title);
bt_eventbus_send_main = (Button)findViewById(R.id.bt_eventbus_send_main);
}
}
这是自定义的所传递的消息类,此处我们只传递一个name字符串。
// 自定义发送消息类
public class MessageEvent {
public String name;
public MessageEvent(String name) {
this.name = name;
}
}
由此可得,EventBusSendActivity 活动发送(post)一个new MessageEvent("主线程发送过来的数据"),EventBusActivity活动可以及时通过@Subscribe注解下的onEvent方法监听并对该消息进行响应。
我们从EventBus类开始分析,EventBus的构造函数是由单例模式和构造者模式一起组成的。这样EventBus既可以通过EventBus.getDefault()单例使用(中心总线),也可以通过EventBusBuilder建造出多个EventBus分别作用在各自的作用域,下一篇文章我们会分析建造者模式Builder。
public class EventBus {
static volatile EventBus defaultInstance; // volatile关键字保证defaultInstance所有线程共享
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
// 对于应用程序,使用一个所有线程都能使用EventBus实例,单例。
// 用的是Double Check Lock实现单例
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
// 创建一个新的EventBus实例,每个实例都是一个单独的作用域,在该作用域中传递事件
// 若想要一个中心总线,可以考虑使用getDefault()返回单例
public EventBus() {
this(DEFAULT_BUILDER);
}
EventBus(EventBusBuilder builder) {
......
}
}
此处单例模式的实现采用的是双检锁(DCL)的方式,是最广泛的单例模式实现。volatile关键字保证defaultInstance所有线程共享。双检过程如下,第一次判断主要是为了避免不必要的同步,第二次判断则是在若无才new一个对象出来,从而保证了实例defaultInstance的唯一性。
基于单例模式构建的其他代码
1、Android源码中的PhoneLayoutInflater
2、ImageLoader库
参考文献
1、设计模式|菜鸟教程:https://www.runoob.com/design-pattern/design-pattern-tutorial.html
2、《Android源码设计模式解析与实战》何红辉,关爱民著
3、蕉下孤客:https://www.jianshu.com/p/1b68ace4600a
4、野生的安卓兽:https://www.jianshu.com/nb/10598547