美文网首页
EventBus无法连续发送粘性事件问题改造日记

EventBus无法连续发送粘性事件问题改造日记

作者: SeptemberWei | 来源:发表于2019-08-26 13:55 被阅读0次

在EventBus中可以使用粘性事件功能在目标注册之前进行发送消息,这样在目标注册后可以接受之前发送的消息,但是存在一个问题,那就是如果之前连续发送好多消息,那只能接收到最后一个粘性事件的消息。
现在项目遇到一个问题就是需要在新的页面打开之前就发送许多消息出去,在新打开的页面需要连续接受,因此这里做了个简易版本的改造来完成需求。具体代码如下所示,其中涉及到的相关类在之前的文章 《EventBus撸代码》 https://www.jianshu.com/p/4ba245331cd7 中有提及,在此记录下笔记。

/**
 * @param <T>参数
 * @param <C>注册类s
 * @author wilson
 * @since 2019年8月26日10:33:06
 */
public class MessageQueen<T, C> {
    private ConcurrentLinkedQueue<T> linkedQueue;
    private Handler handler;
    private ExecutorService cacheExecutorService;
    private HashMap<C, List<SubscribleMethod>> methodCache;
    private boolean isRegist;

    private MessageQueen() {
        methodCache = new HashMap<>();
        linkedQueue = new ConcurrentLinkedQueue<>();
        handler = new Handler();
        cacheExecutorService = Executors.newCachedThreadPool();
    }

    private final static class Create {
        private static final MessageQueen instance = new MessageQueen();
    }

    public static MessageQueen getDefault() {
        return MessageQueen.Create.instance;
    }


    public void post(T bean) {
        if (isRegist) {
            postPriv(bean);
        } else {
            if (linkedQueue != null) {
                linkedQueue.offer(bean);
            }
        }
    }

    public void regist(C clz) {
        synchronized (MessageQueen.class) {
            isRegist = true;
            List<SubscribleMethod> list = methodCache.get(clz);
            if (list == null) {
                list = findSubscribleMethods(clz);
                methodCache.put(clz, list);
            }
        }

        List<SubscribleMethod> subscribleMethods = findSubscribleMethods(clz);
        if (subscribleMethods != null && linkedQueue.size() > 0) {
            while (linkedQueue.size() > 0) {
                for (SubscribleMethod method : subscribleMethods) {
                    T poll = linkedQueue.poll();
                    if (poll != null) {
                        postThread(clz, method, (T) poll);
                    }
                }
            }
        }
    }

    private void postThread(C clz, SubscribleMethod method, T poll) {
        if (method.getParam().isAssignableFrom(poll.getClass())) {
            switch (method.getmThreadModel()) {
                case MAIN:
                    if (Looper.myLooper() == Looper.getMainLooper()) {
                        invoke(method, clz, poll);
                    } else {
                        handler.post(() -> invoke(method, clz, poll));
                    }
                    break;
                case BACKGROUND:
                    cacheExecutorService.execute(() -> invoke(method, clz, poll));
                    break;
            }
        }
    }


    public void unregist() {
        linkedQueue.clear();
    }

    private void invoke(SubscribleMethod subscribleMethod, C obj, T param) {
        Method method1 = subscribleMethod.getmMethod();
        try {
            method1.invoke(obj, param);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    private List<SubscribleMethod> findSubscribleMethods(Object object) {
        List<SubscribleMethod> list = new ArrayList<>();
        Class<?> claz = object.getClass();
        Method[] declaredMethods = claz.getDeclaredMethods();
        while (claz != null) {
            String name = claz.getName();
            if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
                break;
            }
            for (Method method : declaredMethods) {
                Subscribe annotation = method.getAnnotation(Subscribe.class);

                if (annotation != null) {
                    Class<?>[] parameterTypes = method.getParameterTypes();
                    if (parameterTypes.length != 1) {
                        Log.e("wilson", "只能处理一个参数");
                    }
                    ThreadModel threadModel = annotation.threadMode();

                    SubscribleMethod subscribleMethod = new SubscribleMethod(method, threadModel, parameterTypes[0]);

                    list.add(subscribleMethod);
                }
            }
            claz = claz.getSuperclass();
        }

        return list;
    }

    private void postPriv(final T param) {
        Set<C> set = methodCache.keySet();
        Iterator<C> iterator = set.iterator();
        while (iterator.hasNext()) {
            final C obj = iterator.next();
            List<SubscribleMethod> list = methodCache.get(obj);
            for (final SubscribleMethod method : list) {
                postThread(obj, method, param);
            }
        }
    }

}

相关文章

  • EventBus无法连续发送粘性事件问题改造日记

    在EventBus中可以使用粘性事件功能在目标注册之前进行发送消息,这样在目标注册后可以接受之前发送的消息,但是存...

  • Android EventBus粘性事件实现机制探究

    Android EventBus粘性事件实现机制探究 众所周知,eventbus是支持粘性事件的,即可以先发送粘性...

  • EventBus 3.X源码分析

    前言 本文会通过阅读 EventBus 源码的方式分析订阅者注册、反注册、事件发送、粘性事件发送的过程。 依赖 基...

  • 手把手debug源码之EventBus

    本文基于EventBus3.1.1进行源码分析,以发送一个正常事件和粘性事件为例,探索EventBus工作的整个过...

  • EventBus3.0源码分析

    本文分为以下几个部分:创建、注册、发送事件、粘性事件来讲解它的实现原理,本文使用Eventbus版本为3.1.1。...

  • EventBus源码分析

    问题 使用限制 事件发送以及接收原理 设计模式 分析 EventBus#getDefault() EventBus...

  • EventBus源码分析(二)——粘性事件

    前言 在EventBus源码分析(一)中我们介绍了事件的注册、发送与反注册,本文的粘性事件是基于上篇文章,不同于一...

  • EventBus 3.1.1 源码解析

    本文要解决的问题 什么是粘性事件?如何实现的? 存储粘性事件 通过源码得知当粘性事件发送之后就会被存储到stick...

  • EventBus框架初解

    EventBus其实解决了这样几个问题:保存订阅者、发布事件、切换线程、粘性事件 保存订阅者 在register(...

  • EventBus全解析系列(五)

    EventBus 源代码分析-你不知道的EventBus小环节 1.STICKY 粘性事件 在EventBus中有...

网友评论

      本文标题:EventBus无法连续发送粘性事件问题改造日记

      本文链接:https://www.haomeiwen.com/subject/mdbrectx.html