EventBus3.0学习笔记

本文详细介绍了EventBus的使用方法及原理,包括发布/订阅模式的基本概念、不同线程模式下的事件处理方式,以及如何在Android应用中实现跨组件通信。
public void onEvent(MessageEvent event) {
        log(event.message);
    }
public void onEventMainThread(MessageEvent event) {
        textField.setText(event.message);
    }
public void onEventBackgroundThread(MessageEvent event){
        saveToDisk(event.message);
    }

什么是EventBus

EventBus是一个发布 / 订阅的事件总线。git地址:https://github.com/greenrobot/EventBus

笼统来讲EventBus可以分为三部分,发布者、订阅者、总线。订阅者通过总线订阅事件,发布者通过总线发布时间,因此订阅者就可以收到发布者发布的事件了。

如何使用EventBus

EventBus的使用也是很简单的,首先来看几个方法:

EventBus.getDefault().register(this);//订阅事件

EventBus.getDefault().post(object);//发布事件

EventBus.getDefault().unregister(this);//取消订阅

首先需要在oncreat里面注册EventBus,类似广播的注册,当然也需要在destory的时候取消注册。在需要发送也就是发布消息的地方调用post方法,注意里面的参数,然后在接受也就是事件处理的地方写几个方法即可。在3.0以前接收事件是这样的:

 public void onEvent(MessageEvent event) {
        log(event.message);
    }
 public void onEventMainThread(MessageEvent event) {
        textField.setText(event.message);
    }
public void onEventBackgroundThread(MessageEvent event){
        saveToDisk(event.message);
    }

方法必须以onEvent开头,但是3.0以后采用了注解的方式:

    @Subscribe(threadMode = ThreadMode.MainThread) //在ui线程执行
    public void onUserEvent(UserEvent event) {
    }
    @Subscribe(threadMode = ThreadMode.BackgroundThread) //在后台线程执行
    public void onUserEvent(UserEvent event) {
    }
    @Subscribe(threadMode = ThreadMode.Async) //强制在后台执行
    public void onUserEvent(UserEvent event) {
    }
    @Subscribe(threadMode = ThreadMode.PostThread) //默认方式, 在发送线程执行
    public void onUserEvent(UserEvent event) {
    }

举个栗子

public class MainActivity extends Activity {

    private final static String TAG = "EventBusTest";  
    
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);
        // 1.注册事件订阅者("登录")
        EventBus.getDefault().register(this);  
    }  
  
    @Override  
    protected void onDestroy() {  
        super.onDestroy();  
        // 4.解除注册("注销")
        EventBus.getDefault().unregister(this);  
    }  
	
    public void testActivity(View view){
    	Intent intent = new Intent(this,third.class);
    	startActivity(intent);
    }
    
	// 3.接收方处理消息(处理数据)-- 主线程中执行  
    @Subscribe(threadMode = ThreadMode.MainThread)  
    public void onMainEventBus(MainMessage msg) {  
        Log.e(TAG, "onEventBus() handling message: " + Thread.currentThread().getName());  
    }  
  
    // 3.接收方处理消息(处理数据)-- 后台线程或子线程中执行
    @Subscribe(threadMode = ThreadMode.BackgroundThread)  
    public void onBackgroundEventBus(BackgroundMessage msg) {  
        Log.e(TAG, "onEventBusBackground() handling message: " + Thread.currentThread().getName());  
    }  
  
    // 3.接收方处理消息(处理数据)-- 后台线程中执行  
    @Subscribe(threadMode = ThreadMode.Async)  
    public void onAsyncEventBus(AsyncMessage msg) { 
    	Log.e(TAG, "onEventBusAsync() handling message: " + Thread.currentThread().getName());  
    }  
  
    // 3.接收方处理消息(处理数据)-- 和发送方在同一个线程  
    @Subscribe(threadMode = ThreadMode.PostThread)  
    public void onPostEventBus(PostMessage msg) {  
        Log.e(TAG, "onEventBusPost() handling message: " + Thread.currentThread().getName());  
    }  
}

另一个负责发布事件的类:

public class OtherActivity extends Activity {
	private final static String TAG = "EventBusTest";  
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.other_activity);
		
		 EventBus.getDefault().register(this);
		
	}
	// 3.接收方处理消息(处理数据)-- 主线程中执行  
    @Subscribe(threadMode = ThreadMode.MainThread)  
    public void onMainEventBus(MainMessage msg) {  
        Log.e(TAG, "onEventBus() handling message: " + Thread.currentThread().getName());  
    } 
	public void btnClick(View view) {  
        switch (view.getId()) {  
            case R.id.btn1: 
            	
            	
            	// 2.发送方发送消息 -- 发送MainMessage这个自己定义的对象,可以丰富这个对象,用来传递消息(数据)
				EventBus.getDefault().post(new MainMessage("Hello EventBus"));  
                
            	break;  
            case R.id.btn2:
            	// 2.发送方发送消息 -- 发送BackgroundMessage这个自己定义的对象,可以丰富这个对象,用来传递消息(数据)
            	// 注意,这里是在主线程中发送消息
				EventBus.getDefault().post(new BackgroundMessage("Hello EventBus"));  
                break;  
            case R.id.btn3:  
            	new Thread(){
            		public void run() {
            			// 2.发送方发送消息 -- 发送AsyncMessage这个自己定义的对象,可以丰富这个对象,用来传递消息(数据)
            			EventBus.getDefault().post(new AsyncMessage("Hello EventBus"));  
            		};
            	}.start();
                break;  
            case R.id.btn4:  
            	new Thread(){
            		public void run() {
            			// 2.发送方发送消息 -- 发送PostMessage这个自己定义的对象,可以丰富这个对象,用来传递消息(数据)
            			EventBus.getDefault().post(new PostMessage("Hello EventBus"));  
            		};
            	}.start();
                break;  
        }  
    }  
}

用法还是很简单的,需要的可以下载demo:https://yunpan.cn/cSDavPcfvgLvY (提取码:9423)

简单源码解析

还是来简单看下源码,需要源码的可自行去git下载。

注册

register.java这个类是一个单例模式的类,按顺序我们先看他的register方法。

/**
     * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
     * are no longer interested in receiving events.
     * <p/>
     * Subscribers have event handling methods that must be annotated by {@link Subscribe}.
     * The {@link Subscribe} annotation also allows configuration like {@link
     * ThreadMode} and priority.
     */
    public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

findSubscriberMethods方法作用就是遍历当前类里面的所有@Subscriber注解的方法。然后返回一个list,接着遍历List,调用subscribe方法订阅事件。

// Must be called in synchronized block
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class<?> eventType = subscriberMethod.eventType;
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
            if (subscriptions.contains(newSubscription)) {
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                        + eventType);
            }
        }

        int size = subscriptions.size();
        for (int i = 0; i <= size; i++) {
            if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }

        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);

        if (subscriberMethod.sticky) {
            if (eventInheritance) {
                // Existing sticky events of all subclasses of eventType have to be considered.
                // Note: Iterating over all events may be inefficient with lots of sticky events,
                // thus data structure should be changed to allow a more efficient lookup
                // (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
                Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
                for (Map.Entry<Class<?>, Object> entry : entries) {
                    Class<?> candidateEventType = entry.getKey();
                    if (eventType.isAssignableFrom(candidateEventType)) {
                        Object stickyEvent = entry.getValue();
                        checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                    }
                }
            } else {
                Object stickyEvent = stickyEvents.get(eventType);
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }
    }

根据subscriberMethod.eventType,去subscriptionsByEventType去查找一个CopyOnWriteArrayList<Subscription> ,如果没有则创建。

顺便把我们的传入的参数封装成了一个:Subscription(subscriber, subscriberMethod, priority);

这里的subscriptionsByEventType是个Map,key:eventType ; value:CopyOnWriteArrayList<Subscription> ; 这个Map其实就是EventBus存储方法的地方,一定要记住!

简单来讲这个方法就是把该类里面的所有@Subscriber注解的方法放进subscriptionsByEventType这个map里面,为后面事件做准备。

发送

 /** Posts the given event to the event bus. */
    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;
            }
        }
    }

