EventBus框架的简单介绍

EventBus(事件总线)

历史背景

它是由开源组织greenrobot贡献的Android事件发布/订阅的框架.

主要功能

通过解耦发布者和订阅者来简化Android中事件的传递(通俗来讲,就是一个人发事件的消息告诉另一个人该做什么,或者是某个人想将数据交给另一个人),这个事件传递既可用于四大组件之间的数据传递(也叫通信),也可以用于异步线程和主线程之间的通信.代替了传统的事件传递方式:Handler , BrocastReceiver , 接口回调,在Fragment , Activity , Service , 线程之间传递数据,执行方法.一句话:任何一个java类通可以用这个通讯

概念

事件(Event)

又可称为消息.其实就是一个对象.该对象可以是任意数据类型,不像Intent,Bundle传递数据一样局限.通常这个对象都是通过自定义一个事件类来实例化的

订阅者(Subscriber)

订阅某种事件类型的对象,也就是订阅接收事件信息的对象.当有发布者发布这类事件后,EventBus会执行订阅者的订阅函数,这个订阅函数俗称事件响应函数.订阅者通过注册(register)接口订阅某个事件类型,unregister进行接口退订.注意:订阅者存在优先级,优先级高的订阅者可以取消事件继续向优先级低的订阅者分发,默认所有订阅者优先级都为0.

发布者(Publisher)

发布某种事件的对象,通过post接口发布事件.

简单的使用案例

分别创建两个Activity,分别是SubscriberActivity(作为订阅者),PublisherActivity(作为发布者),PublisherActivity发布事件类型给SubscriberActivity接收,也就是发布者发布事件类型给订阅者接收,订阅者在订阅方法中做相应的处理.

创建事件类型,通常一个自定义类,这里我们命名为MyEvent

package jansonwang.example.com.myapplication;

/**
 * Created by Jason Wang on 2017/5/22.
 * 这是一个事件类型,它可以携带各种各样的数据类型
 */
public class MyEvent {
    public String msg;
    public MyEvent(String msg){
        this.msg = msg;
    }
}

创建SubscriberActivity(作为订阅者),并且注册订阅接口,自定义订阅函数,反注册订阅接口

package jansonwang.example.com.myapplication;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

public class SubscriberActivity extends AppCompatActivity {

    private static final String TAG ="SubscriberActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //EventBus.getDefault();创建单个事件总线对象
        EventBus.getDefault().register(this);  //注册事件总线
    }

    public void start(View view) {
        Intent intent = new Intent(this, PublisherActivity.class);
        startActivity(intent);
    }


    /**
     * 接收发布者的事件消息,
     * ThreadMode.MAIN模式:无论发布者在子线程中还是主线程中发送事件信息,最后订阅者方法都会在主线程中执行,所以这种模式下不能在订阅者方法中进行耗时操作
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void receiveEventOnMain(MyEvent event) {
        Log.d(TAG, "receiveEventOnMain: " + event.msg + "    " + Thread.currentThread().getName());
        Toast.makeText(SubscriberActivity.this, "ThreadMode.MAIN", Toast.LENGTH_SHORT).show();
    }

    /**
     * 接收发布者的事件消息
     *  ThreadMode.POSTING模式:发布者在哪个线程中发布事件消息,订阅者方法就会在哪个线程中执行,所以这个模式下也不能进行耗时操作,会延迟分发
     * @param event
     */
    @Subscribe(threadMode = ThreadMode.POSTING)
    public void receiveEventPosting(MyEvent event){
        Log.d(TAG, "receiveEventPosting: " + event.msg + "    " + Thread.currentThread().getName());
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(SubscriberActivity.this, "ThreadMode.POSTING", Toast.LENGTH_SHORT).show();
            }
        });

    }

    /**
     * 接收发布者的事件消息
     *  ThreadMode.ASYNC模式:发布者无论在哪个线程中发布事件消息,订阅者方法都会自己重新创建一个子线程执行
     * @param event
     */
    @Subscribe(threadMode = ThreadMode.ASYNC)
    public void receiveEventASYNC(MyEvent event){
        Log.d(TAG, "receiveEventPosting: " + event.msg + "    " + Thread.currentThread().getName());
        runOnUiThread(new Runnable() {
            @Override
            public void run() {

        Toast.makeText(SubscriberActivity.this, "ThreadMode.ASYNC", Toast.LENGTH_SHORT).show();
            }
        });
    }

    /**
     *  接收发布者的事件消息
     *   ThreadMode.BACKGROUND模式:发布者如果在子线程中发布事件消息,订阅者方法就会在同一个子线程中执行;
     *                             发布者如果在主线程中发布事件消息,订阅者方法就会自己创建一个子线程执行
     * @param event
     */
    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void receiveEventBACKGROUND(MyEvent event){
        Log.d(TAG, "receiveEventPosting: " + event.msg + "    " + Thread.currentThread().getName());
        runOnUiThread(new Runnable() {
            @Override
            public void run() {

        Toast.makeText(SubscriberActivity.this, "ThreadMode.BACKGROUND", Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //反注册事件总线
        EventBus.getDefault().unregister(this);
    }


}

创建PublisherActivity(作为发布者),并且发布事件

package jansonwang.example.com.myapplication;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

import org.greenrobot.eventbus.EventBus;

/**
 * Created by Jason Wang on 2017/5/22.
 */
public class PublisherActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_publisher);
    }

    /**
     * 在主线程中发布消息
     * @param view
     */
    public void send1(View view) {
        EventBus.getDefault().post(new MyEvent("发布者向订阅者发送事件消息"));
    }

    /**
     * 在子线程中发布消息
     * @param view
     */
    public void send2(View view) {
        new Thread(new Runnable() {
            @Override
            public void run() {

        EventBus.getDefault().post(new MyEvent("发布者向订阅者发送事件消息"));
            }
        }).start();
    }
}

