EventBus(二):Poster

简介

事件分发的核心代码:

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 MAIN_ORDERED:
                if (mainThreadPoster != null) {
                    mainThreadPoster.enqueue(subscription, event);
                } else {
                    // temporary: technically not correct as poster not decoupled from subscriber
                    invokeSubscriber(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);
        }
    }

isMainThread 表示post所在线程。
订阅方法不同的线程模式,分发方式略有不同:

  1. POSTING:事件发布和接收在相同的线程,直接调用invokeSubscriber。
  2. MAIN:如果发布者线程不是主线程,就把此事件送到mainThreadPoster主线程消息循环处理队列,在主线程中处理此事件。
  3. BACKGROUND:如果注册方法则直接在该线程中被调用,如果在主线程发送事件,则注册方法由backgroundPoster派发到工作线程中调用。
  4. ASYNC:直接由asyncPoster派发到工作线程中调用,不管发布者处在主线程与否,为每一个事件单独开辟一个线程处理。

mainThreadPoster

    private final MainThreadSupport mainThreadSupport;
    private final Poster mainThreadPoster;
    private final BackgroundPoster backgroundPoster;
    private final AsyncPoster asyncPoster;
    mainThreadSupport = builder.getMainThreadSupport();
    mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;

其中mainThreadSupport.createPoster(this) 实际是通过实例化对象调用createPoster方法返回new HandlerPoster(eventBus, looper, 10)得到主线程的handler

class AndroidHandlerMainThreadSupport implements MainThreadSupport {

        private final Looper looper;

        public AndroidHandlerMainThreadSupport(Looper looper) {
            this.looper = looper;
        }

        @Override
        public boolean isMainThread() {
            return looper == Looper.myLooper();//获取主线程的looper,用哪个线程的looper创建handler,handler就运行在哪个线程。
        }

        @Override
        public Poster createPoster(EventBus eventBus) {
            return new HandlerPoster(eventBus, looper, 10);
        }
    }
public class HandlerPoster extends Handler implements Poster {

    //PendingPostQueue队列,待发送的post队列
    private final PendingPostQueue queue;
    //规定最大的运行时间,因为运行在主线程,不能阻塞主线程
    private final int maxMillisInsideHandleMessage;
    private final EventBus eventBus;
    private boolean handlerActive;

    //传入的第二个参数是主线程的Looper,第三个参数表示主线程事件处理最大时间为10ms
    protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
        super(looper);
        this.eventBus = eventBus;
        this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
        queue = new PendingPostQueue();
    }

    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);
            if (!handlerActive) {
                handlerActive = true;
                if (!sendMessage(obtainMessage())) {
                    throw new EventBusException("Could not send handler message");
                }
            }
        }
    }

    @Override
    public void handleMessage(Message msg) {
        boolean rescheduled = false;
        try {
            long started = SystemClock.uptimeMillis();
            while (true) {
                PendingPost pendingPost = queue.poll();
                if (pendingPost == null) {
                    synchronized (this) {
                        // Check again, this time in synchronized
                        pendingPost = queue.poll();
                        if (pendingPost == null) {
                            handlerActive = false;
                            return;
                        }
                    }
                }
                eventBus.invokeSubscriber(pendingPost);
                long timeInMethod = SystemClock.uptimeMillis() - started;
                if (timeInMethod >= maxMillisInsideHandleMessage) {
                    if (!sendMessage(obtainMessage())) {
                        throw new EventBusException("Could not send handler message");
                    }
                    rescheduled = true;
                    return;
                }
            }
        } finally {
            handlerActive = rescheduled;
        }
    }
}
  • 该handler内部有一个PendingPostQueue,这是一个队列,保存了PendingPost,即待发送的post。
  • PendingPost封装了事件类型event和subscription,subscription则是封装了订阅者和订阅方法。
  • 加入队列,调用Handler方法进行分发。
  • sendMessage()发送成功返回true,接着会调用下面handleMessage。

HandlerPoster#handleMessage方法:

@Override
    public void handleMessage(Message msg) {
        boolean rescheduled = false;
        try {
            long started = SystemClock.uptimeMillis();
            //死循环,从消息队列取出消息逐一处理
            while (true) {
                //获取队首
                PendingPost pendingPost = queue.poll();
                /*如果队列为空*/
                if (pendingPost == null) {
                    synchronized (this) {
                        // Check again, this time in synchronized
                        pendingPost = queue.poll();
                        //如果队里中没有消息需要处理,设置标志位,然后直接返回,退出循环
                        if (pendingPost == null) {
                            handlerActive = false;
                            return;
                        }
                    }
                }
                /*运用反射调用事件处理方法*/ 
                eventBus.invokeSubscriber(pendingPost);
                long timeInMethod = SystemClock.uptimeMillis() - started;
                if (timeInMethod >= maxMillisInsideHandleMessage) {
                    if (!sendMessage(obtainMessage())) {
                        throw new EventBusException("Could not send handler message");
                    }
                    rescheduled = true;
                    return;
                }
            }
        } finally {
            handlerActive = rescheduled;
        }
    }

两次判断pendingPost是否为空是处理多线程的同步问题,这里与单例模式是同样的道理。调用eventBus.invokeSubscriber处理事件,while循环超过10ms之后会退出handleMessage方法,并将handleActive置位true,并再次发送消息,使得该handler再次调用handleMessage()方法,继续处理队列中的注册信息,这是为了避免队列过长时,while循环阻塞主线程造成卡顿。

EventBus#invokeSubscriber 方法:

void invokeSubscriber(PendingPost pendingPost) {
        Object event = pendingPost.event;
        Subscription subscription = pendingPost.subscription;
        PendingPost.releasePendingPost(pendingPost);
        if (subscription.active) {
            invokeSubscriber(subscription, event);
        }
    }

释放pendingPost,判断subscription.active是否有true,默认为true,只有在unregister中设置为false,接着调用 invokeSubscriber(subscription, event)反射执行订阅者的订阅方法。到此分发完毕。
判断subscription.active的原因注释有说,大概意思说,事件可能会在订阅方法未注册之后传递。

PendingPostQueue消息队列

final class PendingPostQueue {
    private PendingPost head;
    private PendingPost tail;

    //入队列
    synchronized void enqueue(PendingPost pendingPost) {
         //良好编程习惯,入口参数检查
        if (pendingPost == null) {
            throw new NullPointerException("null cannot be enqueued");
        }
        if (tail != null) {
            tail.next = pendingPost;
            tail = pendingPost;
        } else if (head == null) {
            head = tail = pendingPost;
        } else {
            throw new IllegalStateException("Head present, but no tail");
        }
        notifyAll();
    }

    synchronized PendingPost poll() {
        PendingPost pendingPost = head;
        if (head != null) {
            head = head.next;
            if (head == null) {
                tail = null;
            }
        }
        return pendingPost;
    }

    //如果队列为空,挂起当前线程,直到有新的数据加入队列(入队列操作后调用了notifyall() )
    synchronized PendingPost poll(int maxMillisToWait) throws InterruptedException {
        if (head == null) {
            wait(maxMillisToWait);
        }
        return poll();
    }

}

队列是以链表的形式连接,从尾部加入,头部弹出。

  1. wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。
  2. 调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对象的monitor(即锁)。
  3. 调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程, 如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程.。
  4. 调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程。

  5. 调用某个对象的wait()方法,当前线程必须拥有这个对象的monitor(即锁), 因此调用wait()方法必须在同步块或者同步方法中进行(synchronized块或者synchronized方法) ,调用某个对象的wait()方法,相当于让当前线程交出此对象的monitor,然后进入等待状态, 等待后续再次获得此对象的锁(Thread类中的sleep方法使当前线程暂停执行一段时间,从而让其他线程有机会继续执行,但它并不释放对象锁)。

  6. notify()方法能够唤醒一个正在等待该对象的monitor的线程,当有多个线程都在等待该对象的monitor的话, 则只能唤醒其中一个线程,具体唤醒哪个线程则不得而知。同样地,调用某个对象的notify()方法,当前线程也必须拥有这个对象的monitor, 因此调用notify()方法必须在同步块或者同步方法中进行(synchronized块或者synchronized方法)。
  7. nofityAll()方法能够唤醒所有正在等待该对象的monitor的线程,这一点与notify()方法是不同的。
    这里要注意一点:notify()和notifyAll()方法只是唤醒等待该对象的monitor的线程,并不决定哪个线程能够获取到monitor。 一个线程被唤醒不代表立即获取了对象的monitor,只有等调用完notify()或者notifyAll()并退出synchronized块, 释放对象锁后,其余线程才可获得锁执行。