这个方法负责把事件发布到事件总线。currentPostingThreadState是一个ThreadLocal类型的,里面存储了PostingThreadState;PostingThreadState包含了一个eventQueue和一些标志位。把我们传入的event,保存到了当前线程中的一个变量PostingThreadState的eventQueue中。

根据isPosting为false的情况不断的调用postSingleEvent(eventQueue.remove(0), postingState)方法。

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        if (eventInheritance) {
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
        if (!subscriptionFound) {
            if (logNoSubscriberMessages) {
                Log.d(TAG, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }
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;
                } finally {
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                if (aborted) {
                    break;
                }
            }
            return true;
        }
        return false;
    }

 

根据event的Class,去得到一个List<Class<?>>;其实就是得到event当前对象的Class,以及父类和接口的Class类型,遍历所有的Class,到subscriptionsByEventType去查找subscriptions这个map与register里面的map是同一个。遍历每个subscription,依次去调用postToSubscription(subscription, event, postingState.isMainThread);

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING:
                invokeSubscriber(subscription, event);
                break;
            case MAIN:
                if (isMainThread) {
                    invokeSubscriber(subscription, event);
                } else {
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case BACKGROUND:
                if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);
                } else {
                    invokeSubscriber(subscription, event);
                }
                break;
            case ASYNC:
                asyncPoster.enqueue(subscription, event);
                break;
            default:
                throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
        }
    }

这个就是根据注解里的threadMode去判断在哪个线程执行了。

case PostThread:

void invokeSubscriber(Subscription subscription, Object event) throws Error {  
          subscription.subscriberMethod.method.invoke(subscription.subscriber, event);  
}

直接在当前线程里面执行了。

case MAIN:

if (isMainThread) {
      invokeSubscriber(subscription, event);
     } else {
        mainThreadPoster.enqueue(subscription, event);
     }

首先去判断当前如果是UI线程,则直接调用;否则: mainThreadPoster.enqueue(subscription, event);把当前的方法加入到队列,然后直接通过handler去发送一个消息,在handler的handleMessage中,去执行我们的方法。说白了就是通过Handler去发送消息,然后执行的。

case BACKGROUND:

              if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);
                } else {
                    invokeSubscriber(subscription, event);
                }

如果当前非UI线程,则直接调用;如果是UI线程,则将任务加入到后台的一个队列,最终由Eventbus中的一个线程池去调用

executorService = Executors.newCachedThreadPool();。

case ASYNC:

asyncPoster.enqueue(subscription, event);

将任务加入到后台的一个队列,最终由Eventbus中的一个线程池去调用;线程池与BackgroundThread用的是同一个。

这么说BackgroundThread和Async有什么区别呢?

BackgroundThread中的任务,一个接着一个去调用,中间使用了一个布尔型变量handlerActive进行的控制。

Async则会动态控制并发。

取消

 /** Unregisters the given subscriber from all event classes. */
    public synchronized void unregister(Object subscriber) {
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            for (Class<?> eventType : subscribedTypes) {
                unsubscribeByEventType(subscriber, eventType);
            }
            typesBySubscriber.remove(subscriber);
        } else {
            Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
    private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
        List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions != null) {
            int size = subscriptions.size();
            for (int i = 0; i < size; i++) {
                Subscription subscription = subscriptions.get(i);
                if (subscription.subscriber == subscriber) {
                    subscription.active = false;
                    subscriptions.remove(i);
                    i--;
                    size--;
                }
            }
        }
    }

Subscribe

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
    ThreadMode threadMode() default ThreadMode.POSTING;

    /**
     * If true, delivers the most recent sticky event (posted with
     * {@link EventBus#postSticky(Object)}) to this subscriber (if event available).
     */
    boolean sticky() default false;

    /** Subscriber priority to influence the order of event delivery.
     * Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before
     * others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of
     * delivery among subscribers with different {@link ThreadMode}s! */
    int priority() default 0;
}

ThreadMode threadMode() default ThreadMode.POSTING;

也就是前面说道的执行方式,主线程还是其他线程,默认是当前线程。

boolean sticky() default false;

默认为false,时间立即执行。如果为true那表示事件事件不被马上处理。

int priority() default 0;

优先级,数字越大优先级越高,默认0。

转载于:https://my.oschina.net/tomcater/blog/685493

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值