*主要步骤:

1.订阅者注册订阅接口

 //EventBus.getDefault();创建单个事件总线对象
        EventBus.getDefault().register(订阅者类);  //注册事件总线

2.在订阅者类中自定义订阅函数(记得在函数头上加引用,例如 @Subscribe(threadMode = ThreadMode.MAIN)),用来接收发布者发布事件类型,

    /**
     * 接收发布者的事件消息,
     * ThreadMode.MAIN模式:无论发布者在子线程中还是主线程中发送事件信息,最后订阅者方法都会在主线程中执行,所以这种模式下不能在订阅者方法中进行耗时操作
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void receiveEventOnMain(MyEvent event) {
        Log.d(TAG, "receiveEventOnMain: " + event.msg + "    " + Thread.currentThread().getName());
        Toast.makeText(SubscriberActivity.this, "ThreadMode.MAIN", Toast.LENGTH_SHORT).show();
    }

    /**
     * 接收发布者的事件消息
     *  ThreadMode.POSTING模式:发布者在哪个线程中发布事件消息,订阅者方法就会在哪个线程中执行,所以这个模式下也不能进行耗时操作,会延迟分发
     * @param event
     */
    @Subscribe(threadMode = ThreadMode.POSTING)
    public void receiveEventPosting(MyEvent event){
        Log.d(TAG, "receiveEventPosting: " + event.msg + "    " + Thread.currentThread().getName());
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(SubscriberActivity.this, "ThreadMode.POSTING", Toast.LENGTH_SHORT).show();
            }
        });

    }

    /**
     * 接收发布者的事件消息
     *  ThreadMode.ASYNC模式:发布者无论在哪个线程中发布事件消息,订阅者方法都会自己重新创建一个子线程执行
     * @param event
     */
    @Subscribe(threadMode = ThreadMode.ASYNC)
    public void receiveEventASYNC(MyEvent event){
        Log.d(TAG, "receiveEventPosting: " + event.msg + "    " + Thread.currentThread().getName());
        runOnUiThread(new Runnable() {
            @Override
            public void run() {

        Toast.makeText(SubscriberActivity.this, "ThreadMode.ASYNC", Toast.LENGTH_SHORT).show();
            }
        });
    }

    /**
     *  接收发布者的事件消息
     *   ThreadMode.BACKGROUND模式:发布者如果在子线程中发布事件消息,订阅者方法就会在同一个子线程中执行;
     *                             发布者如果在主线程中发布事件消息,订阅者方法就会自己创建一个子线程执行
     * @param event
     */
    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void receiveEventBACKGROUND(MyEvent event){
        Log.d(TAG, "receiveEventPosting: " + event.msg + "    " + Thread.currentThread().getName());
        runOnUiThread(new Runnable() {
            @Override
            public void run() {

        Toast.makeText(SubscriberActivity.this, "ThreadMode.BACKGROUND", Toast.LENGTH_SHORT).show();
            }
        });
    }

3.创建一个类,作为要发布的事件类型

package jansonwang.example.com.myapplication;

/**
 * Created by Jason Wang on 2017/5/22.
 * 这是一个事件类型,它可以携带各种各样的数据类型
 */
