EventBus 3.0 正确使用、原理讲解以及手写实现

子曰:温故而知新,可以为师矣。 《论语》-- 孔子



一、常规的事件传递

  • Intent 意图: 跳转 + 传参 (局限性非常大)。
  • Handler:通常用来更新主线程 UI,使用不当容易出现内存泄漏。
  • Interface 接口:仅限于同一线程中数据交互。
  • BroadCastReceiver:有序广播 + 无序广播。 onReceive() 方法不能超过 10 秒。
  • AIDL 跨进程通信:代码阅读性不友好,维护成本偏高。
  • 其他方式:本地存储…


二、EventBus 正确使用

1. 概念
  • 一个 Android 优化的 publish / subscribe 消息事件总线。简化了应用程序内各个组件间,组件与后台线程间的通信。
2. 使用场景。
  • 网络请求,返回时通过 Handler 或者 BroadCastReceiver 通知更新主线程 UI;多个 Fragment 之间需要通过 Listener(监听)通信。这些需求都可以通过 EventBus 完成和实现。
3. 官方架构图

在这里插入图片描述

4. 正确使用
1)导包
// app 目录下的 build.gradle 文件 defaultConfig 节点下加入 
//给注解处理器传参
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [ eventBusIndex : 'com.kww.eventbusdemo.MyEventBusIndex' ]
            }
        }

 // dependencies 节点下
 implementation 'org.greenrobot:eventbus:3.2.0'
 annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.2.0'
2)注册,反注册,订阅事件
public class BaseApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
    }
}
public class SendMessageEvent {
    private String message;

    public SendMessageEvent(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
// MainActivity
public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity >>>>";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        EventBus.getDefault().register(this);

        findViewById(R.id.btn_jump).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this,SecondActivity.class));
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(EventBus.getDefault().isRegistered(this)){
            EventBus.getDefault().unregister(this);
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void receiveMessage(SendMessageEvent event){
        Log.e(TAG,event.getMessage());
    }
}
3)发送事件
public class SecondActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        findViewById(R.id.btn_send_message).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().post(new SendMessageEvent("Hello"));
            }
        });
    }
}
4)运行程序,查看 Log 日志:
com.kww.eventbusdemo E/MainActivity >>>>: Hello
5)EventBus 的四种 ThreadMode
  • POSTING(默认):如果使用事件处理函数指定了线程模型为 POSTING,那么该事件在哪个线程发布出来的,事件处理函数就会在这个线程中运行,也就是说 发布事件和接收事件在同一个线程。在线程模型为 POSTING 的事件处理函数中尽量避免执行耗时操作,因为它会阻塞事件的传递,甚至有可能会引起 ANR
  • MAIN:事件的处理会在 UI 线程中执行。事件处理时间不能太长,否则可能会导致ANR
  • BACKGROUND:如果事件是在 UI 线程中发布出来的,那么该事件处理函数就会在新的线程中运行,如果事件本来就是子线程中发布出来的,那么该事件处理函数直接在发布事件的线程中执行。在此事件处理函数中禁止进行 UI 更新操作。
  • ASYNC:无论事件在哪个线程发布,该事件处理函数都会在新建的 子线程 中执行,同样,此事件处理函数中禁止进行 UI 更新操作。
6)粘性事件
// MainActivity 类
findViewById(R.id.btn_jump).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 发送粘性事件
                EventBus.getDefault().postSticky(new SendMessageEvent("粘性事件"));
                startActivity(new Intent(MainActivity.this,SecondActivity.class));
            }
        });

public class SecondActivity extends AppCompatActivity {

    private static final String TAG = "SecondActivity >>>>";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        EventBus.getDefault().register(this);


    @Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
    public void receiveMessageStick(SendMessageEvent event){
        Log.e(TAG,event.getMessage());
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(EventBus.getDefault().isRegistered(this)){
            EventBus.getDefault().unregister(this);
        }
    }
}

这就类似于列表与详情页的关系,我们的 MainActivity 就是列表页,我们发送了一个粘性事件,相当于我们点击某一个 item,将当前 itemid 传递给 详情页去请求接口,那么我们在 SecondActivity ,也就是 详情页,先收到粘性事件的 id,然后跳转到详情页面上。


7)添加混淆
-keepattributes *Annotation*
-keepclassmembers class * {
    @org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
 
# And if you use AsyncExecutor:
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
    <init>(java.lang.Throwable);
}

以上就是 EventBus 3.0 之后的正确使用,可能有的人和我用的不太一样,其实上面这中写法才是正确的写法,具体的可以看官方文档:EventBus 注解处理器使用 以及GitHub传送门



三、EventBus 3.0 之前源码理解

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

