天天看點

EventBus的使用及 解決異常 has no public methods called

平時一直使用EventBus這個元件,真的挺好用的,最近使用的時候偶爾出現錯誤就找了一下資料。

以下内容為轉載,記錄下來以後記不清楚了可以再回顧一下

EvenBus簡化了應用程式内各元件間、元件與背景線程間的通信。比如請求網絡,等網絡傳回時通過Handler或Broadcast通知UI,兩個Fragment之間需要通過Listener通信,這些需求都可以通過EventBus實作。它的效果和Handler的效果大緻相同,但是實作原理和使用方法是完全不同的,它是基于儲存相應方法,然後通過反射機制來實作的。更多的使用和原理,請參考:[Android EventBus實戰](http://blog.csdn.net/jdsjlzx/article/details/40856535) 和[EventBus使用詳解(二)——EventBus使用進階](http://blog.csdn.net/harvic880925/article/details/40787203) ,他們會教會你怎樣去使用EventBus,網上還有更多的教程,可以去搜尋學習。

它是一個開源架構,可以在github上下載下傳到:

https://github.com/greenrobot/EventBus

下載下傳來後它的目錄結構如下:

EventBus的使用及 解決異常 has no public methods called

我們要使用EventBus隻需将EventBus這個檔案夾拷貝到我們的項目中,這樣在我們的工程中就會出現兩個包:

EventBus的使用及 解決異常 has no public methods called

最後是我在第一次使用時出現的一個異常,或許初學者也會遇到的異常:

Subscriber ****has no public methods called

我們分析下為什麼?

我這裡先給出原因,個那些急忙解決的人:是因為在我們的類裡使用了EventBus.getDefualt().register(this)了,但是在這個類裡卻沒有定義一個以onEvent開頭的、非靜态的、public權限以及僅僅隻有一個參數 的方法,也就是沒有類似于:public void onEvent**(Object arg)這樣的方法,導緻出現了這個錯誤。

想要徹底知道為什麼,請先檢視EventBus的實作原理: Android EventBus源碼解析 帶你深入了解EventBus(http://blog.csdn.net/lmj623565791/article/details/40920453) 。

看完了這篇文章,你将會知道EventBus的實作原理,那麼我們就再來看看這個異常發生的原因:

在de.greenrobot.event.SubscriberMethodFinder類裡findSubscriberMethods()的方法,是在調用EventBus.getDefualt().register(this)後,經過層層調用,最後會調用到這個方法,

看源碼:

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
    ...
    //擷取clazz這個類的所有方法
     Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                String methodName = method.getName();
                if (methodName.startsWith(ON_EVENT_METHOD_NAME)) {
                    int modifiers = method.getModifiers();
                    //public的非靜态的方法
                    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();
        }
        //到此為查找目标對象(regiter(this)的this對象)中 onEvent開頭的、非靜态的、public權限以及僅僅隻有一個參數 的方法,然後将這些方法放入到subscriberMethods中
  if (subscriberMethods.isEmpty()) {
            throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called "
                    + ON_EVENT_METHOD_NAME);
        }
       //看到沒有,這就是這個異常抛出的地方,就是判斷subscriberMethods如果是null,就抛出這個異常。
....
}
           

好了,這個異常我們就分析到此,希望童鞋們能夠很好的查找錯誤,分析錯誤,更好的去避免。通過源碼是一個很好的方時。