public class 事件类型 {
    public String msg;
    public MyEvent(String msg){
        this.msg = msg;
    }
}

4.发布者发布事件类型

   EventBus.getDefault().post(事件类型对象);

每个步骤的源码分析

 EventBus.getDefault();//创建事件总线对象

这段代码采用的是单例模式:

```

//两个非空,一个加锁

public static EventBus getDefault() {

if (defaultInstance == null) {
    synchronized (EventBus.class) {
        if (defaultInstance == null) {
            defaultInstance = new EventBus();
        }
    }
}
return defaultInstance;

}

```

下面是优化历史

//简单单例,当多线程时,还是会创建多个示例
public static EventBus getDefault() {
    if (defaultInstance == null) {
        defaultInstance = new EventBus();
    }
    return defaultInstance;
}

//加锁单例,每次调用都检查是否加锁
public static synchronized EventBus getDefault() {
    if (defaultInstance == null) {
        defaultInstance = new EventBus();
    }
    return defaultInstance;
}

//两个非空,一个加锁
public static EventBus getDefault() {
    if (defaultInstance == null) {
        synchronized (EventBus.class) {
            if (defaultInstance == null) {
                defaultInstance = new EventBus();
            }
        }
    }
    return defaultInstance;
}

 EventBus.getDefault().register(this);  //注册事件总线

下面是注册的源码

public void register(Object subscriber) {
    Class<?> subscriberClass = subscriber.getClass();
    //找到订阅者中所有的订阅方法
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) {
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            //将订阅方法记录下来保存到对应事件的订阅列表中
            //Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType
            subscribe(subscriber, subscriberMethod);
        }
    }
}

 EventBus.getDefault().post(事件类型对象)

下面是发布者发布事件的源码:

public void post(Object event) {
    PostingThreadState postingState = currentPostingThreadState.get();
    List<Object> eventQueue = postingState.eventQueue;
    eventQueue.add(event);.//添加到事件队列

    if (!postingState.isPosting) {
        postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
        postingState.isPosting = true;
        if (postingState.canceled) {
            throw new EventBusException("Internal error. Abort state was not reset");
        }
        try {
            while (!eventQueue.isEmpty()) {
                //发布的单个事件
                postSingleEvent(eventQueue.remove(0), postingState);
            }
        } finally {
            postingState.isPosting = false;
            postingState.isMainThread = false;
        }
    }
}


private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
    Class<?> eventClass = event.getClass();
    boolean subscriptionFound = false;
    if (eventInheritance) {
        ........
    } else {
        //发布对应事件类型的事件
        subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
    }
    .........
}

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
    CopyOnWriteArrayList<Subscription> subscriptions;
    synchronized (this) {
        subscriptions = subscriptionsByEventType.get(eventClass);//获取对应事件的订阅列表
    }
    if (subscriptions != null && !subscriptions.isEmpty()) {
        //遍历订阅列表
        for (Subscription subscription : subscriptions) {
            postingState.event = event;
            postingState.subscription = subscription;
            boolean aborted = false;
            try {
                //发布事件到一个订阅
                postToSubscription(subscription, event, postingState.isMainThread);
                aborted = postingState.canceled;
            }
            ........
        }
        return true;
    }
    ......
}

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
    //判断订阅方法的线程模型
    switch (subscription.subscriberMethod.threadMode) {
        case POSTING:
            //POSTING线程模型下,直接反射调用订阅方法
            invokeSubscriber(subscription, event);
            break;
        case MAIN:
            //MAIN线程模型
            if (isMainThread) {
                //如果当前是主线程,则直接反射调用订阅方法
                invokeSubscriber(subscription, event);
            } else {
                //如果当前不是主线程,则使用绑定主线程Looper的Handler在主线程调用订阅方法
                mainThreadPoster.enqueue(subscription, event);
            }
            break;
        case BACKGROUND:
            //BACKGROUND线程模型
            if (isMainThread) {
                //如果当前是主线程,则在EventBus内部的线程池中执行
                backgroundPoster.enqueue(subscription, event);
            } else {
                //如果当前是子线程,则直接在该子线程反射调用订阅方法
                invokeSubscriber(subscription, event);
            }
            break;
        case ASYNC:
            //ASYNC线程模型
            //直接在EventBus的线程池中执行
            asyncPoster.enqueue(subscription, event);
            break;
        default:
            throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
    }
}
    原文作者:阳光底下的那个少年
    原文地址: https://www.jianshu.com/p/18c98a4a2163
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