Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

我使用eventbus传递点击事件,出现了订阅者执行俩次的问题 #46

Open
chengzhijun0706 opened this issue Dec 28, 2016 · 8 comments

Comments

@chengzhijun0706
Copy link

image
传递的参数中的对象有一个字段是list

@chengzhijun0706
Copy link
Author

我打断点看,发送事件的位置只发送了一遍,但是接收事件的位置出现了俩次

@ccclll1990
Copy link

我收到三次。。

@chengzhijun0706
Copy link
Author

@ccclll1990 问题的原因找到了,是fragment的复用引起的,如果fragment要复用就要进行特殊的处理

@creky
Copy link

creky commented Mar 9, 2018

还有种情况,如果传的参数是Map类型,还会执行N次(N>5),看源码是Map继承自多个类的子类,然后符合这些类的响应,自然就执行多次了,解决办法是只传基础类型数据,int,boolean,string及数组类型,或者改源码

@yangkun19921001
Copy link

@creky 我也遇见这个问题了,我直接传递父类的直接子类就解决了这个问题,谢谢了哈。

@xilost
Copy link

xilost commented Dec 29, 2018

@chengzhijun0706 你好,我也是fragment出现的,怎么处理的?

@maruiwhu
Copy link

@chengzhijun0706 你好,我也是fragment出现的,怎么处理的?

如果fragment存在复用的场景需要特殊处理,我是这样处理的,仅供参考(前提时发布事件的时候能够取到订阅的对象)
需要对源码进行改动
为了区分不同的fragment的对象,我想把fragment对象的hash作为tag,进行事件注册。
但是在注解中又只能使用常量。所以想了一个迂回的办法。
1.注解的时候用参数标识这个事件注册的时候需要把对象object的hash加到tag中,
2.在EventBus注册的时候识别这个参数,并把object的hash加到tag中
3.事件发布的时候将fragment对象的hash手动添加到tag中

1.首先Subscriber注解中增加一个方法
/**
*/
boolean registerWithObjectHash() default false;
2.Eventbus注册的时候判断该参数,并注册的时候特殊处理
浏览代码容易找到Eventus注册的方法是在SubsciberMethodHunter. findSubcribeMethods 的方法中,对该方法略作改动

/**
     * 查找订阅对象中的所有订阅函数,订阅函数的参数只能有一个.找到订阅函数之后构建Subscription存储到Map中
     * 
     * @param subscriber 订阅对象
     * @return
     */
    public void findSubcribeMethods(Object subscriber) {
        if (mSubcriberMap == null) {
            throw new NullPointerException("the mSubcriberMap is null. ");
        }
        Class<?> clazz = subscriber.getClass();
        // 查找类中符合要求的注册方法,直到Object类
        while (clazz != null && !isSystemCalss(clazz.getName())) {
            final Method[] allMethods = clazz.getDeclaredMethods();
            for (int i = 0; i < allMethods.length; i++) {
                Method method = allMethods[i];
                // 根据注解来解析函数
                Subscriber annotation = method.getAnnotation(Subscriber.class);
                if (annotation != null) {
                    // 获取方法参数
                    Class<?>[] paramsTypeClass = method.getParameterTypes();
                    // 订阅函数只支持一个参数
                    if (paramsTypeClass != null && paramsTypeClass.length == 1) {
                        Class<?> paramType = convertType(paramsTypeClass[0]);
                        EventType eventType 
                        if(annotation.registerWithObjectHash()){
                        eventType = new EventType(paramType, annotation.tag()+subscriber.toString());   
                        }else{
                         eventType = new EventType(paramType, annotation.tag());
                        }
                        TargetMethod subscribeMethod = new TargetMethod(method, eventType,
                                annotation.mode());
                        subscibe(eventType, subscribeMethod, subscriber);
                    }
                }
            } // end for
              // 获取父类,以继续查找父类中符合要求的方法
            clazz = clazz.getSuperclass();
        }
    }

example:

注册时

class Fragment
...

@Subscriber(tag="testevent",registerWithObjectHash=true)
public void test(String test){
}

发布事件时

post("","testevent"+fragment.toString)

@chengzhijun0706
Copy link
Author

@xilost 我用了一个比较笨的办法,就是在你传递的对象中携带有一个区分页面的字段,在接受的地方判断这个字段的值是否和本页面相等就好了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants