EventBus基本学习

本文深入解析EventBus的工作原理,包括单例模式的实现、事件注册流程、事件分发机制及不同线程模式的处理方式。通过源码分析帮助读者理解EventBus如何高效地管理事件订阅与发布。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

EventBus:
EventBus.getDefault().register(this);

    源码:
    public static EventBus getDefault() {
    if(defaultInstance == null) {
        Class var0 = EventBus.class;
        synchronized(EventBus.class) {
            if(defaultInstance == null) {
                defaultInstance = new EventBus();
            }
        }
    }

    return defaultInstance;
    }
    getDefault函数是获取对象实例,采用线程安全的单例。
    注册register函数源码:
    public void register(Object subscriber) {
        this.register(subscriber, false, 0);
    }

    *****我们使用时一般注入的是一个this。

    继续查看 register(Object subscriber, boolean sticky, int priority)函数
private synchronized void register(Object subscriber, boolean sticky, int priority) {
    List subscriberMethods = this.subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
    Iterator i$ = subscriberMethods.iterator();

    while(i$.hasNext()) {
        SubscriberMethod subscriberMethod = (SubscriberMethod)i$.next();
        this.subscribe(subscriber, subscriberMethod, sticky, priority);
    }

}
注意:
List subscriberMethods = this.subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());该行代码使用反射技术注入类的信息

subscriberMethodFinder从名称看是订阅者的方法发现类,对象实例于EventBus构造函数中获得。
如下:
EventBus(EventBusBuilder builder) {
    this.currentPostingThreadState = new ThreadLocal() {
        protected EventBus.PostingThreadState initialValue() {
            return new EventBus.PostingThreadState();
        }
    };
    this.subscriptionsByEventType = new HashMap();
    this.typesBySubscriber = new HashMap();
    this.stickyEvents = new ConcurrentHashMap();
    this.mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
    this.backgroundPoster = new BackgroundPoster(this);
    this.asyncPoster = new AsyncPoster(this);
    this.subscriberMethodFinder = new SubscriberMethodFinder(builder.skipMethodVerificationForClasses);
    this.logSubscriberExceptions = builder.logSubscriberExceptions;
    this.logNoSubscriberMessages = builder.logNoSubscriberMessages;
    this.sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
    this.sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
    this.throwSubscriberException = builder.throwSubscriberException;
    this.eventInheritance = builder.eventInheritance;
    this.executorService = builder.executorService;
}

findSubscriberMethods(Param)源码:

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
    String key = subscriberClass.getName();
    List<SubscriberMethod> subscriberMethods;
    synchronized (methodCache) {
        subscriberMethods = methodCache.get(key);
    }
    if (subscriberMethods != null) {
        return subscriberMethods;
    }
    subscriberMethods = new ArrayList<SubscriberMethod>();
    Class<?> clazz = subscriberClass;
    HashSet<String> eventTypesFound = new HashSet<String>();
    StringBuilder methodKeyBuilder = new StringBuilder();
    while (clazz != null) {
        String name = clazz.getName();
        if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
            // Skip system classes, this just degrades performance
            break;
        }

        // Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            String methodName = method.getName();
            if (methodName.startsWith(ON_EVENT_METHOD_NAME)) {
                int modifiers = method.getModifiers();
                if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                    Class<?>[] parameterTypes = method.getParameterTypes();
                    if (parameterTypes.length == 1) {
                        String modifierString = methodName.substring(ON_EVENT_METHOD_NAME.length());
                        ThreadMode threadMode;
                        if (modifierString.length() == 0) {
                            threadMode = ThreadMode.PostThread;
                        } else if (modifierString.equals("MainThread")) {
                            threadMode = ThreadMode.MainThread;
                        } else if (modifierString.equals("BackgroundThread")) {
                            threadMode = ThreadMode.BackgroundThread;
                        } else if (modifierString.equals("Async")) {
                            threadMode = ThreadMode.Async;
                        } else {
                            if (skipMethodVerificationForClasses.containsKey(clazz)) {
                                continue;
                            } else {
                                throw new EventBusException("Illegal onEvent method, check for typos: " + method);
                            }
                        }
                        Class<?> eventType = parameterTypes[0];
                        methodKeyBuilder.setLength(0);
                        methodKeyBuilder.append(methodName);
                        methodKeyBuilder.append('>').append(eventType.getName());
                        String methodKey = methodKeyBuilder.toString();
                        if (eventTypesFound.add(methodKey)) {
                            // Only add if not already found in a sub class
                            subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));
                        }
                    }
                } else if (!skipMethodVerificationForClasses.containsKey(clazz)) {
                    Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + clazz + "."
                            + methodName);
                }
            }
        }
        clazz = clazz.getSuperclass();
    }
    if (subscriberMethods.isEmpty()) {
        throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called "
                + ON_EVENT_METHOD_NAME);
    } else {
        synchronized (methodCache) {
            methodCache.put(key, subscriberMethods);
        }
        return subscriberMethods;
    }
}
注入通配型的Class,采用反射技术获取类型类名称(类信息),methodCache是一个用于存下相关类信息的HashMap数据结构,定义如下:
private static final Map<String, List<SubscriberMethod>> methodCache = new HashMap();随后根据类名称到该methodCache去取出值,
取到就结束函数做返回处理。关注点是后面的放射技术的处理。
反射的一个相关博客地址:http://blog.youkuaiyun.com/stevenhu_223/article/details/9286121