在这行代码中, EventBus.getDefault() 方法获取的是 EventBus 对象,很明显这是一个单例模式,采用了双重检查模式 (DCL):

 /** Convenience singleton for apps using a process-wide EventBus instance. */
    public static EventBus getDefault() {
        EventBus instance = defaultInstance;
        if (instance == null) {
            synchronized (EventBus.class) {
                instance = EventBus.defaultInstance;
                if (instance == null) {
                    instance = EventBus.defaultInstance = new EventBus();
                }
            }
        }
        return instance;
    }

我们看到 register() 方法的源码:

 public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        // 用 subscriberMethodFinder 提供的方法,找到在 subscriber 这个类里面订阅的内容。
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

在这个方法中,它首先要拿到 List<SubscriberMethod> 这个集合,也就是传进来的订阅者所有的订阅的方法,接下来遍历订阅者的订阅方法来完成订阅者的订阅操作。对于SubscriberMethod(订阅方法)类中,主要就是用保存订阅方法的 Method 对象、线程模式、事件类型、优先级、是否是粘性事件等属性。

public class SubscriberMethod {
    final Method method;
    final ThreadMode threadMode;
    final Class<?> eventType;
    final int priority;
    final boolean sticky;
    /** Used for efficient comparison */
    String methodString;
    //......
}

好的,我们进入这个 findSubscriberMethods() 方法,看一下是如何拿到订阅者所有方法的:

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
       //从缓存中获取SubscriberMethod集合
       List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
       if (subscriberMethods != null) {
           return subscriberMethods;
       }
       //ignoreGeneratedIndex属性表示是否忽略注解器生成的MyEventBusIndex
       if (ignoreGeneratedIndex) {
        //通过反射获取subscriberMethods
           subscriberMethods = findUsingReflection(subscriberClass);
       } else {
           subscriberMethods = findUsingInfo(subscriberClass);
       }
       //在获得subscriberMethods以后,如果订阅者中不存在@Subscribe注解并且为public的订阅方法,则会抛出异常。
       if (subscriberMethods.isEmpty()) {
           throw new EventBusException("Subscriber " + subscriberClass
                   + " and its super classes have no public methods with the @Subscribe annotation");
       } else {
           METHOD_CACHE.put(subscriberClass, subscriberMethods);
           return subscriberMethods;
       }
   }

首先从缓存中查找,如果找到了就立马返回。如果缓存中没有的话,则根据ignoreGeneratedIndex 选择如何查找订阅方法,该属性默认就是false,它可以通过内部构建者类 EventBusBuilder 设置,表示是否忽略注解器生成的 MyEventBusIndex,这个就是采用我上面所写的使用方式后,在编译期 EventBus 就会自动帮我生成 MyEventBusIndex 文件。最后,找到订阅方法后,放入缓存,以免下次继续查找。

至于 findUsingReflection() 方法 和 findUsingReflection() 方法就不细说了,就是通过反射来获取订阅者中所有的方法。并依据方法的类型,参数和注解来找到根据 EventBus 指定的规则所写的订阅方法。

在查找完所有的订阅方法以后便开始对所有的订阅方法进行注册:

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class<?> eventType = subscriberMethod.eventType;
          //根据订阅者和订阅方法构造一个订阅事件
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
          //获取当前订阅事件中Subscription的List集合
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
         //该事件对应的Subscription的List集合不存在,则重新创建并保存在subscriptionsByEventType中
        if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
        //订阅者已经注册则抛出EventBusException
            if (subscriptions.contains(newSubscription)) {
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                        + eventType);
            }
        }
        //遍历订阅事件,找到比subscriptions中订阅事件小的位置,然后插进去
        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中
        subscribedEvents.add(eventType);
        if (subscriberMethod.sticky) {
            if (eventInheritance) {
            //粘性事件的处理
                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);
            }
        }
    }

这段源码做了两件事,其一就是将 订阅方法订阅者 封装到subscriptionsByEventTypetypesBySubscriber ,其二就是如果是粘性事件的话,就立马投递、执行。

  • subscriptionsByEventType:当我们 post 时,根据 EventType 找到订阅事件,从而去分发事件,处理事件的。
  • typesBySubscriber:调用 unregister(this) 的时候,根据订阅者找到 EventType,又根据 EventType 找到订阅事件,从而对订阅者进行解绑。

用一张图来总结一下 register
在这里插入图片描述


2. EventBus.getDefault().post(new SendMessageEvent("Hello"));

