Android面试相关

EventBus设计模式剖析(一)单例模式

2019-07-15  本文已影响0人  YongtaoHuang

下一篇 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

下一篇 EventBus设计模式剖析(二)建造者模式

All is well.

上一篇 下一篇

猜你喜欢

热点阅读