Method[] methods = var24.getDeclaredMethods();获取方法,遍历方法名,并且判断函数的修饰权限(public等),接着获取函数参数的对应的class类型,
****Method对象
******getParameterTypes()——返回值为Class<?>:得到目标方法各参数类型对应的Class对象
******getModifiers()——返回值为int:得到目标方法修饰符的值
******getName()——返回值String:得到目标方法的名字
******method.invoke(owner, args):执行该Method.invoke方法的参数是执行这个方法的对象owner,和参数数组args。owner对象中带有参数args的method方法。返回值是Object,也既是该方法的返回值。
按照“onEvent"截取字符串后判断函数所对应的线程,EventBus共有四种函数类型:
public void onEventMainThread(param)   
public void onEventPostThread(param)  
public void onEventBackgroundThread(param)     
public void onEventAsync(param)    
——————————————————————————————————————————————————————————————————————————————
随后添加函数进List集合:
                        if (eventTypesFound.add(methodKey)) {
                            // Only add if not already found in a sub class
                            subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));
                        }
当中的eventTypesFound是一个HashSet,即无序的,只包含KEY的结构,不可以重复添加。    即注释:“// Only add if not already found in a sub class”                   
synchronized (methodCache) {
            methodCache.put(key, subscriberMethods);
}
存进HashMap集合作为缓存数据。
new SubscriberMethod(method, threadMode, eventType) ——
即:
SubscriberMethod(Method method, ThreadMode threadMode, Class<?> eventType) {
    this.method = method;
    this.threadMode = threadMode;
    this.eventType = eventType;
}

线程枚举:
public enum ThreadMode {
/**
用户将被调用在同一个线程中,这是发布事件。这是默认值。事件传递
至少意味着开销,因为它完全避免了线程切换。因此,这是推荐的模式
已知完成的简单任务是一个很短的时间,而不需要主线程。事件处理
使用此模式必须迅速返回,以避免阻塞post线程,这可能是主线程。
PostThread,

/**
 * 用户将被调用在安卓的主线程(有时被称为用户界面线程)。
 */
MainThread,

/**
 将在后台线程中调用订阅服务器。
 如果post线程不是主线程,则将在post线程中直接调用事件处理程序方法。
 如果在线程是主线程,eventbus使用一个后台线程,将提供所有的事件顺序。
 使用此模式的事件处理程序应尽量快速返回,以避免阻塞后台线程。
 */
BackgroundThread,

/**
 *事件处理程序方法被调用在一个单独的线程中。这总是独立于发布线程和
  主线程。发布事件从来不会等待使用这种模式的事件处理程序方法。事件处理程序方法
 *使用此模式,如果他们的执行可能需要一段时间,例如用于网络访问。避免触发大量
 *在同一时间运行长时间运行的异步处理程序方法以限制并发线程的数目。eventbus
 *使用一个线程池来有效地重用已完成的异步事件处理程序通知的线程。
 * /
Async
}

以上为订阅(线程),注册的分析
EventBus.getDefault().post(new CameraSnapShotMsgEvent(true));此代码为发布消息的处理。
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;
        }
    }
}

1、currentPostingThreadState:ThreadLocal<PostingThreadState> 
ThreadLocal:每个线程都有自己的局部变量,独立于变量的初始化副本,ThreadLocal不是用于解决共享变量的问题的,不是为了协调线程同步而存在,
而是为了方便每个线程处理自己的状态(变量)而引入的一个机制:https://my.oschina.net/clopopo/blog/149368。
currentPostingThreadState.get();将会获取到本地线程变量的初始化对象。

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 void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
    switch (subscription.subscriberMethod.threadMode) {
        case PostThread:
            invokeSubscriber(subscription, event);
            break;
        case MainThread:
            if (isMainThread) {
                invokeSubscriber(subscription, event);
            } else {
                mainThreadPoster.enqueue(subscription, event);
            }
            break;
        case BackgroundThread:
            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);
    }
}
反射调用EventBus的四个函数:
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
其中不是同个线程或者非主线程的函数分别由:
private final HandlerPoster mainThreadPoster;
private final BackgroundPoster backgroundPoster;
private final AsyncPoster asyncPoster;
三个对象管理,HandlerPoster继承自Handler。
BackgroundPoster,AsyncPoster实现Runnable接口,当中启用线程池来处理。
Class:EventBusBuilder—— private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
BackgroundPoster中的两个重要函数:
 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) {
            Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
        }
    } finally {
        executorRunning = false;
    }
}

最终都是采用反射调用函数eventBus.invokeSubscriber(pendingPost);
void invokeSubscriber(PendingPost pendingPost) {
    Object event = pendingPost.event;
    Subscription subscription = pendingPost.subscription;
    PendingPost.releasePendingPost(pendingPost);
    if (subscription.active) {
        invokeSubscriber(subscription, event);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值