现在来说一下 post发送。


    /** Posts the given event to the event bus. */
    public void post(Object event) {
        //PostingThreadState保存着事件队列和线程状态信息
        PostingThreadState postingState = currentPostingThreadState.get();
        //获取事件队列,并将当前事插入到事件队列中
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);

        if (!postingState.isPosting) {
            postingState.isMainThread = isMainThread();
            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;
            }
        }
    }

首先从 PostingThreadState 对象中取出事件队列,然后再将当前的事件插入到事件队列当中。最后将队列中的事件依次交由 postSingleEvent 方法进行处理,并移除该事件。来看看 postSingleEvent()方法里做了什么:

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
       Class<?> eventClass = event.getClass();
       boolean subscriptionFound = false;
       //eventInheritance表示是否向上查找事件的父类,默认为true
       if (eventInheritance) {
          //通过lookupAllEventTypes找到所有的父类事件并存在List中,然后通过postSingleEventForEventType方法对事件逐一处理
           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));
           }
       }
   }

接下来看看 postSingleEventForEventType方法:

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
      CopyOnWriteArrayList<Subscription> subscriptions;
         //取出该事件对应的Subscription集合
      synchronized (this) {
          subscriptions = subscriptionsByEventType.get(eventClass);
      }
      if (subscriptions != null && !subscriptions.isEmpty()) {
      //将该事件的event和对应的Subscription中的信息(包扩订阅者类和订阅方法)传递给postingState
          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;
  }

接下来看看 postToSubscription()方法:

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);
    }
}

取出订阅方法的线程模式,之后根据线程模式来分别处理。举个例子,如果线程模式是 MAIN,提交事件的线程是主线程的话则通过反射,直接运行订阅的方法,如果不是主线程,我们需要 mainThreadPoster 将我们的订阅事件入队列,mainThreadPosterHandlerPoster 类型的继承自Handler,通过Handler 将订阅方法切换到主线程执行。

下面用一张图来说明一下 post 流程:
在这里插入图片描述

3. EventBus.getDefault().unregister(this);

我们最后说一下解绑过程

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());
    }
}

typesBySubscriber 就是在订阅者注册的过程中讲到过这个属性,它根据订阅者找到 EventType,然后根据 EventType 和订阅者来得到订阅事件来对订阅者进行解绑。



四、手写 EventBus

// Subscribe 类
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Subscribe {

    ThreadMode threadMode() default ThreadMode.POSTING;
}
/**
 * 线程状态
 */
public enum ThreadMode {

    // 事件的处理在和事件的发送在相同的进程,所以事件处理时间不应太长,不然影响事件的发送线程,而这个线程可能是UI线程
    POSTING,

    // 事件的处理会在UI线程中执行,事件处理不应太长时间
    MAIN,

    // 后台进程,处理如保存到数据库等操作
    BACKGROUND,

    // 异步执行,另起线程操作。事件处理会在单独的线程中执行,主要用于在后台线程中执行耗时操作
    ASYNC
}
/**
 * 保存符合要求的订阅方法封装类
 */
public class MethodManager {

    // 订阅者的回调方法(注解方法)的参数类型
    private Class<?> type;

    // 订阅者的回调方法(注解方法)的线程模式
    private ThreadMode threadMode;

    // 订阅者的回调方法(注解方法)
    private Method method;

    public MethodManager(Class<?> type, ThreadMode threadMode, Method method) {
        this.type = type;
        this.threadMode = threadMode;
        this.method = method;
    }

    public Class<?> getType() {
        return type;
    }

    public void setType(Class<?> type) {
        this.type = type;
    }

    public ThreadMode getThreadMode() {
        return threadMode;
    }

    public void setThreadMode(ThreadMode threadMode) {
        this.threadMode = threadMode;
    }

    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }

    @NonNull
    @Override
    public String toString() {
        return "MethodManager{" +
                "type=" + type +
                ", threadMode=" + threadMode +
                ", method=" + method +
                '}';
    }
}

public class EventBus {

    // volatile修饰的变量不允许线程内部缓存和重排序,即直接修改内存
    private static volatile EventBus instance;
    // 用来保存这些带注解的方法(订阅者的回调方法)
    private Map<Object, List<MethodManager>> cacheMap;

    private Handler handler;
    private ExecutorService executorService;

    private EventBus() {
        cacheMap = new HashMap<>();

        // Handler高级用法:将handler放在主线程使用
        handler = new Handler(Looper.getMainLooper());
        // 创建一个子线程(缓存线程池)
        executorService = Executors.newCachedThreadPool();
    }

    public static EventBus getDefault() {
        if (instance == null) {
            synchronized (EventBus.class) {
                if (instance == null) {
                    instance = new EventBus();
                }
            }
        }
        return instance;
    }