PendingPost类:封装了event事件和Subscription(订阅者和订阅方法)

final class PendingPost {
    private final static List pendingPostPool = new ArrayList();

    Object event;
    Subscription subscription;
    PendingPost next;

    private PendingPost(Object event, Subscription subscription) {
        this.event = event;
        this.subscription = subscription;
    }

    static PendingPost obtainPendingPost(Subscription subscription, Object event) {
        synchronized (pendingPostPool) {
            int size = pendingPostPool.size();
            //如果对象池保存的有备胎对象,就用备胎对象,节省一次new对象
            if (size > 0) {
                PendingPost pendingPost = pendingPostPool.remove(size - 1);
                pendingPost.event = event;
                pendingPost.subscription = subscription;
                pendingPost.next = null;
                return pendingPost;
            }
        }
        return new PendingPost(event, subscription);
    }

    static void releasePendingPost(PendingPost pendingPost) {
        pendingPost.event = null;
        pendingPost.subscription = null;
        pendingPost.next = null;
        synchronized (pendingPostPool) {
            // Don't let the pool grow indefinitely
            if (pendingPostPool.size() < 10000) {
                pendingPostPool.add(pendingPost);
            }
        }
    }

}

BackgroundPoster

订阅事件在子线程执行,两种情况:

  • 如果在子线程中Post(发送)Event事件,那么该模式的订阅事件也在当前子线程执行。
  • 如果在主线程中Post(发送)Event事件,那么EventBus会给该模式的订阅事件创建一个独立的子线程来执行订阅方法。
private final BackgroundPoster backgroundPoster;
backgroundPoster = new BackgroundPoster(this);
final class BackgroundPoster implements Runnable, Poster {

    private final PendingPostQueue queue;
    private final EventBus eventBus;

    //标志位,是否正在执行事件处理方法,防止重复执行
    private volatile boolean executorRunning;

    BackgroundPoster(EventBus eventBus) {
        this.eventBus = eventBus;
        queue = new PendingPostQueue();
    }

    public void enqueue(Subscription subscription, Object event) {
    //订阅者和消息封装后进队列
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);
            if (!executorRunning) {
                executorRunning = true;
                eventBus.getExecutorService().execute(this);
            }
        }
    }

    @Override
    public void run() {
        try {
            try {
                while (true) {
                    PendingPost pendingPost = queue.poll(1000);
                    if (pendingPost == null) {
                        synchronized (this) {
                            // Check again, this time in synchronized
                            pendingPost = queue.poll();
                            if (pendingPost == null) {
                                executorRunning = false;
                                return;
                            }
                        }
                    }
                    eventBus.invokeSubscriber(pendingPost);
                }
            } catch (InterruptedException e) {
                eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
            }
        } finally {
            executorRunning = false;
        }
    }

}

首先BackgroundPoster是实现Runnable接口,是一个可执行的任务,而mainThreadPoster是继承Handler进行事件分发。不过代码实现相识。
eventBus.getExecutorService().execute(this),进队列后判断此线程是否在执行,如果没有在执行就执行此线程(调用run方法),是通过线程池来执行Runable接口。

@Override
    public void run() {
        try {
            try {
                while (true) {
                    PendingPost pendingPost = queue.poll(1000);
                    if (pendingPost == null) {
                        synchronized (this) {
                            // Check again, this time in synchronized
                            pendingPost = queue.poll();
                            if (pendingPost == null) {
                                executorRunning = false;
                                return;
                            }
                        }
                    }
                    eventBus.invokeSubscriber(pendingPost);
                }
            } catch (InterruptedException e) {
                eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
            }
        } finally {
            executorRunning = false;
        }
    }

执行流程与HandlerPoster相似,不过在取事件时,有一个等待时间,即queue.poll(1000),这里有一个等待过程,即从队列中取PendingPost对象时,如果没有PendingPost会等待1000毫秒。BackgroundPoster会将1000毫秒以内入队的事件消息在同一个线程中调用,这一点也是与AsyncPoster最重要的区别。

AsyncPoster

不管发布者处在主线程与否,为每一个事件单独开辟一个线程处理。
EventBus有专门的线程池对子线程进行管理,但仍然要避免同一时间开启太多的ASYNC模式线程。

private final AsyncPoster asyncPoster;
 asyncPoster = new AsyncPoster(this);
class AsyncPoster implements Runnable, Poster {

    private final PendingPostQueue queue;
    private final EventBus eventBus;

    AsyncPoster(EventBus eventBus) {
        this.eventBus = eventBus;
        queue = new PendingPostQueue();
    }

    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        queue.enqueue(pendingPost);
        eventBus.getExecutorService().execute(this);
    }

    @Override
    public void run() {
        //为每一个事件单独开一个线程,因此不需要判断线程是否在执行,也不需要循环遍历
        PendingPost pendingPost = queue.poll();
        if(pendingPost == null) {
            throw new IllegalStateException("No pending post available");
        }
        eventBus.invokeSubscriber(pendingPost);
    }

}

AsyncPoster同样是实现Runnable接口,这里注意enqueue是同步的方法,不用担心同步问题,然后调用线程池的线程执行该Runnable,run方法的逻辑就是取出队列的pendingPost, 并执行invokeSubscriber方法,由于是入队一次调用一次execute方法,所以正常情况下队列中不会取不出pendingPost, 也不会剩余pendingPost。
前面也提到过BackgroundPoster设定一个时间上限,并且在该段时间内post过来的事件入队的订阅方法会在同一个线程中调用,而AsyncPoster则是完全异步的调用。也就是说BackgroundPoster会尽可能在同一线程中调用订阅方法,并且有一定的先后顺序,而AsyncPoster对订阅方法的调用则是完全异步,不确定在哪个线程,也不确定顺序。

总结

  1. 总结起来只是三个不同的Poster, HandlerPoster是继承自Handler, 通过handler机制可以将线程调度分派给主线程,而BackgroundPoster和AsyncPoster则是继承自Runnable,覆写run方法定义调用注册方法的任务,并有线程池负责调度启动该任务,进而完成对注册方法的调用。
  2. 从整个EventBus可以看出,事件是被观察者,订阅者类是观察者,当事件出现或者发送变更的时候,会通过EventBus通知观察者,使得观察者的订阅方法能够被自动调用。
  3. 线程调度
    1)POSTING:这种模式就是eventBus默认的模式,但是这种只能在同一个线程中接收,避免了线程切换操作,该模式运行效率最快。也就是说,如果是在主线程中发布消息就只能在主线程中接收消息,如果是在子线程中,那么也只能在相同的子线程中去接收消息。
    2)MAIN:这种模式保证了订阅者指定的那个接收方法在主线程中执行,通常该模式的发布事件都是在子线程中运行,然后主线程中订阅事件去响应UI。
    3)BACKGROUND:如果发布者是在主线程发布消息,订阅事件创建一个独立的子线程来执行订阅方法。如果发布者是在子线程发布消息,订阅事件也在当前子线程执行。
    4)ASYNC:这种模式是无论你在那个线程中发布消息都会在不同的线程中接受消息。发布者在主线程发布,订阅事件随机开辟子线程。如果发布者在子线程发布,订阅事件在另一条线程中。

你可能感兴趣的:(Android)