From 2f79b6350a3714544d106a1b2742306ece1bbe42 Mon Sep 17 00:00:00 2001 From: Graeme Sutherland Date: Thu, 24 Jan 2019 15:59:13 +1000 Subject: [PATCH 1/2] Fix for crash on AndroidX Eventbus is crashing when my app is running on a device with an API level below 26 and using the AndroidX libraries. The problem is that a NoClassDefFoundError is being thrown for the TextClassifier that's a parameter in the AppCompatTextView#setTextClassifier() method. The reflection code you use doesn't filter for API level, unfortunately. A quick fix is to add "androidx." to the system classes in the moveToSuperClass() method. You should probably do this for performance reasons in any case. --- .../src/org/greenrobot/eventbus/SubscriberMethodFinder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java index db5e0ad3..421cf465 100644 --- a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java @@ -260,7 +260,8 @@ void moveToSuperclass() { clazz = clazz.getSuperclass(); String clazzName = clazz.getName(); /** Skip system classes, this just degrades performance. */ - if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) { + if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.") + || clazzName.startsWith("androidx.")) { clazz = null; } } From 1f1fff2510644b1073d53c8c15551a7799c1821c Mon Sep 17 00:00:00 2001 From: Graeme Sutherland Date: Fri, 25 Jan 2019 08:38:48 +1000 Subject: [PATCH 2/2] Refinements to the class not found exception fix The EventBus API will crash if it runs into a method that takes a parameter that the app doesn't recognise. Android gets around this using the @TargetAPI annotation, but this requires a minimum API level of 15. The easiest way to fix this is reverse the order of checking the number of parameters a method takes and whether the Subscribe annotation is present. This means the getParameterTypes() call is deferred, and if a system library incorporates something not available on a given API level, it won't find an unknown type. --- .../eventbus/SubscriberMethodFinder.java | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java index 421cf465..05e95b94 100644 --- a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java @@ -160,21 +160,21 @@ private void findUsingReflectionInSingleClass(FindState findState) { for (Method method : methods) { int modifiers = method.getModifiers(); if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { - Class[] parameterTypes = method.getParameterTypes(); - if (parameterTypes.length == 1) { - Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); - if (subscribeAnnotation != null) { + Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); + if (subscribeAnnotation != null) { + Class[] parameterTypes = method.getParameterTypes(); + if (parameterTypes.length == 1) { Class eventType = parameterTypes[0]; if (findState.checkAdd(method, eventType)) { ThreadMode threadMode = subscribeAnnotation.threadMode(); findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, subscribeAnnotation.priority(), subscribeAnnotation.sticky())); } + } else if (strictMethodVerification) { + String methodName = method.getDeclaringClass().getName() + "." + method.getName(); + throw new EventBusException("@Subscribe method " + methodName + + "must have exactly 1 parameter but has " + parameterTypes.length); } - } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { - String methodName = method.getDeclaringClass().getName() + "." + method.getName(); - throw new EventBusException("@Subscribe method " + methodName + - "must have exactly 1 parameter but has " + parameterTypes.length); } } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { String methodName = method.getDeclaringClass().getName() + "." + method.getName(); @@ -258,14 +258,15 @@ void moveToSuperclass() { clazz = null; } else { clazz = clazz.getSuperclass(); - String clazzName = clazz.getName(); - /** Skip system classes, this just degrades performance. */ - if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.") - || clazzName.startsWith("androidx.")) { - clazz = null; + if (clazz != null) { + String clazzName = clazz.getName(); + // Skip system classes, this just degrades performance. + if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") + || clazzName.startsWith("android.") || clazzName.startsWith("androidx.")) { + clazz = null; + } } } } } - }