    // 找到MainActivity所有带符合注解的方法
    public void register(Object getter) {
        // 获取MainActivity所有的方法
        List<MethodManager> methodList = cacheMap.get(getter);
        if (methodList == null) { // 不为空表示以前注册完成
            methodList = findAnnotationMethod(getter);
            cacheMap.put(getter, methodList);
        }
    }

    // 获取MainActivity中所有注解的方法
    private List<MethodManager> findAnnotationMethod(Object getter) {
        List<MethodManager> methodList = new ArrayList<>();
        // 获取类
        Class<?> clazz = getter.getClass();
        // 获取所有方法
        Method[] methods = clazz.getMethods();

        // 性能优化。N个父类不可能有自定义注解。排除后再反射
        while (clazz != null) {
            // 找出系统类,直接跳出,不添加cacheMap(因为不是订阅者)
            String clazzName = clazz.getName();
            if (clazzName.startsWith("java.") || clazzName.startsWith("javax.")
                    || clazzName.startsWith("android.")) {
                break;
            }

            // 循环方法
            for (Method method : methods) {
                // 获取方法的注解
                Subscribe subscribe = method.getAnnotation(Subscribe.class);
                // 判断注解不为空,切记不能抛异常
                if (subscribe == null) {
                    continue;
                }
                // 严格控制方法格式和规范
                // 方法必须是返回void(一次匹配)
                Type returnType = method.getGenericReturnType();
                if (!"void".equals(returnType.toString())) {
                    throw new RuntimeException(method.getName() + "方法返回必须是void");
                }
                // 方法参数必须有值(二次匹配)
                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length != 1) {
                    throw new RuntimeException(method.getName() + "方法有且只有一个参数");
                }

                // 完全符合要求、规范的方法,保存到方法对象中MethodManager(3个重要成员:方法、参数、线程)
                MethodManager manager = new MethodManager(parameterTypes[0], subscribe.threadMode(), method);
                methodList.add(manager);
            }

            // 不断循环找出父类含有订阅者(注解方法)的类。直到为空,比如AppCompatActivity没有吧
            clazz = clazz.getSuperclass();
        }
        return methodList;
    }

    // SecondActivity发送消息
    public void post(final Object setter) {
        // 订阅者已经登记,从登记表中找出
        Set<Object> set = cacheMap.keySet();
        // 比如获取MainActivity对象
        for (final Object getter : set) {
            // 获取MainActivity中所有注解的方法
            List<MethodManager> methodList = cacheMap.get(getter);
            if (methodList != null) {
                // 循环每个方法
                for (final MethodManager method : methodList) {
                    // 有可能多个方法的参数一样,从而都同时收到发送的消息
                    // 通过EventBean来判断是否匹配上
                    if (method.getType().isAssignableFrom(setter.getClass())) {
                        // 通过方法的类型匹配,从SecondActivity发送的EventBean对象(参数)
                        // 匹配MainActivity中所有注解的方法符合要求的,都发送消息

                        // class1.isAssignableFrom(class2) 判定此 Class 对象所表示的类或接口
                        // 与指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口

                        // 线程调度
                        switch (method.getThreadMode()) {
                            case POSTING:
                                invoke(method, getter, setter);
                                break;

                            case MAIN:
                                // 先判断发送方是否在主线程
                                if (Looper.myLooper() == Looper.getMainLooper()) {
                                    invoke(method, getter, setter);
                                } else { // 子线程 - 主线程,切换线程(用到Handler)
                                    handler.post(new Runnable() {
                                        @Override
                                        public void run() {
                                            invoke(method, getter, setter);
                                        }
                                    });
                                }
                                break;

                            case BACKGROUND:
                                // 先判断发送方是否在主线程
                                if (Looper.myLooper() == Looper.getMainLooper()) {
                                    // 主线程 - 子线程,创建一个子线程(缓存线程池)
                                    executorService.execute(new Runnable() {
                                        @Override
                                        public void run() {
                                            invoke(method, getter, setter);
                                        }
                                    });
                                } else { // 子线程 到 子线程,不用切换线程
                                    invoke(method, getter, setter);
                                }
                                break;
                        }
                    }
                }
            }
        }
    }

    // 找到匹配方法后,通过反射调用MainActivity中所有符合要求的方法
    private void invoke(MethodManager method, Object getter, Object setter) {
        Method execute = method.getMethod();
        try {
            execute.invoke(getter, setter);
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}





写在文末

纸上得来终觉浅,绝知此事要躬行。 《冬夜读书示子聿》-- 陆游

至此,EventBus正确使用原理理解以及 手写实现 就说到这,各位看官食用愉快。


码字不易,如果本篇文章对您哪怕有一点点帮助,请不要吝啬您的点赞,我将持续带来更多优质文章。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值