From 91a7980443696fda25198520e1ce538f2b534798 Mon Sep 17 00:00:00 2001 From: Rick Brock Date: Fri, 14 Nov 2014 15:31:16 -0800 Subject: [PATCH 001/288] Changed method subscription to use Annotations - Removed use of onEvent, onEventThreadName - Added @Subscribe annotation with an optional threadMode arg --- .../de/greenrobot/event/SubscriberMethod.java | 4 +- .../event/SubscriberMethodFinder.java | 56 ++++++++----------- .../event/annotations/Subscribe.java | 18 ++++++ .../eventperf/TestRunnerActivity.java | 4 ++ .../testsubject/PerfTestEventBus.java | 6 ++ .../test/EventBusBackgroundThreadTest.java | 3 + .../event/test/EventBusBasicTest.java | 9 +++ .../event/test/EventBusBuilderTest.java | 4 ++ .../test/EventBusCancelEventDeliveryTest.java | 5 ++ .../event/test/EventBusInheritanceTest.java | 7 +++ .../test/EventBusMainThreadRacingTest.java | 3 + .../event/test/EventBusMainThreadTest.java | 3 + .../test/EventBusMethodModifiersTest.java | 29 ++-------- .../event/test/EventBusMultithreadedTest.java | 10 ++++ .../test/EventBusNoSubscriberEventTest.java | 5 ++ .../EventBusOrderedSubscriptionsTest.java | 5 ++ .../test/EventBusRegistrationRacingTest.java | 3 + .../event/test/EventBusStickyEventTest.java | 5 ++ .../test/EventBusSubscriberExceptionTest.java | 4 ++ .../test/EventBusSubscriberLegalTest.java | 6 ++ 20 files changed, 133 insertions(+), 56 deletions(-) create mode 100644 EventBus/src/de/greenrobot/event/annotations/Subscribe.java diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethod.java b/EventBus/src/de/greenrobot/event/SubscriberMethod.java index 5e0df398..cf13c292 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethod.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethod.java @@ -32,7 +32,9 @@ final class SubscriberMethod { @Override public boolean equals(Object other) { - if (other instanceof SubscriberMethod) { + if (other == this) { + return true; + } else if (other instanceof SubscriberMethod) { checkMethodString(); SubscriberMethod otherSubscriberMethod = (SubscriberMethod)other; otherSubscriberMethod.checkMethodString(); diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 823cb0ec..9caa7b9f 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -16,6 +16,7 @@ package de.greenrobot.event; import android.util.Log; +import de.greenrobot.event.annotations.Subscribe; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -27,11 +28,10 @@ import java.util.concurrent.ConcurrentHashMap; class SubscriberMethodFinder { - private static final String ON_EVENT_METHOD_NAME = "onEvent"; /* * In newer class files, compilers may add methods. Those are called bridge or synthetic methods. - * EventBus must ignore both. There modifiers are not public but defined in the Java class file format: + * EventBus must ignore both. Their modifiers are not public but defined in the Java class file format: * http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6-200-A.1 */ private static final int BRIDGE = 0x40; @@ -75,49 +75,41 @@ List findSubscriberMethods(Class subscriberClass) { Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { String methodName = method.getName(); - if (methodName.startsWith(ON_EVENT_METHOD_NAME)) { + + // Now we find acceptable methods via annotations + if (method.isAnnotationPresent(Subscribe.class)) { + Log.e("EventBus", "Annotation is present for " + methodName); int modifiers = method.getModifiers(); 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); + Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); + if (subscribeAnnotation != null && subscribeAnnotation.threadMode() != null) { + ThreadMode threadMode = subscribeAnnotation.threadMode(); + 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)); } } - 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); } + + } else { + Log.e("EventBus", "Annotation is NOT present for " + methodName); } } + clazz = clazz.getSuperclass(); } if (subscriberMethods.isEmpty()) { - throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called " - + ON_EVENT_METHOD_NAME); + throw new EventBusException("Subscriber " + subscriberClass + + " has no public methods called with the @Subscribe annotation"); } else { synchronized (methodCache) { methodCache.put(key, subscriberMethods); diff --git a/EventBus/src/de/greenrobot/event/annotations/Subscribe.java b/EventBus/src/de/greenrobot/event/annotations/Subscribe.java new file mode 100644 index 00000000..cf8af04c --- /dev/null +++ b/EventBus/src/de/greenrobot/event/annotations/Subscribe.java @@ -0,0 +1,18 @@ +package de.greenrobot.event.annotations; + + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import de.greenrobot.event.ThreadMode; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface Subscribe { + ThreadMode threadMode() default ThreadMode.PostThread; +} + diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java b/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java index 127d528b..a9dcf7a5 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java @@ -1,5 +1,8 @@ package de.greenrobot.eventperf; +import de.greenrobot.event.ThreadMode; +import de.greenrobot.event.annotations.Subscribe; + import android.app.Activity; import android.os.Bundle; import android.os.Process; @@ -43,6 +46,7 @@ protected void onResume() { } } + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(TestFinishedEvent event) { Test test = event.test; String text = "" + test.getDisplayName() + "
" + // diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java index 16920dc3..ca7a3d92 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java @@ -6,6 +6,8 @@ import android.content.Context; import de.greenrobot.event.EventBus; +import de.greenrobot.event.ThreadMode; +import de.greenrobot.event.annotations.Subscribe; import de.greenrobot.eventperf.Test; import de.greenrobot.eventperf.TestEvent; import de.greenrobot.eventperf.TestParams; @@ -174,6 +176,7 @@ public String getDisplayName() { } public class SubscribeClassEventBusDefault { + @Subscribe public void onEvent(TestEvent event) { eventsReceivedCount.incrementAndGet(); } @@ -195,6 +198,7 @@ public void dummy5() { } public class SubscribeClassEventBusMain { + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(TestEvent event) { eventsReceivedCount.incrementAndGet(); } @@ -216,6 +220,7 @@ public void dummy5() { } public class SubscribeClassEventBusBackground { + @Subscribe(threadMode = ThreadMode.BackgroundThread) public void onEventBackgroundThread(TestEvent event) { eventsReceivedCount.incrementAndGet(); } @@ -237,6 +242,7 @@ public void dummy5() { } public class SubscriberClassEventBusAsync { + @Subscribe(threadMode = ThreadMode.Async) public void onEventAsync(TestEvent event) { eventsReceivedCount.incrementAndGet(); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java index 888b37d5..1d9dae38 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java @@ -16,6 +16,8 @@ package de.greenrobot.event.test; import android.os.Looper; +import de.greenrobot.event.ThreadMode; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -40,6 +42,7 @@ public void testPostFromMain() throws InterruptedException { assertFalse(lastThread.equals(Looper.getMainLooper().getThread())); } + @Subscribe(threadMode = ThreadMode.BackgroundThread) public void onEventBackgroundThread(String event) { trackEvent(event); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java index c34feb38..ae0313de 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java @@ -18,6 +18,7 @@ import android.app.Activity; import android.util.Log; import de.greenrobot.event.EventBus; +import de.greenrobot.event.annotations.Subscribe; import junit.framework.TestCase; import java.lang.ref.WeakReference; @@ -187,6 +188,7 @@ public void testHasSubscriberForEventSuperclass() { assertFalse(eventBus.hasSubscriberForEvent(String.class)); Object subscriber = new Object() { + @Subscribe public void onEvent(Object event) { } }; @@ -201,6 +203,7 @@ public void testHasSubscriberForEventImplementedInterface() { assertFalse(eventBus.hasSubscriberForEvent(String.class)); Object subscriber = new Object() { + @Subscribe public void onEvent(CharSequence event) { } }; @@ -213,20 +216,24 @@ public void onEvent(CharSequence event) { assertFalse(eventBus.hasSubscriberForEvent(String.class)); } + @Subscribe public void onEvent(String event) { lastStringEvent = event; countStringEvent++; } + @Subscribe public void onEvent(Integer event) { lastIntEvent = event; countIntEvent++; } + @Subscribe public void onEvent(MyEvent event) { countMyEvent++; } + @Subscribe public void onEvent(MyEventExtended event) { countMyEventExtended++; } @@ -234,6 +241,7 @@ public void onEvent(MyEventExtended event) { static class TestActivity extends Activity { public String lastStringEvent; + @Subscribe public void onEvent(String event) { lastStringEvent = event; } @@ -249,6 +257,7 @@ class RepostInteger { public int lastEvent; public int countEvent; + @Subscribe public void onEvent(Integer event) { lastEvent = event; countEvent++; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java index 58b6bc8d..3bfd9733 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java @@ -20,6 +20,7 @@ import de.greenrobot.event.EventBusException; import de.greenrobot.event.NoSubscriberEvent; import de.greenrobot.event.SubscriberExceptionEvent; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -75,18 +76,21 @@ public void testEventInheritance() { } class SubscriberExceptionEventTracker { + @Subscribe public void onEvent(SubscriberExceptionEvent event) { trackEvent(event); } } class NoSubscriberEventTracker { + @Subscribe public void onEvent(NoSubscriberEvent event) { trackEvent(event); } } class ThrowingSubscriber { + @Subscribe public void onEvent(Object event) { throw new RuntimeException(); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java index 027d74f9..3b026db0 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java @@ -19,6 +19,8 @@ import android.test.UiThreadTest; import de.greenrobot.event.EventBusException; +import de.greenrobot.event.ThreadMode; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -82,6 +84,7 @@ public Subscriber(boolean cancel) { this.cancel = cancel; } + @Subscribe public void onEvent(String event) { trackEvent(event); if (cancel) { @@ -91,6 +94,7 @@ public void onEvent(String event) { } class SubscriberCancelOtherEvent { + @Subscribe public void onEvent(String event) { try { eventBus.cancelEventDelivery(this); @@ -103,6 +107,7 @@ public void onEvent(String event) { class SubscriberMainThread { final CountDownLatch done = new CountDownLatch(1); + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(String event) { try { eventBus.cancelEventDelivery(event); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java index 27e3d7b7..1d54f5d0 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java @@ -15,6 +15,7 @@ */ package de.greenrobot.event.test; +import de.greenrobot.event.annotations.Subscribe; import junit.framework.TestCase; import de.greenrobot.event.EventBus; @@ -91,22 +92,27 @@ public void testSubscriberClassHierarchy() { assertEquals(2, subscriber.countMyEventOverwritten); } + @Subscribe public void onEvent(Object event) { countObjectEvent++; } + @Subscribe public void onEvent(MyEvent event) { countMyEvent++; } + @Subscribe public void onEvent(MyEventExtended event) { countMyEventExtended++; } + @Subscribe public void onEvent(MyEventInterface event) { countMyEventInterface++; } + @Subscribe public void onEvent(MyEventInterfaceExtended event) { countMyEventInterfaceExtended++; } @@ -126,6 +132,7 @@ static class MyEventExtended extends MyEvent implements MyEventInterfaceExtended static class SubscriberExtended extends EventBusInheritanceTest { private int countMyEventOverwritten; + @Subscribe public void onEvent(MyEvent event) { countMyEventOverwritten++; } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java index 0b3ac3a8..e740dd44 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java @@ -20,6 +20,8 @@ import android.os.Handler; import android.os.Looper; +import de.greenrobot.event.ThreadMode; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -84,6 +86,7 @@ public void run() { awaitLatch(doneLatch, 10); } + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(String event) { trackEvent(event); if (unregistered) { diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java index 41b6302b..6f60c24d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java @@ -19,6 +19,8 @@ import java.util.List; import android.os.Looper; +import de.greenrobot.event.ThreadMode; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -57,6 +59,7 @@ public void testPostInBackgroundThread() throws InterruptedException { assertEquals(Looper.getMainLooper().getThread(), lastThread); } + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(String event) { trackEvent(event); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java index 6d664b9c..8f54b91b 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java @@ -18,6 +18,8 @@ import android.os.Looper; import de.greenrobot.event.EventBus; import de.greenrobot.event.EventBusException; +import de.greenrobot.event.ThreadMode; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -31,47 +33,28 @@ public void testRegisterForEventTypeAndPost() throws InterruptedException { waitForEventCount(4, 1000); } - public void testIllegalMethodNameThrow() { - try { - eventBus.register(new IllegalEventMethodName()); - fail("Illegal name registered"); - } catch (EventBusException ex) { - // OK, expected - } - } - - public void testIllegalMethodNameSkip() { - eventBus=EventBus.builder().skipMethodVerificationFor(IllegalEventMethodName.class).build(); - eventBus.register(new IllegalEventMethodName()); - eventBus.post(new Object()); - } - + @Subscribe public void onEvent(String event) { trackEvent(event); assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(String event) { trackEvent(event); assertSame(Looper.getMainLooper(), Looper.myLooper()); } + @Subscribe(threadMode = ThreadMode.BackgroundThread) public void onEventBackgroundThread(String event) { trackEvent(event); assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } + @Subscribe(threadMode = ThreadMode.Async) public void onEventAsync(String event) { trackEvent(event); assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } - public static class IllegalEventMethodName { - public void onEventIllegalName(Object event) { - fail("onEventIllegalName got called"); - } - - public void onEvent(IntTestEvent event) { - } - } } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java index be68fd12..61032a7d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java @@ -23,6 +23,8 @@ import android.os.Looper; import android.util.Log; import de.greenrobot.event.EventBus; +import de.greenrobot.event.ThreadMode; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -164,24 +166,28 @@ private List startThreads(CountDownLatch latch, int threadCount, i return threads; } + @Subscribe(threadMode = ThreadMode.BackgroundThread) public void onEventBackgroundThread(String event) { lastStringEvent = event; countStringEvent.incrementAndGet(); trackEvent(event); } + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(Integer event) { lastIntegerEvent = event; countIntegerEvent.incrementAndGet(); trackEvent(event); } + @Subscribe(threadMode = ThreadMode.Async) public void onEventAsync(IntTestEvent event) { countIntTestEvent.incrementAndGet(); lastIntTestEvent = event; trackEvent(event); } + @Subscribe public void onEvent(Object event) { countObjectEvent.incrementAndGet(); trackEvent(event); @@ -239,18 +245,22 @@ public void run() { } } + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(String event) { assertSame(Looper.getMainLooper(), Looper.myLooper()); } + @Subscribe(threadMode = ThreadMode.BackgroundThread) public void onEventBackgroundThread(Integer event) { assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } + @Subscribe public void onEvent(Object event) { assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } + @Subscribe(threadMode = ThreadMode.Async) public void onEventAsync(Object event) { assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java index ffe48f10..5d87ff4e 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java @@ -18,6 +18,7 @@ import de.greenrobot.event.EventBus; import de.greenrobot.event.NoSubscriberEvent; import de.greenrobot.event.SubscriberExceptionEvent; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -37,6 +38,7 @@ public void testNoSubscriberEvent() { public void testNoSubscriberEventAfterUnregister() { Object subscriber = new Object() { @SuppressWarnings("unused") + @Subscribe public void onEvent(String dummy) { } }; @@ -57,15 +59,18 @@ public void testBadNoSubscriberSubscriber() { assertEquals("Foo", noSub.originalEvent); } + @Subscribe public void onEvent(NoSubscriberEvent event) { trackEvent(event); } + @Subscribe public void onEvent(SubscriberExceptionEvent event) { trackEvent(event); } class BadNoSubscriberSubscriber { + @Subscribe public void onEvent(NoSubscriberEvent event) { throw new RuntimeException("I'm bad"); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java index 0cb794ac..67e26f96 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java @@ -20,6 +20,8 @@ import de.greenrobot.event.EventBus; import android.util.Log; +import de.greenrobot.event.ThreadMode; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -96,14 +98,17 @@ public PrioSubscriber(int prio) { // TODO Auto-generated constructor stub } + @Subscribe public void onEvent(String event) { handleEvent(event); } + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(IntTestEvent event) { handleEvent(event); } + @Subscribe(threadMode = ThreadMode.BackgroundThread) public void onEventBackgroundThread(Integer event) { handleEvent(event); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java index 41808dc7..9289a547 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java @@ -15,6 +15,8 @@ */ package de.greenrobot.event.test; +import de.greenrobot.event.annotations.Subscribe; + import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; @@ -87,6 +89,7 @@ public void run() { unregisteredLatch.countDown(); } + @Subscribe public void onEvent(String event) { eventCount++; } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java index 04be4d91..b17ccd60 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java @@ -15,6 +15,8 @@ */ package de.greenrobot.event.test; +import de.greenrobot.event.annotations.Subscribe; + /** * @author Markus Junginger, greenrobot */ @@ -119,6 +121,7 @@ public void testPostStickyRemoveAll() throws InterruptedException { public void testRemoveStickyEventInSubscriber() throws InterruptedException { eventBus.registerSticky(new Object() { @SuppressWarnings("unused") + @Subscribe public void onEvent(String event) { eventBus.removeStickyEvent(event); } @@ -130,10 +133,12 @@ public void onEvent(String event) { assertNull(eventBus.getStickyEvent(String.class)); } + @Subscribe public void onEvent(String event) { trackEvent(event); } + @Subscribe public void onEvent(IntTestEvent event) { trackEvent(event); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java index f9acaa7e..8a610a6d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java @@ -17,6 +17,7 @@ import de.greenrobot.event.EventBus; import de.greenrobot.event.SubscriberExceptionEvent; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -43,15 +44,18 @@ public void testBadExceptionSubscriber() { assertEventCount(1); } + @Subscribe public void onEvent(String event) { throw new RuntimeException("Bar"); } + @Subscribe public void onEvent(SubscriberExceptionEvent event) { trackEvent(event); } class BadExceptionSubscriber { + @Subscribe public void onEvent(SubscriberExceptionEvent event) { throw new RuntimeException("Bad"); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java index ee435219..b7b0fbf3 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java @@ -16,6 +16,7 @@ package de.greenrobot.event.test; import de.greenrobot.event.EventBusException; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -51,6 +52,7 @@ public void testSubscriberLegalAbstract() { eventBus.register(new Abstract() { @Override + @Subscribe public void onEvent(String event) { trackEvent(event); } @@ -61,20 +63,24 @@ public void onEvent(String event) { assertEquals(1, eventCount.intValue()); } + @Subscribe public void onEvent(String event) { trackEvent(event); } static class NotPublic { + @Subscribe void onEvent(String event) { } } static abstract class Abstract { + @Subscribe public abstract void onEvent(String event); } static class Static { + @Subscribe public static void onEvent(String event) { } } From 3b66bcd114fa010d6c93e4457185a8ddfcd71b54 Mon Sep 17 00:00:00 2001 From: Rick Brock Date: Fri, 14 Nov 2014 16:15:17 -0800 Subject: [PATCH 002/288] Updated documentation to reflect annotations --- HOWTO.md | 27 ++++++++++++++------------- README.md | 13 +++++++------ 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/HOWTO.md b/HOWTO.md index 740ad573..eeff213a 100644 --- a/HOWTO.md +++ b/HOWTO.md @@ -19,7 +19,7 @@ public class MessageEvent { ``` ### 2: Prepare subscribers ### -Subscribers implement event handling `onEvent` methods that will be called when an event is received. They also need to register and unregister themselves to the bus. +Subscribers implement event handling methods that will be called when an event is received. These are defined with the ``@Subscribe`` annotation. They also need to register and unregister themselves to the bus. ```java @Override @@ -35,11 +35,13 @@ Subscribers implement event handling `onEvent` methods that will be called when } // This method will be called when a MessageEvent is posted - public void onEvent(MessageEvent event){ + @Subscribe + public void onMessageEvent(MessageEvent event){ Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show(); } // This method will be called when a SomeOtherEvent is posted + @Subscribe public void onEvent(SomeOtherEvent event){ doSomethingWith(event); } @@ -58,11 +60,12 @@ EventBus can handle threading for you: events can be posted in threads different A common use case is dealing with UI changes. In Android, UI changes must be done in the UI (main) thread. On the other hand, networking, or any time consuming task, must not run on the main thread. EventBus helps you to deal with those tasks and synchronize with the UI thread (without having to delve into thread transitions, using AsyncTask, etc). -In EventBus, you may define the thread that will call the event handling method `onEvent` by using a **ThreadMode**: +In EventBus, you may define the thread that will call the event handling method by using a **ThreadMode**: * **PostThread:** Subscriber will be called in the same thread, which is posting the event. This is the default. Event delivery implies the least overhead because it avoids thread switching completely. Thus this is the recommended mode for simple tasks that are known to complete is a very short time without requiring the main thread. Event handlers using this mode should return quickly to avoid blocking the posting thread, which may be the main thread. Example: ```java // Called in the same thread (default) + @Subscribe public void onEvent(MessageEvent event) { log(event.message); } @@ -71,6 +74,7 @@ Example: Example: ```java // Called in Android UI's main thread + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(MessageEvent event) { textField.setText(event.message); } @@ -78,6 +82,7 @@ Example: * **BackgroundThread:** Subscriber will be called in a background thread. If posting thread is not the main thread, event handler methods will be called directly in the posting thread. If the posting thread is the main thread, EventBus uses a single background thread that will deliver all its events sequentially. Event handlers using this mode should try to return quickly to avoid blocking the background thread. ```java // Called in the background thread + @Subscribe(threadMode = ThreadMode.BackgroundThread) public void onEventBackgroundThread(MessageEvent event){ saveToDisk(event.message); } @@ -85,12 +90,13 @@ Example: * **Async:** Event handler methods are called in a separate thread. This is always independent from the posting thread and the main thread. Posting events never wait for event handler methods using this mode. Event handler methods should use this mode if their execution might take some time, e.g. for network access. Avoid triggering a large number of long running asynchronous handler methods at the same time to limit the number of concurrent threads. EventBus uses a thread pool to efficiently reuse threads from completed asynchronous event handler notifications. ```java // Called in a separate thread + @Subscribe(threadMode = ThreadMode.Async) public void onEventAsync(MessageEvent event){ backend.send(event.message); } ``` -*Note:* EventBus takes care of calling the `onEvent` method in the proper thread depending on its name (onEvent, onEventAsync, etc.). +*Note:* EventBus takes care of calling the subscribing method in the proper thread depending on its annotations threadMode argument (threadMode=ThreadMode.Async, MainThread, etc...). Subscriber priorities and ordered event delivery ------------------------------------------------ @@ -164,7 +170,8 @@ After that, a new Activity gets started. During registration using registerStick super.onStart(); EventBus.getDefault().registerSticky(this); } - + + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(MessageEvent event) { textField.setText(event.message); } @@ -185,9 +192,8 @@ ProGuard configuration ---------------------- ProGuard obfuscates method names. However, the onEvent methods must not renamed because they are accessed using reflection. Use the following snip in your ProGuard configuration file (proguard.cfg):
-keepclassmembers class ** {
-    public void onEvent*(**);
-}
-
+ @de.greenrobot.event.annotations.Subscribe public *; +} Comparison with Square's Otto @@ -199,11 +205,6 @@ Otto is another event bus library for Android; actually it's a fork of Guava's E EventBus Otto - - Declare event handling methods - Name conventions - Annotations - Event inheritance Yes diff --git a/README.md b/README.md index 3e5a457e..00bd8a8d 100644 --- a/README.md +++ b/README.md @@ -17,14 +17,16 @@ EventBus... [![Build Status](https://travis-ci.org/greenrobot/EventBus.svg?branch=master)](https://travis-ci.org/greenrobot/EventBus) -EventBus in 3 steps +EventBus in 4 steps ------------------- 1. Define events:
public class MessageEvent { /* Additional fields if needed */ }

-2. Prepare subscribers:
-eventBus.register(this);
+2. Register your subscriber (in your onCreate or in a constructor):
+eventBus.register(this);

+3. Declare your subscribing method
+@Subscribe
public void onEvent(AnyEventType event) {/* Do something */};

-3. Post events:
+4. Post events:
eventBus.post(event); Add EventBus to your project @@ -54,8 +56,7 @@ Details on EventBus and its API are available in the [HOWTO document](HOWTO.md). Additional Features and Notes ----------------------------- -* **NOT based on annotations:** Querying annotations are slow on Android, especially before Android 4.0. Have a look at this [Android bug report](http://code.google.com/p/android/issues/detail?id=7811). -* **Based on conventions:** Event handling methods are called "onEvent". +* **Based on annotations:** Event handling methods can be named however you want, and only need to be annotated with **@Subscribe**. * **Performance optimized:** It's probably the fastest event bus for Android. * **Convenience singleton:** You can get a process wide event bus instance by calling EventBus.getDefault(). You can still call new EventBus() to create any number of local busses. * **Subscriber and event inheritance:** Event handler methods may be defined in super classes, and events are posted to handlers of the event's super classes including any implemented interfaces. For example, subscriber may register to events of the type Object to receive all events posted on the event bus. From df91aeba6ae163a759ba88c2be728fb7b6e4d4bb Mon Sep 17 00:00:00 2001 From: Rick Brock Date: Mon, 17 Nov 2014 14:14:28 -0800 Subject: [PATCH 003/288] Added logging and sped up method finding - Moved check for bridge and synthetic methods up to rule them out asap - Reorganized method finding to be more clear - Added comments - Added logging to method finding if the user enables it --- .../src/de/greenrobot/event/EventBus.java | 3 +- .../event/SubscriberMethodFinder.java | 96 +++++++++++++------ 2 files changed, 68 insertions(+), 31 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index 4bac5cbe..4ba22a7c 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -160,7 +160,8 @@ public void registerSticky(Object subscriber, int priority) { } private synchronized void register(Object subscriber, boolean sticky, int priority) { - List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass()); + List subscriberMethods + = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass(), logSubscriberExceptions); for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod, sticky, priority); } diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 9caa7b9f..57d9c8c2 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -29,15 +29,8 @@ class SubscriberMethodFinder { - /* - * In newer class files, compilers may add methods. Those are called bridge or synthetic methods. - * EventBus must ignore both. Their modifiers are not public but defined in the Java class file format: - * http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6-200-A.1 - */ - private static final int BRIDGE = 0x40; - private static final int SYNTHETIC = 0x1000; - private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC; + private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC; private static final Map> methodCache = new HashMap>(); private final Map, Class> skipMethodVerificationForClasses; @@ -51,7 +44,7 @@ class SubscriberMethodFinder { } } - List findSubscriberMethods(Class subscriberClass) { + List findSubscriberMethods(Class subscriberClass, boolean logSubscriberExceptions) { String key = subscriberClass.getName(); List subscriberMethods; synchronized (methodCache) { @@ -71,37 +64,67 @@ List findSubscriberMethods(Class subscriberClass) { break; } + // Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again) Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { String methodName = method.getName(); + + /* + * In newer class files, compilers may add methods. Those are called bridge or synthetic methods. + * EventBus must ignore both. Their modifiers are not public but defined in the Java class file format: + * http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6-200-A.1 + */ + if (method.isBridge() || method.isSynthetic()) { + continue; + } + // Now we find acceptable methods via annotations if (method.isAnnotationPresent(Subscribe.class)) { - Log.e("EventBus", "Annotation is present for " + methodName); + + // make sure the method is public 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 && subscribeAnnotation.threadMode() != null) { - ThreadMode threadMode = subscribeAnnotation.threadMode(); - 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)); - } - } - } + if ((modifiers & Modifier.PUBLIC) == 0) { + logErrorIfEnabled(logSubscriberExceptions, methodName, + "Method (%s) has subscribe annotation but is not public"); + continue; + } + + // make sure the method is not static or abstract + if ((modifiers & MODIFIERS_IGNORE) != 0) { + logErrorIfEnabled(logSubscriberExceptions, methodName, + "Method (%s) has subscribe annotation but is either static or abstract"); + continue; + } + + // verify that there is exactly 1 parameter (the event) + Class[] parameterTypes = method.getParameterTypes(); + if (parameterTypes.length != 1) { + logErrorIfEnabled(logSubscriberExceptions, methodName, + "Method (%s) does not have exactly 1 parameter"); + continue; + } + + // This method is valid, so now we get the threadMode and add to the cache + Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); + Class eventType = parameterTypes[0]; + ThreadMode threadMode; + if (subscribeAnnotation != null && subscribeAnnotation.threadMode() != null) { + threadMode = subscribeAnnotation.threadMode(); + } else { + threadMode = ThreadMode.PostThread; } - } else { - Log.e("EventBus", "Annotation is NOT present for " + methodName); + 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)); + } } } @@ -118,6 +141,19 @@ List findSubscriberMethods(Class subscriberClass) { } } + /** + * If the user has enabled logging subscriber errors, log the message to log.e + * + * @param logSubscriberErrors if logSubscriberErrors is enabled + * @param methodName method name + * @param error error message + */ + private void logErrorIfEnabled(boolean logSubscriberErrors, String methodName, String error) { + if (logSubscriberErrors) { + Log.e(EventBus.TAG, String.format(error, methodName)); + } + } + static void clearCaches() { synchronized (methodCache) { methodCache.clear(); From 442ba1d7bc4b9dee83c59d93731fc8bdf6a660cf Mon Sep 17 00:00:00 2001 From: Markus Date: Sun, 22 Feb 2015 14:23:11 +0100 Subject: [PATCH 004/288] updated to gradle 2.2.1 and build tools 1.1.0 --- EventBusPerformance/build.gradle | 2 +- EventBusTest/build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index cd15599a..c88b9cea 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:0.13.3' + classpath 'com.android.tools.build:gradle:1.1.0' } } diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 169fa718..ce4f2471 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:0.13.3' + classpath 'com.android.tools.build:gradle:1.1.0' } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2583d2d1..c8dcd502 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sat Nov 08 10:08:52 CET 2014 +#Sun Feb 22 14:20:02 CET 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip From 3f069ae015d4c2281c35e1937fd2fadd7e9bdf2d Mon Sep 17 00:00:00 2001 From: Markus Date: Sun, 22 Feb 2015 14:32:48 +0100 Subject: [PATCH 005/288] buildToolsVersion '21.1.2' --- .travis.yml | 2 +- EventBusPerformance/build.gradle | 2 +- EventBusTest/build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 51017 -> 51018 bytes 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index f2076297..e086ce10 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ jdk: # http://docs.travis-ci.com/user/languages/android/ android: components: - - build-tools-21.0.2 + - build-tools-21.1.2 - android-10 before_script: diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index c88b9cea..570c64b0 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -20,7 +20,7 @@ dependencies { } android { - buildToolsVersion '20.0.0' + buildToolsVersion '21.1.2' compileSdkVersion 19 sourceSets { diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index ce4f2471..2f48f9c5 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -19,7 +19,7 @@ dependencies { } android { - buildToolsVersion '20.0.0' + buildToolsVersion '21.1.2' compileSdkVersion 19 sourceSets { diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 3d0dee6e8edfecc92e04653ec780de06f7b34f8b..c97a8bdb9088d370da7e88784a7a093b971aa23a 100644 GIT binary patch delta 4503 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 C(p{zi delta 4629 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 BAg=%b From cf6f736057c3f4bfe23495c4fe562b4636fd872c Mon Sep 17 00:00:00 2001 From: Markus Date: Sun, 22 Feb 2015 19:02:03 +0100 Subject: [PATCH 006/288] improving annotation look-up performance --- .../src/de/greenrobot/event/EventBus.java | 5 +- .../event/SubscriberMethodFinder.java | 121 ++++++------------ 2 files changed, 43 insertions(+), 83 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index 4ba22a7c..ba759d33 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -108,7 +108,7 @@ public EventBus() { mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); - subscriberMethodFinder = new SubscriberMethodFinder(builder.skipMethodVerificationForClasses); + subscriberMethodFinder = new SubscriberMethodFinder(/* TODO */ false); logSubscriberExceptions = builder.logSubscriberExceptions; logNoSubscriberMessages = builder.logNoSubscriberMessages; sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent; @@ -160,8 +160,7 @@ public void registerSticky(Object subscriber, int priority) { } private synchronized void register(Object subscriber, boolean sticky, int priority) { - List subscriberMethods - = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass(), logSubscriberExceptions); + List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass()); for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod, sticky, priority); } diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 57d9c8c2..d6a21523 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -15,7 +15,6 @@ */ package de.greenrobot.event; -import android.util.Log; import de.greenrobot.event.annotations.Subscribe; import java.lang.reflect.Method; @@ -25,26 +24,26 @@ import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; class SubscriberMethodFinder { + /* + * In newer class files, compilers may add methods. Those are called bridge or synthetic methods. + * EventBus must ignore both. There modifiers are not public but defined in the Java class file format: + * http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6-200-A.1 + */ + private static final int BRIDGE = 0x40; + private static final int SYNTHETIC = 0x1000; - private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC; + private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC; private static final Map> methodCache = new HashMap>(); + private final boolean strictMethodVerification; - private final Map, Class> skipMethodVerificationForClasses; - - SubscriberMethodFinder(List> skipMethodVerificationForClassesList) { - skipMethodVerificationForClasses = new ConcurrentHashMap, Class>(); - if (skipMethodVerificationForClassesList != null) { - for (Class clazz : skipMethodVerificationForClassesList) { - skipMethodVerificationForClasses.put(clazz, clazz); - } - } + SubscriberMethodFinder(boolean strictMethodVerification) { + this.strictMethodVerification = strictMethodVerification; } - List findSubscriberMethods(Class subscriberClass, boolean logSubscriberExceptions) { + List findSubscriberMethods(Class subscriberClass) { String key = subscriberClass.getName(); List subscriberMethods; synchronized (methodCache) { @@ -64,67 +63,42 @@ List findSubscriberMethods(Class subscriberClass, boolean l break; } - // Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again) Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { - String methodName = method.getName(); - - - /* - * In newer class files, compilers may add methods. Those are called bridge or synthetic methods. - * EventBus must ignore both. Their modifiers are not public but defined in the Java class file format: - * http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6-200-A.1 - */ - if (method.isBridge() || method.isSynthetic()) { - continue; - } - - // Now we find acceptable methods via annotations - if (method.isAnnotationPresent(Subscribe.class)) { - - // make sure the method is public - int modifiers = method.getModifiers(); - if ((modifiers & Modifier.PUBLIC) == 0) { - logErrorIfEnabled(logSubscriberExceptions, methodName, - "Method (%s) has subscribe annotation but is not public"); - continue; - } - - // make sure the method is not static or abstract - if ((modifiers & MODIFIERS_IGNORE) != 0) { - logErrorIfEnabled(logSubscriberExceptions, methodName, - "Method (%s) has subscribe annotation but is either static or abstract"); - continue; - } - - // verify that there is exactly 1 parameter (the event) + int modifiers = method.getModifiers(); + if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { Class[] parameterTypes = method.getParameterTypes(); - if (parameterTypes.length != 1) { - logErrorIfEnabled(logSubscriberExceptions, methodName, - "Method (%s) does not have exactly 1 parameter"); - continue; + if (parameterTypes.length == 1) { + Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); + if (subscribeAnnotation != null) { + String methodName = method.getName(); + 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 + ThreadMode threadMode = subscribeAnnotation.threadMode(); + subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType)); + } + } + } else if (strictMethodVerification) { + if (method.isAnnotationPresent(Subscribe.class)) { + String methodName = name + "." + method.getName(); + throw new EventBusException("@Subscribe method " + methodName + + "must have exactly 1 parameter but has " + parameterTypes.length); + } } - - // This method is valid, so now we get the threadMode and add to the cache - Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); - Class eventType = parameterTypes[0]; - ThreadMode threadMode; - if (subscribeAnnotation != null && subscribeAnnotation.threadMode() != null) { - threadMode = subscribeAnnotation.threadMode(); - } else { - threadMode = ThreadMode.PostThread; + } else if (strictMethodVerification) { + if (method.isAnnotationPresent(Subscribe.class)) { + String methodName = name + "." + method.getName(); + throw new EventBusException(methodName + + " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); } - 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)); - } } } @@ -141,19 +115,6 @@ List findSubscriberMethods(Class subscriberClass, boolean l } } - /** - * If the user has enabled logging subscriber errors, log the message to log.e - * - * @param logSubscriberErrors if logSubscriberErrors is enabled - * @param methodName method name - * @param error error message - */ - private void logErrorIfEnabled(boolean logSubscriberErrors, String methodName, String error) { - if (logSubscriberErrors) { - Log.e(EventBus.TAG, String.format(error, methodName)); - } - } - static void clearCaches() { synchronized (methodCache) { methodCache.clear(); From daa7370c8fa833e477e42ef281fd7279fb079a88 Mon Sep 17 00:00:00 2001 From: Markus Date: Sun, 22 Feb 2015 21:13:26 +0100 Subject: [PATCH 007/288] moved @Subscribe into main package --- .../src/de/greenrobot/event/{annotations => }/Subscribe.java | 2 +- EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java | 2 -- .../src/de/greenrobot/eventperf/TestRunnerActivity.java | 2 +- .../de/greenrobot/eventperf/testsubject/PerfTestEventBus.java | 2 +- .../de/greenrobot/event/test/EventBusBackgroundThreadTest.java | 2 +- .../src/de/greenrobot/event/test/EventBusBasicTest.java | 2 +- .../src/de/greenrobot/event/test/EventBusBuilderTest.java | 2 +- .../greenrobot/event/test/EventBusCancelEventDeliveryTest.java | 2 +- .../src/de/greenrobot/event/test/EventBusInheritanceTest.java | 2 +- .../de/greenrobot/event/test/EventBusMainThreadRacingTest.java | 2 +- .../src/de/greenrobot/event/test/EventBusMainThreadTest.java | 2 +- .../de/greenrobot/event/test/EventBusMethodModifiersTest.java | 2 +- .../src/de/greenrobot/event/test/EventBusMultithreadedTest.java | 2 +- .../de/greenrobot/event/test/EventBusNoSubscriberEventTest.java | 2 +- .../greenrobot/event/test/EventBusOrderedSubscriptionsTest.java | 2 +- .../greenrobot/event/test/EventBusRegistrationRacingTest.java | 2 +- .../src/de/greenrobot/event/test/EventBusStickyEventTest.java | 2 +- .../greenrobot/event/test/EventBusSubscriberExceptionTest.java | 2 +- .../de/greenrobot/event/test/EventBusSubscriberLegalTest.java | 2 +- 19 files changed, 18 insertions(+), 20 deletions(-) rename EventBus/src/de/greenrobot/event/{annotations => }/Subscribe.java (90%) diff --git a/EventBus/src/de/greenrobot/event/annotations/Subscribe.java b/EventBus/src/de/greenrobot/event/Subscribe.java similarity index 90% rename from EventBus/src/de/greenrobot/event/annotations/Subscribe.java rename to EventBus/src/de/greenrobot/event/Subscribe.java index cf8af04c..76ff1c88 100644 --- a/EventBus/src/de/greenrobot/event/annotations/Subscribe.java +++ b/EventBus/src/de/greenrobot/event/Subscribe.java @@ -1,4 +1,4 @@ -package de.greenrobot.event.annotations; +package de.greenrobot.event; import java.lang.annotation.Documented; diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index d6a21523..eb1ea759 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -15,8 +15,6 @@ */ package de.greenrobot.event; -import de.greenrobot.event.annotations.Subscribe; - import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java b/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java index a9dcf7a5..07f55777 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java @@ -1,7 +1,7 @@ package de.greenrobot.eventperf; import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; import android.app.Activity; import android.os.Bundle; diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java index ca7a3d92..66bf9131 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java @@ -7,7 +7,7 @@ import android.content.Context; import de.greenrobot.event.EventBus; import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; import de.greenrobot.eventperf.Test; import de.greenrobot.eventperf.TestEvent; import de.greenrobot.eventperf.TestParams; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java index 1d9dae38..99de5a32 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java @@ -17,7 +17,7 @@ import android.os.Looper; import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java index ae0313de..464079ea 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java @@ -18,7 +18,7 @@ import android.app.Activity; import android.util.Log; import de.greenrobot.event.EventBus; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; import junit.framework.TestCase; import java.lang.ref.WeakReference; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java index 3bfd9733..6896264c 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java @@ -20,7 +20,7 @@ import de.greenrobot.event.EventBusException; import de.greenrobot.event.NoSubscriberEvent; import de.greenrobot.event.SubscriberExceptionEvent; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java index 3b026db0..92d02f7b 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java @@ -20,7 +20,7 @@ import android.test.UiThreadTest; import de.greenrobot.event.EventBusException; import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java index 1d54f5d0..b7fcf9a9 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java @@ -15,7 +15,7 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; import junit.framework.TestCase; import de.greenrobot.event.EventBus; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java index e740dd44..9fa4a487 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java @@ -21,7 +21,7 @@ import android.os.Handler; import android.os.Looper; import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java index 6f60c24d..3d6b7541 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java @@ -20,7 +20,7 @@ import android.os.Looper; import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java index 8f54b91b..aad8d781 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java @@ -19,7 +19,7 @@ import de.greenrobot.event.EventBus; import de.greenrobot.event.EventBusException; import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java index 61032a7d..7535de6d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java @@ -24,7 +24,7 @@ import android.util.Log; import de.greenrobot.event.EventBus; import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java index 5d87ff4e..41339796 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java @@ -18,7 +18,7 @@ import de.greenrobot.event.EventBus; import de.greenrobot.event.NoSubscriberEvent; import de.greenrobot.event.SubscriberExceptionEvent; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java index 67e26f96..e5e85c23 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java @@ -21,7 +21,7 @@ import de.greenrobot.event.EventBus; import android.util.Log; import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java index 9289a547..f5510fcb 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java @@ -15,7 +15,7 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; import java.util.ArrayList; import java.util.List; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java index b17ccd60..084b1be6 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java @@ -15,7 +15,7 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java index 8a610a6d..988ce720 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java @@ -17,7 +17,7 @@ import de.greenrobot.event.EventBus; import de.greenrobot.event.SubscriberExceptionEvent; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java index b7b0fbf3..1b5c57a8 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java @@ -16,7 +16,7 @@ package de.greenrobot.event.test; import de.greenrobot.event.EventBusException; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot From 9bd7391bf8fee11be781d34d1cbce4d861fd4249 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 11:20:46 +0100 Subject: [PATCH 008/288] EventBusAnnotationProcessor for creating a subscriber index during build --- .../event/SubscriberIndexEntry.java | 17 +++ .../event/SubscriberMethodFinder.java | 88 ++++++++++--- EventBusAnnotationProcessor/build.gradle | 122 ++++++++++++++++++ .../javax.annotation.processing.Processor | 1 + EventBusAnnotationProcessor/settings.gradle | 1 + .../EventBusAnnotationProcessor.java | 68 ++++++++++ EventBusPerformance/build.gradle | 1 + settings.gradle | 1 + 8 files changed, 284 insertions(+), 15 deletions(-) create mode 100644 EventBus/src/de/greenrobot/event/SubscriberIndexEntry.java create mode 100644 EventBusAnnotationProcessor/build.gradle create mode 100644 EventBusAnnotationProcessor/res/META-INF/services/javax.annotation.processing.Processor create mode 100644 EventBusAnnotationProcessor/settings.gradle create mode 100644 EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java diff --git a/EventBus/src/de/greenrobot/event/SubscriberIndexEntry.java b/EventBus/src/de/greenrobot/event/SubscriberIndexEntry.java new file mode 100644 index 00000000..7a051233 --- /dev/null +++ b/EventBus/src/de/greenrobot/event/SubscriberIndexEntry.java @@ -0,0 +1,17 @@ +package de.greenrobot.event; + +/** Preprocessed index as used with annotation-preprocessed code generation */ +public class SubscriberIndexEntry { + final Class subscriberType; + final String methodName; + final Class eventType; + final ThreadMode threadMode; + + public SubscriberIndexEntry(Class subscriberType, String methodName, Class eventType, + ThreadMode threadMode) { + this.subscriberType = subscriberType; + this.methodName = methodName; + this.eventType = eventType; + this.threadMode = threadMode; + } +} diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index eb1ea759..a0d70298 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -15,6 +15,8 @@ */ package de.greenrobot.event; +import android.util.Log; + import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; @@ -34,7 +36,37 @@ class SubscriberMethodFinder { private static final int SYNTHETIC = 0x1000; private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC; - private static final Map> methodCache = new HashMap>(); + private static final Map> METHOD_CACHE = new HashMap>(); + + /** Optional generated index without entries from subscribers super classes */ + private static final Map> METHOD_INDEX; + + static { + Map> index = null; + try { + Class clazz = Class.forName("MyGeneratedEventBusSubscriberIndex"); + SubscriberIndexEntry[] entries = (SubscriberIndexEntry[]) clazz.getField("INDEX").get(null); + Map> newIndex = new HashMap>(); + for (SubscriberIndexEntry entry : entries) { + String key = entry.subscriberType.getName(); + List subscriberMethods = newIndex.get(key); + if (subscriberMethods == null) { + subscriberMethods = new ArrayList(); + newIndex.put(key, subscriberMethods); + } + Method method = entry.subscriberType.getMethod(entry.methodName, entry.eventType); + SubscriberMethod subscriberMethod = new SubscriberMethod(method, entry.threadMode, entry.eventType); + subscriberMethods.add(subscriberMethod); + } + index = newIndex; + } catch (ClassNotFoundException e) { + // Fine + } catch (Exception e) { + Log.w("Could not init @Subscribe index, reverting to dynamic look-up (slower)", e); + } + METHOD_INDEX = index; + } + private final boolean strictMethodVerification; SubscriberMethodFinder(boolean strictMethodVerification) { @@ -44,13 +76,47 @@ class SubscriberMethodFinder { List findSubscriberMethods(Class subscriberClass) { String key = subscriberClass.getName(); List subscriberMethods; - synchronized (methodCache) { - subscriberMethods = methodCache.get(key); + synchronized (METHOD_CACHE) { + subscriberMethods = METHOD_CACHE.get(key); } if (subscriberMethods != null) { return subscriberMethods; } - subscriberMethods = new ArrayList(); + if(METHOD_INDEX != null) { + subscriberMethods = findSubscriberMethodsWithIndex(subscriberClass); + } else { + subscriberMethods = findSubscriberMethodsWithReflection(subscriberClass); + } + if (subscriberMethods.isEmpty()) { + throw new EventBusException("Subscriber " + subscriberClass + + " and its super classes have no public methods with the @Subscribe annotation"); + } else { + synchronized (METHOD_CACHE) { + METHOD_CACHE.put(key, subscriberMethods); + } + return subscriberMethods; + } + } + + private List findSubscriberMethodsWithIndex(Class subscriberClass) { + List subscriberMethods = new ArrayList(); + Class clazz = subscriberClass; + while (clazz != null) { + String name = clazz.getName(); + if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) { + // Skip system classes, this just degrades performance + break; + } + List flatList = METHOD_INDEX.get(name); + subscriberMethods.addAll(flatList); + + clazz = clazz.getSuperclass(); + } + return subscriberMethods; + } + + private List findSubscriberMethodsWithReflection(Class subscriberClass) { + List subscriberMethods = new ArrayList(); Class clazz = subscriberClass; HashSet eventTypesFound = new HashSet(); StringBuilder methodKeyBuilder = new StringBuilder(); @@ -102,20 +168,12 @@ List findSubscriberMethods(Class subscriberClass) { clazz = clazz.getSuperclass(); } - if (subscriberMethods.isEmpty()) { - throw new EventBusException("Subscriber " + subscriberClass - + " has no public methods called with the @Subscribe annotation"); - } else { - synchronized (methodCache) { - methodCache.put(key, subscriberMethods); - } - return subscriberMethods; - } + return subscriberMethods; } static void clearCaches() { - synchronized (methodCache) { - methodCache.clear(); + synchronized (METHOD_CACHE) { + METHOD_CACHE.clear(); } } diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle new file mode 100644 index 00000000..aa94d975 --- /dev/null +++ b/EventBusAnnotationProcessor/build.gradle @@ -0,0 +1,122 @@ +apply plugin: 'java' +apply plugin: 'maven' +apply plugin: 'signing' + +group = 'de.greenrobot' +version = '3.0.0' +sourceCompatibility = 1.7 + +def isSnapshot = version.endsWith('-SNAPSHOT') +def sonatypeRepositoryUrl +if(isSnapshot) { + sonatypeRepositoryUrl = "https://oss.sonatype.org/content/repositories/snapshots/" +} else { + sonatypeRepositoryUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" +} + +repositories { + mavenCentral() +} + +// Still unsupported, see http://issues.gradle.org/browse/GRADLE-784 +// Like this, it won't appear at all in the POM +configurations { + provided + deployerJars +} + +dependencies { + compile project(':EventBus') + deployerJars 'org.apache.maven.wagon:wagon-webdav:1.0-beta-2' +} + +sourceSets { + main { + compileClasspath += configurations.provided + java { + srcDir 'src' + } + resources { + srcDir 'res' + } + } +} + +task sourcesJar(type: Jar) { + from sourceSets.main.allSource + classifier = 'sources' +} + +artifacts { + archives jar + archives sourcesJar +} + +signing { + if(project.hasProperty('signing.keyId') && project.hasProperty('signing.password') && + project.hasProperty('signing.secretKeyRingFile')) { + sign configurations.archives + } else { + println "Signing information missing/incomplete for ${project.name}" + } +} + +uploadArchives { + repositories { + mavenDeployer { + if(project.hasProperty('preferedRepo') && project.hasProperty('preferedUsername') + && project.hasProperty('preferedPassword')) { + configuration = configurations.deployerJars + repository(url: preferedRepo) { + authentication(userName: preferedUsername, password: preferedPassword) + } + } else if(project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePassword')) { + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + repository(url: sonatypeRepositoryUrl) { + authentication(userName: sonatypeUsername, password: sonatypePassword) + } + } else { + println "Settings sonatypeUsername/sonatypePassword missing/incomplete for ${project.name}" + } + + pom.artifactId = 'eventbus-annotation-processor' + pom.project { + name 'EventBus Annotation Processor' + packaging 'jar' + description 'Precompiler for EventBus Annotations.' + url 'https://github.com/greenrobot/EventBus' + + scm { + url 'https://github.com/greenrobot/EventBus' + connection 'scm:git@github.com:greenrobot/EventBus.git' + developerConnection 'scm:git@github.com:greenrobot/EventBus.git' + } + + licenses { + license { + name 'The Apache Software License, Version 2.0' + url 'http://www.apache.org/licenses/LICENSE-2.0.txt' + distribution 'repo' + } + } + + developers { + developer { + id 'greenrobot' + name 'greenrobot' + } + } + + issueManagement { + system 'GitHub Issues' + url 'https://github.com/greenrobot/EventBus/issues' + } + + organization { + name 'greenrobot' + url 'http://greenrobot.de' + } + } + } + } +} \ No newline at end of file diff --git a/EventBusAnnotationProcessor/res/META-INF/services/javax.annotation.processing.Processor b/EventBusAnnotationProcessor/res/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 00000000..ec7e34b6 --- /dev/null +++ b/EventBusAnnotationProcessor/res/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1 @@ +de.greenrobot.event.annotationprocessor.EventBusAnnotationProcessor diff --git a/EventBusAnnotationProcessor/settings.gradle b/EventBusAnnotationProcessor/settings.gradle new file mode 100644 index 00000000..51ebbb79 --- /dev/null +++ b/EventBusAnnotationProcessor/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'eventbus-annotation-processor' \ No newline at end of file diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java new file mode 100644 index 00000000..b4390607 --- /dev/null +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -0,0 +1,68 @@ +package de.greenrobot.event.annotationprocessor; + +import de.greenrobot.event.Subscribe; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.Messager; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Name; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +@SupportedAnnotationTypes("de.greenrobot.event.Subscribe") +public class EventBusAnnotationProcessor extends AbstractProcessor { + @Override + public boolean process(Set annotations, RoundEnvironment env) { + if (annotations.isEmpty()) { + return false; + } + Messager messager = processingEnv.getMessager(); + try { + String className = "MyGeneratedEventBusSubscriberIndex"; + JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(className); + try (BufferedWriter writer = new BufferedWriter(sourceFile.openWriter())) { + writer.write("import de.greenrobot.event.SubscriberIndexEntry;\n"); + writer.write("import de.greenrobot.event.ThreadMode;\n\n"); + writer.write("/** This class is generated by EventBus, do not edit. */\n"); + writer.write("public class " + className + " {\n"); + writer.write(" public static final SubscriberIndexEntry[] INDEX = {\n"); + + for (TypeElement annotation : annotations) { + Set elements = env.getElementsAnnotatedWith(annotation); + for (Element element : elements) { + writeIndexEntry(writer, element, messager); + } + } + writer.write(" };\n}\n"); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + return true; + } + + private void writeIndexEntry(BufferedWriter writer, Element element, Messager messager) throws IOException { + Subscribe subscribe = element.getAnnotation(Subscribe.class); + String subscriberClass = element.getEnclosingElement().asType().toString(); + messager.printMessage(Diagnostic.Kind.NOTE, "Found @Subscribe in " + subscriberClass); + List parameters = ((ExecutableElement) element).getParameters(); + if (parameters.size() != 1) { + throw new RuntimeException("Must have exactly 1 parameter"); + } + String eventType = parameters.get(0).asType().toString(); + writer.append(" new SubscriberIndexEntry(\n"); + writer.append(" ").append(subscriberClass).append(".class,\n"); + writer.append(" \"").append(element.getSimpleName()).append("\",\n"); + writer.append(" ").append(eventType).append(".class,\n"); + writer.append(" ThreadMode.").append(subscribe.threadMode().name()).append("),\n"); + } +} diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 570c64b0..a0b4b276 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -16,6 +16,7 @@ repositories { dependencies { compile project(':EventBus') + compile project(':EventBusAnnotationProcessor') compile 'com.squareup:otto:1.3.5' } diff --git a/settings.gradle b/settings.gradle index 76c570b0..d51c4e7b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,4 @@ include 'EventBus' +include 'EventBusAnnotationProcessor' include 'EventBusTest' include 'EventBusPerformance' From 0c89485f73911d57a0d2a6d33c17733e92a8bd02 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 15:40:41 +0100 Subject: [PATCH 009/288] more checks for EventBusAnnotationProcessor --- .../EventBusAnnotationProcessor.java | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index b4390607..19be88b0 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -6,11 +6,15 @@ import javax.annotation.processing.Messager; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; import javax.lang.model.element.Name; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; import java.io.BufferedWriter; @@ -19,6 +23,7 @@ import java.util.Set; @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") +@SupportedSourceVersion(SourceVersion.RELEASE_6) public class EventBusAnnotationProcessor extends AbstractProcessor { @Override public boolean process(Set annotations, RoundEnvironment env) { @@ -52,17 +57,42 @@ public boolean process(Set annotations, RoundEnvironment private void writeIndexEntry(BufferedWriter writer, Element element, Messager messager) throws IOException { Subscribe subscribe = element.getAnnotation(Subscribe.class); - String subscriberClass = element.getEnclosingElement().asType().toString(); - messager.printMessage(Diagnostic.Kind.NOTE, "Found @Subscribe in " + subscriberClass); + if (element.getModifiers().contains(Modifier.STATIC)) { + messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must not be static", element); + return; + } + + Set subscriberClassModifiers = element.getEnclosingElement().getModifiers(); + if (!subscriberClassModifiers.contains(Modifier.PUBLIC)) { + messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber class must be public", + element.getEnclosingElement()); + return; + } + List parameters = ((ExecutableElement) element).getParameters(); if (parameters.size() != 1) { - throw new RuntimeException("Must have exactly 1 parameter"); + messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must have exactly 1 parameter", element); + return; } - String eventType = parameters.get(0).asType().toString(); + + VariableElement param = parameters.get(0); + DeclaredType paramType = (DeclaredType) param.asType(); + Set eventClassModifiers = paramType.asElement().getModifiers(); + if (!eventClassModifiers.contains(Modifier.PUBLIC)) { + messager.printMessage(Diagnostic.Kind.ERROR, "Event type must be public: " + paramType, param); + return; + } + + String subscriberClass = element.getEnclosingElement().asType().toString(); + Name methodName = element.getSimpleName(); writer.append(" new SubscriberIndexEntry(\n"); writer.append(" ").append(subscriberClass).append(".class,\n"); - writer.append(" \"").append(element.getSimpleName()).append("\",\n"); - writer.append(" ").append(eventType).append(".class,\n"); + writer.append(" \"").append(methodName).append("\",\n"); + writer.append(" ").append(paramType.toString()).append(".class,\n"); writer.append(" ThreadMode.").append(subscribe.threadMode().name()).append("),\n"); + + messager.printMessage(Diagnostic.Kind.NOTE, "Indexed @Subscribe at " + + element.getEnclosingElement().getSimpleName() + "." + methodName + + "(" + paramType.asElement().getSimpleName() + ")"); } } From 41409f616ca0ef24fdf6cb8ce173a469c25ed3b0 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 15:41:03 +0100 Subject: [PATCH 010/288] set version to 3.0.0-alpha1 --- EventBus/build.gradle | 2 +- EventBusAnnotationProcessor/build.gradle | 92 ++++++++++++------------ 2 files changed, 48 insertions(+), 46 deletions(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index 153a6440..ef61ec44 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'maven' apply plugin: 'signing' group = 'de.greenrobot' -version = '2.4.0' +version = '3.0.0-alpha1' sourceCompatibility = 1.6 def isSnapshot = version.endsWith('-SNAPSHOT') diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index aa94d975..84304201 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -3,15 +3,17 @@ apply plugin: 'maven' apply plugin: 'signing' group = 'de.greenrobot' -version = '3.0.0' +version = '3.0.0-alpha1' + sourceCompatibility = 1.7 +targetCompatibility = 1.7 def isSnapshot = version.endsWith('-SNAPSHOT') def sonatypeRepositoryUrl -if(isSnapshot) { - sonatypeRepositoryUrl = "https://oss.sonatype.org/content/repositories/snapshots/" +if (isSnapshot) { + sonatypeRepositoryUrl = "https://oss.sonatype.org/content/repositories/snapshots/" } else { - sonatypeRepositoryUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" + sonatypeRepositoryUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" } repositories { @@ -53,8 +55,8 @@ artifacts { } signing { - if(project.hasProperty('signing.keyId') && project.hasProperty('signing.password') && - project.hasProperty('signing.secretKeyRingFile')) { + if (project.hasProperty('signing.keyId') && project.hasProperty('signing.password') && + project.hasProperty('signing.secretKeyRingFile')) { sign configurations.archives } else { println "Signing information missing/incomplete for ${project.name}" @@ -64,13 +66,13 @@ signing { uploadArchives { repositories { mavenDeployer { - if(project.hasProperty('preferedRepo') && project.hasProperty('preferedUsername') - && project.hasProperty('preferedPassword')) { + if (project.hasProperty('preferedRepo') && project.hasProperty('preferedUsername') + && project.hasProperty('preferedPassword')) { configuration = configurations.deployerJars repository(url: preferedRepo) { authentication(userName: preferedUsername, password: preferedPassword) } - } else if(project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePassword')) { + } else if (project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePassword')) { beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } repository(url: sonatypeRepositoryUrl) { authentication(userName: sonatypeUsername, password: sonatypePassword) @@ -81,42 +83,42 @@ uploadArchives { pom.artifactId = 'eventbus-annotation-processor' pom.project { - name 'EventBus Annotation Processor' - packaging 'jar' - description 'Precompiler for EventBus Annotations.' - url 'https://github.com/greenrobot/EventBus' - - scm { - url 'https://github.com/greenrobot/EventBus' - connection 'scm:git@github.com:greenrobot/EventBus.git' - developerConnection 'scm:git@github.com:greenrobot/EventBus.git' - } - - licenses { - license { - name 'The Apache Software License, Version 2.0' - url 'http://www.apache.org/licenses/LICENSE-2.0.txt' - distribution 'repo' - } - } - - developers { - developer { - id 'greenrobot' - name 'greenrobot' - } - } - - issueManagement { - system 'GitHub Issues' - url 'https://github.com/greenrobot/EventBus/issues' - } - - organization { - name 'greenrobot' - url 'http://greenrobot.de' - } - } + name 'EventBus Annotation Processor' + packaging 'jar' + description 'Precompiler for EventBus Annotations.' + url 'https://github.com/greenrobot/EventBus' + + scm { + url 'https://github.com/greenrobot/EventBus' + connection 'scm:git@github.com:greenrobot/EventBus.git' + developerConnection 'scm:git@github.com:greenrobot/EventBus.git' + } + + licenses { + license { + name 'The Apache Software License, Version 2.0' + url 'http://www.apache.org/licenses/LICENSE-2.0.txt' + distribution 'repo' + } + } + + developers { + developer { + id 'greenrobot' + name 'greenrobot' + } + } + + issueManagement { + system 'GitHub Issues' + url 'https://github.com/greenrobot/EventBus/issues' + } + + organization { + name 'greenrobot' + url 'http://greenrobot.de' + } + } } } } \ No newline at end of file From 65b080697364a5760551f1c8e60b184966e7b9df Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 15:41:21 +0100 Subject: [PATCH 011/288] provided scope for EventBusAnnotationProcessor --- EventBusPerformance/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index a0b4b276..46adb91b 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -16,8 +16,8 @@ repositories { dependencies { compile project(':EventBus') - compile project(':EventBusAnnotationProcessor') - compile 'com.squareup:otto:1.3.5' + provided project(':EventBusAnnotationProcessor') + compile 'com.squareup:otto:1.3.6' } android { From b492674030e1c0cbe64be8c496dbb66a20f8fb5e Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 16:08:33 +0100 Subject: [PATCH 012/288] changed log tag to EventBus --- EventBus/src/de/greenrobot/event/EventBus.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index ba759d33..dfaefeab 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -39,7 +39,7 @@ public class EventBus { /** Log tag, apps may override it. */ - public static String TAG = "Event"; + public static String TAG = "EventBus"; static volatile EventBus defaultInstance; From 83e193c78b18720ba150ef9cdc12d4d2a475c522 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 16:08:59 +0100 Subject: [PATCH 013/288] added "Subscriber method must be public" check --- .../annotationprocessor/EventBusAnnotationProcessor.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 19be88b0..61bdd3da 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -62,6 +62,11 @@ private void writeIndexEntry(BufferedWriter writer, Element element, Messager me return; } + if (!element.getModifiers().contains(Modifier.PUBLIC)) { + messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must be public", element); + return; + } + Set subscriberClassModifiers = element.getEnclosingElement().getModifiers(); if (!subscriberClassModifiers.contains(Modifier.PUBLIC)) { messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber class must be public", From 72e080b330b12773daa47585559fd99a66fd93d5 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 16:09:38 +0100 Subject: [PATCH 014/288] fixed a null problem, added index logging --- .../event/SubscriberMethodFinder.java | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index a0d70298..5e816b91 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -54,15 +54,24 @@ class SubscriberMethodFinder { subscriberMethods = new ArrayList(); newIndex.put(key, subscriberMethods); } - Method method = entry.subscriberType.getMethod(entry.methodName, entry.eventType); - SubscriberMethod subscriberMethod = new SubscriberMethod(method, entry.threadMode, entry.eventType); - subscriberMethods.add(subscriberMethod); + try { + Method method = entry.subscriberType.getMethod(entry.methodName, entry.eventType); + SubscriberMethod subscriberMethod = new SubscriberMethod(method, entry.threadMode, entry.eventType); + subscriberMethods.add(subscriberMethod); + } catch (NoSuchMethodException e) { + // Offending class is not part of standard message + throw new NoSuchMethodException(entry.subscriberType.getName() + "." + + entry.methodName + "(" + entry.eventType.getName() + ")"); + } } index = newIndex; + Log.d(EventBus.TAG, "Initialized subscriber index with " + entries.length + " entries for " + index.size() + + " classes"); } catch (ClassNotFoundException e) { + Log.d(EventBus.TAG, "No subscriber index available, reverting to dynamic look-up (slower)"); // Fine } catch (Exception e) { - Log.w("Could not init @Subscribe index, reverting to dynamic look-up (slower)", e); + Log.w(EventBus.TAG, "Could not init subscriber index, reverting to dynamic look-up (slower)", e); } METHOD_INDEX = index; } @@ -82,7 +91,7 @@ List findSubscriberMethods(Class subscriberClass) { if (subscriberMethods != null) { return subscriberMethods; } - if(METHOD_INDEX != null) { + if (METHOD_INDEX != null) { subscriberMethods = findSubscriberMethodsWithIndex(subscriberClass); } else { subscriberMethods = findSubscriberMethodsWithReflection(subscriberClass); @@ -108,7 +117,9 @@ private List findSubscriberMethodsWithIndex(Class subscribe break; } List flatList = METHOD_INDEX.get(name); - subscriberMethods.addAll(flatList); + if(flatList != null) { + subscriberMethods.addAll(flatList); + } clazz = clazz.getSuperclass(); } From 19f86df6b57cf0d9673297a5b72f2ffd92a9ab8f Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 16:12:39 +0100 Subject: [PATCH 015/288] adjusted tests to work with subscriber index (made subscriber methods and classes public) --- EventBusTest/build.gradle | 3 + .../event/test/EventBusBasicTest.java | 8 +-- .../event/test/EventBusBuilderTest.java | 6 +- .../test/EventBusCancelEventDeliveryTest.java | 6 +- .../event/test/EventBusInheritanceTest.java | 10 ++-- .../event/test/EventBusMultithreadedTest.java | 2 +- .../test/EventBusNoSubscriberEventTest.java | 2 +- .../EventBusOrderedSubscriptionsTest.java | 2 +- .../test/EventBusRegistrationRacingTest.java | 2 +- .../test/EventBusSubscriberExceptionTest.java | 2 +- .../test/EventBusSubscriberLegalTest.java | 55 ++++++++++--------- 11 files changed, 51 insertions(+), 47 deletions(-) diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 2f48f9c5..5983a7ab 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -5,16 +5,19 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:1.1.0' + classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4' } } apply plugin: 'com.android.application' +apply plugin: 'com.neenbedankt.android-apt' repositories { mavenCentral() } dependencies { + androidTestApt project(':EventBusAnnotationProcessor') androidTestCompile project(':EventBus') } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java index 464079ea..57a65d22 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java @@ -238,7 +238,7 @@ public void onEvent(MyEventExtended event) { countMyEventExtended++; } - static class TestActivity extends Activity { + public static class TestActivity extends Activity { public String lastStringEvent; @Subscribe @@ -247,13 +247,13 @@ public void onEvent(String event) { } } - class MyEvent { + public class MyEvent { } - class MyEventExtended extends MyEvent { + public class MyEventExtended extends MyEvent { } - class RepostInteger { + public class RepostInteger { public int lastEvent; public int countEvent; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java index 6896264c..2bab15e0 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java @@ -75,21 +75,21 @@ public void testEventInheritance() { eventBus.post("Foo"); } - class SubscriberExceptionEventTracker { + public class SubscriberExceptionEventTracker { @Subscribe public void onEvent(SubscriberExceptionEvent event) { trackEvent(event); } } - class NoSubscriberEventTracker { + public class NoSubscriberEventTracker { @Subscribe public void onEvent(NoSubscriberEvent event) { trackEvent(event); } } - class ThrowingSubscriber { + public class ThrowingSubscriber { @Subscribe public void onEvent(Object event) { throw new RuntimeException(); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java index 92d02f7b..0950f71c 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java @@ -77,7 +77,7 @@ public void testCancelInMainThread() { assertNotNull(failed); } - class Subscriber { + public class Subscriber { private final boolean cancel; public Subscriber(boolean cancel) { @@ -93,7 +93,7 @@ public void onEvent(String event) { } } - class SubscriberCancelOtherEvent { + public class SubscriberCancelOtherEvent { @Subscribe public void onEvent(String event) { try { @@ -104,7 +104,7 @@ public void onEvent(String event) { } } - class SubscriberMainThread { + public class SubscriberMainThread { final CountDownLatch done = new CountDownLatch(1); @Subscribe(threadMode = ThreadMode.MainThread) diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java index b7fcf9a9..bfaac04d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java @@ -117,19 +117,19 @@ public void onEvent(MyEventInterfaceExtended event) { countMyEventInterfaceExtended++; } - static interface MyEventInterface { + public static interface MyEventInterface { } - static class MyEvent implements MyEventInterface { + public static class MyEvent implements MyEventInterface { } - static interface MyEventInterfaceExtended extends MyEventInterface { + public static interface MyEventInterfaceExtended extends MyEventInterface { } - static class MyEventExtended extends MyEvent implements MyEventInterfaceExtended { + public static class MyEventExtended extends MyEvent implements MyEventInterfaceExtended { } - static class SubscriberExtended extends EventBusInheritanceTest { + public static class SubscriberExtended extends EventBusInheritanceTest { private int countMyEventOverwritten; @Subscribe diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java index 7535de6d..87d89d13 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java @@ -220,7 +220,7 @@ public void run() { } } - class SubscribeUnsubscribeThread extends Thread { + public class SubscribeUnsubscribeThread extends Thread { boolean running = true; public void shutdown() { diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java index 41339796..846816bf 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java @@ -69,7 +69,7 @@ public void onEvent(SubscriberExceptionEvent event) { trackEvent(event); } - class BadNoSubscriberSubscriber { + public class BadNoSubscriberSubscriber { @Subscribe public void onEvent(NoSubscriberEvent event) { throw new RuntimeException("I'm bad"); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java index e5e85c23..1864da54 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java @@ -89,7 +89,7 @@ protected PrioSubscriber register(int priority, boolean sticky) { return subscriber; } - private final class PrioSubscriber { + public final class PrioSubscriber { final int prio; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java index f5510fcb..7c4dbf9d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java @@ -72,7 +72,7 @@ private List startThreads() { return threads; } - class SubscriberThread implements Runnable { + public class SubscriberThread implements Runnable { volatile int eventCount; @Override diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java index 988ce720..21c79f95 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java @@ -54,7 +54,7 @@ public void onEvent(SubscriberExceptionEvent event) { trackEvent(event); } - class BadExceptionSubscriber { + public class BadExceptionSubscriber { @Subscribe public void onEvent(SubscriberExceptionEvent event) { throw new RuntimeException("Bad"); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java index 1b5c57a8..d122ece9 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java @@ -30,23 +30,24 @@ public void testSubscriberLegal() { assertEquals(1, eventCount.intValue()); } - public void testSubscriberNotPublic() { - try { - eventBus.register(new NotPublic()); - fail("Registration of ilegal subscriber successful"); - } catch (EventBusException e) { - // Expected - } - } + // With build time verification, some of these tests are obsolete (and cause problems during build) +// public void testSubscriberNotPublic() { +// try { +// eventBus.register(new NotPublic()); +// fail("Registration of ilegal subscriber successful"); +// } catch (EventBusException e) { +// // Expected +// } +// } - public void testSubscriberStatic() { - try { - eventBus.register(new Static()); - fail("Registration of ilegal subscriber successful"); - } catch (EventBusException e) { - // Expected - } - } +// public void testSubscriberStatic() { +// try { +// eventBus.register(new Static()); +// fail("Registration of ilegal subscriber successful"); +// } catch (EventBusException e) { +// // Expected +// } +// } public void testSubscriberLegalAbstract() { eventBus.register(new Abstract() { @@ -68,21 +69,21 @@ public void onEvent(String event) { trackEvent(event); } - static class NotPublic { - @Subscribe - void onEvent(String event) { - } - } +// public static class NotPublic { +// @Subscribe +// void onEvent(String event) { +// } +// } - static abstract class Abstract { + public static abstract class Abstract { @Subscribe public abstract void onEvent(String event); } - static class Static { - @Subscribe - public static void onEvent(String event) { - } - } +// public static class Static { +// @Subscribe +// public static void onEvent(String event) { +// } +// } } From 255128d043c85274ec2c0125e46bddd190a902bd Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 16:35:40 +0100 Subject: [PATCH 016/288] set version to 3.0.0-SNAPSHOT --- EventBus/build.gradle | 2 +- EventBusAnnotationProcessor/build.gradle | 5 ++--- README.md | 7 +++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index ef61ec44..b8ad8c0f 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'maven' apply plugin: 'signing' group = 'de.greenrobot' -version = '3.0.0-alpha1' +version = '3.0.0-SNAPSHOT' sourceCompatibility = 1.6 def isSnapshot = version.endsWith('-SNAPSHOT') diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index 84304201..ffe5eba5 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -3,10 +3,9 @@ apply plugin: 'maven' apply plugin: 'signing' group = 'de.greenrobot' -version = '3.0.0-alpha1' +version = '3.0.0-SNAPSHOT' -sourceCompatibility = 1.7 -targetCompatibility = 1.7 +sourceCompatibility = 1.6 def isSnapshot = version.endsWith('-SNAPSHOT') def sonatypeRepositoryUrl diff --git a/README.md b/README.md index e8bf090f..e20a9bcd 100644 --- a/README.md +++ b/README.md @@ -33,9 +33,12 @@ Add EventBus to your project ---------------------------- EventBus is available on Maven Central. Please ensure that you are using the latest version by [checking here](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22de.greenrobot%22%20AND%20a%3A%22eventbus%22) +Note: This SNAPSHOT version is only available on Sonatype's snapshot repository (https://oss.sonatype.org/content/repositories/snapshots). + Gradle: ``` - compile 'de.greenrobot:eventbus:2.4.0' + compile 'de.greenrobot:eventbus:3.0.0-SNAPSHOT' + provided 'de.greenrobot:eventbus-annotation-processor:3.0.0-SNAPSHOT' ``` Maven: @@ -43,7 +46,7 @@ Maven: de.greenrobot eventbus - 2.4.0 + 3.0.0-SNAPSHOT ``` From a1b9e3e9d50ba018088c70cb9330c83b0a851b5a Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 16:54:30 +0100 Subject: [PATCH 017/288] removed Java 7 try() from EventBusAnnotationProcessor --- .../annotationprocessor/EventBusAnnotationProcessor.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 61bdd3da..63eaf54b 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -34,7 +34,8 @@ public boolean process(Set annotations, RoundEnvironment try { String className = "MyGeneratedEventBusSubscriberIndex"; JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(className); - try (BufferedWriter writer = new BufferedWriter(sourceFile.openWriter())) { + BufferedWriter writer = new BufferedWriter(sourceFile.openWriter()); + try { writer.write("import de.greenrobot.event.SubscriberIndexEntry;\n"); writer.write("import de.greenrobot.event.ThreadMode;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); @@ -44,10 +45,12 @@ public boolean process(Set annotations, RoundEnvironment for (TypeElement annotation : annotations) { Set elements = env.getElementsAnnotatedWith(annotation); for (Element element : elements) { - writeIndexEntry(writer, element, messager); + checkAndWriteIndexEntry(writer, element, messager); } } writer.write(" };\n}\n"); + } finally { + writer.close(); } } catch (IOException e) { throw new RuntimeException(e); @@ -55,7 +58,7 @@ public boolean process(Set annotations, RoundEnvironment return true; } - private void writeIndexEntry(BufferedWriter writer, Element element, Messager messager) throws IOException { + private void checkAndWriteIndexEntry(BufferedWriter writer, Element element, Messager messager) throws IOException { Subscribe subscribe = element.getAnnotation(Subscribe.class); if (element.getModifiers().contains(Modifier.STATIC)) { messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must not be static", element); From aa7022eea162f43c10e8bbb5f1ef47c569fad979 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 20:41:04 +0100 Subject: [PATCH 018/288] README.md: added section "Limitations of the SNAPSHOT version" --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index e20a9bcd..808d044a 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,14 @@ EventBus... [![Build Status](https://travis-ci.org/greenrobot/EventBus.svg?branch=master)](https://travis-ci.org/greenrobot/EventBus) +Limitations of the SNAPSHOT version +----------------------------------- +The "subscriber index" is an optional optimization to speed up initial subscriber registration. The subscriber index is created during build time using an annotation processor. There are a couple of limitations of the current implementation: + + * Subscriber classes must be public + * Event classes must be public + * @Subscribe seems to be not recognized when inside of anonymous classes + EventBus in 4 steps ------------------- 1. Define events:
From 6a37ce715294cccc57586fd4f00352319c0899f7 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 25 Feb 2015 22:36:34 +0100 Subject: [PATCH 019/288] reworked EventBusAnnotationProcessor, dynamic creation of SubscriberMethod by subscriber index --- .../de/greenrobot/event/SubscriberIndex.java | 35 ++++ .../event/SubscriberIndexEntry.java | 17 -- .../event/SubscriberMethodFinder.java | 47 ++--- .../EventBusAnnotationProcessor.java | 179 ++++++++++++++---- 4 files changed, 188 insertions(+), 90 deletions(-) create mode 100644 EventBus/src/de/greenrobot/event/SubscriberIndex.java delete mode 100644 EventBus/src/de/greenrobot/event/SubscriberIndexEntry.java diff --git a/EventBus/src/de/greenrobot/event/SubscriberIndex.java b/EventBus/src/de/greenrobot/event/SubscriberIndex.java new file mode 100644 index 00000000..a442d1cc --- /dev/null +++ b/EventBus/src/de/greenrobot/event/SubscriberIndex.java @@ -0,0 +1,35 @@ +package de.greenrobot.event; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** Preprocessed index: base class for generated "MyGeneratedSubscriberIndex" class by annotation processing. */ +abstract class SubscriberIndex { + private Map, SubscriberMethod[]> map = new HashMap, SubscriberMethod[]>(); + + SubscriberMethod[] getSubscribersFor(Class subscriberClass) { + SubscriberMethod[] entries = map.get(subscriberClass); + if (entries == null) { + entries = createSubscribersFor(subscriberClass); + if (entries != null) { + map.put(subscriberClass, entries); + } + } + return entries; + } + + abstract SubscriberMethod[] createSubscribersFor(Class subscriberClass); + + SubscriberMethod createSubscriberMethod(Class subscriberClass, String methodName, Class eventType, + ThreadMode threadMode) { + try { + Method method = subscriberClass.getDeclaredMethod(methodName, eventType); + return new SubscriberMethod(method, threadMode, eventType); + } catch (NoSuchMethodException e) { + throw new EventBusException("Could not find subscriber method in " + subscriberClass + + ". Maybe a missing ProGuard rule?", e); + } + } + +} diff --git a/EventBus/src/de/greenrobot/event/SubscriberIndexEntry.java b/EventBus/src/de/greenrobot/event/SubscriberIndexEntry.java deleted file mode 100644 index 7a051233..00000000 --- a/EventBus/src/de/greenrobot/event/SubscriberIndexEntry.java +++ /dev/null @@ -1,17 +0,0 @@ -package de.greenrobot.event; - -/** Preprocessed index as used with annotation-preprocessed code generation */ -public class SubscriberIndexEntry { - final Class subscriberType; - final String methodName; - final Class eventType; - final ThreadMode threadMode; - - public SubscriberIndexEntry(Class subscriberType, String methodName, Class eventType, - ThreadMode threadMode) { - this.subscriberType = subscriberType; - this.methodName = methodName; - this.eventType = eventType; - this.threadMode = threadMode; - } -} diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 5e816b91..29af9226 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -26,7 +26,6 @@ import java.util.Map; class SubscriberMethodFinder { - /* * In newer class files, compilers may add methods. Those are called bridge or synthetic methods. * EventBus must ignore both. There modifiers are not public but defined in the Java class file format: @@ -39,41 +38,20 @@ class SubscriberMethodFinder { private static final Map> METHOD_CACHE = new HashMap>(); /** Optional generated index without entries from subscribers super classes */ - private static final Map> METHOD_INDEX; + private static final SubscriberIndex INDEX; static { - Map> index = null; + SubscriberIndex newIndex = null; try { - Class clazz = Class.forName("MyGeneratedEventBusSubscriberIndex"); - SubscriberIndexEntry[] entries = (SubscriberIndexEntry[]) clazz.getField("INDEX").get(null); - Map> newIndex = new HashMap>(); - for (SubscriberIndexEntry entry : entries) { - String key = entry.subscriberType.getName(); - List subscriberMethods = newIndex.get(key); - if (subscriberMethods == null) { - subscriberMethods = new ArrayList(); - newIndex.put(key, subscriberMethods); - } - try { - Method method = entry.subscriberType.getMethod(entry.methodName, entry.eventType); - SubscriberMethod subscriberMethod = new SubscriberMethod(method, entry.threadMode, entry.eventType); - subscriberMethods.add(subscriberMethod); - } catch (NoSuchMethodException e) { - // Offending class is not part of standard message - throw new NoSuchMethodException(entry.subscriberType.getName() + "." + - entry.methodName + "(" + entry.eventType.getName() + ")"); - } - } - index = newIndex; - Log.d(EventBus.TAG, "Initialized subscriber index with " + entries.length + " entries for " + index.size() - + " classes"); + Class clazz = Class.forName("de.greenrobot.event.MyGeneratedSubscriberIndex"); + newIndex = (SubscriberIndex) clazz.newInstance(); } catch (ClassNotFoundException e) { - Log.d(EventBus.TAG, "No subscriber index available, reverting to dynamic look-up (slower)"); + Log.d(EventBus.TAG, "No subscriber index available, reverting to dynamic look-up"); // Fine } catch (Exception e) { - Log.w(EventBus.TAG, "Could not init subscriber index, reverting to dynamic look-up (slower)", e); + Log.w(EventBus.TAG, "Could not init subscriber index, reverting to dynamic look-up", e); } - METHOD_INDEX = index; + INDEX = newIndex; } private final boolean strictMethodVerification; @@ -91,7 +69,7 @@ List findSubscriberMethods(Class subscriberClass) { if (subscriberMethods != null) { return subscriberMethods; } - if (METHOD_INDEX != null) { + if (INDEX != null) { subscriberMethods = findSubscriberMethodsWithIndex(subscriberClass); } else { subscriberMethods = findSubscriberMethodsWithReflection(subscriberClass); @@ -116,9 +94,12 @@ private List findSubscriberMethodsWithIndex(Class subscribe // Skip system classes, this just degrades performance break; } - List flatList = METHOD_INDEX.get(name); - if(flatList != null) { - subscriberMethods.addAll(flatList); + SubscriberMethod[] flatList = INDEX.getSubscribersFor(clazz); + if (flatList != null) { + // TODO check + for (SubscriberMethod subscriberMethod : flatList) { + subscriberMethods.add(subscriberMethod); + } } clazz = clazz.getSuperclass(); diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 63eaf54b..906e3bc2 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -11,7 +11,6 @@ import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; -import javax.lang.model.element.Name; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; @@ -19,68 +18,87 @@ import javax.tools.JavaFileObject; import java.io.BufferedWriter; import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") @SupportedSourceVersion(SourceVersion.RELEASE_6) public class EventBusAnnotationProcessor extends AbstractProcessor { + private final Map> methodsByClass = new HashMap>(); + private boolean writerRoundDone; + private int round; + @Override public boolean process(Set annotations, RoundEnvironment env) { + Messager messager = processingEnv.getMessager(); + round++; + messager.printMessage(Diagnostic.Kind.NOTE, "Processing round " + round + ", new annotations: " + + !annotations.isEmpty() + ", processingOver: " + env.processingOver()); + if (env.processingOver()) { + if (!annotations.isEmpty()) { + messager.printMessage(Diagnostic.Kind.ERROR, + "Unexpected processing state: annotations still available after processing over"); + return false; + } + } if (annotations.isEmpty()) { return false; } - Messager messager = processingEnv.getMessager(); - try { - String className = "MyGeneratedEventBusSubscriberIndex"; - JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(className); - BufferedWriter writer = new BufferedWriter(sourceFile.openWriter()); - try { - writer.write("import de.greenrobot.event.SubscriberIndexEntry;\n"); - writer.write("import de.greenrobot.event.ThreadMode;\n\n"); - writer.write("/** This class is generated by EventBus, do not edit. */\n"); - writer.write("public class " + className + " {\n"); - writer.write(" public static final SubscriberIndexEntry[] INDEX = {\n"); - - for (TypeElement annotation : annotations) { - Set elements = env.getElementsAnnotatedWith(annotation); - for (Element element : elements) { - checkAndWriteIndexEntry(writer, element, messager); + + if (writerRoundDone) { + messager.printMessage(Diagnostic.Kind.ERROR, + "Unexpected processing state: annotations still available after writing."); + } + for (TypeElement annotation : annotations) { + Set elements = env.getElementsAnnotatedWith(annotation); + for (Element element : elements) { + if (checkElement(element, messager)) { + Element classElement = element.getEnclosingElement(); + List methods = methodsByClass.get(classElement); + if (methods == null) { + methods = new ArrayList(); + methodsByClass.put(classElement, methods); } + methods.add(element); } - writer.write(" };\n}\n"); - } finally { - writer.close(); } - } catch (IOException e) { - throw new RuntimeException(e); } + + if (!methodsByClass.isEmpty()) { + writeSources(); + } else { + messager.printMessage(Diagnostic.Kind.WARNING, "No @Subscribe annotations found"); + } + writerRoundDone = true; + return true; } - private void checkAndWriteIndexEntry(BufferedWriter writer, Element element, Messager messager) throws IOException { - Subscribe subscribe = element.getAnnotation(Subscribe.class); + private boolean checkElement(Element element, Messager messager) { if (element.getModifiers().contains(Modifier.STATIC)) { messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must not be static", element); - return; + return false; } if (!element.getModifiers().contains(Modifier.PUBLIC)) { messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must be public", element); - return; + return false; } Set subscriberClassModifiers = element.getEnclosingElement().getModifiers(); if (!subscriberClassModifiers.contains(Modifier.PUBLIC)) { messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber class must be public", element.getEnclosingElement()); - return; + return false; } List parameters = ((ExecutableElement) element).getParameters(); if (parameters.size() != 1) { messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must have exactly 1 parameter", element); - return; + return false; } VariableElement param = parameters.get(0); @@ -88,19 +106,100 @@ private void checkAndWriteIndexEntry(BufferedWriter writer, Element element, Mes Set eventClassModifiers = paramType.asElement().getModifiers(); if (!eventClassModifiers.contains(Modifier.PUBLIC)) { messager.printMessage(Diagnostic.Kind.ERROR, "Event type must be public: " + paramType, param); - return; + return false; + } + return true; + } + + private void writeSources() { + String pack = "de.greenrobot.event"; + String className = "MyGeneratedSubscriberIndex"; + BufferedWriter writer = null; + try { + JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(pack + '.' + className); + writer = new BufferedWriter(sourceFile.openWriter()); + writer.write("package de.greenrobot.event;\n\n"); + // writer.write("import de.greenrobot.event.SubscriberIndexEntry;\n"); + // writer.write("import de.greenrobot.event.ThreadMode;\n\n"); + writer.write("/** This class is generated by EventBus, do not edit. */\n"); + writer.write("class " + className + " extends SubscriberIndex {\n"); + writer.write(" SubscriberMethod[] createSubscribersFor(Class subscriberClass) {\n"); + + boolean first = true; + for (Map.Entry> entry : methodsByClass.entrySet()) { + String ifPrefix; + if (first) { + ifPrefix = ""; + first = false; + } else { + ifPrefix = "} else "; + } + writeLine(writer, 2, ifPrefix + "if(subscriberClass ==", entry.getKey().asType() + ".class) {"); + writer.write(" return new SubscriberMethod[] {\n"); + writeIndexEntries(writer, entry.getValue()); + writer.write(" };\n"); + } + if (!methodsByClass.isEmpty()) { + writer.write(" }\n"); + } + writer.write(" return null;\n"); + writer.write(" };\n}\n"); + } catch (IOException e) { + throw new RuntimeException("Could not write source for " + className, e); + } finally { + try { + writer.close(); + } catch (IOException e) { + //Silent + } } + } + + + private void writeIndexEntries(BufferedWriter writer, List elements) throws IOException { + for (Element element : elements) { + Subscribe subscribe = element.getAnnotation(Subscribe.class); - String subscriberClass = element.getEnclosingElement().asType().toString(); - Name methodName = element.getSimpleName(); - writer.append(" new SubscriberIndexEntry(\n"); - writer.append(" ").append(subscriberClass).append(".class,\n"); - writer.append(" \"").append(methodName).append("\",\n"); - writer.append(" ").append(paramType.toString()).append(".class,\n"); - writer.append(" ThreadMode.").append(subscribe.threadMode().name()).append("),\n"); - - messager.printMessage(Diagnostic.Kind.NOTE, "Indexed @Subscribe at " + - element.getEnclosingElement().getSimpleName() + "." + methodName + - "(" + paramType.asElement().getSimpleName() + ")"); + List parameters = ((ExecutableElement) element).getParameters(); + VariableElement param = parameters.get(0); + DeclaredType paramType = (DeclaredType) param.asType(); + + String methodName = element.getSimpleName().toString(); + writeLine(writer, 4, "createSubscriberMethod(subscriberClass,", + "\"" + methodName + "\",", + paramType.toString() + ".class,", + "ThreadMode." + subscribe.threadMode().name() + "),"); + + processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Indexed @Subscribe at " + + element.getEnclosingElement().getSimpleName() + "." + methodName + + "(" + paramType.asElement().getSimpleName() + ")"); + } + } + + private void writeLine(BufferedWriter writer, int indentLevel, String... parts) throws IOException { + writeIndent(writer, indentLevel); + int len = indentLevel * 4; + for (int i = 0; i < parts.length; i++) { + String part = parts[i]; + if (len + part.length() > 118) { + writer.write("\n"); + if (indentLevel < 12) { + indentLevel += 2; + } + writeIndent(writer, indentLevel); + len = indentLevel * 4; + } else if (i != 0) { + writer.write(" "); + } + writer.write(part); + len += part.length(); + } + writer.write("\n"); + } + + private void writeIndent(BufferedWriter writer, int indentLevel) throws IOException { + for (int i = 0; i < indentLevel; i++) { + writer.write(" "); + } } } From 44b7004cf37ff4c2c5ce1b649d58a3a443fca891 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 25 Feb 2015 23:25:22 +0100 Subject: [PATCH 020/288] We cannot get @Subscribe annotations from anonymous classes, so fail fast --- EventBus/src/de/greenrobot/event/EventBus.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index dfaefeab..b901a209 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -160,7 +160,12 @@ public void registerSticky(Object subscriber, int priority) { } private synchronized void register(Object subscriber, boolean sticky, int priority) { - List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass()); + Class subscriberClass = subscriber.getClass(); + if(subscriberClass.isAnonymousClass()) { + // We cannot get @Subscribe annotations from anonymous classes, so fail fast + throw new EventBusException("Anonymous class cannot be registered: "+ subscriberClass); + } + List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod, sticky, priority); } From 89bb5357d7ac0bcf45696a86832cc9ee67650039 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 25 Feb 2015 23:27:07 +0100 Subject: [PATCH 021/288] generate super class hierarchy and consider method inheritance --- .../event/SubscriberMethodFinder.java | 26 +++----- .../EventBusAnnotationProcessor.java | 63 +++++++++++++------ 2 files changed, 52 insertions(+), 37 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 29af9226..ae15620e 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -20,6 +20,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -86,25 +87,16 @@ List findSubscriberMethods(Class subscriberClass) { } private List findSubscriberMethodsWithIndex(Class subscriberClass) { - List subscriberMethods = new ArrayList(); - Class clazz = subscriberClass; - while (clazz != null) { - String name = clazz.getName(); - if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) { - // Skip system classes, this just degrades performance - break; + SubscriberMethod[] array = INDEX.getSubscribersFor(subscriberClass); + if (array != null && array.length > 0) { + List subscriberMethods = new ArrayList(); + for (SubscriberMethod subscriberMethod : array) { + subscriberMethods.add(subscriberMethod); } - SubscriberMethod[] flatList = INDEX.getSubscribersFor(clazz); - if (flatList != null) { - // TODO check - for (SubscriberMethod subscriberMethod : flatList) { - subscriberMethods.add(subscriberMethod); - } - } - - clazz = clazz.getSuperclass(); + return subscriberMethods; + } else { + return Collections.EMPTY_LIST; } - return subscriberMethods; } private List findSubscriberMethodsWithReflection(Class subscriberClass) { diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 906e3bc2..6fdec9f5 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -14,12 +14,14 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; import java.io.BufferedWriter; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -52,20 +54,7 @@ public boolean process(Set annotations, RoundEnvironment messager.printMessage(Diagnostic.Kind.ERROR, "Unexpected processing state: annotations still available after writing."); } - for (TypeElement annotation : annotations) { - Set elements = env.getElementsAnnotatedWith(annotation); - for (Element element : elements) { - if (checkElement(element, messager)) { - Element classElement = element.getEnclosingElement(); - List methods = methodsByClass.get(classElement); - if (methods == null) { - methods = new ArrayList(); - methodsByClass.put(classElement, methods); - } - methods.add(element); - } - } - } + collectSubscribers(annotations, env, messager); if (!methodsByClass.isEmpty()) { writeSources(); @@ -111,6 +100,23 @@ private boolean checkElement(Element element, Messager messager) { return true; } + private void collectSubscribers(Set annotations, RoundEnvironment env, Messager messager) { + for (TypeElement annotation : annotations) { + Set elements = env.getElementsAnnotatedWith(annotation); + for (Element element : elements) { + if (checkElement(element, messager)) { + Element classElement = element.getEnclosingElement(); + List methods = methodsByClass.get(classElement); + if (methods == null) { + methods = new ArrayList(); + methodsByClass.put(classElement, methods); + } + methods.add(element); + } + } + } + } + private void writeSources() { String pack = "de.greenrobot.event"; String className = "MyGeneratedSubscriberIndex"; @@ -134,9 +140,19 @@ private void writeSources() { } else { ifPrefix = "} else "; } - writeLine(writer, 2, ifPrefix + "if(subscriberClass ==", entry.getKey().asType() + ".class) {"); + TypeElement subscriberClass = (TypeElement) entry.getKey(); + writeLine(writer, 2, ifPrefix + "if(subscriberClass ==", subscriberClass.asType() + ".class) {"); writer.write(" return new SubscriberMethod[] {\n"); - writeIndexEntries(writer, entry.getValue()); + + Set methodSignatures = new HashSet(); + writeIndexEntries(writer, null, entry.getValue(), methodSignatures); + while (subscriberClass.getSuperclass().getKind() == TypeKind.DECLARED) { + subscriberClass = (TypeElement) processingEnv.getTypeUtils().asElement(subscriberClass.getSuperclass()); + List superClassMethods = methodsByClass.get(subscriberClass); + if (superClassMethods != null) { + writeIndexEntries(writer, subscriberClass, superClassMethods, methodSignatures); + } + } writer.write(" };\n"); } if (!methodsByClass.isEmpty()) { @@ -155,17 +171,24 @@ private void writeSources() { } } - - private void writeIndexEntries(BufferedWriter writer, List elements) throws IOException { + private void writeIndexEntries(BufferedWriter writer, TypeElement subscriberClass, List elements, Set methodSignatures) throws IOException { for (Element element : elements) { - Subscribe subscribe = element.getAnnotation(Subscribe.class); List parameters = ((ExecutableElement) element).getParameters(); VariableElement param = parameters.get(0); DeclaredType paramType = (DeclaredType) param.asType(); + String methodSignature = element+">"+paramType; + if(!methodSignatures.add(methodSignature)) { + continue; + } + String methodName = element.getSimpleName().toString(); - writeLine(writer, 4, "createSubscriberMethod(subscriberClass,", + String subscriberClassString = subscriberClass == null ? "subscriberClass" : + subscriberClass.asType().toString() + ".class"; + + Subscribe subscribe = element.getAnnotation(Subscribe.class); + writeLine(writer, 4, "createSubscriberMethod(" + subscriberClassString + ",", "\"" + methodName + "\",", paramType.toString() + ".class,", "ThreadMode." + subscribe.threadMode().name() + "),"); From 1880c305ab883359728f1aac44d8a7417afb360c Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 26 Feb 2015 21:27:52 +0100 Subject: [PATCH 022/288] 2.4.1-SNAPSHOT, added testSubscriberClassHierarchyWithoutNewSubscriberMethod --- EventBus/build.gradle | 2 +- .../event/test/EventBusInheritanceTest.java | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index 153a6440..b377bf64 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'maven' apply plugin: 'signing' group = 'de.greenrobot' -version = '2.4.0' +version = '2.4.1-SNAPSHOT' sourceCompatibility = 1.6 def isSnapshot = version.endsWith('-SNAPSHOT') diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java index 27e3d7b7..90238f75 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java @@ -91,6 +91,23 @@ public void testSubscriberClassHierarchy() { assertEquals(2, subscriber.countMyEventOverwritten); } + public void testSubscriberClassHierarchyWithoutNewSubscriberMethod() { + SubscriberExtendedWithoutNewSubscriberMethod subscriber = new SubscriberExtendedWithoutNewSubscriberMethod(); + eventBus.register(subscriber); + + eventBus.post("Hello"); + assertEquals(1, subscriber.countObjectEvent); + + eventBus.post(new MyEvent()); + assertEquals(2, subscriber.countObjectEvent); + assertEquals(1, subscriber.countMyEvent); + + eventBus.post(new MyEventExtended()); + assertEquals(3, subscriber.countObjectEvent); + assertEquals(2, subscriber.countMyEvent); + assertEquals(1, subscriber.countMyEventExtended); + } + public void onEvent(Object event) { countObjectEvent++; } @@ -131,4 +148,7 @@ public void onEvent(MyEvent event) { } } + static class SubscriberExtendedWithoutNewSubscriberMethod extends EventBusInheritanceTest { + } + } From a604b625a1cf039b7febfc306b21e8298434046d Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 26 Feb 2015 23:48:15 +0100 Subject: [PATCH 023/288] Registering for sticky events now considers sticky events of subclasses (#24, #135) --- CHANGELOG.md | 3 + .../src/de/greenrobot/event/EventBus.java | 33 +++- .../test/EventBusInheritanceDisabledTest.java | 164 ++++++++++++++++++ .../event/test/EventBusInheritanceTest.java | 10 ++ 4 files changed, 202 insertions(+), 8 deletions(-) create mode 100644 EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 2db0fc27..1db6f10c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### V2.x.x (2015-0x-xx) Future release +* Registering for sticky events now considers sticky events of subclasses, not just the exact same event type. This makes the semantic consistent to posting events. Note, that this may lead to subscribers being called more than once if matching sticky events of event type subclasses are available. + ### V2.4.0 (2014-11-11) Clean up release * Removed deprecated APIs: A year ago in Version 2.2.0, a couple of EventBus methods were deprecated and flagged to be removed in a future release. Well, version 2.4.0 is that release. Clean ups like this one keep the API concise and simple. diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index 4bac5cbe..95863ade 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -23,6 +23,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; @@ -200,18 +201,34 @@ private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boo subscribedEvents.add(eventType); if (sticky) { - Object stickyEvent; - synchronized (stickyEvents) { - stickyEvent = stickyEvents.get(eventType); - } - if (stickyEvent != null) { - // If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state) - // --> Strange corner case, which we don't take care of here. - postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper()); + if (eventInheritance) { + // Existing sticky events of all subclasses of eventType have to be considered. + // Note: Iterating over all events may be inefficient with lots of sticky events, + // thus data structure should be changed to allow a more efficient lookup + // (e.g. an additional map storing sub classes of super classes: Class -> List). + Set, Object>> entries = stickyEvents.entrySet(); + for (Map.Entry, 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); } } } + private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) { + if (stickyEvent != null) { + // If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state) + // --> Strange corner case, which we don't take care of here. + postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper()); + } + } + public synchronized boolean isRegistered(Object subscriber) { return typesBySubscriber.containsKey(subscriber); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java new file mode 100644 index 00000000..43aaf467 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.greenrobot.event.test; + +import de.greenrobot.event.EventBus; +import junit.framework.TestCase; + +/** + * @author Markus Junginger, greenrobot + */ +public class EventBusInheritanceDisabledTest extends TestCase { + + private EventBus eventBus; + + protected int countMyEventExtended; + protected int countMyEvent; + protected int countObjectEvent; + private int countMyEventInterface; + private int countMyEventInterfaceExtended; + + protected void setUp() throws Exception { + super.setUp(); + eventBus = EventBus.builder().eventInheritance(false).build(); + } + + public void testEventClassHierarchy() { + eventBus.register(this); + + eventBus.post("Hello"); + assertEquals(0, countObjectEvent); + + eventBus.post(new MyEvent()); + assertEquals(0, countObjectEvent); + assertEquals(1, countMyEvent); + + eventBus.post(new MyEventExtended()); + assertEquals(0, countObjectEvent); + assertEquals(1, countMyEvent); + assertEquals(1, countMyEventExtended); + } + + public void testEventClassHierarchySticky() { + eventBus.postSticky("Hello"); + eventBus.postSticky(new MyEvent()); + eventBus.postSticky(new MyEventExtended()); + eventBus.registerSticky(this); + assertEquals(1, countMyEventExtended); + assertEquals(1, countMyEvent); + assertEquals(0, countObjectEvent); + } + + public void testEventInterfaceHierarchy() { + eventBus.register(this); + + eventBus.post(new MyEvent()); + assertEquals(0, countMyEventInterface); + + eventBus.post(new MyEventExtended()); + assertEquals(0, countMyEventInterface); + assertEquals(0, countMyEventInterfaceExtended); + } + + public void testEventSuperInterfaceHierarchy() { + eventBus.register(this); + + eventBus.post(new MyEventInterfaceExtended() { + }); + assertEquals(0, countMyEventInterface); + assertEquals(0, countMyEventInterfaceExtended); + } + + public void testSubscriberClassHierarchy() { + SubscriberExtended subscriber = new SubscriberExtended(); + eventBus.register(subscriber); + + eventBus.post("Hello"); + assertEquals(0, subscriber.countObjectEvent); + + eventBus.post(new MyEvent()); + assertEquals(0, subscriber.countObjectEvent); + assertEquals(0, subscriber.countMyEvent); + assertEquals(1, subscriber.countMyEventOverwritten); + + eventBus.post(new MyEventExtended()); + assertEquals(0, subscriber.countObjectEvent); + assertEquals(0, subscriber.countMyEvent); + assertEquals(1, subscriber.countMyEventExtended); + assertEquals(1, subscriber.countMyEventOverwritten); + } + + public void testSubscriberClassHierarchyWithoutNewSubscriberMethod() { + SubscriberExtendedWithoutNewSubscriberMethod subscriber = new SubscriberExtendedWithoutNewSubscriberMethod(); + eventBus.register(subscriber); + + eventBus.post("Hello"); + assertEquals(0, subscriber.countObjectEvent); + + eventBus.post(new MyEvent()); + assertEquals(0, subscriber.countObjectEvent); + assertEquals(1, subscriber.countMyEvent); + + eventBus.post(new MyEventExtended()); + assertEquals(0, subscriber.countObjectEvent); + assertEquals(1, subscriber.countMyEvent); + assertEquals(1, subscriber.countMyEventExtended); + } + + public void onEvent(Object event) { + countObjectEvent++; + } + + public void onEvent(MyEvent event) { + countMyEvent++; + } + + public void onEvent(MyEventExtended event) { + countMyEventExtended++; + } + + public void onEvent(MyEventInterface event) { + countMyEventInterface++; + } + + public void onEvent(MyEventInterfaceExtended event) { + countMyEventInterfaceExtended++; + } + + static interface MyEventInterface { + } + + static class MyEvent implements MyEventInterface { + } + + static interface MyEventInterfaceExtended extends MyEventInterface { + } + + static class MyEventExtended extends MyEvent implements MyEventInterfaceExtended { + } + + static class SubscriberExtended extends EventBusInheritanceDisabledTest { + private int countMyEventOverwritten; + + public void onEvent(MyEvent event) { + countMyEventOverwritten++; + } + } + + static class SubscriberExtendedWithoutNewSubscriberMethod extends EventBusInheritanceDisabledTest { + } + +} diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java index 90238f75..10384951 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java @@ -52,6 +52,16 @@ public void testEventClassHierarchy() { assertEquals(1, countMyEventExtended); } + public void testEventClassHierarchySticky() { + eventBus.postSticky("Hello"); + eventBus.postSticky(new MyEvent()); + eventBus.postSticky(new MyEventExtended()); + eventBus.registerSticky(this); + assertEquals(1, countMyEventExtended); + assertEquals(2, countMyEvent); + assertEquals(3, countObjectEvent); + } + public void testEventInterfaceHierarchy() { eventBus.register(this); From 1aa2e3353b4882034cd3e25c561af4b092a67d6d Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 27 Feb 2015 00:08:53 +0100 Subject: [PATCH 024/288] use fenced code blocks to make visible --- HOWTO.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/HOWTO.md b/HOWTO.md index ab0729ca..5016e6d7 100644 --- a/HOWTO.md +++ b/HOWTO.md @@ -186,7 +186,9 @@ It's also possible to remove previously posted sticky events using one of the re ProGuard configuration ---------------------- ProGuard obfuscates method names. However, the onEvent methods must not renamed because they are accessed using reflection. Use the following snip in your ProGuard configuration file (proguard.cfg): -
-keepclassmembers class ** {
+
+```
+-keepclassmembers class ** {
     public void onEvent*(**);
 }
 
@@ -194,7 +196,7 @@ ProGuard obfuscates method names. However, the onEvent methods must not renamed
 -keepclassmembers class * extends de.greenrobot.event.util.ThrowableFailureEvent {
     (java.lang.Throwable);
 }
-
+``` AsyncExecutor From 996c6732e9b49546d8e8c68d80f4afb372b9a4e3 Mon Sep 17 00:00:00 2001 From: Marcin Mikosik Date: Sun, 1 Mar 2015 19:40:05 +0100 Subject: [PATCH 025/288] fixed typos in HOWTO.md --- HOWTO.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/HOWTO.md b/HOWTO.md index 5016e6d7..8661770c 100644 --- a/HOWTO.md +++ b/HOWTO.md @@ -113,7 +113,7 @@ EventBus 2.3 added EventBusBuilder to configure various aspects of EventBus. For EventBus eventBus = EventBus.builder().logNoSubscriberMessages(false).sendNoSubscriberEvent(false).build(); ``` -Another example is to fail when a subscriber throws an exception. Note: by default, EventBus catches exceptions thrown from onEvent methods and sends an SubscriberExceptionEvent that may but do not have to be handled. +Another example is to fail when a subscriber throws an exception. Note: by default, EventBus catches exceptions thrown from onEvent methods and sends a SubscriberExceptionEvent that may but do not have to be handled. ```java EventBus eventBus = EventBus.builder().throwSubscriberException(true).build(); @@ -122,7 +122,7 @@ Another example is to fail when a subscriber throws an exception. Note: by defau Check the EventBusBuilder class and its JavaDoc for all possible configuration possibilities. ### Configure the default EventBus instance ### -Using EventBus.getDefault() is a simple way to get an shared EventBus instance. EventBusBuilder also allows to configure this default instance using the method installDefaultEventBus(). +Using EventBus.getDefault() is a simple way to get a shared EventBus instance. EventBusBuilder also allows to configure this default instance using the method installDefaultEventBus(). For example, it's possible to configure the default EventBus instance to rethrow exceptions, which occurred in onEvent methods. But let's to this only for DEBUG builds, because this will likely crash the app on exceptions: @@ -152,7 +152,7 @@ Sticky Events ------------- Some events carry information that is of interest after the event is posted. For example, this could be an event signalizing that some initialization is complete. Or if you have some sensor or location data and you want to hold on the most recent values. Instead of implementing your own caching, you can use sticky events. EventBus keeps the last sticky event of a certain type in memory. The sticky event can be delivered to subscribers or queried explicitly. Thus, you don't need any special logic to consider already available data. -Let's say, an sticky event was posted some time ago: +Let's say, a sticky event was posted some time ago: ```java EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!")); ``` @@ -239,7 +239,7 @@ AsyncExecutor Builder --------------------- If you want to customize your AsyncExecutor instance, call the static method AsyncExecutor.builder(). It will return a builder which lets you customize the EventBus instance, the thread pool, and the class of the failure event. -Another customization options is the execution scope, which gives failure events context information. For example, an failure event may be relevant only to a specific Activity instance or class. If your custom failure event class implements the HasExecutionScope interface, AsyncExecutor will set the execution scope automatically. Like this, your subscriber can query the failure event for its execution scope and react depending on it. +Another customization options is the execution scope, which gives failure events context information. For example, a failure event may be relevant only to a specific Activity instance or class. If your custom failure event class implements the HasExecutionScope interface, AsyncExecutor will set the execution scope automatically. Like this, your subscriber can query the failure event for its execution scope and react depending on it. Comparison with Square's Otto From 251f64ec7d442a43f3d04c0a686adc4117a6ce76 Mon Sep 17 00:00:00 2001 From: Markus Date: Sun, 8 Mar 2015 20:05:02 +0100 Subject: [PATCH 026/288] adjustments in test project for annotations: no anonymous subscriber classes, public event and subscriber classes --- .../event/test/EventBusBasicTest.java | 24 +++++++++++-------- .../test/EventBusInheritanceDisabledTest.java | 17 +++++++++---- .../test/EventBusNoSubscriberEventTest.java | 14 ++++++----- .../event/test/EventBusStickyEventTest.java | 15 ++++++------ .../test/EventBusSubscriberLegalTest.java | 20 +++++++++------- 5 files changed, 53 insertions(+), 37 deletions(-) diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java index 57a65d22..7ee87e68 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java @@ -187,11 +187,7 @@ public void testHasSubscriberForEvent() { public void testHasSubscriberForEventSuperclass() { assertFalse(eventBus.hasSubscriberForEvent(String.class)); - Object subscriber = new Object() { - @Subscribe - public void onEvent(Object event) { - } - }; + Object subscriber = new ObjectSubscriber(); eventBus.register(subscriber); assertTrue(eventBus.hasSubscriberForEvent(String.class)); @@ -202,11 +198,7 @@ public void onEvent(Object event) { public void testHasSubscriberForEventImplementedInterface() { assertFalse(eventBus.hasSubscriberForEvent(String.class)); - Object subscriber = new Object() { - @Subscribe - public void onEvent(CharSequence event) { - } - }; + Object subscriber = new CharSequenceSubscriber(); eventBus.register(subscriber); assertTrue(eventBus.hasSubscriberForEvent(CharSequence.class)); assertTrue(eventBus.hasSubscriberForEvent(String.class)); @@ -247,6 +239,18 @@ public void onEvent(String event) { } } + public static class CharSequenceSubscriber { + @Subscribe + public void onEvent(CharSequence event) { + } + } + + public static class ObjectSubscriber { + @Subscribe + public void onEvent(Object event) { + } + } + public class MyEvent { } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java index 43aaf467..20a5195c 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java @@ -16,6 +16,7 @@ package de.greenrobot.event.test; import de.greenrobot.event.EventBus; +import de.greenrobot.event.Subscribe; import junit.framework.TestCase; /** @@ -118,41 +119,47 @@ public void testSubscriberClassHierarchyWithoutNewSubscriberMethod() { assertEquals(1, subscriber.countMyEventExtended); } + @Subscribe public void onEvent(Object event) { countObjectEvent++; } + @Subscribe public void onEvent(MyEvent event) { countMyEvent++; } + @Subscribe public void onEvent(MyEventExtended event) { countMyEventExtended++; } + @Subscribe public void onEvent(MyEventInterface event) { countMyEventInterface++; } + @Subscribe public void onEvent(MyEventInterfaceExtended event) { countMyEventInterfaceExtended++; } - static interface MyEventInterface { + public static interface MyEventInterface { } - static class MyEvent implements MyEventInterface { + public static class MyEvent implements MyEventInterface { } - static interface MyEventInterfaceExtended extends MyEventInterface { + public static interface MyEventInterfaceExtended extends MyEventInterface { } - static class MyEventExtended extends MyEvent implements MyEventInterfaceExtended { + public static class MyEventExtended extends MyEvent implements MyEventInterfaceExtended { } - static class SubscriberExtended extends EventBusInheritanceDisabledTest { + public static class SubscriberExtended extends EventBusInheritanceDisabledTest { private int countMyEventOverwritten; + @Subscribe public void onEvent(MyEvent event) { countMyEventOverwritten++; } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java index 846816bf..f6d7516b 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java @@ -36,12 +36,7 @@ public void testNoSubscriberEvent() { } public void testNoSubscriberEventAfterUnregister() { - Object subscriber = new Object() { - @SuppressWarnings("unused") - @Subscribe - public void onEvent(String dummy) { - } - }; + Object subscriber = new DummySubscriber(); eventBus.register(subscriber); eventBus.unregister(subscriber); testNoSubscriberEvent(); @@ -69,6 +64,13 @@ public void onEvent(SubscriberExceptionEvent event) { trackEvent(event); } + public static class DummySubscriber { + @SuppressWarnings("unused") + @Subscribe + public void onEvent(String dummy) { + } + } + public class BadNoSubscriberSubscriber { @Subscribe public void onEvent(NoSubscriberEvent event) { diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java index 084b1be6..9223bb32 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java @@ -119,13 +119,7 @@ public void testPostStickyRemoveAll() throws InterruptedException { } public void testRemoveStickyEventInSubscriber() throws InterruptedException { - eventBus.registerSticky(new Object() { - @SuppressWarnings("unused") - @Subscribe - public void onEvent(String event) { - eventBus.removeStickyEvent(event); - } - }); + eventBus.registerSticky(new RemoveStickySubscriber()); eventBus.postSticky("Sticky"); eventBus.registerSticky(this); assertNull(lastEvent); @@ -143,4 +137,11 @@ public void onEvent(IntTestEvent event) { trackEvent(event); } + public class RemoveStickySubscriber { + @SuppressWarnings("unused") + @Subscribe + public void onEvent(String event) { + eventBus.removeStickyEvent(event); + } + } } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java index d122ece9..1c84dda6 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java @@ -50,15 +50,7 @@ public void testSubscriberLegal() { // } public void testSubscriberLegalAbstract() { - eventBus.register(new Abstract() { - - @Override - @Subscribe - public void onEvent(String event) { - trackEvent(event); - } - - }); + eventBus.register(new AbstractImpl()); eventBus.post("42"); assertEquals(1, eventCount.intValue()); @@ -80,6 +72,16 @@ public static abstract class Abstract { public abstract void onEvent(String event); } + public class AbstractImpl extends Abstract { + + @Override + @Subscribe + public void onEvent(String event) { + trackEvent(event); + } + + } + // public static class Static { // @Subscribe // public static void onEvent(String event) { From 232a70fa22f21c3f675badb4415c34760e63af51 Mon Sep 17 00:00:00 2001 From: Markus Date: Sun, 8 Mar 2015 20:17:51 +0100 Subject: [PATCH 027/288] fix: query superclasses when using subscriber index --- .../event/SubscriberMethodFinder.java | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index ae15620e..35b982e3 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -87,16 +87,25 @@ List findSubscriberMethods(Class subscriberClass) { } private List findSubscriberMethodsWithIndex(Class subscriberClass) { - SubscriberMethod[] array = INDEX.getSubscribersFor(subscriberClass); - if (array != null && array.length > 0) { - List subscriberMethods = new ArrayList(); - for (SubscriberMethod subscriberMethod : array) { - subscriberMethods.add(subscriberMethod); + Class clazz = subscriberClass; + while (clazz != null) { + SubscriberMethod[] array = INDEX.getSubscribersFor(clazz); + if (array != null && array.length > 0) { + List subscriberMethods = new ArrayList(); + for (SubscriberMethod subscriberMethod : array) { + subscriberMethods.add(subscriberMethod); + } + return subscriberMethods; + } else { + String name = clazz.getName(); + if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) { + // Skip system classes, this just degrades performance + break; + } + clazz = clazz.getSuperclass(); } - return subscriberMethods; - } else { - return Collections.EMPTY_LIST; } + return Collections.EMPTY_LIST; } private List findSubscriberMethodsWithReflection(Class subscriberClass) { From 8084e31e5a85c198df7119b6195449589f40b58d Mon Sep 17 00:00:00 2001 From: Markus Date: Sun, 8 Mar 2015 20:25:39 +0100 Subject: [PATCH 028/288] added testMultipleSubscribeMethodsForEvent --- .../greenrobot/event/test/EventBusBasicTest.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java index 7ee87e68..ad8c20f2 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java @@ -35,6 +35,7 @@ public class EventBusBasicTest extends TestCase { private int lastIntEvent; private int countMyEventExtended; private int countMyEvent; + private int countMyEvent2; protected void setUp() throws Exception { super.setUp(); @@ -130,6 +131,14 @@ public void testPostMultipleTimes() { assertEquals(count, countMyEvent); } + public void testMultipleSubscribeMethodsForEvent() { + eventBus.register(this); + MyEvent event = new MyEvent(); + eventBus.post(event); + assertEquals(1, countMyEvent); + assertEquals(1, countMyEvent2); + } + public void testPostAfterUnregister() { eventBus.register(this); eventBus.unregister(this); @@ -225,6 +234,11 @@ public void onEvent(MyEvent event) { countMyEvent++; } + @Subscribe + public void onEvent2(MyEvent event) { + countMyEvent2++; + } + @Subscribe public void onEvent(MyEventExtended event) { countMyEventExtended++; From ecfc93a28059c021eadea45381bcb891cd2aa9b8 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 25 May 2015 03:38:52 +0200 Subject: [PATCH 029/288] @Subscribe in anonymous classes is invisible to annotation processing, always fall back to reflection --- .../src/de/greenrobot/event/EventBus.java | 9 +++--- .../event/SubscriberMethodFinder.java | 4 +-- .../EventBusAnnotationProcessor.java | 4 +-- .../event/test/EventBusInheritanceTest.java | 29 +++++++++++++++++++ 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index 85075b7c..bd2b95a0 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -162,11 +162,10 @@ public void registerSticky(Object subscriber, int priority) { private synchronized void register(Object subscriber, boolean sticky, int priority) { Class subscriberClass = subscriber.getClass(); - if(subscriberClass.isAnonymousClass()) { - // We cannot get @Subscribe annotations from anonymous classes, so fail fast - throw new EventBusException("Anonymous class cannot be registered: "+ subscriberClass); - } - List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); + // @Subscribe in anonymous classes is invisible to annotation processing, always fall back to reflection + boolean forceReflection = subscriberClass.isAnonymousClass(); + List subscriberMethods = + subscriberMethodFinder.findSubscriberMethods(subscriberClass, forceReflection); for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod, sticky, priority); } diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 35b982e3..10864cc8 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -61,7 +61,7 @@ class SubscriberMethodFinder { this.strictMethodVerification = strictMethodVerification; } - List findSubscriberMethods(Class subscriberClass) { + List findSubscriberMethods(Class subscriberClass, boolean forceReflection) { String key = subscriberClass.getName(); List subscriberMethods; synchronized (METHOD_CACHE) { @@ -70,7 +70,7 @@ List findSubscriberMethods(Class subscriberClass) { if (subscriberMethods != null) { return subscriberMethods; } - if (INDEX != null) { + if (INDEX != null && !forceReflection) { subscriberMethods = findSubscriberMethodsWithIndex(subscriberClass); } else { subscriberMethods = findSubscriberMethodsWithReflection(subscriberClass); diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 6fdec9f5..30aa8024 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -178,8 +178,8 @@ private void writeIndexEntries(BufferedWriter writer, TypeElement subscriberClas VariableElement param = parameters.get(0); DeclaredType paramType = (DeclaredType) param.asType(); - String methodSignature = element+">"+paramType; - if(!methodSignatures.add(methodSignature)) { + String methodSignature = element + ">" + paramType; + if (!methodSignatures.add(methodSignature)) { continue; } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java index 1de6943a..7bcea781 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java @@ -19,6 +19,9 @@ import junit.framework.TestCase; import de.greenrobot.event.EventBus; +import java.util.ArrayList; +import java.util.List; + /** * @author Markus Junginger, greenrobot */ @@ -102,6 +105,32 @@ public void testSubscriberClassHierarchy() { assertEquals(2, subscriber.countMyEventOverwritten); } + public void testSubscriberClassHierarchyAnonymousExtension() { + SubscriberExtended subscriber = new SubscriberExtended() { + + }; + eventBus.register(subscriber); + + eventBus.post("Hello"); + assertEquals(1, subscriber.countObjectEvent); + } + + public void testSubscriberClassHierarchyAnonymous() { + final List received = new ArrayList(); + Object subscriber = new Object() { + @Subscribe + public void onEvent(String event) { + received.add(event); + } + }; + eventBus.register(subscriber); + + eventBus.post("Hello"); + assertEquals(1, received.size()); + assertEquals("Hello", received.get(0)); + } + + public void testSubscriberClassHierarchyWithoutNewSubscriberMethod() { SubscriberExtendedWithoutNewSubscriberMethod subscriber = new SubscriberExtendedWithoutNewSubscriberMethod(); eventBus.register(subscriber); From db5bf136c4fb017eec203784dd9d6671255eb34a Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 26 May 2015 02:43:02 +0200 Subject: [PATCH 030/288] Extracted 2 test into EventBusFallbackToReflectionTest --- .../EventBusFallbackToReflectionTest.java | 56 +++++++++++++++++++ .../event/test/EventBusInheritanceTest.java | 26 --------- 2 files changed, 56 insertions(+), 26 deletions(-) create mode 100644 EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java new file mode 100644 index 00000000..dc04cd1d --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java @@ -0,0 +1,56 @@ +package de.greenrobot.event.test; + +import de.greenrobot.event.Subscribe; + +import java.util.ArrayList; +import java.util.List; + +/** TODO */ +public class EventBusFallbackToReflectionTest extends AbstractEventBusTest { + public class PublicSuperClass { + @Subscribe + public void onEvent(Object any) { + trackEvent(any); + } + } + +// private class PrivateSuperClass { +// @Subscribe +// public void onEvent(Object any) { +// trackEvent(any); +// } +// } + + public EventBusFallbackToReflectionTest() { + super(true); + } + + public void testAnonymousSubscriberClass() { + Object subscriber = new Object() { + @Subscribe + public void onEvent(String event) { + trackEvent(event); + } + }; + eventBus.register(subscriber); + + eventBus.post("Hello"); + assertEquals("Hello", lastEvent); + assertEquals(1, eventsReceived.size()); + } + + public void testAnonymousSubscriberClassWithPublicSuperclass() { + Object subscriber = new PublicSuperClass() { + @Subscribe + public void onEvent(String event) { + trackEvent(event); + } + }; + eventBus.register(subscriber); + + eventBus.post("Hello"); + assertEquals("Hello", lastEvent); + assertEquals(2, eventsReceived.size()); + } + +} diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java index 7bcea781..dd93a757 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java @@ -105,32 +105,6 @@ public void testSubscriberClassHierarchy() { assertEquals(2, subscriber.countMyEventOverwritten); } - public void testSubscriberClassHierarchyAnonymousExtension() { - SubscriberExtended subscriber = new SubscriberExtended() { - - }; - eventBus.register(subscriber); - - eventBus.post("Hello"); - assertEquals(1, subscriber.countObjectEvent); - } - - public void testSubscriberClassHierarchyAnonymous() { - final List received = new ArrayList(); - Object subscriber = new Object() { - @Subscribe - public void onEvent(String event) { - received.add(event); - } - }; - eventBus.register(subscriber); - - eventBus.post("Hello"); - assertEquals(1, received.size()); - assertEquals("Hello", received.get(0)); - } - - public void testSubscriberClassHierarchyWithoutNewSubscriberMethod() { SubscriberExtendedWithoutNewSubscriberMethod subscriber = new SubscriberExtendedWithoutNewSubscriberMethod(); eventBus.register(subscriber); From f5106bc144f2f0ba89c90b0b64766f06a248ec90 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 1 Jun 2015 23:21:08 +0200 Subject: [PATCH 031/288] subscriber index: skip subscriber classes that are non-public or use non-public events (directly or in superclasses) --- .../event/SubscriberMethodFinder.java | 5 +- .../EventBusAnnotationProcessor.java | 192 ++++++++++++------ .../EventBusFallbackToReflectionTest.java | 29 ++- 3 files changed, 152 insertions(+), 74 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 10864cc8..f6699f70 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -44,7 +44,7 @@ class SubscriberMethodFinder { static { SubscriberIndex newIndex = null; try { - Class clazz = Class.forName("de.greenrobot.event.MyGeneratedSubscriberIndex"); + Class clazz = Class.forName("de.greenrobot.event.GeneratedSubscriberIndex"); newIndex = (SubscriberIndex) clazz.newInstance(); } catch (ClassNotFoundException e) { Log.d(EventBus.TAG, "No subscriber index available, reverting to dynamic look-up"); @@ -72,6 +72,9 @@ List findSubscriberMethods(Class subscriberClass, boolean f } if (INDEX != null && !forceReflection) { subscriberMethods = findSubscriberMethodsWithIndex(subscriberClass); + if (subscriberMethods.isEmpty()) { + subscriberMethods = findSubscriberMethodsWithReflection(subscriberClass); + } } else { subscriberMethods = findSubscriberMethodsWithReflection(subscriberClass); } diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 30aa8024..1af29114 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -29,44 +29,75 @@ @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") @SupportedSourceVersion(SourceVersion.RELEASE_6) public class EventBusAnnotationProcessor extends AbstractProcessor { - private final Map> methodsByClass = new HashMap>(); + private final Map> methodsByClass = + new HashMap>(); + private final Set classesToSkip = new HashSet(); + private boolean writerRoundDone; private int round; @Override public boolean process(Set annotations, RoundEnvironment env) { Messager messager = processingEnv.getMessager(); - round++; - messager.printMessage(Diagnostic.Kind.NOTE, "Processing round " + round + ", new annotations: " + - !annotations.isEmpty() + ", processingOver: " + env.processingOver()); - if (env.processingOver()) { - if (!annotations.isEmpty()) { - messager.printMessage(Diagnostic.Kind.ERROR, - "Unexpected processing state: annotations still available after processing over"); + try { + round++; + messager.printMessage(Diagnostic.Kind.NOTE, "Processing round " + round + ", new annotations: " + + !annotations.isEmpty() + ", processingOver: " + env.processingOver()); + if (env.processingOver()) { + if (!annotations.isEmpty()) { + messager.printMessage(Diagnostic.Kind.ERROR, + "Unexpected processing state: annotations still available after processing over"); + return false; + } + } + if (annotations.isEmpty()) { return false; } - } - if (annotations.isEmpty()) { - return false; - } - if (writerRoundDone) { - messager.printMessage(Diagnostic.Kind.ERROR, - "Unexpected processing state: annotations still available after writing."); - } - collectSubscribers(annotations, env, messager); + if (writerRoundDone) { + messager.printMessage(Diagnostic.Kind.ERROR, + "Unexpected processing state: annotations still available after writing."); + } + collectSubscribers(annotations, env, messager); + checkForSubscribersToSkip(messager); - if (!methodsByClass.isEmpty()) { - writeSources(); - } else { - messager.printMessage(Diagnostic.Kind.WARNING, "No @Subscribe annotations found"); + if (!methodsByClass.isEmpty()) { + writeSources(); + } else { + messager.printMessage(Diagnostic.Kind.WARNING, "No @Subscribe annotations found"); + } + writerRoundDone = true; + } catch (RuntimeException e) { + // IntelliJ does not handle exceptions nicely, so log and print a message + e.printStackTrace(); + messager.printMessage(Diagnostic.Kind.ERROR, "Unexpected error in EventBusAnnotationProcessor: " + e); } - writerRoundDone = true; - return true; } - private boolean checkElement(Element element, Messager messager) { + private void collectSubscribers(Set annotations, RoundEnvironment env, Messager messager) { + for (TypeElement annotation : annotations) { + Set elements = env.getElementsAnnotatedWith(annotation); + for (Element element : elements) { + if (element instanceof ExecutableElement) { + ExecutableElement method = (ExecutableElement) element; + if (checkHasErrors(method, messager)) { + Element classElement = method.getEnclosingElement(); + List methods = methodsByClass.get(classElement); + if (methods == null) { + methods = new ArrayList(); + methodsByClass.put((TypeElement) classElement, methods); + } + methods.add(method); + } + } else { + messager.printMessage(Diagnostic.Kind.ERROR, "@Subscribe is only valid for methods", element); + } + } + } + } + + private boolean checkHasErrors(ExecutableElement element, Messager messager) { if (element.getModifiers().contains(Modifier.STATIC)) { messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must not be static", element); return false; @@ -77,49 +108,78 @@ private boolean checkElement(Element element, Messager messager) { return false; } - Set subscriberClassModifiers = element.getEnclosingElement().getModifiers(); - if (!subscriberClassModifiers.contains(Modifier.PUBLIC)) { - messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber class must be public", - element.getEnclosingElement()); - return false; - } - List parameters = ((ExecutableElement) element).getParameters(); if (parameters.size() != 1) { messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must have exactly 1 parameter", element); return false; } - - VariableElement param = parameters.get(0); - DeclaredType paramType = (DeclaredType) param.asType(); - Set eventClassModifiers = paramType.asElement().getModifiers(); - if (!eventClassModifiers.contains(Modifier.PUBLIC)) { - messager.printMessage(Diagnostic.Kind.ERROR, "Event type must be public: " + paramType, param); - return false; - } return true; } - private void collectSubscribers(Set annotations, RoundEnvironment env, Messager messager) { - for (TypeElement annotation : annotations) { - Set elements = env.getElementsAnnotatedWith(annotation); - for (Element element : elements) { - if (checkElement(element, messager)) { - Element classElement = element.getEnclosingElement(); - List methods = methodsByClass.get(classElement); - if (methods == null) { - methods = new ArrayList(); - methodsByClass.put(classElement, methods); + private void checkForSubscribersToSkip(Messager messager) { + for (Map.Entry> entry : methodsByClass.entrySet()) { + TypeElement skipCandidate = entry.getKey(); + TypeElement subscriberClass = skipCandidate; + while (subscriberClass != null) { + if (!subscriberClass.getModifiers().contains(Modifier.PUBLIC)) { + boolean added = classesToSkip.add(skipCandidate); + if (added) { + String msg; + if (subscriberClass.equals(skipCandidate)) { + msg = "Falling back to reflection because class is not public"; + } else { + msg = "Falling back to reflection because " + skipCandidate + + " has a non-public super class"; + } + messager.printMessage(Diagnostic.Kind.NOTE, msg, subscriberClass); } - methods.add(element); + break; } + List methods = methodsByClass.get(subscriberClass); + if (methods != null) { + for (ExecutableElement method : methods) { + VariableElement param = method.getParameters().get(0); + DeclaredType paramType = (DeclaredType) param.asType(); + Set eventClassModifiers = paramType.asElement().getModifiers(); + if (!eventClassModifiers.contains(Modifier.PUBLIC)) { + boolean added = classesToSkip.add(skipCandidate); + if (added) { + String msg; + if (subscriberClass.equals(skipCandidate)) { + msg = "Falling back to reflection because event type is not public"; + } else { + msg = "Falling back to reflection because " + skipCandidate + + " has a super class using a non-public event type"; + } + messager.printMessage(Diagnostic.Kind.NOTE, msg, subscriberClass); + } + break; + } + } + } + subscriberClass = getSuperclass(subscriberClass); } } } + private TypeElement getSuperclass(TypeElement type) { + if (type.getSuperclass().getKind() == TypeKind.DECLARED) { + TypeElement superclass = (TypeElement) processingEnv.getTypeUtils().asElement(type.getSuperclass()); + String name = superclass.getQualifiedName().toString(); + if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) { + // Skip system classes, this just degrades performance + return null; + } else { + return superclass; + } + } else { + return null; + } + } + private void writeSources() { String pack = "de.greenrobot.event"; - String className = "MyGeneratedSubscriberIndex"; + String className = "GeneratedSubscriberIndex"; BufferedWriter writer = null; try { JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(pack + '.' + className); @@ -132,7 +192,11 @@ private void writeSources() { writer.write(" SubscriberMethod[] createSubscribersFor(Class subscriberClass) {\n"); boolean first = true; - for (Map.Entry> entry : methodsByClass.entrySet()) { + for (Map.Entry> entry : methodsByClass.entrySet()) { + TypeElement subscriberClass = entry.getKey(); + if (classesToSkip.contains(subscriberClass)) { + continue; + } String ifPrefix; if (first) { ifPrefix = ""; @@ -140,18 +204,18 @@ private void writeSources() { } else { ifPrefix = "} else "; } - TypeElement subscriberClass = (TypeElement) entry.getKey(); writeLine(writer, 2, ifPrefix + "if(subscriberClass ==", subscriberClass.asType() + ".class) {"); writer.write(" return new SubscriberMethod[] {\n"); Set methodSignatures = new HashSet(); writeIndexEntries(writer, null, entry.getValue(), methodSignatures); - while (subscriberClass.getSuperclass().getKind() == TypeKind.DECLARED) { - subscriberClass = (TypeElement) processingEnv.getTypeUtils().asElement(subscriberClass.getSuperclass()); - List superClassMethods = methodsByClass.get(subscriberClass); + TypeElement superclass = getSuperclass(subscriberClass); + while (superclass != null) { + List superClassMethods = methodsByClass.get(superclass); if (superClassMethods != null) { - writeIndexEntries(writer, subscriberClass, superClassMethods, methodSignatures); + writeIndexEntries(writer, superclass, superClassMethods, methodSignatures); } + superclass = getSuperclass(superclass); } writer.write(" };\n"); } @@ -171,30 +235,30 @@ private void writeSources() { } } - private void writeIndexEntries(BufferedWriter writer, TypeElement subscriberClass, List elements, Set methodSignatures) throws IOException { - for (Element element : elements) { + private void writeIndexEntries(BufferedWriter writer, TypeElement subscriberClass, List methods, Set methodSignatures) throws IOException { + for (ExecutableElement method : methods) { - List parameters = ((ExecutableElement) element).getParameters(); + List parameters = method.getParameters(); VariableElement param = parameters.get(0); DeclaredType paramType = (DeclaredType) param.asType(); - String methodSignature = element + ">" + paramType; + String methodSignature = method + ">" + paramType; if (!methodSignatures.add(methodSignature)) { continue; } - String methodName = element.getSimpleName().toString(); + String methodName = method.getSimpleName().toString(); String subscriberClassString = subscriberClass == null ? "subscriberClass" : subscriberClass.asType().toString() + ".class"; - Subscribe subscribe = element.getAnnotation(Subscribe.class); + Subscribe subscribe = method.getAnnotation(Subscribe.class); writeLine(writer, 4, "createSubscriberMethod(" + subscriberClassString + ",", "\"" + methodName + "\",", paramType.toString() + ".class,", "ThreadMode." + subscribe.threadMode().name() + "),"); processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Indexed @Subscribe at " + - element.getEnclosingElement().getSimpleName() + "." + methodName + + method.getEnclosingElement().getSimpleName() + "." + methodName + "(" + paramType.asElement().getSimpleName() + ")"); } } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java index dc04cd1d..7c5d46ae 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java @@ -2,9 +2,6 @@ import de.greenrobot.event.Subscribe; -import java.util.ArrayList; -import java.util.List; - /** TODO */ public class EventBusFallbackToReflectionTest extends AbstractEventBusTest { public class PublicSuperClass { @@ -14,12 +11,19 @@ public void onEvent(Object any) { } } -// private class PrivateSuperClass { -// @Subscribe -// public void onEvent(Object any) { -// trackEvent(any); -// } -// } + private class PrivateSuperClass { + @Subscribe + public void onEvent(Object any) { + trackEvent(any); + } + } + + public class PublicWithPrivateSuperClass extends PrivateSuperClass { + @Subscribe + public void onEvent(String any) { + trackEvent(any); + } + } public EventBusFallbackToReflectionTest() { super(true); @@ -53,4 +57,11 @@ public void onEvent(String event) { assertEquals(2, eventsReceived.size()); } + public void testAnonymousSubscriberClassWithPrivateSuperclass() { + eventBus.register(new PublicWithPrivateSuperClass()); + eventBus.post("Hello"); + assertEquals("Hello", lastEvent); + assertEquals(2, eventsReceived.size()); + } + } From 8f2088e4e407e33d0b953409c8f916d92bd71760 Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 2 Jun 2015 20:09:30 +0200 Subject: [PATCH 032/288] added tests for private event classes --- .../EventBusFallbackToReflectionTest.java | 41 +++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java index 7c5d46ae..a85cfcaf 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java @@ -4,27 +4,44 @@ /** TODO */ public class EventBusFallbackToReflectionTest extends AbstractEventBusTest { - public class PublicSuperClass { + private class PrivateEvent { + } + + public class PublicClass { @Subscribe public void onEvent(Object any) { trackEvent(any); } } - private class PrivateSuperClass { + private class PrivateClass { @Subscribe public void onEvent(Object any) { trackEvent(any); } } - public class PublicWithPrivateSuperClass extends PrivateSuperClass { + public class PublicWithPrivateSuperClass extends PrivateClass { @Subscribe public void onEvent(String any) { trackEvent(any); } } + public class PublicClassWithPrivateEvent { + @Subscribe + public void onEvent(PrivateEvent any) { + trackEvent(any); + } + } + + public class PublicWithPrivateEventInSuperclass extends PublicClassWithPrivateEvent { + @Subscribe + public void onEvent(Object any) { + trackEvent(any); + } + } + public EventBusFallbackToReflectionTest() { super(true); } @@ -44,7 +61,7 @@ public void onEvent(String event) { } public void testAnonymousSubscriberClassWithPublicSuperclass() { - Object subscriber = new PublicSuperClass() { + Object subscriber = new PublicClass() { @Subscribe public void onEvent(String event) { trackEvent(event); @@ -64,4 +81,20 @@ public void testAnonymousSubscriberClassWithPrivateSuperclass() { assertEquals(2, eventsReceived.size()); } + public void testSubscriberClassWithPrivateEvent() { + eventBus.register(new PublicClassWithPrivateEvent()); + PrivateEvent privateEvent = new PrivateEvent(); + eventBus.post(privateEvent); + assertEquals(privateEvent, lastEvent); + assertEquals(1, eventsReceived.size()); + } + + public void testSubscriberExtendingClassWithPrivateEvent() { + eventBus.register(new PublicWithPrivateEventInSuperclass()); + PrivateEvent privateEvent = new PrivateEvent(); + eventBus.post(privateEvent); + assertEquals(privateEvent, lastEvent); + assertEquals(2, eventsReceived.size()); + } + } From 4c225398eebf037802f95bd6a11448f0f3bb7151 Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 2 Jun 2015 20:09:55 +0200 Subject: [PATCH 033/288] updated android build tools --- EventBusPerformance/build.gradle | 4 ++-- EventBusTest/build.gradle | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 46adb91b..46f10f86 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:1.1.0' + classpath 'com.android.tools.build:gradle:1.2.3' } } @@ -21,7 +21,7 @@ dependencies { } android { - buildToolsVersion '21.1.2' + buildToolsVersion '22.0.1' compileSdkVersion 19 sourceSets { diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 5983a7ab..80248410 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:1.1.0' + classpath 'com.android.tools.build:gradle:1.2.3' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4' } } @@ -22,7 +22,7 @@ dependencies { } android { - buildToolsVersion '21.1.2' + buildToolsVersion '22.0.1' compileSdkVersion 19 sourceSets { From 7952c05234bb845552599fe86148112eb2bcf20c Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 2 Jun 2015 22:36:27 +0200 Subject: [PATCH 034/288] subscriber priority and stickyness are now part of @Subscribe --- .../src/de/greenrobot/event/EventBus.java | 91 ++++----- .../src/de/greenrobot/event/Subscribe.java | 12 ++ .../de/greenrobot/event/SubscriberIndex.java | 4 +- .../de/greenrobot/event/SubscriberMethod.java | 6 +- .../event/SubscriberMethodFinder.java | 3 +- .../src/de/greenrobot/event/Subscription.java | 4 +- .../EventBusAnnotationProcessor.java | 3 +- .../test/EventBusCancelEventDeliveryTest.java | 46 +++-- .../test/EventBusInheritanceDisabledTest.java | 29 ++- .../event/test/EventBusInheritanceTest.java | 29 ++- .../EventBusOrderedSubscriptionsTest.java | 176 +++++++++++++----- .../event/test/EventBusStickyEventTest.java | 46 +++-- 12 files changed, 303 insertions(+), 146 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index bd2b95a0..22a99f63 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -31,9 +31,10 @@ /** * EventBus is a central publish/subscribe event system for Android. Events are posted ({@link #post(Object)}) to the * bus, which delivers it to subscribers that have a matching handler method for the event type. To receive events, - * subscribers must register themselves to the bus using {@link #register(Object)}. Once registered, - * subscribers receive events until {@link #unregister(Object)} is called. By convention, event handling methods must - * be named "onEvent", be public, return nothing (void), and have exactly one parameter (the event). + * subscribers must register themselves to the bus using {@link #register(Object)}. Once registered, subscribers + * receive events until {@link #unregister(Object)} is called. Event handling methods must be annotated by + * {@link de.greenrobot.event.Subscribe}, must be public, return nothing (void), and have exactly one parameter + * (the event). * * @author Markus Junginger, greenrobot */ @@ -58,7 +59,6 @@ protected PostingThreadState initialValue() { } }; - private final HandlerPoster mainThreadPoster; private final BackgroundPoster backgroundPoster; private final AsyncPoster asyncPoster; @@ -124,58 +124,26 @@ public EventBus() { * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they * are no longer interested in receiving events. *

- * Subscribers have event handling methods that are identified by their name, typically called "onEvent". Event - * handling methods must have exactly one parameter, the event. If the event handling method is to be called in a - * specific thread, a modifier is appended to the method name. Valid modifiers match one of the {@link ThreadMode} - * enums. For example, if a method is to be called in the UI/main thread by EventBus, it would be called - * "onEventMainThread". + * Subscribers have event handling methods that must be annotated by {@link de.greenrobot.event.Subscribe}. + * The {@link de.greenrobot.event.Subscribe} annotation also allows configuration like {@link + * de.greenrobot.event.ThreadMode} and priority. */ public void register(Object subscriber) { - register(subscriber, false, 0); - } - - /** - * Like {@link #register(Object)} with an additional subscriber priority to influence the order of event delivery. - * Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before - * others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of - * delivery among subscribers with different {@link ThreadMode}s! - */ - public void register(Object subscriber, int priority) { - register(subscriber, false, priority); - } - - /** - * Like {@link #register(Object)}, but also triggers delivery of the most recent sticky event (posted with - * {@link #postSticky(Object)}) to the given subscriber. - */ - public void registerSticky(Object subscriber) { - register(subscriber, true, 0); - } - - /** - * Like {@link #register(Object, int)}, but also triggers delivery of the most recent sticky event (posted with - * {@link #postSticky(Object)}) to the given subscriber. - */ - public void registerSticky(Object subscriber, int priority) { - register(subscriber, true, priority); - } - - private synchronized void register(Object subscriber, boolean sticky, int priority) { Class subscriberClass = subscriber.getClass(); // @Subscribe in anonymous classes is invisible to annotation processing, always fall back to reflection boolean forceReflection = subscriberClass.isAnonymousClass(); List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass, forceReflection); for (SubscriberMethod subscriberMethod : subscriberMethods) { - subscribe(subscriber, subscriberMethod, sticky, priority); + subscribe(subscriber, subscriberMethod); } } // Must be called in synchronized block - private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) { + private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { Class eventType = subscriberMethod.eventType; CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType); - Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority); + Subscription newSubscription = new Subscription(subscriber, subscriberMethod); if (subscriptions == null) { subscriptions = new CopyOnWriteArrayList(); subscriptionsByEventType.put(eventType, subscriptions); @@ -189,11 +157,14 @@ private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boo // Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again) // subscriberMethod.method.setAccessible(true); - int size = subscriptions.size(); - for (int i = 0; i <= size; i++) { - if (i == size || newSubscription.priority > subscriptions.get(i).priority) { - subscriptions.add(i, newSubscription); - break; + // Got to synchronize to avoid shifted positions when adding/removing concurrently + synchronized (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; + } } } @@ -204,7 +175,7 @@ private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boo } subscribedEvents.add(eventType); - if (sticky) { + if (subscriberMethod.sticky) { if (eventInheritance) { // Existing sticky events of all subclasses of eventType have to be considered. // Note: Iterating over all events may be inefficient with lots of sticky events, @@ -241,14 +212,17 @@ public synchronized boolean isRegistered(Object subscriber) { private void unubscribeByEventType(Object subscriber, Class eventType) { List subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions != null) { - int size = subscriptions.size(); - for (int i = 0; i < size; i++) { - Subscription subscription = subscriptions.get(i); - if (subscription.subscriber == subscriber) { - subscription.active = false; - subscriptions.remove(i); - i--; - size--; + // Got to synchronize to avoid shifted positions when adding/removing concurrently + synchronized (subscriptions) { + int size = subscriptions.size(); + for (int i = 0; i < size; i++) { + Subscription subscription = subscriptions.get(i); + if (subscription.subscriber == subscriber) { + subscription.active = false; + subscriptions.remove(i); + i--; + size--; + } } } } @@ -294,7 +268,7 @@ public void post(Object event) { * Called from a subscriber's event handling method, further event delivery will be canceled. Subsequent * subscribers * won't receive the event. Events are usually canceled by higher priority subscribers (see - * {@link #register(Object, int)}). Canceling is restricted to event handling methods running in posting thread + * {@link Subscribe#priority()}). Canceling is restricted to event handling methods running in posting thread * {@link ThreadMode#PostThread}. */ public void cancelEventDelivery(Object event) { @@ -315,8 +289,7 @@ public void cancelEventDelivery(Object event) { /** * Posts the given event to the event bus and holds on to the event (because it is sticky). The most recent sticky - * event of an event's type is kept in memory for future access. This can be {@link #registerSticky(Object)} or - * {@link #getStickyEvent(Class)}. + * event of an event's type is kept in memory for future access by subscribers using {@link Subscribe#sticky()}. */ public void postSticky(Object event) { synchronized (stickyEvents) { diff --git a/EventBus/src/de/greenrobot/event/Subscribe.java b/EventBus/src/de/greenrobot/event/Subscribe.java index 76ff1c88..82cf51fc 100644 --- a/EventBus/src/de/greenrobot/event/Subscribe.java +++ b/EventBus/src/de/greenrobot/event/Subscribe.java @@ -14,5 +14,17 @@ @Target({ElementType.METHOD}) public @interface Subscribe { ThreadMode threadMode() default ThreadMode.PostThread; + + /** + * If true, delivers the most recent sticky event (posted with + * {@link de.greenrobot.event.EventBus#postSticky(Object)}) to this subscriber (if event available). + */ + boolean sticky() default false; + + /** Subscriber priority to influence the order of event delivery. + * Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before + * others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of + * delivery among subscribers with different {@link ThreadMode}s! */ + int priority() default 0; } diff --git a/EventBus/src/de/greenrobot/event/SubscriberIndex.java b/EventBus/src/de/greenrobot/event/SubscriberIndex.java index a442d1cc..8dbee7f6 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberIndex.java +++ b/EventBus/src/de/greenrobot/event/SubscriberIndex.java @@ -22,10 +22,10 @@ SubscriberMethod[] getSubscribersFor(Class subscriberClass) { abstract SubscriberMethod[] createSubscribersFor(Class subscriberClass); SubscriberMethod createSubscriberMethod(Class subscriberClass, String methodName, Class eventType, - ThreadMode threadMode) { + ThreadMode threadMode, int priority, boolean sticky) { try { Method method = subscriberClass.getDeclaredMethod(methodName, eventType); - return new SubscriberMethod(method, threadMode, eventType); + return new SubscriberMethod(method, eventType, threadMode, priority, sticky); } catch (NoSuchMethodException e) { throw new EventBusException("Could not find subscriber method in " + subscriberClass + ". Maybe a missing ProGuard rule?", e); diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethod.java b/EventBus/src/de/greenrobot/event/SubscriberMethod.java index cf13c292..1dcd74f1 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethod.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethod.java @@ -21,13 +21,17 @@ final class SubscriberMethod { final Method method; final ThreadMode threadMode; final Class eventType; + final int priority; + final boolean sticky; /** Used for efficient comparison */ String methodString; - SubscriberMethod(Method method, ThreadMode threadMode, Class eventType) { + SubscriberMethod(Method method, Class eventType, ThreadMode threadMode, int priority, boolean sticky) { this.method = method; this.threadMode = threadMode; this.eventType = eventType; + this.priority = priority; + this.sticky = sticky; } @Override diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index f6699f70..830f8893 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -142,7 +142,8 @@ private List findSubscriberMethodsWithReflection(Class subs if (eventTypesFound.add(methodKey)) { // Only add if not already found in a sub class ThreadMode threadMode = subscribeAnnotation.threadMode(); - subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType)); + subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, + subscribeAnnotation.priority(), subscribeAnnotation.sticky())); } } } else if (strictMethodVerification) { diff --git a/EventBus/src/de/greenrobot/event/Subscription.java b/EventBus/src/de/greenrobot/event/Subscription.java index 6c84c440..868cbebe 100644 --- a/EventBus/src/de/greenrobot/event/Subscription.java +++ b/EventBus/src/de/greenrobot/event/Subscription.java @@ -18,17 +18,15 @@ final class Subscription { final Object subscriber; final SubscriberMethod subscriberMethod; - final int priority; /** * Becomes false as soon as {@link EventBus#unregister(Object)} is called, which is checked by queued event delivery * {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions. */ volatile boolean active; - Subscription(Object subscriber, SubscriberMethod subscriberMethod, int priority) { + Subscription(Object subscriber, SubscriberMethod subscriberMethod) { this.subscriber = subscriber; this.subscriberMethod = subscriberMethod; - this.priority = priority; active = true; } diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 1af29114..3add6d64 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -255,7 +255,8 @@ private void writeIndexEntries(BufferedWriter writer, TypeElement subscriberClas writeLine(writer, 4, "createSubscriberMethod(" + subscriberClassString + ",", "\"" + methodName + "\",", paramType.toString() + ".class,", - "ThreadMode." + subscribe.threadMode().name() + "),"); + "ThreadMode." + subscribe.threadMode().name() + ", " + + subscribe.priority() + ", " + subscribe.sticky(), "),"); processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Indexed @Subscribe at " + method.getEnclosingElement().getSimpleName() + "." + methodName + diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java index 0950f71c..748adcaa 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java @@ -30,10 +30,10 @@ public class EventBusCancelEventDeliveryTest extends AbstractEventBusTest { private Throwable failed; public void testCancel() { - Subscriber canceler = new Subscriber(true); - eventBus.register(new Subscriber(false)); - eventBus.register(canceler, 1); - eventBus.register(new Subscriber(false)); + Subscriber canceler = new Subscriber(1, true); + eventBus.register(new Subscriber(0, false)); + eventBus.register(canceler); + eventBus.register(new Subscriber(0, false)); eventBus.post("42"); assertEquals(1, eventCount.intValue()); @@ -43,10 +43,9 @@ public void testCancel() { } public void testCancelInBetween() { - Subscriber canceler = new Subscriber(true); - eventBus.register(canceler, 2); - eventBus.register(new Subscriber(false), 1); - eventBus.register(new Subscriber(false), 3); + eventBus.register(new Subscriber(2, true)); + eventBus.register(new Subscriber(1, false)); + eventBus.register(new Subscriber(3, false)); eventBus.post("42"); assertEquals(2, eventCount.intValue()); } @@ -78,17 +77,40 @@ public void testCancelInMainThread() { } public class Subscriber { + private final int prio; private final boolean cancel; - public Subscriber(boolean cancel) { + public Subscriber(int prio, boolean cancel) { + this.prio = prio; this.cancel = cancel; } @Subscribe public void onEvent(String event) { - trackEvent(event); - if (cancel) { - eventBus.cancelEventDelivery(event); + handleEvent(event, 0); + } + + @Subscribe(priority = 1) + public void onEvent1(String event) { + handleEvent(event, 1); + } + + @Subscribe(priority = 2) + public void onEvent2(String event) { + handleEvent(event, 2); + } + + @Subscribe(priority = 3) + public void onEvent3(String event) { + handleEvent(event, 3); + } + + private void handleEvent(String event, int prio) { + if(this.prio == prio) { + trackEvent(event); + if (cancel) { + eventBus.cancelEventDelivery(event); + } } } } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java index 20a5195c..70eb9bde 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java @@ -57,7 +57,7 @@ public void testEventClassHierarchySticky() { eventBus.postSticky("Hello"); eventBus.postSticky(new MyEvent()); eventBus.postSticky(new MyEventExtended()); - eventBus.registerSticky(this); + eventBus.register(new StickySubscriber()); assertEquals(1, countMyEventExtended); assertEquals(1, countMyEvent); assertEquals(0, countObjectEvent); @@ -168,4 +168,31 @@ public void onEvent(MyEvent event) { static class SubscriberExtendedWithoutNewSubscriberMethod extends EventBusInheritanceDisabledTest { } + public class StickySubscriber { + @Subscribe(sticky = true) + public void onEvent(Object event) { + countObjectEvent++; + } + + @Subscribe(sticky = true) + public void onEvent(MyEvent event) { + countMyEvent++; + } + + @Subscribe(sticky = true) + public void onEvent(MyEventExtended event) { + countMyEventExtended++; + } + + @Subscribe(sticky = true) + public void onEvent(MyEventInterface event) { + countMyEventInterface++; + } + + @Subscribe(sticky = true) + public void onEvent(MyEventInterfaceExtended event) { + countMyEventInterfaceExtended++; + } + } + } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java index dd93a757..183fe89d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java @@ -60,7 +60,7 @@ public void testEventClassHierarchySticky() { eventBus.postSticky("Hello"); eventBus.postSticky(new MyEvent()); eventBus.postSticky(new MyEventExtended()); - eventBus.registerSticky(this); + eventBus.register(new StickySubscriber()); assertEquals(1, countMyEventExtended); assertEquals(2, countMyEvent); assertEquals(3, countObjectEvent); @@ -171,4 +171,31 @@ public void onEvent(MyEvent event) { static class SubscriberExtendedWithoutNewSubscriberMethod extends EventBusInheritanceTest { } + public class StickySubscriber { + @Subscribe(sticky = true) + public void onEvent(Object event) { + countObjectEvent++; + } + + @Subscribe(sticky = true) + public void onEvent(MyEvent event) { + countMyEvent++; + } + + @Subscribe(sticky = true) + public void onEvent(MyEventExtended event) { + countMyEventExtended++; + } + + @Subscribe(sticky = true) + public void onEvent(MyEventInterface event) { + countMyEventInterface++; + } + + @Subscribe(sticky = true) + public void onEvent(MyEventInterfaceExtended event) { + countMyEventInterfaceExtended++; + } + } + } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java index 1864da54..5bba1a64 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java @@ -15,13 +15,13 @@ */ package de.greenrobot.event.test; -import java.util.ArrayList; -import java.util.List; - -import de.greenrobot.event.EventBus; import android.util.Log; -import de.greenrobot.event.ThreadMode; +import de.greenrobot.event.EventBus; import de.greenrobot.event.Subscribe; +import de.greenrobot.event.ThreadMode; + +import java.util.ArrayList; +import java.util.List; /** * @author Markus Junginger, greenrobot @@ -33,87 +33,167 @@ public class EventBusOrderedSubscriptionsTest extends AbstractEventBusTest { private String fail; public void testOrdered() { - runTestOrdered("42", false); + runTestOrdered("42", false, 5); } public void testOrderedMainThread() { - runTestOrdered(new IntTestEvent(42), false); + runTestOrdered(new IntTestEvent(42), false, 3); } public void testOrderedBackgroundThread() { - runTestOrdered(Integer.valueOf(42), false); + runTestOrdered(Integer.valueOf(42), false, 3); } - + public void testOrderedSticky() { - runTestOrdered("42", true); + runTestOrdered("42", true, 5); } public void testOrderedMainThreadSticky() { - runTestOrdered(new IntTestEvent(42), true); + runTestOrdered(new IntTestEvent(42), true, 3); } public void testOrderedBackgroundThreadSticky() { - runTestOrdered(Integer.valueOf(42), true); + runTestOrdered(Integer.valueOf(42), true, 3); } - protected void runTestOrdered(Object event, boolean sticky) { - register(1, sticky); - register(-1, sticky); - register(10, sticky); - register(0, sticky); - register(-100, sticky); - assertEquals(5, registered.size()); - + protected void runTestOrdered(Object event, boolean sticky, int expectedEventCount) { + Object subscriber = sticky ? new PrioSubscriberSticky() : new PrioSubscriber(); + eventBus.register(subscriber); eventBus.post(event); - waitForEventCount(5, 10000); + waitForEventCount(expectedEventCount, 10000); assertEquals(null, fail); - unregisterAll(); + eventBus.unregister(subscriber); } - private void unregisterAll() { - for (PrioSubscriber subscriber : registered) { - eventBus.unregister(subscriber); + public final class PrioSubscriber { + @Subscribe(priority = 1) + public void onEventP1(String event) { + handleEvent(1, event); } - } - protected PrioSubscriber register(int priority, boolean sticky) { - PrioSubscriber subscriber = new PrioSubscriber(priority); - if (sticky) { - eventBus.registerSticky(subscriber, priority); - } else { - eventBus.register(subscriber, priority); + @Subscribe(priority = -1) + public void onEventM1(String event) { + handleEvent(-1, event); } - registered.add(subscriber); - return subscriber; - } - public final class PrioSubscriber { + @Subscribe(priority = 0) + public void onEventP0(String event) { + handleEvent(0, event); + } - final int prio; + @Subscribe(priority = 10) + public void onEventP10(String event) { + handleEvent(10, event); + } - public PrioSubscriber(int prio) { - this.prio = prio; - // TODO Auto-generated constructor stub + @Subscribe(priority = -100) + public void onEventM100(String event) { + handleEvent(-100, event); } - @Subscribe - public void onEvent(String event) { - handleEvent(event); + + @Subscribe(threadMode = ThreadMode.MainThread, priority = -1) + public void onEventMainThreadM1(IntTestEvent event) { + handleEvent(-1, event); } @Subscribe(threadMode = ThreadMode.MainThread) - public void onEventMainThread(IntTestEvent event) { - handleEvent(event); + public void onEventMainThreadP0(IntTestEvent event) { + handleEvent(0, event); + } + + @Subscribe(threadMode = ThreadMode.MainThread, priority = 1) + public void onEventMainThreadP1(IntTestEvent event) { + handleEvent(1, event); + } + + @Subscribe(threadMode = ThreadMode.BackgroundThread, priority = 1) + public void onEventBackgroundThreadP1(Integer event) { + handleEvent(1, event); } @Subscribe(threadMode = ThreadMode.BackgroundThread) - public void onEventBackgroundThread(Integer event) { - handleEvent(event); + public void onEventBackgroundThreadP0(Integer event) { + handleEvent(0, event); + } + + @Subscribe(threadMode = ThreadMode.BackgroundThread, priority = -1) + public void onEventBackgroundThreadM1(Integer event) { + handleEvent(-1, event); + } + + protected void handleEvent(int prio, Object event) { + if (prio > lastPrio) { + fail = "Called prio " + prio + " after " + lastPrio; + } + lastPrio = prio; + + Log.d(EventBus.TAG, "Subscriber " + prio + " got: " + event); + trackEvent(event); + } + + } + + public final class PrioSubscriberSticky { + @Subscribe(priority = 1, sticky = true) + public void onEventP1(String event) { + handleEvent(1, event); + } + + + @Subscribe(priority = -1, sticky = true) + public void onEventM1(String event) { + handleEvent(-1, event); + } + + @Subscribe(priority = 0, sticky = true) + public void onEventP0(String event) { + handleEvent(0, event); + } + + @Subscribe(priority = 10, sticky = true) + public void onEventP10(String event) { + handleEvent(10, event); + } + + @Subscribe(priority = -100, sticky = true) + public void onEventM100(String event) { + handleEvent(-100, event); + } + + @Subscribe(threadMode = ThreadMode.MainThread, priority = -1, sticky = true) + public void onEventMainThreadM1(IntTestEvent event) { + handleEvent(-1, event); + } + + @Subscribe(threadMode = ThreadMode.MainThread, sticky = true) + public void onEventMainThreadP0(IntTestEvent event) { + handleEvent(0, event); + } + + @Subscribe(threadMode = ThreadMode.MainThread, priority = 1, sticky = true) + public void onEventMainThreadP1(IntTestEvent event) { + handleEvent(1, event); + } + + @Subscribe(threadMode = ThreadMode.BackgroundThread, priority = 1, sticky = true) + public void onEventBackgroundThreadP1(Integer event) { + handleEvent(1, event); + } + + @Subscribe(threadMode = ThreadMode.BackgroundThread, sticky = true) + public void onEventBackgroundThreadP0(Integer event) { + handleEvent(0, event); + } + + @Subscribe(threadMode = ThreadMode.BackgroundThread, priority = -1, sticky = true) + public void onEventBackgroundThreadM1(Integer event) { + handleEvent(-1, event); } - protected void handleEvent(Object event) { + protected void handleEvent(int prio, Object event) { if (prio > lastPrio) { fail = "Called prio " + prio + " after " + lastPrio; } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java index 9223bb32..d092ae8d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java @@ -24,7 +24,7 @@ public class EventBusStickyEventTest extends AbstractEventBusTest { public void testPostSticky() throws InterruptedException { eventBus.postSticky("Sticky"); - eventBus.registerSticky(this); + eventBus.register(this); assertEquals("Sticky", lastEvent); assertEquals(Thread.currentThread(), lastThread); } @@ -32,20 +32,20 @@ public void testPostSticky() throws InterruptedException { public void testPostStickyTwoEvents() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.postSticky(new IntTestEvent(7)); - eventBus.registerSticky(this); + eventBus.register(this); assertEquals(2, eventCount.intValue()); } public void testPostStickyRegisterNonSticky() throws InterruptedException { eventBus.postSticky("Sticky"); - eventBus.register(this); + eventBus.register(new NonStickySubscriber()); assertNull(lastEvent); assertEquals(0, eventCount.intValue()); } public void testPostNonStickyRegisterSticky() throws InterruptedException { eventBus.post("NonSticky"); - eventBus.registerSticky(this); + eventBus.register(this); assertNull(lastEvent); assertEquals(0, eventCount.intValue()); } @@ -53,24 +53,24 @@ public void testPostNonStickyRegisterSticky() throws InterruptedException { public void testPostStickyTwice() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.postSticky("NewSticky"); - eventBus.registerSticky(this); + eventBus.register(this); assertEquals("NewSticky", lastEvent); } public void testPostStickyThenPostNormal() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.post("NonSticky"); - eventBus.registerSticky(this); + eventBus.register(this); assertEquals("Sticky", lastEvent); } public void testPostStickyWithRegisterAndUnregister() throws InterruptedException { - eventBus.registerSticky(this); + eventBus.register(this); eventBus.postSticky("Sticky"); assertEquals("Sticky", lastEvent); eventBus.unregister(this); - eventBus.registerSticky(this); + eventBus.register(this); assertEquals("Sticky", lastEvent); assertEquals(2, eventCount.intValue()); @@ -79,7 +79,7 @@ public void testPostStickyWithRegisterAndUnregister() throws InterruptedExceptio assertEquals("NewSticky", lastEvent); eventBus.unregister(this); - eventBus.registerSticky(this); + eventBus.register(this); assertEquals(4, eventCount.intValue()); assertEquals("NewSticky", lastEvent); } @@ -93,7 +93,7 @@ public void testPostStickyRemoveClass() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.removeStickyEvent(String.class); assertNull(eventBus.getStickyEvent(String.class)); - eventBus.registerSticky(this); + eventBus.register(this); assertNull(lastEvent); assertEquals(0, eventCount.intValue()); } @@ -102,7 +102,7 @@ public void testPostStickyRemoveEvent() throws InterruptedException { eventBus.postSticky("Sticky"); assertTrue(eventBus.removeStickyEvent("Sticky")); assertNull(eventBus.getStickyEvent(String.class)); - eventBus.registerSticky(this); + eventBus.register(this); assertNull(lastEvent); assertEquals(0, eventCount.intValue()); } @@ -113,35 +113,47 @@ public void testPostStickyRemoveAll() throws InterruptedException { eventBus.removeAllStickyEvents(); assertNull(eventBus.getStickyEvent(String.class)); assertNull(eventBus.getStickyEvent(IntTestEvent.class)); - eventBus.registerSticky(this); + eventBus.register(this); assertNull(lastEvent); assertEquals(0, eventCount.intValue()); } public void testRemoveStickyEventInSubscriber() throws InterruptedException { - eventBus.registerSticky(new RemoveStickySubscriber()); + eventBus.register(new RemoveStickySubscriber()); eventBus.postSticky("Sticky"); - eventBus.registerSticky(this); + eventBus.register(this); assertNull(lastEvent); assertEquals(0, eventCount.intValue()); assertNull(eventBus.getStickyEvent(String.class)); } - @Subscribe + @Subscribe(sticky = true) public void onEvent(String event) { trackEvent(event); } - @Subscribe + @Subscribe(sticky = true) public void onEvent(IntTestEvent event) { trackEvent(event); } public class RemoveStickySubscriber { @SuppressWarnings("unused") - @Subscribe + @Subscribe(sticky = true) public void onEvent(String event) { eventBus.removeStickyEvent(event); } } + + public class NonStickySubscriber { + @Subscribe + public void onEvent(String event) { + trackEvent(event); + } + + @Subscribe + public void onEvent(IntTestEvent event) { + trackEvent(event); + } + } } From 56787cdabbdc3985e7917860689297b9eebc3051 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 3 Jun 2015 10:50:41 +0200 Subject: [PATCH 035/288] version 3.0.0-beta1 --- EventBus/build.gradle | 2 +- EventBusAnnotationProcessor/build.gradle | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index b8ad8c0f..7fac0de5 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'maven' apply plugin: 'signing' group = 'de.greenrobot' -version = '3.0.0-SNAPSHOT' +version = '3.0.0-beta1' sourceCompatibility = 1.6 def isSnapshot = version.endsWith('-SNAPSHOT') diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index ffe5eba5..bd761ddc 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'maven' apply plugin: 'signing' group = 'de.greenrobot' -version = '3.0.0-SNAPSHOT' +version = '3.0.0-beta1' sourceCompatibility = 1.6 @@ -43,6 +43,17 @@ sourceSets { } } +javadoc { + classpath += configurations.provided + title = "EventBus Annotation Processor ${version} API" + options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2015 greenrobot.de. All Rights Reserved.' +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + classifier = 'javadoc' + from 'build/docs/javadoc' +} + task sourcesJar(type: Jar) { from sourceSets.main.allSource classifier = 'sources' @@ -50,6 +61,7 @@ task sourcesJar(type: Jar) { artifacts { archives jar + archives javadocJar archives sourcesJar } From 06ae2be5cddff51fd12e22d8e2102ba78d3823e1 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 3 Jun 2015 12:09:08 +0200 Subject: [PATCH 036/288] upgrade otto to 1.3.7 --- EventBusPerformance/build.gradle | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 46f10f86..d391c75b 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -17,7 +17,7 @@ repositories { dependencies { compile project(':EventBus') provided project(':EventBusAnnotationProcessor') - compile 'com.squareup:otto:1.3.6' + compile 'com.squareup:otto:1.3.7' } android { @@ -30,7 +30,6 @@ android { java.srcDirs = ['src'] res.srcDirs = ['res'] } - } } From 0b3fbb9ba26ee98d4337c13bc96775ea67f93d58 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 3 Jun 2015 12:10:37 +0200 Subject: [PATCH 037/288] work around for Class.isAnonymousClass() that is super slow, added ignoreGeneratedIndex builder flag, updated performance app with the new flag --- .../src/de/greenrobot/event/EventBus.java | 10 ++++++++-- .../de/greenrobot/event/EventBusBuilder.java | 7 +++++++ .../event/SubscriberMethodFinder.java | 6 ++++-- .../res/layout/activity_setuptests.xml | 8 ++++++++ EventBusPerformance/res/values/strings.xml | 1 + .../de/greenrobot/eventperf/TestParams.java | 9 +++++++++ .../eventperf/TestSetupActivity.java | 1 + .../testsubject/PerfTestEventBus.java | 20 +++++++++++++------ 8 files changed, 52 insertions(+), 10 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index 22a99f63..a8b6e0bb 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -109,7 +109,7 @@ public EventBus() { mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); - subscriberMethodFinder = new SubscriberMethodFinder(/* TODO */ false); + subscriberMethodFinder = new SubscriberMethodFinder(/* TODO */ false, builder.ignoreGeneratedIndex); logSubscriberExceptions = builder.logSubscriberExceptions; logNoSubscriberMessages = builder.logNoSubscriberMessages; sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent; @@ -130,8 +130,14 @@ public EventBus() { */ public void register(Object subscriber) { Class subscriberClass = subscriber.getClass(); + // @Subscribe in anonymous classes is invisible to annotation processing, always fall back to reflection - boolean forceReflection = subscriberClass.isAnonymousClass(); + // Note: Avoid Class.isAnonymousClass() because it is super slow (getSimpleName() is super slow, too) + String name = subscriberClass.getName(); + int dollarIndex = name.lastIndexOf('$'); + boolean forceReflection = dollarIndex != -1 && dollarIndex < name.length() - 1 && + Character.isDigit(name.charAt(dollarIndex + 1)); + List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass, forceReflection); for (SubscriberMethod subscriberMethod : subscriberMethods) { diff --git a/EventBus/src/de/greenrobot/event/EventBusBuilder.java b/EventBus/src/de/greenrobot/event/EventBusBuilder.java index 06350609..c8b75a6d 100644 --- a/EventBus/src/de/greenrobot/event/EventBusBuilder.java +++ b/EventBus/src/de/greenrobot/event/EventBusBuilder.java @@ -33,6 +33,7 @@ public class EventBusBuilder { boolean sendNoSubscriberEvent = true; boolean throwSubscriberException; boolean eventInheritance = true; + boolean ignoreGeneratedIndex; ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE; List> skipMethodVerificationForClasses; @@ -111,6 +112,12 @@ public EventBusBuilder skipMethodVerificationFor(Class clazz) { return this; } + /** Forces the use of reflection even if there's a generated index (default: false). */ + public EventBusBuilder ignoreGeneratedIndex(boolean ignoreGeneratedIndex) { + this.ignoreGeneratedIndex = ignoreGeneratedIndex; + return this; + } + /** * Installs the default EventBus returned by {@link EventBus#getDefault()} using this builders' values. Must be * done only once before the first usage of the default EventBus. diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 830f8893..4951a7f2 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -56,9 +56,11 @@ class SubscriberMethodFinder { } private final boolean strictMethodVerification; + private final boolean ignoreGeneratedIndex; - SubscriberMethodFinder(boolean strictMethodVerification) { + SubscriberMethodFinder(boolean strictMethodVerification, boolean ignoreGeneratedIndex) { this.strictMethodVerification = strictMethodVerification; + this.ignoreGeneratedIndex = ignoreGeneratedIndex; } List findSubscriberMethods(Class subscriberClass, boolean forceReflection) { @@ -70,7 +72,7 @@ List findSubscriberMethods(Class subscriberClass, boolean f if (subscriberMethods != null) { return subscriberMethods; } - if (INDEX != null && !forceReflection) { + if (!ignoreGeneratedIndex && INDEX != null && !forceReflection) { subscriberMethods = findSubscriberMethodsWithIndex(subscriberClass); if (subscriberMethods.isEmpty()) { subscriberMethods = findSubscriberMethodsWithReflection(subscriberClass); diff --git a/EventBusPerformance/res/layout/activity_setuptests.xml b/EventBusPerformance/res/layout/activity_setuptests.xml index da77afe6..27064758 100644 --- a/EventBusPerformance/res/layout/activity_setuptests.xml +++ b/EventBusPerformance/res/layout/activity_setuptests.xml @@ -51,6 +51,14 @@ android:layout_marginLeft="48dp" android:text="@string/test_eventBusEventHierarchy" /> + + Event Performance EventBus Event Inheritance + Ignore generated index OttoBus Broadcast Local Broadcast diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java b/EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java index 1cebfec2..0776bd53 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java @@ -13,6 +13,7 @@ public class TestParams implements Serializable { private int publisherCount; private ThreadMode threadMode; private boolean eventInheritance; + private boolean ignoreGeneratedIndex; private int testNumber; private ArrayList> testClasses; @@ -56,6 +57,14 @@ public void setEventInheritance(boolean eventInheritance) { this.eventInheritance = eventInheritance; } + public boolean isIgnoreGeneratedIndex() { + return ignoreGeneratedIndex; + } + + public void setIgnoreGeneratedIndex(boolean ignoreGeneratedIndex) { + this.ignoreGeneratedIndex = ignoreGeneratedIndex; + } + public ArrayList> getTestClasses() { return testClasses; } diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java b/EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java index 2b018b41..6b760baf 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java @@ -61,6 +61,7 @@ public void startClick(View v) { params.setThreadMode(threadMode); params.setEventInheritance(((CheckBox) findViewById(R.id.checkBoxEventBusEventHierarchy)).isChecked()); + params.setIgnoreGeneratedIndex(((CheckBox) findViewById(R.id.checkBoxEventBusIgnoreGeneratedIndex)).isChecked()); EditText editTextEvent = (EditText) findViewById(R.id.editTextEvent); params.setEventCount(Integer.parseInt(editTextEvent.getText().toString())); diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java index 66bf9131..df8b13a3 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java @@ -22,7 +22,8 @@ public abstract class PerfTestEventBus extends Test { public PerfTestEventBus(Context context, TestParams params) { super(context, params); - eventBus = EventBus.builder().eventInheritance(params.isEventInheritance()).build(); + eventBus = EventBus.builder().eventInheritance(params.isEventInheritance()) + .ignoreGeneratedIndex(params.isIgnoreGeneratedIndex()).build(); subscribers = new ArrayList(); eventCount = params.getEventCount(); expectedEventCount = eventCount * params.getSubscriberCount(); @@ -57,6 +58,13 @@ private Class getSubscriberClassForThreadMode() { } } + private static String getDisplayModifier(TestParams params) { + String inheritance = params.isEventInheritance() ? "" : ", no event inheritance"; + String ignoreIndex = params.isIgnoreGeneratedIndex() ? ", ignore index" : ""; + return inheritance + ignoreIndex; + } + + public static class Post extends PerfTestEventBus { public Post(Context context, TestParams params) { super(context, params); @@ -91,9 +99,9 @@ public void runTest() { @Override public String getDisplayName() { - String inheritance = params.isEventInheritance() ? ", event inheritance" : ", no event inheritance"; - return "EventBus Post Events, " + params.getThreadMode() + inheritance; + return "EventBus Post Events, " + params.getThreadMode() + getDisplayModifier(params); } + } public static class RegisterAll extends PerfTestEventBus { @@ -110,7 +118,7 @@ public void runTest() { @Override public String getDisplayName() { - return "EventBus Register, no unregister"; + return "EventBus Register, no unregister" + getDisplayModifier(params); } } @@ -151,7 +159,7 @@ public void runTest() { @Override public String getDisplayName() { - return "EventBus Register"; + return "EventBus Register" + getDisplayModifier(params); } } @@ -170,7 +178,7 @@ public RegisterFirstTime(Context context, TestParams params) { @Override public String getDisplayName() { - return "EventBus Register, first time"; + return "EventBus Register, first time"+ getDisplayModifier(params); } } From b2f02b92297066d56a3be2d002e1a3140992c4e7 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 3 Jun 2015 22:08:43 +0200 Subject: [PATCH 038/288] typo with unsubscribeByEventType --- EventBus/src/de/greenrobot/event/EventBus.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index a8b6e0bb..33817aa8 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -215,7 +215,7 @@ public synchronized boolean isRegistered(Object subscriber) { } /** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */ - private void unubscribeByEventType(Object subscriber, Class eventType) { + private void unsubscribeByEventType(Object subscriber, Class eventType) { List subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions != null) { // Got to synchronize to avoid shifted positions when adding/removing concurrently @@ -239,7 +239,7 @@ public synchronized void unregister(Object subscriber) { List> subscribedTypes = typesBySubscriber.get(subscriber); if (subscribedTypes != null) { for (Class eventType : subscribedTypes) { - unubscribeByEventType(subscriber, eventType); + unsubscribeByEventType(subscriber, eventType); } typesBySubscriber.remove(subscriber); } else { From 1b556731c410b49639d668ff2c76dcb1ddcbaffb Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 5 Jun 2015 07:49:28 +0200 Subject: [PATCH 039/288] added EventBusSubscriberInJarTest --- EventBusTest/build.gradle | 1 + ...ventBusTestSubscriberInJar-3.0.0-beta1.jar | Bin 0 -> 1351 bytes .../test/EventBusSubscriberInJarTest.java | 17 +++++++++++++++ EventBusTestSubscriberInJar/build.gradle | 17 +++++++++++++++ .../event/test/SubscriberInJar.java | 20 ++++++++++++++++++ settings.gradle | 1 + 6 files changed, 56 insertions(+) create mode 100644 EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta1.jar create mode 100644 EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java create mode 100644 EventBusTestSubscriberInJar/build.gradle create mode 100644 EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 80248410..3e30de69 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -19,6 +19,7 @@ repositories { dependencies { androidTestApt project(':EventBusAnnotationProcessor') androidTestCompile project(':EventBus') + compile fileTree(dir: 'libs', include: '*.jar') } android { diff --git a/EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta1.jar b/EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta1.jar new file mode 100644 index 0000000000000000000000000000000000000000..bdfeab2124918adea44f041f85c5d9586c515c7c GIT binary patch literal 1351 zcmWIWW@h1HVBp|jxNd#ajR6RlKm-tQ0iYh?4Z8)YQD9{G|L6ysAO20~&~=I<+h{55FFeudwMUNiD|IXn8&3)H6l~hUq}3 z>*3QFT$)szT$GuVTI8AMl~|;goRe5w+#8geeZ@hb?pvJD`&swqUJqNVzxGo0CwT2S};(iG;UL5F*NL{HxQw|Wk@>Xf}= z+{HUgF8oW_VRLD(>IeDe9RJHP?T=<|X^xD4@q451#|Md1yW%g&W}Lkr?Z+Q}q3Gj* z!*X&)Jpan)ZDF0B6nEBtg<{*e`Bg8kf6|DOD3P?5+qYP?IO8jWn|$Yj-M(SG+AAje zcD;NfV5C{Iz}$*my4LyaTgzATFaC&dDSx?THFr|RgsaM@wI3IX{%xw~eJzr>bKa%g zWwP2_4FH@7WzoyVv7Ld@p+sT*C#qoi95W7Kai{OxvdU*~Mm-Tw2|-r4d-UN2)V z)0_WlYa;`v@!nT@Q_B)Ls5=cDi~uk+ Bqmuvt literal 0 HcmV?d00001 diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java new file mode 100644 index 00000000..60882fc7 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java @@ -0,0 +1,17 @@ +package de.greenrobot.event.test; + +import de.greenrobot.event.EventBus; +import junit.framework.Assert; +import junit.framework.TestCase; + +public class EventBusSubscriberInJarTest extends TestCase { + public void testSubscriberInJar() { + SubscriberInJar subscriber = new SubscriberInJar(); + EventBus eventBus = EventBus.builder().build(); + eventBus.register(subscriber); + eventBus.post("Hi Jar"); + eventBus.post(42); + Assert.assertEquals(1, subscriber.getCollectedStrings().size()); + Assert.assertEquals("Hi Jar", subscriber.getCollectedStrings().get(0)); + } +} diff --git a/EventBusTestSubscriberInJar/build.gradle b/EventBusTestSubscriberInJar/build.gradle new file mode 100644 index 00000000..7eab9494 --- /dev/null +++ b/EventBusTestSubscriberInJar/build.gradle @@ -0,0 +1,17 @@ +apply plugin: 'java' + +group = 'de.greenrobot' +version = '3.0.0-beta1' +sourceCompatibility = 1.6 + +dependencies { + compile project(':EventBus') +} + +sourceSets { + main { + java { + srcDir 'src' + } + } +} diff --git a/EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java b/EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java new file mode 100644 index 00000000..ea3bba4e --- /dev/null +++ b/EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java @@ -0,0 +1,20 @@ +package de.greenrobot.event.test; + +import de.greenrobot.event.Subscribe; + +import java.util.ArrayList; +import java.util.List; + +/** Helper class used by test inside a jar. */ +public class SubscriberInJar { + List collectedStrings = new ArrayList(); + + @Subscribe + public void collectString(String string) { + collectedStrings.add(string); + } + + public List getCollectedStrings() { + return collectedStrings; + } +} diff --git a/settings.gradle b/settings.gradle index d51c4e7b..a11c17d8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,5 @@ include 'EventBus' include 'EventBusAnnotationProcessor' include 'EventBusTest' +include 'EventBusTestSubscriberInJar' include 'EventBusPerformance' From 0671cd22ea20f545e321d3251b5cf8b27b643ec7 Mon Sep 17 00:00:00 2001 From: zsoltvilagos Date: Fri, 5 Jun 2015 14:26:16 +0200 Subject: [PATCH 040/288] Update COMPARISON.md --- COMPARISON.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/COMPARISON.md b/COMPARISON.md index 1ba60ccd..d7733f8d 100644 --- a/COMPARISON.md +++ b/COMPARISON.md @@ -51,7 +51,7 @@ Otto is another event bus library for Android; actually it's a fork of Guava's E No - Aynchronous event delivery + Asynchronous event delivery Yes No From e9bc508737685db41e5469a62567fded7b6e82c1 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 15 Jun 2015 18:27:49 +0200 Subject: [PATCH 041/288] fix code gen for ignored classes --- .../EventBusAnnotationProcessor.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 3add6d64..65630d92 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -219,7 +219,7 @@ private void writeSources() { } writer.write(" };\n"); } - if (!methodsByClass.isEmpty()) { + if (!first) { writer.write(" }\n"); } writer.write(" return null;\n"); @@ -227,10 +227,12 @@ private void writeSources() { } catch (IOException e) { throw new RuntimeException("Could not write source for " + className, e); } finally { - try { - writer.close(); - } catch (IOException e) { - //Silent + if (writer != null) { + try { + writer.close(); + } catch (IOException e) { + //Silent + } } } } From fd8a4c837cd80cd13879f97128b14500ab236508 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 19 Jun 2015 17:26:24 +0200 Subject: [PATCH 042/288] generating one SubscriberInfo per subscriber class --- EventBus/build.gradle | 2 +- .../de/greenrobot/event/SubscriberIndex.java | 35 ----- .../de/greenrobot/event/SubscriberInfo.java | 47 ++++++ .../de/greenrobot/event/SubscriberMethod.java | 3 +- .../event/SubscriberMethodFinder.java | 8 +- EventBusAnnotationProcessor/build.gradle | 2 +- .../EventBusAnnotationProcessor.java | 138 +++++++++++------- EventBusTestSubscriberInJar/build.gradle | 3 +- 8 files changed, 145 insertions(+), 93 deletions(-) delete mode 100644 EventBus/src/de/greenrobot/event/SubscriberIndex.java create mode 100644 EventBus/src/de/greenrobot/event/SubscriberInfo.java diff --git a/EventBus/build.gradle b/EventBus/build.gradle index 7fac0de5..0193f2dd 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'maven' apply plugin: 'signing' group = 'de.greenrobot' -version = '3.0.0-beta1' +version = '3.0.0-beta2' sourceCompatibility = 1.6 def isSnapshot = version.endsWith('-SNAPSHOT') diff --git a/EventBus/src/de/greenrobot/event/SubscriberIndex.java b/EventBus/src/de/greenrobot/event/SubscriberIndex.java deleted file mode 100644 index 8dbee7f6..00000000 --- a/EventBus/src/de/greenrobot/event/SubscriberIndex.java +++ /dev/null @@ -1,35 +0,0 @@ -package de.greenrobot.event; - -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; - -/** Preprocessed index: base class for generated "MyGeneratedSubscriberIndex" class by annotation processing. */ -abstract class SubscriberIndex { - private Map, SubscriberMethod[]> map = new HashMap, SubscriberMethod[]>(); - - SubscriberMethod[] getSubscribersFor(Class subscriberClass) { - SubscriberMethod[] entries = map.get(subscriberClass); - if (entries == null) { - entries = createSubscribersFor(subscriberClass); - if (entries != null) { - map.put(subscriberClass, entries); - } - } - return entries; - } - - abstract SubscriberMethod[] createSubscribersFor(Class subscriberClass); - - SubscriberMethod createSubscriberMethod(Class subscriberClass, String methodName, Class eventType, - ThreadMode threadMode, int priority, boolean sticky) { - try { - Method method = subscriberClass.getDeclaredMethod(methodName, eventType); - return new SubscriberMethod(method, eventType, threadMode, priority, sticky); - } catch (NoSuchMethodException e) { - throw new EventBusException("Could not find subscriber method in " + subscriberClass + - ". Maybe a missing ProGuard rule?", e); - } - } - -} diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfo.java b/EventBus/src/de/greenrobot/event/SubscriberInfo.java new file mode 100644 index 00000000..f544528f --- /dev/null +++ b/EventBus/src/de/greenrobot/event/SubscriberInfo.java @@ -0,0 +1,47 @@ +package de.greenrobot.event; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** Preprocessed index: base class for generated "MyGeneratedSubscriberIndex" class by annotation processing. */ +public abstract class SubscriberInfo { + public static class Data { + public final Class subscriberClass; + public final SubscriberMethod[] subscriberMethods; + public final Class nextInfo; + + public Data(Class subscriberClass, SubscriberMethod[] subscriberMethods, Class nextInfo) { + this.subscriberClass = subscriberClass; + this.subscriberMethods = subscriberMethods; + this.nextInfo = nextInfo; + } + } + + private Map, Data> map = new HashMap, Data>(); + + Data getSubscriberData(Class subscriberClass) { + Data data = map.get(subscriberClass); + if (data == null) { + data = createSubscriberData(); + if (data != null) { + map.put(subscriberClass, data); + } + } + return data; + } + + abstract protected Data createSubscriberData(); + + protected SubscriberMethod createSubscriberMethod(Class subscriberClass, String methodName, Class eventType, + ThreadMode threadMode, int priority, boolean sticky) { + try { + Method method = subscriberClass.getDeclaredMethod(methodName, eventType); + return new SubscriberMethod(method, eventType, threadMode, priority, sticky); + } catch (NoSuchMethodException e) { + throw new EventBusException("Could not find subscriber method in " + subscriberClass + + ". Maybe a missing ProGuard rule?", e); + } + } + +} diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethod.java b/EventBus/src/de/greenrobot/event/SubscriberMethod.java index 1dcd74f1..4d77446a 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethod.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethod.java @@ -17,7 +17,8 @@ import java.lang.reflect.Method; -final class SubscriberMethod { +/** Used internally by EventBus and generated subscriber indexes. */ +public class SubscriberMethod { final Method method; final ThreadMode threadMode; final Class eventType; diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 4951a7f2..da737f48 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -39,13 +39,13 @@ class SubscriberMethodFinder { private static final Map> METHOD_CACHE = new HashMap>(); /** Optional generated index without entries from subscribers super classes */ - private static final SubscriberIndex INDEX; + private static final SubscriberInfo INDEX; static { - SubscriberIndex newIndex = null; + SubscriberInfo newIndex = null; try { Class clazz = Class.forName("de.greenrobot.event.GeneratedSubscriberIndex"); - newIndex = (SubscriberIndex) clazz.newInstance(); + newIndex = (SubscriberInfo) clazz.newInstance(); } catch (ClassNotFoundException e) { Log.d(EventBus.TAG, "No subscriber index available, reverting to dynamic look-up"); // Fine @@ -94,7 +94,7 @@ List findSubscriberMethods(Class subscriberClass, boolean f private List findSubscriberMethodsWithIndex(Class subscriberClass) { Class clazz = subscriberClass; while (clazz != null) { - SubscriberMethod[] array = INDEX.getSubscribersFor(clazz); + SubscriberMethod[] array = null; //TODO INDEX.getSubscriberData(clazz); if (array != null && array.length > 0) { List subscriberMethods = new ArrayList(); for (SubscriberMethod subscriberMethod : array) { diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index bd761ddc..72b0ac29 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'maven' apply plugin: 'signing' group = 'de.greenrobot' -version = '3.0.0-beta1' +version = '3.0.0-beta2' sourceCompatibility = 1.6 diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 65630d92..e3310c6a 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -11,6 +11,7 @@ import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; +import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; @@ -29,6 +30,7 @@ @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") @SupportedSourceVersion(SourceVersion.RELEASE_6) public class EventBusAnnotationProcessor extends AbstractProcessor { + public static final String CLASS_POSTFIX = "_EventBusInfo"; private final Map> methodsByClass = new HashMap>(); private final Set classesToSkip = new HashSet(); @@ -178,66 +180,101 @@ private TypeElement getSuperclass(TypeElement type) { } private void writeSources() { - String pack = "de.greenrobot.event"; - String className = "GeneratedSubscriberIndex"; - BufferedWriter writer = null; - try { - JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(pack + '.' + className); - writer = new BufferedWriter(sourceFile.openWriter()); - writer.write("package de.greenrobot.event;\n\n"); - // writer.write("import de.greenrobot.event.SubscriberIndexEntry;\n"); - // writer.write("import de.greenrobot.event.ThreadMode;\n\n"); - writer.write("/** This class is generated by EventBus, do not edit. */\n"); - writer.write("class " + className + " extends SubscriberIndex {\n"); - writer.write(" SubscriberMethod[] createSubscribersFor(Class subscriberClass) {\n"); + List>> entries = + new ArrayList>>(methodsByClass.entrySet()); + for (int i = 0; i < entries.size(); i++) { + Map.Entry> entry = entries.get(i); + TypeElement subscriberClass = entry.getKey(); + if (classesToSkip.contains(subscriberClass)) { + continue; + } - boolean first = true; - for (Map.Entry> entry : methodsByClass.entrySet()) { - TypeElement subscriberClass = entry.getKey(); - if (classesToSkip.contains(subscriberClass)) { - continue; - } - String ifPrefix; - if (first) { - ifPrefix = ""; - first = false; - } else { - ifPrefix = "} else "; - } - writeLine(writer, 2, ifPrefix + "if(subscriberClass ==", subscriberClass.asType() + ".class) {"); - writer.write(" return new SubscriberMethod[] {\n"); + BufferedWriter writer = null; + try { + PackageElement packageElement = getPackageElement(subscriberClass); + String myPackage = packageElement.getQualifiedName().toString(); + String subscriberClassName = getClassString(subscriberClass, myPackage); + String infoClassName = subscriberClassName.replace('.', '_') + CLASS_POSTFIX; + JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(myPackage + '.' + infoClassName); + writer = new BufferedWriter(sourceFile.openWriter()); + writer.write("package " + myPackage + ";\n\n"); + writer.write("import de.greenrobot.event.SubscriberInfo;\n"); + writer.write("import de.greenrobot.event.SubscriberInfo.Data;\n"); + writer.write("import de.greenrobot.event.SubscriberMethod;\n"); + writer.write("import de.greenrobot.event.ThreadMode;\n\n"); + writer.write("/** This class is generated by EventBus, do not edit. */\n"); + writer.write("public class " + infoClassName + " extends SubscriberInfo {\n"); + writer.write("\nstatic {new Exception(\"" + infoClassName + "created\").printStackTrace();}\n\n"); + writer.write(" protected Data createSubscriberData() {\n"); + writer.write(" Class subscriberClass = " + subscriberClassName + ".class;\n"); + writer.write(" SubscriberMethod[] subscriberMethods = new SubscriberMethod[] {\n"); Set methodSignatures = new HashSet(); - writeIndexEntries(writer, null, entry.getValue(), methodSignatures); - TypeElement superclass = getSuperclass(subscriberClass); - while (superclass != null) { - List superClassMethods = methodsByClass.get(superclass); - if (superClassMethods != null) { - writeIndexEntries(writer, superclass, superClassMethods, methodSignatures); + writeMethods(writer, null, entry.getValue(), methodSignatures); + writer.write(" };\n"); + TypeElement nextEntry = nextEntry(entries, entry, i); + writeNextEntry(writer, myPackage, nextEntry); + writer.write(" return new Data(subscriberClass, subscriberMethods, next);\n"); + writer.write(" }\n}\n"); + } catch (IOException e) { + throw new RuntimeException("Could not write source for " + subscriberClass.getQualifiedName(), e); + } finally { + if (writer != null) { + try { + writer.close(); + } catch (IOException e) { + //Silent } - superclass = getSuperclass(superclass); } - writer.write(" };\n"); } - if (!first) { - writer.write(" }\n"); + } + } + + private void writeNextEntry(BufferedWriter writer, String myPackage, TypeElement nextEntry) throws IOException { + if (nextEntry != null) { + PackageElement nextPackageElement = getPackageElement(nextEntry); + String nextPackage = nextPackageElement.getQualifiedName().toString(); + String nextSubscriberClassName = getClassString(nextEntry, nextPackage); + String nextInfoClassName = nextSubscriberClassName.replace('.', '_') + CLASS_POSTFIX; + if (!myPackage.equals(nextPackage)) { + nextInfoClassName = nextPackage + "." + nextInfoClassName; } - writer.write(" return null;\n"); - writer.write(" };\n}\n"); - } catch (IOException e) { - throw new RuntimeException("Could not write source for " + className, e); - } finally { - if (writer != null) { - try { - writer.close(); - } catch (IOException e) { - //Silent - } + writer.write(" Class next = " + nextInfoClassName + ".class" + ";\n"); + } else { + writer.write(" Class next = null;\n"); + } + } + + private String getClassString(TypeElement subscriberClass, String subscriberPackage) { + int beginIndex = subscriberPackage.length() == 0 ? 0 : subscriberPackage.length() + 1; + return subscriberClass.getQualifiedName().toString().substring(beginIndex); + } + + private PackageElement getPackageElement(TypeElement subscriberClass) { + Element candidate = subscriberClass.getEnclosingElement(); + while (!(candidate instanceof PackageElement)) { + candidate = candidate.getEnclosingElement(); + } + return (PackageElement) candidate; + } + + private TypeElement nextEntry(List>> entries, + Map.Entry> current, int currentIdx) { + for (int i = currentIdx + 1; ; i++) { + if (i == entries.size()) { + i = 0; + } + if (i == currentIdx) { + return null; + } else { + Map.Entry> candidate = entries.get(i); + System.out.println(); + return candidate.getKey(); } } } - private void writeIndexEntries(BufferedWriter writer, TypeElement subscriberClass, List methods, Set methodSignatures) throws IOException { + private void writeMethods(BufferedWriter writer, TypeElement subscriberClass, List methods, Set methodSignatures) throws IOException { for (ExecutableElement method : methods) { List parameters = method.getParameters(); @@ -254,7 +291,7 @@ private void writeIndexEntries(BufferedWriter writer, TypeElement subscriberClas subscriberClass.asType().toString() + ".class"; Subscribe subscribe = method.getAnnotation(Subscribe.class); - writeLine(writer, 4, "createSubscriberMethod(" + subscriberClassString + ",", + writeLine(writer, 3, "createSubscriberMethod(" + subscriberClassString + ",", "\"" + methodName + "\",", paramType.toString() + ".class,", "ThreadMode." + subscribe.threadMode().name() + ", " + @@ -263,6 +300,7 @@ private void writeIndexEntries(BufferedWriter writer, TypeElement subscriberClas processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Indexed @Subscribe at " + method.getEnclosingElement().getSimpleName() + "." + methodName + "(" + paramType.asElement().getSimpleName() + ")"); + } } diff --git a/EventBusTestSubscriberInJar/build.gradle b/EventBusTestSubscriberInJar/build.gradle index 7eab9494..19afffbf 100644 --- a/EventBusTestSubscriberInJar/build.gradle +++ b/EventBusTestSubscriberInJar/build.gradle @@ -1,11 +1,12 @@ apply plugin: 'java' group = 'de.greenrobot' -version = '3.0.0-beta1' +version = '3.0.0-beta2' sourceCompatibility = 1.6 dependencies { compile project(':EventBus') + compile project(':EventBusAnnotationProcessor') } sourceSets { From 9d7e19298a111097696a50b007d3e985b70c862c Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 22 Jun 2015 18:37:15 +0200 Subject: [PATCH 043/288] reworked SubscriberMethodFinder to use SubscriberInfo whenever possible --- .../de/greenrobot/event/SubscriberInfo.java | 9 +- .../event/SubscriberMethodFinder.java | 189 ++++++++++-------- .../EventBusAnnotationProcessor.java | 5 +- 3 files changed, 109 insertions(+), 94 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfo.java b/EventBus/src/de/greenrobot/event/SubscriberInfo.java index f544528f..00b9ca17 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberInfo.java +++ b/EventBus/src/de/greenrobot/event/SubscriberInfo.java @@ -6,6 +6,7 @@ /** Preprocessed index: base class for generated "MyGeneratedSubscriberIndex" class by annotation processing. */ public abstract class SubscriberInfo { + // TODO move class fields into SubscriberInfo public static class Data { public final Class subscriberClass; public final SubscriberMethod[] subscriberMethods; @@ -18,15 +19,11 @@ public Data(Class subscriberClass, SubscriberMethod[] subscriberMethods, Clas } } - private Map, Data> map = new HashMap, Data>(); + private volatile Data data; - Data getSubscriberData(Class subscriberClass) { - Data data = map.get(subscriberClass); + Data getSubscriberData() { if (data == null) { data = createSubscriberData(); - if (data != null) { - map.put(subscriberClass, data); - } } return data; } diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index da737f48..96635ef9 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -15,12 +15,9 @@ */ package de.greenrobot.event; -import android.util.Log; - import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -38,23 +35,6 @@ class SubscriberMethodFinder { private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC; private static final Map> METHOD_CACHE = new HashMap>(); - /** Optional generated index without entries from subscribers super classes */ - private static final SubscriberInfo INDEX; - - static { - SubscriberInfo newIndex = null; - try { - Class clazz = Class.forName("de.greenrobot.event.GeneratedSubscriberIndex"); - newIndex = (SubscriberInfo) clazz.newInstance(); - } catch (ClassNotFoundException e) { - Log.d(EventBus.TAG, "No subscriber index available, reverting to dynamic look-up"); - // Fine - } catch (Exception e) { - Log.w(EventBus.TAG, "Could not init subscriber index, reverting to dynamic look-up", e); - } - INDEX = newIndex; - } - private final boolean strictMethodVerification; private final boolean ignoreGeneratedIndex; @@ -72,13 +52,10 @@ List findSubscriberMethods(Class subscriberClass, boolean f if (subscriberMethods != null) { return subscriberMethods; } - if (!ignoreGeneratedIndex && INDEX != null && !forceReflection) { - subscriberMethods = findSubscriberMethodsWithIndex(subscriberClass); - if (subscriberMethods.isEmpty()) { - subscriberMethods = findSubscriberMethodsWithReflection(subscriberClass); - } + if (!ignoreGeneratedIndex && !forceReflection) { + subscriberMethods = findUsingInfo(subscriberClass); } else { - subscriberMethods = findSubscriberMethodsWithReflection(subscriberClass); + subscriberMethods = findUsingReflection(subscriberClass); } if (subscriberMethods.isEmpty()) { throw new EventBusException("Subscriber " + subscriberClass @@ -91,83 +68,85 @@ List findSubscriberMethods(Class subscriberClass, boolean f } } - private List findSubscriberMethodsWithIndex(Class subscriberClass) { - Class clazz = subscriberClass; - while (clazz != null) { - SubscriberMethod[] array = null; //TODO INDEX.getSubscriberData(clazz); - if (array != null && array.length > 0) { - List subscriberMethods = new ArrayList(); + private List findUsingInfo(Class subscriberClass) { + FindState findState = new FindState(); + findState.initForSubscriber(subscriberClass); + while (findState.clazz != null) { + SubscriberInfo info = getSubscriberInfo(subscriberClass); + if (info != null) { + SubscriberInfo.Data subscriberData = info.getSubscriberData(); + SubscriberMethod[] array = subscriberData.subscriberMethods; for (SubscriberMethod subscriberMethod : array) { - subscriberMethods.add(subscriberMethod); + if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) { + findState.subscriberMethods.add(subscriberMethod); + } } - return subscriberMethods; } else { - String name = clazz.getName(); - if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) { - // Skip system classes, this just degrades performance - break; - } - clazz = clazz.getSuperclass(); + findUsingReflectionInSingleClass(findState); } + findState.nextClass(); } - return Collections.EMPTY_LIST; + return findState.subscriberMethods; } - private List findSubscriberMethodsWithReflection(Class subscriberClass) { - List subscriberMethods = new ArrayList(); - Class clazz = subscriberClass; - HashSet eventTypesFound = new HashSet(); - StringBuilder methodKeyBuilder = new StringBuilder(); - while (clazz != null) { - String name = clazz.getName(); - if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) { - // Skip system classes, this just degrades performance - break; + private SubscriberInfo getSubscriberInfo(Class subscriberClass) { + SubscriberInfo info = null; + String infoClass = subscriberClass.getName().replace('$', '_') + "_EventBusInfo"; + try { + Class aClass = Class.forName(infoClass); + Object object = aClass.newInstance(); + if (object instanceof SubscriberInfo) { + info = (SubscriberInfo) object; } + } catch (ClassNotFoundException e) { + // TODO don't try again + } catch (Exception e) { + throw new EventBusException("Could not get infos for " + subscriberClass, e); + } + return info; + } - // Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again) - Method[] methods = clazz.getDeclaredMethods(); - 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) { - String methodName = method.getName(); - 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 - ThreadMode threadMode = subscribeAnnotation.threadMode(); - subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, - subscribeAnnotation.priority(), subscribeAnnotation.sticky())); - } - } - } else if (strictMethodVerification) { - if (method.isAnnotationPresent(Subscribe.class)) { - String methodName = name + "." + method.getName(); - throw new EventBusException("@Subscribe method " + methodName + - "must have exactly 1 parameter but has " + parameterTypes.length); + private List findUsingReflection(Class subscriberClass) { + FindState findState = new FindState(); + findState.initForSubscriber(subscriberClass); + while (findState.clazz != null) { + findUsingReflectionInSingleClass(findState); + findState.nextClass(); + } + return findState.subscriberMethods; + } + + private void findUsingReflectionInSingleClass(FindState findState) { + Method[] methods = findState.clazz.getDeclaredMethods(); + 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) { + 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) { if (method.isAnnotationPresent(Subscribe.class)) { - String methodName = name + "." + method.getName(); - throw new EventBusException(methodName + - " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); + String methodName = findState.clazzName + "." + method.getName(); + throw new EventBusException("@Subscribe method " + methodName + + "must have exactly 1 parameter but has " + parameterTypes.length); } - + } + } else if (strictMethodVerification) { + if (method.isAnnotationPresent(Subscribe.class)) { + String methodName = findState.clazzName + "." + method.getName(); + throw new EventBusException(methodName + + " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); } } - - clazz = clazz.getSuperclass(); } - return subscriberMethods; } static void clearCaches() { @@ -176,4 +155,42 @@ static void clearCaches() { } } + class FindState { + final List subscriberMethods = new ArrayList(); + final HashSet eventTypesFound = new HashSet(); + final StringBuilder methodKeyBuilder = new StringBuilder(); + Class subscriberClass; + Class clazz; + String clazzName; + + void initForSubscriber(Class subscriberClass) { + this.subscriberClass = clazz = subscriberClass; + } + + void recycle() { + subscriberMethods.clear(); + methodKeyBuilder.setLength(0); + eventTypesFound.clear(); + } + + boolean checkAdd(Method method, Class eventType) { + methodKeyBuilder.setLength(0); + methodKeyBuilder.append(method.getName()); + methodKeyBuilder.append('>').append(eventType.getName()); + + String methodKey = methodKeyBuilder.toString(); + return eventTypesFound.add(methodKey); + } + + void nextClass() { + clazz = clazz.getSuperclass(); + clazzName = clazz.getName(); + /** Skip system classes, this just degrades performance. */ + if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) { + clazz = null; + clazzName = null; + } + } + } + } diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index e3310c6a..52b5b9ab 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -268,8 +268,9 @@ private TypeElement nextEntry(List> candidate = entries.get(i); - System.out.println(); - return candidate.getKey(); + if(!classesToSkip.contains(candidate.getKey())) { + return candidate.getKey(); + } } } } From f72fe79cea4ee12e59168c70c96051aa073f9b10 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 22 Jun 2015 23:06:11 +0200 Subject: [PATCH 044/288] travis: build-tools-22.0.1 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e086ce10..defb5481 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ jdk: # http://docs.travis-ci.com/user/languages/android/ android: components: - - build-tools-21.1.2 + - build-tools-22.0.1 - android-10 before_script: From afdbab048b0882cd918970c951723a68f8b27257 Mon Sep 17 00:00:00 2001 From: Evan Baker Date: Sat, 11 Jul 2015 12:01:20 -0400 Subject: [PATCH 045/288] Fully updated HOWTO.md to annotations Updated threading examples to annotations style. Updated priority example to annotations style. Updated sticky example to annotations style. --- HOWTO.md | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/HOWTO.md b/HOWTO.md index 4804f61f..c5f0f561 100644 --- a/HOWTO.md +++ b/HOWTO.md @@ -65,6 +65,7 @@ In EventBus, you may define the thread that will call the event handling method Example: ```java // Called in the same thread (default) + @Subscribe(threadmode = ThreadMode.PostThread) // ThreadMode is optional here public void onEvent(MessageEvent event) { log(event.message); } @@ -73,6 +74,7 @@ Example: Example: ```java // Called in Android UI's main thread + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(MessageEvent event) { textField.setText(event.message); } @@ -80,6 +82,7 @@ Example: * **BackgroundThread:** Subscriber will be called in a background thread. If posting thread is not the main thread, event handler methods will be called directly in the posting thread. If the posting thread is the main thread, EventBus uses a single background thread that will deliver all its events sequentially. Event handlers using this mode should try to return quickly to avoid blocking the background thread. ```java // Called in the background thread + @Subscribe(threadMode = ThreadMode.BackgroundThread) public void onEventBackgroundThread(MessageEvent event){ saveToDisk(event.message); } @@ -87,20 +90,23 @@ Example: * **Async:** Event handler methods are called in a separate thread. This is always independent from the posting thread and the main thread. Posting events never wait for event handler methods using this mode. Event handler methods should use this mode if their execution might take some time, e.g. for network access. Avoid triggering a large number of long running asynchronous handler methods at the same time to limit the number of concurrent threads. EventBus uses a thread pool to efficiently reuse threads from completed asynchronous event handler notifications. ```java // Called in a separate thread + @Subscribe(threadmode = ThreadMode.Async) public void onEventAsync(MessageEvent event){ backend.send(event.message); } ``` -*Note:* EventBus takes care of calling the `onEvent` method in the proper thread depending on its name (onEvent, onEventAsync, etc.). +*Note:* EventBus takes care of calling the `onEvent` method in the proper thread depending on its annotation. Subscriber priorities and ordered event delivery ------------------------------------------------ You may change the order of event delivery by providing a priority to the subscriber during registration. ```java - int priority = 1; - EventBus.getDefault().register(this, priority); + @Subscribe(priority = 1); + public void onEvent(MessageEvent event) { + ... + } ``` Within the same delivery thread (ThreadMode), higher priority subscribers will receive events before others with a lower priority. The default priority is 0. @@ -140,6 +146,7 @@ You may cancel the event delivery process by calling `cancelEventDelivery(Object Any further event delivery will be cancelled: subsequent subscribers won't receive the event. ```java // Called in the same thread (default) + @Subscribe public void onEvent(MessageEvent event){ // Process the event ... @@ -159,15 +166,17 @@ Let's say, an sticky event was posted some time ago: EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!")); ``` -After that, a new Activity gets started. During registration using registerSticky, it will immediately get the previously posted sticky event: +After that, a new Activity gets started. During registration, and sticky Subscriber methods will immediately get the previously posted sticky event: ```java @Override public void onStart() { super.onStart(); - EventBus.getDefault().registerSticky(this); + EventBus.getDefault().register(this); } - public void onEventMainThread(MessageEvent event) { + @Subscribe(sticky = true, threadmode = ThreadMode.MainThread) + public void onEvent(MessageEvent event) { + // UI updates must run on MainThread textField.setText(event.message); } @@ -185,11 +194,12 @@ You may also get the last sticky event of a certain type with: ProGuard configuration ---------------------- -ProGuard obfuscates method names. However, the onEvent methods must not renamed because they are accessed using reflection. Use the following snip in your ProGuard configuration file (proguard.cfg): +ProGuard obfuscates method names and may remove "unused" methods, including Subscriber methods. Use the following snip in your ProGuard configuration file (proguard.cfg) to prevent Subscribers from being removed: ``` +-keepattributes *Annotation* -keepclassmembers class ** { - public void onEvent*(**); + @de.greenrobot.event.Subscribe public *; } # Only required if you use AsyncExecutor @@ -210,7 +220,7 @@ Otto is another event bus library for Android; actually it's a fork of Guava's E Declare event handling methods - Name conventions + Annotations Annotations From d887e0d57cff66aaab423c869b2136f7d566b86e Mon Sep 17 00:00:00 2001 From: Evan Baker Date: Sat, 11 Jul 2015 13:14:58 -0400 Subject: [PATCH 046/288] threadmode -> threadMode --- HOWTO.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HOWTO.md b/HOWTO.md index c5f0f561..093f61f7 100644 --- a/HOWTO.md +++ b/HOWTO.md @@ -65,7 +65,7 @@ In EventBus, you may define the thread that will call the event handling method Example: ```java // Called in the same thread (default) - @Subscribe(threadmode = ThreadMode.PostThread) // ThreadMode is optional here + @Subscribe(threadMode = ThreadMode.PostThread) // ThreadMode is optional here public void onEvent(MessageEvent event) { log(event.message); } @@ -90,7 +90,7 @@ Example: * **Async:** Event handler methods are called in a separate thread. This is always independent from the posting thread and the main thread. Posting events never wait for event handler methods using this mode. Event handler methods should use this mode if their execution might take some time, e.g. for network access. Avoid triggering a large number of long running asynchronous handler methods at the same time to limit the number of concurrent threads. EventBus uses a thread pool to efficiently reuse threads from completed asynchronous event handler notifications. ```java // Called in a separate thread - @Subscribe(threadmode = ThreadMode.Async) + @Subscribe(threadMode = ThreadMode.Async) public void onEventAsync(MessageEvent event){ backend.send(event.message); } @@ -174,7 +174,7 @@ After that, a new Activity gets started. During registration, and sticky Subscri EventBus.getDefault().register(this); } - @Subscribe(sticky = true, threadmode = ThreadMode.MainThread) + @Subscribe(sticky = true, threadMode = ThreadMode.MainThread) public void onEvent(MessageEvent event) { // UI updates must run on MainThread textField.setText(event.message); From 0309993524c04743f08a245bd99668dbf8a74dca Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 17 Jul 2015 22:12:07 +0200 Subject: [PATCH 047/288] added CONTRIBUTING.md --- CONTRIBUTING.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..8e7aee90 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,44 @@ +Before you create an Issue... +============================= + +There are better Places for Support +----------------------------------- +Please be aware that an issue tracker is not the best place to ask for support. An issue tracker is used to track issues (bugs or feature requests). +Instead, please use [stackoverflow.com](http://stackoverflow.com/questions/tagged/greenrobot-eventbus?sort=frequent) and use the tag [greenrobot-eventbus](http://stackoverflow.com/tags/greenrobot-eventbus/info) for your question. +If you want professional support, you can contact the main author and maintainer [Markus Junginger via Google+](https://plus.google.com/+MarkusJunginger/posts). + +Examples for support questions better asked elsewhere: + +* Asking how something works +* Asking how to use EventBus in a specific scenario +* Your app crashes/misbehaves and you are not sure why + +The perfect Issue Report +------------------------ +A couple of simple steps can save time for everyone. + +Check before reporting: + +* It's not a support inquiry +* You have read the docs +* You searched the web and stackoverflow +* You searched existing issues to avoid duplicates + +Reporting bugs: + + * Please investigate if is the bug is really caused by the library. Isolate the issue: what's the minimal code to reproduce the bug? + * Bonus steps to gain extra karma points: once you isolated and identified the issue, you can prepare an push request. Submit an unit test causing the bug, and ideally a fix for the bug. + +Requesting features: + + * Ask yourself: is the feature useful for a majority users? One of our major goals is to keep the API simple and concise. We do not want to cover all possible use cases, but those that make 80% of users happy. + +A Note on Pull Requests +======================= +Pull requests (and issue) may queue up up a bit. Usually, pull requests and issues are checked when new releases are planned. + +For bigger pull requests, it's a good idea to check with the maintainer upfront about the idea and the implementation outline. + +Thanks for reading! +=================== +It's your contributions and feedback that makes maintaining this library fun. From 8032b085a3c6b598b97ea2bc58d15d6a83bcd73c Mon Sep 17 00:00:00 2001 From: mormih Date: Sat, 5 Sep 2015 22:15:19 +0400 Subject: [PATCH 048/288] Fixes issue #188 --- .../annotationprocessor/EventBusAnnotationProcessor.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 52b5b9ab..6a9cb8e9 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -28,7 +28,6 @@ import java.util.Set; @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") -@SupportedSourceVersion(SourceVersion.RELEASE_6) public class EventBusAnnotationProcessor extends AbstractProcessor { public static final String CLASS_POSTFIX = "_EventBusInfo"; private final Map> methodsByClass = @@ -38,6 +37,11 @@ public class EventBusAnnotationProcessor extends AbstractProcessor { private boolean writerRoundDone; private int round; + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + @Override public boolean process(Set annotations, RoundEnvironment env) { Messager messager = processingEnv.getMessager(); From 0697863f4f8e91da4cc5ec8a8f942b26d1756cc5 Mon Sep 17 00:00:00 2001 From: mormih Date: Sun, 6 Sep 2015 00:24:49 +0400 Subject: [PATCH 049/288] Fix artifactId when install in maven local repo failOnError = false on javadoc --- EventBusAnnotationProcessor/build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index 72b0ac29..e83462d5 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -2,6 +2,7 @@ apply plugin: 'java' apply plugin: 'maven' apply plugin: 'signing' +archivesBaseName = 'eventbus-annotation-processor' group = 'de.greenrobot' version = '3.0.0-beta2' @@ -44,6 +45,7 @@ sourceSets { } javadoc { + options. classpath += configurations.provided title = "EventBus Annotation Processor ${version} API" options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2015 greenrobot.de. All Rights Reserved.' @@ -92,7 +94,6 @@ uploadArchives { println "Settings sonatypeUsername/sonatypePassword missing/incomplete for ${project.name}" } - pom.artifactId = 'eventbus-annotation-processor' pom.project { name 'EventBus Annotation Processor' packaging 'jar' From d3d478b05c4162df22bebc41ab00d6dbd623f557 Mon Sep 17 00:00:00 2001 From: mormih Date: Sun, 6 Sep 2015 00:31:19 +0400 Subject: [PATCH 050/288] options. removed --- EventBusAnnotationProcessor/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index e83462d5..3fb5d8fd 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -45,7 +45,6 @@ sourceSets { } javadoc { - options. classpath += configurations.provided title = "EventBus Annotation Processor ${version} API" options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2015 greenrobot.de. All Rights Reserved.' From 4d21f93a5eea3caf89baaa9180ae60de88035b20 Mon Sep 17 00:00:00 2001 From: mormih Date: Tue, 8 Sep 2015 10:02:05 +0400 Subject: [PATCH 051/288] static part in processor was removed. --- .../event/annotationprocessor/EventBusAnnotationProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 6a9cb8e9..2072d671 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -209,7 +209,7 @@ private void writeSources() { writer.write("import de.greenrobot.event.ThreadMode;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); writer.write("public class " + infoClassName + " extends SubscriberInfo {\n"); - writer.write("\nstatic {new Exception(\"" + infoClassName + "created\").printStackTrace();}\n\n"); +// writer.write("\nstatic {new Exception(\"" + infoClassName + "created\").printStackTrace();}\n\n"); writer.write(" protected Data createSubscriberData() {\n"); writer.write(" Class subscriberClass = " + subscriberClassName + ".class;\n"); writer.write(" SubscriberMethod[] subscriberMethods = new SubscriberMethod[] {\n"); From 91719682b2caf598573c2356f0133704b73b45ca Mon Sep 17 00:00:00 2001 From: mormih Date: Tue, 8 Sep 2015 10:04:57 +0400 Subject: [PATCH 052/288] archivesBaseName --- EventBus/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index 0193f2dd..9f866979 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -2,6 +2,7 @@ apply plugin: 'java' apply plugin: 'maven' apply plugin: 'signing' +archivesBaseName = 'eventbus' group = 'de.greenrobot' version = '3.0.0-beta2' sourceCompatibility = 1.6 @@ -45,6 +46,7 @@ sourceSets { } javadoc { + failOnError = false classpath += configurations.provided title = "EventBus ${version} API" options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2012-2014 greenrobot.de. All Rights Reserved.' @@ -92,8 +94,6 @@ uploadArchives { } else { println "Settings sonatypeUsername/sonatypePassword missing/incomplete for ${project.name}" } - - pom.artifactId = 'eventbus' pom.project { name 'EventBus' packaging 'jar' From 258558111ed2b5e8ebd202fccc72c874d31066f5 Mon Sep 17 00:00:00 2001 From: Justin Tuchek Date: Wed, 23 Sep 2015 13:52:34 -0500 Subject: [PATCH 053/288] Update HOWTO.md remove duplicate instance of 'the' --- HOWTO.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HOWTO.md b/HOWTO.md index 8661770c..86a3d456 100644 --- a/HOWTO.md +++ b/HOWTO.md @@ -130,7 +130,7 @@ For example, it's possible to configure the default EventBus instance to rethrow EventBus.builder().throwSubscriberException(BuildConfig.DEBUG).installDefaultEventBus(); ``` -Note: this can be done only once before the the default EventBus instance is used the first time. This ensures consistent behavior in your app. Your Application class is a good place to configure the default EventBus instance before its used. +Note: this can be done only once before the default EventBus instance is used the first time. This ensures consistent behavior in your app. Your Application class is a good place to configure the default EventBus instance before its used. Cancelling event delivery ------------------------- @@ -244,4 +244,4 @@ Another customization options is the execution scope, which gives failure events Comparison with Square's Otto ----------------------------- -Check the [COMPARISON.md](COMPARISON.md) \ No newline at end of file +Check the [COMPARISON.md](COMPARISON.md) From 8b21b304247ef72e07c5a9f85b69404f248f7769 Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 8 Oct 2015 20:32:25 +0200 Subject: [PATCH 054/288] background.gif for minimal javadoc style adjustment --- javadoc-style/background.gif | Bin 0 -> 2313 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 javadoc-style/background.gif diff --git a/javadoc-style/background.gif b/javadoc-style/background.gif new file mode 100644 index 0000000000000000000000000000000000000000..ec068a06a33ef106d7b41bce36211482ff9ccd68 GIT binary patch literal 2313 zcmV+k3HJ6!Nk%w1VKM-40OkMy00030|NldAJw$RoMRPw&c|%5YKudZ=M|D9`hD%wL~lJqZ9GnYMooQ1OnXF2c|%EeLP&H#L~cD-j80UCOHzeOQG-cP zfk;exL{^DSRESJfh)h$4OHqPJT$58;kWpEVP*;pkR*FtnicV97OInapTaZ#(k5N{M zPGFcUzJu~lvQJ!T4I@5V3=58m{?<)T4tVIW1CxKn_FXT(QiDlRfk;DaJXniPL~T7;j89U5 zNl}1EU6NB;jZj{bR9lWwW0+ZFnObI>TxXnJ|Ns900000000000A^8LW004XdEC2ui z05Sk@000O7fMy|rW`%+wh=YTKi-n1ZgocodjfaVrf)|Evla`8_g`AfmppTQFW^NW0 z5Uj1OuCNfZudfxcwXC z+1T6M-s9WdW8dcJ-wO*3@9+W*5AY543-j^$^!EPz_4eHZ2#>)41`h@dc!2OAgN6$a zCS2I?;lqgx6IR4nkpTe;1RN0f=zxMq2O=q`94V5d$&e>Unta)^<;;^G3>e7yp=ZvW z6DIW3xpSvaogXF?_4%`@(V;s}NR^5J!3hrtJV@1QRV&r5S*L!zYE|rss${iFkg&!? zTN5V#)~=bmMorwgZsEpdOE)iExo+FO-8;8Kga{=HbSQCnF=E6W3?o*|ID%uwi5**> zJXy127Y9m+=HQ|PhXWi+xNwoWv}n_%Pq%(e+H~mGqhq5kv4Mo|-n~g|7!F*xZ{xv< zCpXS~dGg^IGK?4@J-T%b(XnUHFul6n<@2&4)zzyO2) z3Q8`i0+UKY*`$}e9mmp;tg*))`|PsK1|hAo%u0K$vDwm4gaSkm0j{`26k#qAKmbuhxZ#cquDR>B zD{s8+&TH-uNg$C#68QG}1HMBHfrP&L@@w$F_!itRzXdCN@V|LDAu%3!IDtq1#1UV7 z#1RxvT=B(DWbCoU5l=ia$Pp`Hgb_?Mp@hmtxZDI2N-)v#$}PXVvdm1d>@v(v`0TUJ zF)Pu89(q`zv=w^nVTIF3@3BYIPA}c`(@ZCAwbNBEt@PDUKe5CTR8aB66IE1!w%Amt zy+jpcn~k>GZpVFg+H6x{_uOksvBlq0OyT$6TyQZ37k(cOxZr|JEx1sGm<(M9gH z-~PMqyn|tT=))UN`|-FFFUA#KToK0fUOaz=7}Z~KeHhVC&%O27cTfHQ^WBU8z4p&T zp#>D|V}XShTD;Hx745Iz{`>K-Z$A|7!*Boo{mY;G21vjH8t{M!OrQc6$iN0V@PQDF zpadsK!3tXNf*8!81~qnXWuHZ)kytd=_y+ADWvw31ouV;CdZ#ya*(l7-A-C-Y^+iit8O zBy3*`Ls$|5Hn4m_^I^|C7{m7EFn|5vTk;|oywIgCc9Bb*=L+Y$)M>9GC<|HGs@6NB zHLY%03!dDf=eDRt2O6lVSFRcsuWZEwU?=z$CZ0W?#VJfdN>HG(l%oKpyiftJc|Y)xkjSJYCrQal-0PC~()T9xwF!Jf zVi1UA#3BBbh(i8r5&v#Pz!cF41KjbCc?4u2@@Q~oKLirt2TM30;y6b+zyX2`Yl9u; z`0$3;v0-YUp&7 Date: Mon, 2 Nov 2015 07:47:33 +0100 Subject: [PATCH 055/288] java 1.7, ignore javadoc 1.8 lint --- EventBus/build.gradle | 4 ++-- build.gradle | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index b377bf64..ab07c871 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -4,7 +4,7 @@ apply plugin: 'signing' group = 'de.greenrobot' version = '2.4.1-SNAPSHOT' -sourceCompatibility = 1.6 +sourceCompatibility = 1.7 def isSnapshot = version.endsWith('-SNAPSHOT') def sonatypeRepositoryUrl @@ -133,4 +133,4 @@ uploadArchives { } } } -} \ No newline at end of file +} diff --git a/build.gradle b/build.gradle index e69de29b..760a32ad 100644 --- a/build.gradle +++ b/build.gradle @@ -0,0 +1,7 @@ +if (JavaVersion.current().isJava8Compatible()) { + allprojects { + tasks.withType(Javadoc) { + options.addStringOption('Xdoclint:none', '-quiet') + } + } +} \ No newline at end of file From e25cfa4d1b719637269ab18da5087bbc7baaa630 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 2 Nov 2015 20:12:05 +0100 Subject: [PATCH 056/288] fix testUnregisterNotLeaking for Android 6 --- .../event/test/EventBusBasicTest.java | 29 +++++-------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java index c34feb38..f3b14d0f 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java @@ -20,8 +20,6 @@ import de.greenrobot.event.EventBus; import junit.framework.TestCase; -import java.lang.ref.WeakReference; - /** * @author Markus Junginger, greenrobot */ @@ -65,25 +63,14 @@ public void testUnregisterWithoutRegister() { } public void testUnregisterNotLeaking() { - EventBusBasicTest subscriber = new EventBusBasicTest(); - eventBus.register(subscriber); - eventBus.unregister(subscriber); - - WeakReference ref = new WeakReference(subscriber); - subscriber = null; - assertSubscriberNotReferenced(ref); - } - - private void assertSubscriberNotReferenced(WeakReference ref) { - EventBusBasicTest subscriberTest = new EventBusBasicTest(); - WeakReference refTest = new WeakReference(subscriberTest); - subscriberTest = null; - - // Yeah, in theory is is questionable (in practice just fine so far...) - System.gc(); - - assertNull(refTest.get()); - assertNull(ref.get()); + // This will throw "out of memory" if subscribers are leaked + for (int i = 0; i < 300; i++) { + EventBusBasicTest subscriber = new EventBusBasicTest() { + byte[] expensiveObject = new byte[1024 * 1024]; + }; + eventBus.register(subscriber); + eventBus.unregister(subscriber); + } } public void testRegisterTwice() { From be04a2de66981e819f40afd389e417e98c94c7da Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 2 Nov 2015 20:50:48 +0100 Subject: [PATCH 057/288] work around for broken Class.getDeclaredMethods() in Android (should fix #149) --- .../event/SubscriberMethodFinder.java | 113 +++++++++++------- 1 file changed, 71 insertions(+), 42 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 823cb0ec..a1c2c12b 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -21,7 +21,6 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -62,7 +61,7 @@ List findSubscriberMethods(Class subscriberClass) { } subscriberMethods = new ArrayList(); Class clazz = subscriberClass; - HashSet eventTypesFound = new HashSet(); + HashMap eventTypesFound = new HashMap(); StringBuilder methodKeyBuilder = new StringBuilder(); while (clazz != null) { String name = clazz.getName(); @@ -72,46 +71,18 @@ List findSubscriberMethods(Class subscriberClass) { } // Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again) - Method[] methods = clazz.getDeclaredMethods(); - for (Method method : methods) { - String methodName = method.getName(); - if (methodName.startsWith(ON_EVENT_METHOD_NAME)) { - int modifiers = method.getModifiers(); - 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); - } - } + try { + // This is faster than getMethods, especially when subscribers a fat classes like Activities + Method[] methods = clazz.getDeclaredMethods(); + filterSubscriberMethods(subscriberMethods, eventTypesFound, methodKeyBuilder, methods); + } catch (Throwable th) { + th.printStackTrace(); + // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149 + Method[] methods = subscriberClass.getMethods(); + subscriberMethods.clear(); + eventTypesFound.clear(); + filterSubscriberMethods(subscriberMethods, eventTypesFound, methodKeyBuilder, methods); + break; } clazz = clazz.getSuperclass(); } @@ -126,6 +97,64 @@ List findSubscriberMethods(Class subscriberClass) { } } + private void filterSubscriberMethods(List subscriberMethods, + HashMap eventTypesFound, StringBuilder methodKeyBuilder, + Method[] methods) { + for (Method method : methods) { + String methodName = method.getName(); + if (methodName.startsWith(ON_EVENT_METHOD_NAME)) { + int modifiers = method.getModifiers(); + Class methodClass = method.getDeclaringClass(); + if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { + Class[] parameterTypes = method.getParameterTypes(); + if (parameterTypes.length == 1) { + ThreadMode threadMode = getThreadMode(methodClass, method, methodName); + if (threadMode == null) { + continue; + } + Class eventType = parameterTypes[0]; + methodKeyBuilder.setLength(0); + methodKeyBuilder.append(methodName); + methodKeyBuilder.append('>').append(eventType.getName()); + String methodKey = methodKeyBuilder.toString(); + Class methodClassOld = eventTypesFound.put(methodKey, methodClass); + if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) { + // Only add if not already found in a sub class + subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType)); + } else { + // Revert the put, old class is further down the class hierarchy + eventTypesFound.put(methodKey, methodClassOld); + } + } + } else if (!skipMethodVerificationForClasses.containsKey(methodClass)) { + Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + methodClass + "." + + methodName); + } + } + } + } + + private ThreadMode getThreadMode(Class clazz, Method method, String methodName) { + 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)) { + throw new EventBusException("Illegal onEvent method, check for typos: " + method); + } else { + threadMode = null; + } + } + return threadMode; + } + static void clearCaches() { synchronized (methodCache) { methodCache.clear(); From 62e7eb73bc011fa83f3bd7ea307d52b6eb729a74 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 2 Nov 2015 21:05:50 +0100 Subject: [PATCH 058/288] typo, fixes #219 --- EventBus/src/de/greenrobot/event/EventBus.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index 95863ade..16eb3978 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -234,7 +234,7 @@ public synchronized boolean isRegistered(Object subscriber) { } /** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */ - private void unubscribeByEventType(Object subscriber, Class eventType) { + private void unsubscribeByEventType(Object subscriber, Class eventType) { List subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions != null) { int size = subscriptions.size(); @@ -255,7 +255,7 @@ public synchronized void unregister(Object subscriber) { List> subscribedTypes = typesBySubscriber.get(subscriber); if (subscribedTypes != null) { for (Class eventType : subscribedTypes) { - unubscribeByEventType(subscriber, eventType); + unsubscribeByEventType(subscriber, eventType); } typesBySubscriber.remove(subscriber); } else { From 38bdbfa2240958c1bad08299d9488f1268b2a0fe Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 2 Nov 2015 21:26:14 +0100 Subject: [PATCH 059/288] Travis CI: removed Java 1.6, sudo: false --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e086ce10..71a89804 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ +sudo: false language: android jdk: - - openjdk6 - oraclejdk7 # http://docs.travis-ci.com/user/languages/android/ From 8cdcedddbe4a9d5a7607f56f4a1cd04582b0590d Mon Sep 17 00:00:00 2001 From: Andrew Shu Date: Tue, 3 Nov 2015 17:39:43 -0800 Subject: [PATCH 060/288] ProGuard config for @Subscribe annotation --- HOWTO.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/HOWTO.md b/HOWTO.md index 4804f61f..8df11d0b 100644 --- a/HOWTO.md +++ b/HOWTO.md @@ -192,6 +192,12 @@ ProGuard obfuscates method names. However, the onEvent methods must not renamed public void onEvent*(**); } +# EventBus 3.0 annotation +-keepclassmembers class * { + @de.greenrobot.event.Subscribe ; +} +-keep enum de.greenrobot.event.ThreadMode { *; } + # Only required if you use AsyncExecutor -keepclassmembers class * extends de.greenrobot.event.util.ThrowableFailureEvent { (java.lang.Throwable); From 17e779919d18c838a7bebd7ea1eba388a678b4ba Mon Sep 17 00:00:00 2001 From: Frieder Bluemle Date: Wed, 4 Nov 2015 17:42:44 +0800 Subject: [PATCH 061/288] Update .gitignore --- .gitignore | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 36573eee..2efc5853 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,31 @@ -.settings/ +# Built application files +*.apk +*.ap_ -*.iml -.idea +# Files for the Dalvik VM +*.dex -gen/ +# Java class files +*.class + +# Generated files bin/ +gen/ release/ -build/ +# Gradle files .gradle/ -gradle.properties +build/ +# Local configuration file (sdk path, etc) local.properties + +# IntelliJ project files +*.iml +.idea/ + +# Eclipse project files +.settings/ + +# Misc +.DS_Store From dc9b2b595824829a54c30cb2557c22c690937508 Mon Sep 17 00:00:00 2001 From: Frieder Bluemle Date: Wed, 4 Nov 2015 17:33:21 +0800 Subject: [PATCH 062/288] Set executable bit of gradlew --- gradlew | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 gradlew diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 From 78497b3c25c7cc103c425454be0877698a55ef9b Mon Sep 17 00:00:00 2001 From: Frieder Bluemle Date: Wed, 4 Nov 2015 17:33:29 +0800 Subject: [PATCH 063/288] Update Gradle wrapper to 2.8 --- gradle/wrapper/gradle-wrapper.jar | Bin 51018 -> 53637 bytes gradle/wrapper/gradle-wrapper.properties | 4 +- gradlew | 10 +- gradlew.bat | 180 +++++++++++------------ 4 files changed, 95 insertions(+), 99 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index c97a8bdb9088d370da7e88784a7a093b971aa23a..05ef575b0cd0173fc735f2857ce4bd594ce4f6bd 100644 GIT binary patch delta 25737 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 delta 23219 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c8dcd502..c1823e9a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sun Feb 22 14:20:02 CET 2015 +#Wed Nov 04 17:33:28 SGT 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip diff --git a/gradlew b/gradlew index 91a7e269..9d82f789 100755 --- a/gradlew +++ b/gradlew @@ -42,11 +42,6 @@ case "`uname`" in ;; esac -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" @@ -61,9 +56,9 @@ while [ -h "$PRG" ] ; do fi done SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- +cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" -cd "$SAVED" >&- +cd "$SAVED" >/dev/null CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -114,6 +109,7 @@ fi if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` diff --git a/gradlew.bat b/gradlew.bat index 8a0b282a..aec99730 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,90 +1,90 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega From 1b44d620e8e13b8d12e3ffa81db3792ffd4ae473 Mon Sep 17 00:00:00 2001 From: Frieder Bluemle Date: Wed, 4 Nov 2015 17:36:47 +0800 Subject: [PATCH 064/288] Update build tools to 23.0.1 --- .travis.yml | 2 +- EventBusPerformance/build.gradle | 2 +- EventBusTest/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 71a89804..07706ece 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ jdk: # http://docs.travis-ci.com/user/languages/android/ android: components: - - build-tools-21.1.2 + - build-tools-23.0.1 - android-10 before_script: diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 570c64b0..9bd680df 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -20,7 +20,7 @@ dependencies { } android { - buildToolsVersion '21.1.2' + buildToolsVersion '23.0.1' compileSdkVersion 19 sourceSets { diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 2f48f9c5..2bdf4058 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -19,7 +19,7 @@ dependencies { } android { - buildToolsVersion '21.1.2' + buildToolsVersion '23.0.1' compileSdkVersion 19 sourceSets { From 304dabf6135cc8262a1351c8381f28995a65109f Mon Sep 17 00:00:00 2001 From: Frieder Bluemle Date: Wed, 4 Nov 2015 17:47:37 +0800 Subject: [PATCH 065/288] Update Android Gradle plug-in to 1.3.1 --- EventBusPerformance/build.gradle | 6 +++--- EventBusTest/build.gradle | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 9bd680df..f8d7dbfc 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -1,17 +1,17 @@ buildscript { repositories { - mavenCentral() + jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:1.1.0' + classpath 'com.android.tools.build:gradle:1.3.1' } } apply plugin: 'com.android.application' repositories { - mavenCentral() + jcenter() } dependencies { diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 2bdf4058..a8b1fb07 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -1,17 +1,17 @@ buildscript { repositories { - mavenCentral() + jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:1.1.0' + classpath 'com.android.tools.build:gradle:1.3.1' } } apply plugin: 'com.android.application' repositories { - mavenCentral() + jcenter() } dependencies { From f806388af8748286b6826dccc952454b4bf6075f Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 6 Nov 2015 20:35:01 +0100 Subject: [PATCH 066/288] Proguard rule updated: *** matches any type (primitive or non-primitive, array or non-array) fixes #136, #137 --- HOWTO.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HOWTO.md b/HOWTO.md index 86a3d456..aafc2ed6 100644 --- a/HOWTO.md +++ b/HOWTO.md @@ -189,7 +189,7 @@ ProGuard obfuscates method names. However, the onEvent methods must not renamed ``` -keepclassmembers class ** { - public void onEvent*(**); + public void onEvent*(***); } # Only required if you use AsyncExecutor From 81994d6bbcf12cfcc0a531a2201469e1959d91cb Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 6 Nov 2015 20:38:46 +0100 Subject: [PATCH 067/288] added gradle.properties to .gitignore again after merge --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2efc5853..36c5498b 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ release/ # Gradle files .gradle/ build/ +gradle.properties # Local configuration file (sdk path, etc) local.properties From b2454a5ca033249d0c170e8ac22383327510b080 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 9 Nov 2015 11:37:54 +0100 Subject: [PATCH 068/288] Link to survey --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e7c6975b..664c878f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +**Please help us with this short survey: http://bit.ly/eventbus-survey Thank for your support! ** + EventBus ======== EventBus is publish/subscribe event bus optimized for Android.
From 36cfff58f207f0518eff53529b26bb57f1997504 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 9 Nov 2015 11:42:14 +0100 Subject: [PATCH 069/288] minor formatting fixes --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 664c878f..9a8a652a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -**Please help us with this short survey: http://bit.ly/eventbus-survey Thank for your support! ** +**Please help us with this short survey: http://bit.ly/eventbus-survey Thank for your support!** EventBus ======== @@ -69,8 +69,8 @@ FAQ **Q:** How is EventBus different to Android's BroadcastReceiver/Intent system?
**A:** Unlike Android's BroadcastReceiver/Intent system, EventBus uses standard Java classes as events and offers a more convenient API. EventBus is intended for a lot more uses cases where you wouldn't want to go through the hassle of setting up Intents, preparing Intent extras, implementing broadcast receivers, and extracting Intent extras again. Also, EventBus comes with a much lower overhead. - **Q:** How to do pull requests?
- **A:** Ensure good code quality and consistent formatting. EventBus has a good test coverage: if you propose a new feature or fix a bug, please add a unit test. +**Q:** How to do pull requests?
+**A:** Ensure good code quality and consistent formatting. EventBus has a good test coverage: if you propose a new feature or fix a bug, please add a unit test. Release History, License ------------------------ From ff91dcc65c896d0412bf964a3b1d0ce26e4dd0c9 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 9 Nov 2015 19:55:58 +0100 Subject: [PATCH 070/288] typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9a8a652a..3b6c7a26 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -**Please help us with this short survey: http://bit.ly/eventbus-survey Thank for your support!** +**Please help us with this short survey: http://bit.ly/eventbus-survey Thanks for your support!** EventBus ======== From 6f2b5a366c47d7ce82bde68a529a4538630b313d Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 12 Nov 2015 09:56:47 +0100 Subject: [PATCH 071/288] V2.4.1 --- CHANGELOG.md | 3 ++- EventBus/build.gradle | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1db6f10c..afe615df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ -### V2.x.x (2015-0x-xx) Future release +### V2.4.1 (2015-11-12) Bug fix release * Registering for sticky events now considers sticky events of subclasses, not just the exact same event type. This makes the semantic consistent to posting events. Note, that this may lead to subscribers being called more than once if matching sticky events of event type subclasses are available. +* Workaround for an Android bug causing NoClassDefFoundError on some devices ### V2.4.0 (2014-11-11) Clean up release * Removed deprecated APIs: A year ago in Version 2.2.0, a couple of EventBus methods were deprecated and flagged to be removed in a future release. Well, version 2.4.0 is that release. Clean ups like this one keep the API concise and simple. diff --git a/EventBus/build.gradle b/EventBus/build.gradle index ab07c871..856aae4c 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'maven' apply plugin: 'signing' group = 'de.greenrobot' -version = '2.4.1-SNAPSHOT' +version = '2.4.1' sourceCompatibility = 1.7 def isSnapshot = version.endsWith('-SNAPSHOT') @@ -45,9 +45,10 @@ sourceSets { } javadoc { + failOnError = false classpath += configurations.provided title = "EventBus ${version} API" - options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2012-2014
greenrobot.de. All Rights Reserved.' + options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2012-2015 greenrobot.de. All Rights Reserved.' } task javadocJar(type: Jar, dependsOn: javadoc) { From 039faa574d5610f1c7f75a8800d14ff7fc245a88 Mon Sep 17 00:00:00 2001 From: Markus Date: Sun, 15 Nov 2015 17:43:43 -0800 Subject: [PATCH 072/288] prepared 2.4.2-SNAPSHOT --- EventBus/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index 856aae4c..3accb1e5 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'maven' apply plugin: 'signing' group = 'de.greenrobot' -version = '2.4.1' +version = '2.4.2-SNAPSHOT' sourceCompatibility = 1.7 def isSnapshot = version.endsWith('-SNAPSHOT') From d5117be04565d1bf17cd6231cda9b994dbd82f1f Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 17 Nov 2015 19:44:56 -0800 Subject: [PATCH 073/288] adjusted COMPARISON.md --- COMPARISON.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/COMPARISON.md b/COMPARISON.md index d7733f8d..31fadc03 100644 --- a/COMPARISON.md +++ b/COMPARISON.md @@ -12,14 +12,14 @@ Otto is another event bus library for Android; actually it's a fork of Guava's E Declare event handling methods - Name conventions + Annotations (since 3.0, can be precompiled for best performance) Annotations - + Event inheritance Yes Yes - + Subscriber inheritance Yes @@ -39,17 +39,17 @@ Otto is another event bus library for Android; actually it's a fork of Guava's E Event delivery in posting thread Yes (Default) Yes - + Event delivery in main thread Yes No - + Event delivery in background thread Yes No - + Asynchronous event delivery Yes @@ -57,6 +57,8 @@ Otto is another event bus library for Android; actually it's a fork of Guava's E +_**Note:** the following information is outdated, preprocessed annotations are much faster than EventBus 2.x, on which the following table is based._ + Besides features, performance is another differentiator. To compare performance, we created an Android application, which is also part of this repository (EventBusPerformance). You can also run the app on your phone to benchmark different scenarios. Benchmark results indicate that EventBus is significantly faster in almost every scenario: From d2f950940547a74f0b7eed484ed6c76074606cfd Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 18 Nov 2015 13:19:30 +0100 Subject: [PATCH 074/288] minor formatting, javadoc, and rename --- .../EventBusAnnotationProcessor.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 2072d671..c333171d 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -6,7 +6,6 @@ import javax.annotation.processing.Messager; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; -import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; @@ -30,6 +29,8 @@ @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") public class EventBusAnnotationProcessor extends AbstractProcessor { public static final String CLASS_POSTFIX = "_EventBusInfo"; + + /** Found subscriber methods for a class (without superclasses). */ private final Map> methodsByClass = new HashMap>(); private final Set classesToSkip = new HashSet(); @@ -87,7 +88,7 @@ private void collectSubscribers(Set annotations, RoundEnv for (Element element : elements) { if (element instanceof ExecutableElement) { ExecutableElement method = (ExecutableElement) element; - if (checkHasErrors(method, messager)) { + if (checkHasNoErrors(method, messager)) { Element classElement = method.getEnclosingElement(); List methods = methodsByClass.get(classElement); if (methods == null) { @@ -103,7 +104,7 @@ private void collectSubscribers(Set annotations, RoundEnv } } - private boolean checkHasErrors(ExecutableElement element, Messager messager) { + private boolean checkHasNoErrors(ExecutableElement element, Messager messager) { if (element.getModifiers().contains(Modifier.STATIC)) { messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must not be static", element); return false; @@ -209,7 +210,7 @@ private void writeSources() { writer.write("import de.greenrobot.event.ThreadMode;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); writer.write("public class " + infoClassName + " extends SubscriberInfo {\n"); -// writer.write("\nstatic {new Exception(\"" + infoClassName + "created\").printStackTrace();}\n\n"); + // writer.write("\nstatic {new Exception(\"" + infoClassName + "created\").printStackTrace();}\n\n"); writer.write(" protected Data createSubscriberData() {\n"); writer.write(" Class subscriberClass = " + subscriberClassName + ".class;\n"); writer.write(" SubscriberMethod[] subscriberMethods = new SubscriberMethod[] {\n"); @@ -272,7 +273,7 @@ private TypeElement nextEntry(List> candidate = entries.get(i); - if(!classesToSkip.contains(candidate.getKey())) { + if (!classesToSkip.contains(candidate.getKey())) { return candidate.getKey(); } } From 9efffe13f2ffc68fb3deca09b9d2934ba91635f3 Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 19 Nov 2015 19:53:28 +0100 Subject: [PATCH 075/288] fixed getting SubscriberInfo for super class(es) --- .../src/de/greenrobot/event/SubscriberMethodFinder.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 96635ef9..a02c8765 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -72,7 +72,7 @@ private List findUsingInfo(Class subscriberClass) { FindState findState = new FindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { - SubscriberInfo info = getSubscriberInfo(subscriberClass); + SubscriberInfo info = getSubscriberInfo(findState.clazz); if (info != null) { SubscriberInfo.Data subscriberData = info.getSubscriberData(); SubscriberMethod[] array = subscriberData.subscriberMethods; @@ -84,7 +84,7 @@ private List findUsingInfo(Class subscriberClass) { } else { findUsingReflectionInSingleClass(findState); } - findState.nextClass(); + findState.moveToSuperclass(); } return findState.subscriberMethods; } @@ -111,7 +111,7 @@ private List findUsingReflection(Class subscriberClass) { findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { findUsingReflectionInSingleClass(findState); - findState.nextClass(); + findState.moveToSuperclass(); } return findState.subscriberMethods; } @@ -182,7 +182,7 @@ boolean checkAdd(Method method, Class eventType) { return eventTypesFound.add(methodKey); } - void nextClass() { + void moveToSuperclass() { clazz = clazz.getSuperclass(); clazzName = clazz.getName(); /** Skip system classes, this just degrades performance. */ From 45846eb050c3b59fad166d9c9a0165b6e40b091f Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 19 Nov 2015 22:24:39 +0100 Subject: [PATCH 076/288] minor --- EventBus/src/de/greenrobot/event/SubscriberInfo.java | 2 +- .../annotationprocessor/EventBusAnnotationProcessor.java | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfo.java b/EventBus/src/de/greenrobot/event/SubscriberInfo.java index 00b9ca17..5c907cfa 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberInfo.java +++ b/EventBus/src/de/greenrobot/event/SubscriberInfo.java @@ -30,7 +30,7 @@ Data getSubscriberData() { abstract protected Data createSubscriberData(); - protected SubscriberMethod createSubscriberMethod(Class subscriberClass, String methodName, Class eventType, + protected static SubscriberMethod createSubscriberMethod(Class subscriberClass, String methodName, Class eventType, ThreadMode threadMode, int priority, boolean sticky) { try { Method method = subscriberClass.getDeclaredMethod(methodName, eventType); diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index c333171d..16cf695a 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -236,6 +236,7 @@ private void writeSources() { } private void writeNextEntry(BufferedWriter writer, String myPackage, TypeElement nextEntry) throws IOException { + String nextValue; if (nextEntry != null) { PackageElement nextPackageElement = getPackageElement(nextEntry); String nextPackage = nextPackageElement.getQualifiedName().toString(); @@ -244,10 +245,11 @@ private void writeNextEntry(BufferedWriter writer, String myPackage, TypeElement if (!myPackage.equals(nextPackage)) { nextInfoClassName = nextPackage + "." + nextInfoClassName; } - writer.write(" Class next = " + nextInfoClassName + ".class" + ";\n"); + nextValue = nextInfoClassName + ".class"; } else { - writer.write(" Class next = null;\n"); + nextValue = "null"; } + writer.write(" Class next = " + nextValue + ";\n"); } private String getClassString(TypeElement subscriberClass, String subscriberPackage) { From 8c765a88096121bc835a824e50e6684bd689d2ef Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 19 Nov 2015 22:31:13 +0100 Subject: [PATCH 077/288] Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149 - adapted be04a2de66981e819f40afd389e417e98c94c7da from master to annotation based version --- .../event/SubscriberMethodFinder.java | 42 ++++++++++++++----- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index a02c8765..a03cfb37 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -19,7 +19,6 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; @@ -117,7 +116,15 @@ private List findUsingReflection(Class subscriberClass) { } private void findUsingReflectionInSingleClass(FindState findState) { - Method[] methods = findState.clazz.getDeclaredMethods(); + Method[] methods; + try { + // This is faster than getMethods, especially when subscribers a fat classes like Activities + methods = findState.clazz.getDeclaredMethods(); + } catch (Throwable th) { + // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149 + methods = findState.clazz.getMethods(); + findState.skipSuperClasses = true; + } for (Method method : methods) { int modifiers = method.getModifiers(); if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { @@ -134,14 +141,14 @@ private void findUsingReflectionInSingleClass(FindState findState) { } } else if (strictMethodVerification) { if (method.isAnnotationPresent(Subscribe.class)) { - String methodName = findState.clazzName + "." + method.getName(); + 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) { if (method.isAnnotationPresent(Subscribe.class)) { - String methodName = findState.clazzName + "." + method.getName(); + String methodName = method.getDeclaringClass().getName() + "." + method.getName(); throw new EventBusException(methodName + " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); } @@ -157,11 +164,12 @@ static void clearCaches() { class FindState { final List subscriberMethods = new ArrayList(); - final HashSet eventTypesFound = new HashSet(); + final Map eventTypesFound = new HashMap(); final StringBuilder methodKeyBuilder = new StringBuilder(); Class subscriberClass; Class clazz; String clazzName; + boolean skipSuperClasses; void initForSubscriber(Class subscriberClass) { this.subscriberClass = clazz = subscriberClass; @@ -179,16 +187,30 @@ boolean checkAdd(Method method, Class eventType) { methodKeyBuilder.append('>').append(eventType.getName()); String methodKey = methodKeyBuilder.toString(); - return eventTypesFound.add(methodKey); + Class methodClass = method.getDeclaringClass(); + Class methodClassOld = eventTypesFound.put(methodKey, methodClass); + if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) { + // Only add if not already found in a sub class + return true; + } else { + // Revert the put, old class is further down the class hierarchy + eventTypesFound.put(methodKey, methodClassOld); + return false; + } } void moveToSuperclass() { - clazz = clazz.getSuperclass(); - clazzName = clazz.getName(); - /** Skip system classes, this just degrades performance. */ - if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) { + if (skipSuperClasses) { clazz = null; clazzName = null; + } else { + clazz = clazz.getSuperclass(); + clazzName = clazz.getName(); + /** Skip system classes, this just degrades performance. */ + if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) { + clazz = null; + clazzName = null; + } } } } From 4cf3f4c040860d32cf82d30af35583d6afb28e9c Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 19 Nov 2015 22:56:18 +0100 Subject: [PATCH 078/288] faster unit test: testUnregisterNotLeaking should only iterate heapMBytes * 2 --- .../src/de/greenrobot/event/test/EventBusBasicTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java index bb0b1ca8..c81d2140 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java @@ -64,14 +64,16 @@ public void testUnregisterWithoutRegister() { eventBus.unregister(this); } + // This will throw "out of memory" if subscribers are leaked public void testUnregisterNotLeaking() { - // This will throw "out of memory" if subscribers are leaked - for (int i = 0; i < 300; i++) { + int heapMBytes = (int) (Runtime.getRuntime().maxMemory() / (1024L * 1024L)); + for (int i = 0; i < heapMBytes * 2; i++) { EventBusBasicTest subscriber = new EventBusBasicTest() { byte[] expensiveObject = new byte[1024 * 1024]; }; eventBus.register(subscriber); eventBus.unregister(subscriber); + Log.d("Test", "Iteration " + i + " / max heap: " + heapMBytes); } } From 9a4d845e4d86098e1fede8587b1fe2334caa72ba Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 19 Nov 2015 22:59:48 +0100 Subject: [PATCH 079/288] changed ThreadMode enum values (also fixes #203) --- .../src/de/greenrobot/event/EventBus.java | 12 +++++----- .../src/de/greenrobot/event/Subscribe.java | 4 +--- .../src/de/greenrobot/event/ThreadMode.java | 8 +++---- .../test/EventBusBackgroundThreadTest.java | 2 +- .../test/EventBusCancelEventDeliveryTest.java | 2 +- .../test/EventBusMainThreadRacingTest.java | 2 +- .../event/test/EventBusMainThreadTest.java | 2 +- .../test/EventBusMethodModifiersTest.java | 6 ++--- .../event/test/EventBusMultithreadedTest.java | 12 +++++----- .../EventBusOrderedSubscriptionsTest.java | 24 +++++++++---------- 10 files changed, 36 insertions(+), 38 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index 33817aa8..af47c7b9 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -275,7 +275,7 @@ public void post(Object event) { * subscribers * won't receive the event. Events are usually canceled by higher priority subscribers (see * {@link Subscribe#priority()}). Canceling is restricted to event handling methods running in posting thread - * {@link ThreadMode#PostThread}. + * {@link ThreadMode#POSTING}. */ public void cancelEventDelivery(Object event) { PostingThreadState postingState = currentPostingThreadState.get(); @@ -286,7 +286,7 @@ public void cancelEventDelivery(Object event) { throw new EventBusException("Event may not be null"); } else if (postingState.event != event) { throw new EventBusException("Only the currently handled event may be aborted"); - } else if (postingState.subscription.subscriberMethod.threadMode != ThreadMode.PostThread) { + } else if (postingState.subscription.subscriberMethod.threadMode != ThreadMode.POSTING) { throw new EventBusException(" event handlers may only abort the incoming event"); } @@ -425,24 +425,24 @@ private boolean postSingleEventForEventType(Object event, PostingThreadState pos private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { switch (subscription.subscriberMethod.threadMode) { - case PostThread: + case POSTING: invokeSubscriber(subscription, event); break; - case MainThread: + case MAIN: if (isMainThread) { invokeSubscriber(subscription, event); } else { mainThreadPoster.enqueue(subscription, event); } break; - case BackgroundThread: + case BACKGROUND: if (isMainThread) { backgroundPoster.enqueue(subscription, event); } else { invokeSubscriber(subscription, event); } break; - case Async: + case ASYNC: asyncPoster.enqueue(subscription, event); break; default: diff --git a/EventBus/src/de/greenrobot/event/Subscribe.java b/EventBus/src/de/greenrobot/event/Subscribe.java index 82cf51fc..6532c6cd 100644 --- a/EventBus/src/de/greenrobot/event/Subscribe.java +++ b/EventBus/src/de/greenrobot/event/Subscribe.java @@ -7,13 +7,11 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import de.greenrobot.event.ThreadMode; - @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface Subscribe { - ThreadMode threadMode() default ThreadMode.PostThread; + ThreadMode threadMode() default ThreadMode.POSTING; /** * If true, delivers the most recent sticky event (posted with diff --git a/EventBus/src/de/greenrobot/event/ThreadMode.java b/EventBus/src/de/greenrobot/event/ThreadMode.java index 4022ace5..bbe060cd 100644 --- a/EventBus/src/de/greenrobot/event/ThreadMode.java +++ b/EventBus/src/de/greenrobot/event/ThreadMode.java @@ -29,14 +29,14 @@ public enum ThreadMode { * simple tasks that are known to complete is a very short time without requiring the main thread. Event handlers * using this mode must return quickly to avoid blocking the posting thread, which may be the main thread. */ - PostThread, + POSTING, /** * Subscriber will be called in Android's main thread (sometimes referred to as UI thread). If the posting thread is * the main thread, event handler methods will be called directly. Event handlers using this mode must return * quickly to avoid blocking the main thread. */ - MainThread, + MAIN, /** * Subscriber will be called in a background thread. If posting thread is not the main thread, event handler methods @@ -44,7 +44,7 @@ public enum ThreadMode { * background thread, that will deliver all its events sequentially. Event handlers using this mode should try to * return quickly to avoid blocking the background thread. */ - BackgroundThread, + BACKGROUND, /** * Event handler methods are called in a separate thread. This is always independent from the posting thread and the @@ -53,5 +53,5 @@ public enum ThreadMode { * of long running asynchronous handler methods at the same time to limit the number of concurrent threads. EventBus * uses a thread pool to efficiently reuse threads from completed asynchronous event handler notifications. */ - Async + ASYNC } \ No newline at end of file diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java index 99de5a32..b590ed5e 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java @@ -42,7 +42,7 @@ public void testPostFromMain() throws InterruptedException { assertFalse(lastThread.equals(Looper.getMainLooper().getThread())); } - @Subscribe(threadMode = ThreadMode.BackgroundThread) + @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onEventBackgroundThread(String event) { trackEvent(event); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java index 748adcaa..f9b05627 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java @@ -129,7 +129,7 @@ public void onEvent(String event) { public class SubscriberMainThread { final CountDownLatch done = new CountDownLatch(1); - @Subscribe(threadMode = ThreadMode.MainThread) + @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(String event) { try { eventBus.cancelEventDelivery(event); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java index 9fa4a487..b7127db5 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java @@ -86,7 +86,7 @@ public void run() { awaitLatch(doneLatch, 10); } - @Subscribe(threadMode = ThreadMode.MainThread) + @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(String event) { trackEvent(event); if (unregistered) { diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java index 3d6b7541..2d62ab4d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java @@ -59,7 +59,7 @@ public void testPostInBackgroundThread() throws InterruptedException { assertEquals(Looper.getMainLooper().getThread(), lastThread); } - @Subscribe(threadMode = ThreadMode.MainThread) + @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(String event) { trackEvent(event); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java index aad8d781..e3f6c9c5 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java @@ -39,19 +39,19 @@ public void onEvent(String event) { assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } - @Subscribe(threadMode = ThreadMode.MainThread) + @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(String event) { trackEvent(event); assertSame(Looper.getMainLooper(), Looper.myLooper()); } - @Subscribe(threadMode = ThreadMode.BackgroundThread) + @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onEventBackgroundThread(String event) { trackEvent(event); assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } - @Subscribe(threadMode = ThreadMode.Async) + @Subscribe(threadMode = ThreadMode.ASYNC) public void onEventAsync(String event) { trackEvent(event); assertNotSame(Looper.getMainLooper(), Looper.myLooper()); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java index 87d89d13..1efbcd92 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java @@ -166,21 +166,21 @@ private List startThreads(CountDownLatch latch, int threadCount, i return threads; } - @Subscribe(threadMode = ThreadMode.BackgroundThread) + @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onEventBackgroundThread(String event) { lastStringEvent = event; countStringEvent.incrementAndGet(); trackEvent(event); } - @Subscribe(threadMode = ThreadMode.MainThread) + @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(Integer event) { lastIntegerEvent = event; countIntegerEvent.incrementAndGet(); trackEvent(event); } - @Subscribe(threadMode = ThreadMode.Async) + @Subscribe(threadMode = ThreadMode.ASYNC) public void onEventAsync(IntTestEvent event) { countIntTestEvent.incrementAndGet(); lastIntTestEvent = event; @@ -245,12 +245,12 @@ public void run() { } } - @Subscribe(threadMode = ThreadMode.MainThread) + @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(String event) { assertSame(Looper.getMainLooper(), Looper.myLooper()); } - @Subscribe(threadMode = ThreadMode.BackgroundThread) + @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onEventBackgroundThread(Integer event) { assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } @@ -260,7 +260,7 @@ public void onEvent(Object event) { assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } - @Subscribe(threadMode = ThreadMode.Async) + @Subscribe(threadMode = ThreadMode.ASYNC) public void onEventAsync(Object event) { assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java index 5bba1a64..7630ea64 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java @@ -94,32 +94,32 @@ public void onEventM100(String event) { } - @Subscribe(threadMode = ThreadMode.MainThread, priority = -1) + @Subscribe(threadMode = ThreadMode.MAIN, priority = -1) public void onEventMainThreadM1(IntTestEvent event) { handleEvent(-1, event); } - @Subscribe(threadMode = ThreadMode.MainThread) + @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThreadP0(IntTestEvent event) { handleEvent(0, event); } - @Subscribe(threadMode = ThreadMode.MainThread, priority = 1) + @Subscribe(threadMode = ThreadMode.MAIN, priority = 1) public void onEventMainThreadP1(IntTestEvent event) { handleEvent(1, event); } - @Subscribe(threadMode = ThreadMode.BackgroundThread, priority = 1) + @Subscribe(threadMode = ThreadMode.BACKGROUND, priority = 1) public void onEventBackgroundThreadP1(Integer event) { handleEvent(1, event); } - @Subscribe(threadMode = ThreadMode.BackgroundThread) + @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onEventBackgroundThreadP0(Integer event) { handleEvent(0, event); } - @Subscribe(threadMode = ThreadMode.BackgroundThread, priority = -1) + @Subscribe(threadMode = ThreadMode.BACKGROUND, priority = -1) public void onEventBackgroundThreadM1(Integer event) { handleEvent(-1, event); } @@ -163,32 +163,32 @@ public void onEventM100(String event) { handleEvent(-100, event); } - @Subscribe(threadMode = ThreadMode.MainThread, priority = -1, sticky = true) + @Subscribe(threadMode = ThreadMode.MAIN, priority = -1, sticky = true) public void onEventMainThreadM1(IntTestEvent event) { handleEvent(-1, event); } - @Subscribe(threadMode = ThreadMode.MainThread, sticky = true) + @Subscribe(threadMode = ThreadMode.MAIN, sticky = true) public void onEventMainThreadP0(IntTestEvent event) { handleEvent(0, event); } - @Subscribe(threadMode = ThreadMode.MainThread, priority = 1, sticky = true) + @Subscribe(threadMode = ThreadMode.MAIN, priority = 1, sticky = true) public void onEventMainThreadP1(IntTestEvent event) { handleEvent(1, event); } - @Subscribe(threadMode = ThreadMode.BackgroundThread, priority = 1, sticky = true) + @Subscribe(threadMode = ThreadMode.BACKGROUND, priority = 1, sticky = true) public void onEventBackgroundThreadP1(Integer event) { handleEvent(1, event); } - @Subscribe(threadMode = ThreadMode.BackgroundThread, sticky = true) + @Subscribe(threadMode = ThreadMode.BACKGROUND, sticky = true) public void onEventBackgroundThreadP0(Integer event) { handleEvent(0, event); } - @Subscribe(threadMode = ThreadMode.BackgroundThread, priority = -1, sticky = true) + @Subscribe(threadMode = ThreadMode.BACKGROUND, priority = -1, sticky = true) public void onEventBackgroundThreadM1(Integer event) { handleEvent(-1, event); } From d0e4303b32b36c265b3e8550cb1e7f3f2bdfb3f6 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 20 Nov 2015 17:26:37 +0100 Subject: [PATCH 080/288] added testPostStickyTwoSubscribers --- .../event/test/EventBusStickyEventTest.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java index d092ae8d..6be32085 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java @@ -36,6 +36,21 @@ public void testPostStickyTwoEvents() throws InterruptedException { assertEquals(2, eventCount.intValue()); } + public void testPostStickyTwoSubscribers() throws InterruptedException { + eventBus.postSticky("Sticky"); + eventBus.postSticky(new IntTestEvent(7)); + eventBus.register(this); + StickyIntTestSubscriber subscriber2 = new StickyIntTestSubscriber(); + eventBus.register(subscriber2); + assertEquals(3, eventCount.intValue()); + + eventBus.postSticky("Sticky"); + assertEquals(4, eventCount.intValue()); + + eventBus.postSticky(new IntTestEvent(8)); + assertEquals(6, eventCount.intValue()); + } + public void testPostStickyRegisterNonSticky() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.register(new NonStickySubscriber()); @@ -156,4 +171,11 @@ public void onEvent(IntTestEvent event) { trackEvent(event); } } + + public class StickyIntTestSubscriber { + @Subscribe(sticky = true) + public void onEvent(IntTestEvent event) { + trackEvent(event); + } + } } From a589500ed41289c360683ec036df17d7817fe67b Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 20 Nov 2015 17:32:12 +0100 Subject: [PATCH 081/288] added testPostStickyTwoSubscribers --- .../event/test/EventBusStickyEventTest.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java index 04be4d91..3755ab71 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java @@ -34,6 +34,21 @@ public void testPostStickyTwoEvents() throws InterruptedException { assertEquals(2, eventCount.intValue()); } + public void testPostStickyTwoSubscribers() throws InterruptedException { + eventBus.postSticky("Sticky"); + eventBus.postSticky(new IntTestEvent(7)); + eventBus.registerSticky(this); + StickyIntTestSubscriber subscriber2 = new StickyIntTestSubscriber(); + eventBus.registerSticky(subscriber2); + assertEquals(3, eventCount.intValue()); + + eventBus.postSticky("Sticky"); + assertEquals(4, eventCount.intValue()); + + eventBus.postSticky(new IntTestEvent(8)); + assertEquals(6, eventCount.intValue()); + } + public void testPostStickyRegisterNonSticky() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.register(this); @@ -138,4 +153,10 @@ public void onEvent(IntTestEvent event) { trackEvent(event); } + public class StickyIntTestSubscriber { + public void onEvent(IntTestEvent event) { + trackEvent(event); + } + } + } From e39575bec9854ef777401c4dd19c7a87b0d02ded Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 20 Nov 2015 17:46:06 +0100 Subject: [PATCH 082/288] removed th.printStackTrace() left over --- EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java | 1 - 1 file changed, 1 deletion(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index a1c2c12b..4fa4543d 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -76,7 +76,6 @@ List findSubscriberMethods(Class subscriberClass) { Method[] methods = clazz.getDeclaredMethods(); filterSubscriberMethods(subscriberMethods, eventTypesFound, methodKeyBuilder, methods); } catch (Throwable th) { - th.printStackTrace(); // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149 Method[] methods = subscriberClass.getMethods(); subscriberMethods.clear(); From 5caf0c8e059a47e71675df2ed9af5a747530c370 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Nov 2015 09:45:35 +0100 Subject: [PATCH 083/288] adjust perf project to new enum values --- EventBusPerformance/res/values/strings.xml | 8 ++++---- .../greenrobot/eventperf/TestRunnerActivity.java | 2 +- .../eventperf/testsubject/PerfTestEventBus.java | 14 +++++++------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/EventBusPerformance/res/values/strings.xml b/EventBusPerformance/res/values/strings.xml index dcaac60c..c7af6a88 100644 --- a/EventBusPerformance/res/values/strings.xml +++ b/EventBusPerformance/res/values/strings.xml @@ -19,10 +19,10 @@ Register Subscribers, 1. time - PostThread - MainThread - BackgroundThread - Async + POSTING + MAIN + BACKGROUND + ASYNC Test Is \nRunning! diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java b/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java index 07f55777..8ff7ff9f 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java @@ -46,7 +46,7 @@ protected void onResume() { } } - @Subscribe(threadMode = ThreadMode.MainThread) + @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(TestFinishedEvent event) { Test test = event.test; String text = "" + test.getDisplayName() + "
" + // diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java index df8b13a3..16941e9b 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java @@ -45,13 +45,13 @@ public void prepareTest() { private Class getSubscriberClassForThreadMode() { switch (params.getThreadMode()) { - case MainThread: + case MAIN: return SubscribeClassEventBusMain.class; - case BackgroundThread: + case BACKGROUND: return SubscribeClassEventBusBackground.class; - case Async: + case ASYNC: return SubscriberClassEventBusAsync.class; - case PostThread: + case POSTING: return SubscribeClassEventBusDefault.class; default: throw new RuntimeException("Unknown: " + params.getThreadMode()); @@ -206,7 +206,7 @@ public void dummy5() { } public class SubscribeClassEventBusMain { - @Subscribe(threadMode = ThreadMode.MainThread) + @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(TestEvent event) { eventsReceivedCount.incrementAndGet(); } @@ -228,7 +228,7 @@ public void dummy5() { } public class SubscribeClassEventBusBackground { - @Subscribe(threadMode = ThreadMode.BackgroundThread) + @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onEventBackgroundThread(TestEvent event) { eventsReceivedCount.incrementAndGet(); } @@ -250,7 +250,7 @@ public void dummy5() { } public class SubscriberClassEventBusAsync { - @Subscribe(threadMode = ThreadMode.Async) + @Subscribe(threadMode = ThreadMode.ASYNC) public void onEventAsync(TestEvent event) { eventsReceivedCount.incrementAndGet(); } From a6627316b57096ecf540851792ee5a3b43d309f9 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 25 Nov 2015 20:38:21 +0100 Subject: [PATCH 084/288] fix for EventBusMainThreadTest.BackgroundPoster --- .../src/de/greenrobot/event/test/EventBusMainThreadTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java index 2d62ab4d..944dba21 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -116,7 +116,7 @@ void post(Object event) { eventQ.notifyAll(); } synchronized (eventsDone) { - while (eventsDone.remove(event)) { + while (!eventsDone.remove(event)) { try { eventsDone.wait(); } catch (InterruptedException e) { From 7b81bcb59e58e2c08424b52bbed29d22d777d36c Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 25 Nov 2015 20:41:36 +0100 Subject: [PATCH 085/288] simplified SubscriberInfo: no more inner Data class --- .../de/greenrobot/event/SubscriberInfo.java | 30 ++++++------------- .../event/SubscriberMethodFinder.java | 3 +- .../EventBusAnnotationProcessor.java | 17 ++++++----- 3 files changed, 19 insertions(+), 31 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfo.java b/EventBus/src/de/greenrobot/event/SubscriberInfo.java index 5c907cfa..11a496d0 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberInfo.java +++ b/EventBus/src/de/greenrobot/event/SubscriberInfo.java @@ -1,34 +1,22 @@ package de.greenrobot.event; import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; /** Preprocessed index: base class for generated "MyGeneratedSubscriberIndex" class by annotation processing. */ public abstract class SubscriberInfo { - // TODO move class fields into SubscriberInfo - public static class Data { - public final Class subscriberClass; - public final SubscriberMethod[] subscriberMethods; - public final Class nextInfo; + final Class subscriberClass; + final Class superSubscriberInfoClass; + final Class nextSubscriberInfoClass; - public Data(Class subscriberClass, SubscriberMethod[] subscriberMethods, Class nextInfo) { - this.subscriberClass = subscriberClass; - this.subscriberMethods = subscriberMethods; - this.nextInfo = nextInfo; - } - } + protected SubscriberMethod[] subscriberMethods; - private volatile Data data; - - Data getSubscriberData() { - if (data == null) { - data = createSubscriberData(); - } - return data; + protected SubscriberInfo(Class subscriberClass, Class superSubscriberInfoClass, Class nextSubscriberInfoClass) { + this.subscriberClass = subscriberClass; + this.superSubscriberInfoClass = superSubscriberInfoClass; + this.nextSubscriberInfoClass = nextSubscriberInfoClass; } - abstract protected Data createSubscriberData(); + abstract protected SubscriberMethod[] createSubscriberMethods(); protected static SubscriberMethod createSubscriberMethod(Class subscriberClass, String methodName, Class eventType, ThreadMode threadMode, int priority, boolean sticky) { diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index a03cfb37..9c470e88 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -73,8 +73,7 @@ private List findUsingInfo(Class subscriberClass) { while (findState.clazz != null) { SubscriberInfo info = getSubscriberInfo(findState.clazz); if (info != null) { - SubscriberInfo.Data subscriberData = info.getSubscriberData(); - SubscriberMethod[] array = subscriberData.subscriberMethods; + SubscriberMethod[] array = info.createSubscriberMethods(); for (SubscriberMethod subscriberMethod : array) { if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) { findState.subscriberMethods.add(subscriberMethod); diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 16cf695a..c5989fea 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -205,21 +205,22 @@ private void writeSources() { writer = new BufferedWriter(sourceFile.openWriter()); writer.write("package " + myPackage + ";\n\n"); writer.write("import de.greenrobot.event.SubscriberInfo;\n"); - writer.write("import de.greenrobot.event.SubscriberInfo.Data;\n"); writer.write("import de.greenrobot.event.SubscriberMethod;\n"); writer.write("import de.greenrobot.event.ThreadMode;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); writer.write("public class " + infoClassName + " extends SubscriberInfo {\n"); - // writer.write("\nstatic {new Exception(\"" + infoClassName + "created\").printStackTrace();}\n\n"); - writer.write(" protected Data createSubscriberData() {\n"); + writer.write(" public " + infoClassName + "() {\n"); + TypeElement nextEntry = nextEntry(entries, entry, i); + String next = getNextValue(myPackage, nextEntry); + writer.write(" super(" + subscriberClassName + ".class, null, " + next + ");\n"); + writer.write(" }\n\n"); + writer.write(" protected SubscriberMethod[] createSubscriberMethods() {\n"); writer.write(" Class subscriberClass = " + subscriberClassName + ".class;\n"); writer.write(" SubscriberMethod[] subscriberMethods = new SubscriberMethod[] {\n"); Set methodSignatures = new HashSet(); writeMethods(writer, null, entry.getValue(), methodSignatures); writer.write(" };\n"); - TypeElement nextEntry = nextEntry(entries, entry, i); - writeNextEntry(writer, myPackage, nextEntry); - writer.write(" return new Data(subscriberClass, subscriberMethods, next);\n"); + writer.write(" return subscriberMethods;\n"); writer.write(" }\n}\n"); } catch (IOException e) { throw new RuntimeException("Could not write source for " + subscriberClass.getQualifiedName(), e); @@ -235,7 +236,7 @@ private void writeSources() { } } - private void writeNextEntry(BufferedWriter writer, String myPackage, TypeElement nextEntry) throws IOException { + private String getNextValue(String myPackage, TypeElement nextEntry) throws IOException { String nextValue; if (nextEntry != null) { PackageElement nextPackageElement = getPackageElement(nextEntry); @@ -249,7 +250,7 @@ private void writeNextEntry(BufferedWriter writer, String myPackage, TypeElement } else { nextValue = "null"; } - writer.write(" Class next = " + nextValue + ";\n"); + return nextValue; } private String getClassString(TypeElement subscriberClass, String subscriberPackage) { From 26a00665106eeadd3f8c6249fe9e670ffd3483db Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 27 Nov 2015 20:27:57 +0100 Subject: [PATCH 086/288] SubscriberInfo super class --- .../event/SubscriberMethodFinder.java | 23 ++++++--- .../EventBusAnnotationProcessor.java | 50 +++++++++++++------ 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 9c470e88..18e740bd 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -71,9 +71,9 @@ private List findUsingInfo(Class subscriberClass) { FindState findState = new FindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { - SubscriberInfo info = getSubscriberInfo(findState.clazz); - if (info != null) { - SubscriberMethod[] array = info.createSubscriberMethods(); + findState.subscriberInfo = getSubscriberInfo(findState); + if (findState.subscriberInfo != null) { + SubscriberMethod[] array = findState.subscriberInfo.createSubscriberMethods(); for (SubscriberMethod subscriberMethod : array) { if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) { findState.subscriberMethods.add(subscriberMethod); @@ -87,9 +87,19 @@ private List findUsingInfo(Class subscriberClass) { return findState.subscriberMethods; } - private SubscriberInfo getSubscriberInfo(Class subscriberClass) { + private SubscriberInfo getSubscriberInfo(FindState findState) { SubscriberInfo info = null; - String infoClass = subscriberClass.getName().replace('$', '_') + "_EventBusInfo"; + if (findState.subscriberInfo != null && findState.subscriberInfo.superSubscriberInfoClass != null) { + try { + SubscriberInfo superclassInfo = (SubscriberInfo) findState.subscriberInfo.superSubscriberInfoClass.newInstance(); + if (findState.clazz == superclassInfo.subscriberClass) { + return superclassInfo; + } + } catch (IllegalAccessException | InstantiationException e) { + throw new EventBusException(e); + } + } + String infoClass = findState.clazz.getName().replace('$', '_') + "_EventBusInfo"; try { Class aClass = Class.forName(infoClass); Object object = aClass.newInstance(); @@ -99,7 +109,7 @@ private SubscriberInfo getSubscriberInfo(Class subscriberClass) { } catch (ClassNotFoundException e) { // TODO don't try again } catch (Exception e) { - throw new EventBusException("Could not get infos for " + subscriberClass, e); + throw new EventBusException("Could not get infos for " + findState.clazz, e); } return info; } @@ -169,6 +179,7 @@ class FindState { Class clazz; String clazzName; boolean skipSuperClasses; + public SubscriberInfo subscriberInfo; void initForSubscriber(Class subscriberClass) { this.subscriberClass = clazz = subscriberClass; diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index c5989fea..29f7afe6 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -1,6 +1,13 @@ package de.greenrobot.event.annotationprocessor; -import de.greenrobot.event.Subscribe; +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Messager; @@ -17,14 +24,8 @@ import javax.lang.model.type.TypeKind; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; -import java.io.BufferedWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; + +import de.greenrobot.event.Subscribe; @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") public class EventBusAnnotationProcessor extends AbstractProcessor { @@ -199,7 +200,7 @@ private void writeSources() { PackageElement packageElement = getPackageElement(subscriberClass); String myPackage = packageElement.getQualifiedName().toString(); String subscriberClassName = getClassString(subscriberClass, myPackage); - String infoClassName = subscriberClassName.replace('.', '_') + CLASS_POSTFIX; + String infoClassName = getInfoClass(subscriberClass, myPackage); JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(myPackage + '.' + infoClassName); writer = new BufferedWriter(sourceFile.openWriter()); @@ -212,7 +213,8 @@ private void writeSources() { writer.write(" public " + infoClassName + "() {\n"); TypeElement nextEntry = nextEntry(entries, entry, i); String next = getNextValue(myPackage, nextEntry); - writer.write(" super(" + subscriberClassName + ".class, null, " + next + ");\n"); + String infoSuperClass = getSuperclassInfoClass(subscriberClass, myPackage); + writer.write(" super(" + subscriberClassName + ".class, " + infoSuperClass + ", " + next + ");\n"); writer.write(" }\n\n"); writer.write(" protected SubscriberMethod[] createSubscriberMethods() {\n"); writer.write(" Class subscriberClass = " + subscriberClassName + ".class;\n"); @@ -236,13 +238,28 @@ private void writeSources() { } } + private String getSuperclassInfoClass(TypeElement subscriberClass, String myPackage) { + DeclaredType superclassType = (DeclaredType) subscriberClass.getSuperclass(); + if (superclassType != null) { + TypeElement superclass = (TypeElement) superclassType.asElement(); + if (methodsByClass.containsKey(superclass) && !classesToSkip.contains(superclass)) { + return getInfoClass(superclass, myPackage) + ".class"; + } + } + return "null"; + } + + private String getInfoClass(TypeElement subscriberClass, String myPackage) { + String subscriberClassName = getClassString(subscriberClass, myPackage); + return subscriberClassName.replace('.', '_') + CLASS_POSTFIX; + } + private String getNextValue(String myPackage, TypeElement nextEntry) throws IOException { String nextValue; if (nextEntry != null) { PackageElement nextPackageElement = getPackageElement(nextEntry); String nextPackage = nextPackageElement.getQualifiedName().toString(); - String nextSubscriberClassName = getClassString(nextEntry, nextPackage); - String nextInfoClassName = nextSubscriberClassName.replace('.', '_') + CLASS_POSTFIX; + String nextInfoClassName = getInfoClass(nextEntry, nextPackage); if (!myPackage.equals(nextPackage)) { nextInfoClassName = nextPackage + "." + nextInfoClassName; } @@ -254,8 +271,11 @@ private String getNextValue(String myPackage, TypeElement nextEntry) throws IOEx } private String getClassString(TypeElement subscriberClass, String subscriberPackage) { - int beginIndex = subscriberPackage.length() == 0 ? 0 : subscriberPackage.length() + 1; - return subscriberClass.getQualifiedName().toString().substring(beginIndex); + String className = subscriberClass.getQualifiedName().toString(); + if (!subscriberPackage.isEmpty() && className.startsWith(subscriberPackage)) { + className = className.substring(subscriberPackage.length() + 1); + } + return className; } private PackageElement getPackageElement(TypeElement subscriberClass) { From aa3e5dfcebe56e5f74c0d5a06524c32a4b2f3367 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 27 Nov 2015 20:44:21 +0100 Subject: [PATCH 087/288] simplified createSubscriberMethod() calls --- EventBus/src/de/greenrobot/event/SubscriberInfo.java | 2 +- .../EventBusAnnotationProcessor.java | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfo.java b/EventBus/src/de/greenrobot/event/SubscriberInfo.java index 11a496d0..ba757b3a 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberInfo.java +++ b/EventBus/src/de/greenrobot/event/SubscriberInfo.java @@ -18,7 +18,7 @@ protected SubscriberInfo(Class subscriberClass, Class superSubscriberInfoClass, abstract protected SubscriberMethod[] createSubscriberMethods(); - protected static SubscriberMethod createSubscriberMethod(Class subscriberClass, String methodName, Class eventType, + protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType, ThreadMode threadMode, int priority, boolean sticky) { try { Method method = subscriberClass.getDeclaredMethod(methodName, eventType); diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 29f7afe6..2de30d1d 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -217,10 +217,9 @@ private void writeSources() { writer.write(" super(" + subscriberClassName + ".class, " + infoSuperClass + ", " + next + ");\n"); writer.write(" }\n\n"); writer.write(" protected SubscriberMethod[] createSubscriberMethods() {\n"); - writer.write(" Class subscriberClass = " + subscriberClassName + ".class;\n"); writer.write(" SubscriberMethod[] subscriberMethods = new SubscriberMethod[] {\n"); Set methodSignatures = new HashSet(); - writeMethods(writer, null, entry.getValue(), methodSignatures); + writeMethods(writer, entry.getValue(), methodSignatures); writer.write(" };\n"); writer.write(" return subscriberMethods;\n"); writer.write(" }\n}\n"); @@ -303,7 +302,7 @@ private TypeElement nextEntry(List methods, Set methodSignatures) throws IOException { + private void writeMethods(BufferedWriter writer, List methods, Set methodSignatures) throws IOException { for (ExecutableElement method : methods) { List parameters = method.getParameters(); @@ -316,12 +315,9 @@ private void writeMethods(BufferedWriter writer, TypeElement subscriberClass, Li } String methodName = method.getSimpleName().toString(); - String subscriberClassString = subscriberClass == null ? "subscriberClass" : - subscriberClass.asType().toString() + ".class"; Subscribe subscribe = method.getAnnotation(Subscribe.class); - writeLine(writer, 3, "createSubscriberMethod(" + subscriberClassString + ",", - "\"" + methodName + "\",", + writeLine(writer, 3, "createSubscriberMethod(\"" + methodName + "\",", paramType.toString() + ".class,", "ThreadMode." + subscribe.threadMode().name() + ", " + subscribe.priority() + ", " + subscribe.sticky(), "),"); From 4e8259ccc0e7033e79151741f087543a8beddb5b Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 27 Nov 2015 21:13:02 +0100 Subject: [PATCH 088/288] use overloaded createSubscriberMethod() with default parameters to make info classes more compact --- .../de/greenrobot/event/SubscriberInfo.java | 15 ++++++++++--- .../EventBusAnnotationProcessor.java | 22 +++++++++++++++---- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfo.java b/EventBus/src/de/greenrobot/event/SubscriberInfo.java index ba757b3a..54b6db12 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberInfo.java +++ b/EventBus/src/de/greenrobot/event/SubscriberInfo.java @@ -16,10 +16,19 @@ protected SubscriberInfo(Class subscriberClass, Class superSubscriberInfoClass, this.nextSubscriberInfoClass = nextSubscriberInfoClass; } - abstract protected SubscriberMethod[] createSubscriberMethods(); + abstract protected SubscriberMethod[] createSubscriberMethods(); - protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType, - ThreadMode threadMode, int priority, boolean sticky) { + protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType) { + return createSubscriberMethod(methodName, eventType, ThreadMode.POSTING, 0, false); + + } + + protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType, ThreadMode threadMode) { + return createSubscriberMethod(methodName, eventType, threadMode, 0, false); + } + + protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType, ThreadMode threadMode, + int priority, boolean sticky) { try { Method method = subscriberClass.getDeclaredMethod(methodName, eventType); return new SubscriberMethod(method, eventType, threadMode, priority, sticky); diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 2de30d1d..942abd30 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -26,6 +26,7 @@ import javax.tools.JavaFileObject; import de.greenrobot.event.Subscribe; +import de.greenrobot.event.ThreadMode; @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") public class EventBusAnnotationProcessor extends AbstractProcessor { @@ -317,10 +318,23 @@ private void writeMethods(BufferedWriter writer, List methods String methodName = method.getSimpleName().toString(); Subscribe subscribe = method.getAnnotation(Subscribe.class); - writeLine(writer, 3, "createSubscriberMethod(\"" + methodName + "\",", - paramType.toString() + ".class,", - "ThreadMode." + subscribe.threadMode().name() + ", " + - subscribe.priority() + ", " + subscribe.sticky(), "),"); + List parts = new ArrayList(); + parts.add("createSubscriberMethod(\"" + methodName + "\","); + String lineEnd = "),"; + if (subscribe.priority() == 0 && !subscribe.sticky()) { + if (subscribe.threadMode() == ThreadMode.POSTING) { + parts.add(paramType.toString() + ".class" + lineEnd); + } else { + parts.add(paramType.toString() + ".class,"); + parts.add("ThreadMode." + subscribe.threadMode().name() + lineEnd); + } + } else { + parts.add(paramType.toString() + ".class,"); + parts.add("ThreadMode." + subscribe.threadMode().name() + ","); + parts.add(subscribe.priority() + ","); + parts.add(subscribe.sticky() + lineEnd); + } + writeLine(writer, 3, parts.toArray(new String[parts.size()])); processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Indexed @Subscribe at " + method.getEnclosingElement().getSimpleName() + "." + methodName + From 0c289c664ff30f3412d3d2edf78766a1eadb9f08 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 27 Nov 2015 21:19:42 +0100 Subject: [PATCH 089/288] minor improvements for generated info classes --- .../annotationprocessor/EventBusAnnotationProcessor.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 942abd30..b92492e2 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -215,14 +215,13 @@ private void writeSources() { TypeElement nextEntry = nextEntry(entries, entry, i); String next = getNextValue(myPackage, nextEntry); String infoSuperClass = getSuperclassInfoClass(subscriberClass, myPackage); - writer.write(" super(" + subscriberClassName + ".class, " + infoSuperClass + ", " + next + ");\n"); + writeLine(writer, 2, "super(" + subscriberClassName + ".class,", infoSuperClass + ",", next + ");"); writer.write(" }\n\n"); writer.write(" protected SubscriberMethod[] createSubscriberMethods() {\n"); - writer.write(" SubscriberMethod[] subscriberMethods = new SubscriberMethod[] {\n"); + writer.write(" return new SubscriberMethod[] {\n"); Set methodSignatures = new HashSet(); writeMethods(writer, entry.getValue(), methodSignatures); writer.write(" };\n"); - writer.write(" return subscriberMethods;\n"); writer.write(" }\n}\n"); } catch (IOException e) { throw new RuntimeException("Could not write source for " + subscriberClass.getQualifiedName(), e); From db56e6e41250c1e35d788d37acb85f20841dbd30 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 27 Nov 2015 21:25:26 +0100 Subject: [PATCH 090/288] SubscriberInfo clean up --- EventBus/src/de/greenrobot/event/SubscriberInfo.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfo.java b/EventBus/src/de/greenrobot/event/SubscriberInfo.java index 54b6db12..43ed290c 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberInfo.java +++ b/EventBus/src/de/greenrobot/event/SubscriberInfo.java @@ -2,14 +2,12 @@ import java.lang.reflect.Method; -/** Preprocessed index: base class for generated "MyGeneratedSubscriberIndex" class by annotation processing. */ +/** Base class for generated index classes created by annotation processing. */ public abstract class SubscriberInfo { final Class subscriberClass; final Class superSubscriberInfoClass; final Class nextSubscriberInfoClass; - protected SubscriberMethod[] subscriberMethods; - protected SubscriberInfo(Class subscriberClass, Class superSubscriberInfoClass, Class nextSubscriberInfoClass) { this.subscriberClass = subscriberClass; this.superSubscriberInfoClass = superSubscriberInfoClass; From 6fced7ef7d50c02a4a6a3f174b6426c931a5b5c6 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 27 Nov 2015 22:05:06 +0100 Subject: [PATCH 091/288] added FIND_STATE_POOL --- .../event/SubscriberMethodFinder.java | 49 ++++++++++++++++--- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 18e740bd..3a6f62ef 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -37,6 +37,9 @@ class SubscriberMethodFinder { private final boolean strictMethodVerification; private final boolean ignoreGeneratedIndex; + private static final int POOL_SIZE = 4; + private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE]; + SubscriberMethodFinder(boolean strictMethodVerification, boolean ignoreGeneratedIndex) { this.strictMethodVerification = strictMethodVerification; this.ignoreGeneratedIndex = ignoreGeneratedIndex; @@ -68,7 +71,7 @@ List findSubscriberMethods(Class subscriberClass, boolean f } private List findUsingInfo(Class subscriberClass) { - FindState findState = new FindState(); + FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { findState.subscriberInfo = getSubscriberInfo(findState); @@ -84,7 +87,34 @@ private List findUsingInfo(Class subscriberClass) { } findState.moveToSuperclass(); } - return findState.subscriberMethods; + return getMethodsAndRelease(findState); + } + + private List getMethodsAndRelease(FindState findState) { + ArrayList subscriberMethods = new ArrayList<>(findState.subscriberMethods); + findState.recycle(); + synchronized (FIND_STATE_POOL) { + for (int i = 0; i < POOL_SIZE; i++) { + if (FIND_STATE_POOL[i] == null) { + FIND_STATE_POOL[i] = findState; + break; + } + } + } + return subscriberMethods; + } + + private FindState prepareFindState() { + synchronized (FIND_STATE_POOL) { + for (int i = 0; i < POOL_SIZE; i++) { + FindState state = FIND_STATE_POOL[i]; + if (state != null) { + FIND_STATE_POOL[i] = null; + return state; + } + } + } + return new FindState(); } private SubscriberInfo getSubscriberInfo(FindState findState) { @@ -115,13 +145,13 @@ private SubscriberInfo getSubscriberInfo(FindState findState) { } private List findUsingReflection(Class subscriberClass) { - FindState findState = new FindState(); + FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { findUsingReflectionInSingleClass(findState); findState.moveToSuperclass(); } - return findState.subscriberMethods; + return getMethodsAndRelease(findState); } private void findUsingReflectionInSingleClass(FindState findState) { @@ -171,15 +201,16 @@ static void clearCaches() { } } - class FindState { + static class FindState { final List subscriberMethods = new ArrayList(); final Map eventTypesFound = new HashMap(); final StringBuilder methodKeyBuilder = new StringBuilder(); + Class subscriberClass; Class clazz; String clazzName; boolean skipSuperClasses; - public SubscriberInfo subscriberInfo; + SubscriberInfo subscriberInfo; void initForSubscriber(Class subscriberClass) { this.subscriberClass = clazz = subscriberClass; @@ -187,8 +218,12 @@ void initForSubscriber(Class subscriberClass) { void recycle() { subscriberMethods.clear(); - methodKeyBuilder.setLength(0); eventTypesFound.clear(); + methodKeyBuilder.setLength(0); + subscriberClass = null; + clazz = null; + skipSuperClasses = false; + subscriberInfo = null; } boolean checkAdd(Method method, Class eventType) { From e3bf68aeb05a7d2c79d2d61c5e429e29d7e563c5 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 2 Dec 2015 18:29:50 +0100 Subject: [PATCH 092/288] deduct timeMeasureOverhead from time measurement for RegisterOneByOne --- .../greenrobot/eventperf/testsubject/PerfTestEventBus.java | 5 ++++- .../de/greenrobot/eventperf/testsubject/PerfTestOtto.java | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java index 16941e9b..70d4a8cd 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java @@ -145,7 +145,10 @@ public void runTest() { } long beforeRegister = System.nanoTime(); super.eventBus.register(subscriber); - long timeRegister = System.nanoTime() - beforeRegister; + long afterRegister = System.nanoTime(); + long end = System.nanoTime(); + long timeMeasureOverhead = (end - afterRegister) * 2; + long timeRegister = end - beforeRegister - timeMeasureOverhead; time += timeRegister; super.eventBus.unregister(subscriber); if (canceled) { diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java index 8e68adde..6e1cb890 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java @@ -124,7 +124,11 @@ public void runTest() { } long beforeRegister = System.nanoTime(); super.eventBus.register(subscriber); - long timeRegister = System.nanoTime() - beforeRegister; + + long afterRegister = System.nanoTime(); + long end = System.nanoTime(); + long timeMeasureOverhead = (end - afterRegister) * 2; + long timeRegister = end - beforeRegister - timeMeasureOverhead; time += timeRegister; super.eventBus.unregister(subscriber); if (canceled) { From 4e42ed943050cab8b71e0765e0e37c9df142b4a1 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 2 Dec 2015 20:33:30 +0100 Subject: [PATCH 093/288] realistic initial capacity for methodKeyBuilder --- EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 3a6f62ef..b8124e1e 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -204,7 +204,7 @@ static void clearCaches() { static class FindState { final List subscriberMethods = new ArrayList(); final Map eventTypesFound = new HashMap(); - final StringBuilder methodKeyBuilder = new StringBuilder(); + final StringBuilder methodKeyBuilder = new StringBuilder(128); Class subscriberClass; Class clazz; From 365d4b68a7683fec8d33e4516394b4944be2f9fe Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 2 Dec 2015 21:25:04 +0100 Subject: [PATCH 094/288] ClassMapPerfTest to verify testHashMapClassObject is fastest --- .../event/test/ClassMapPerfTest.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 EventBusTest/src/de/greenrobot/event/test/ClassMapPerfTest.java diff --git a/EventBusTest/src/de/greenrobot/event/test/ClassMapPerfTest.java b/EventBusTest/src/de/greenrobot/event/test/ClassMapPerfTest.java new file mode 100644 index 00000000..afeb00bb --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/ClassMapPerfTest.java @@ -0,0 +1,41 @@ +package de.greenrobot.event.test; + +import junit.framework.TestCase; + +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.Map; + +/** + * Just to verify testHashMapClassObject is fastest. Ignore this test. + */ +public class ClassMapPerfTest /* extends TestCase */ { + + static final int COUNT = 10000000; + static final Class CLAZZ = ClassMapPerfTest.class; + + public void testHashMapClassObject() { + Map map = new HashMap(); + for (int i = 0; i < COUNT; i++) { + Class oldValue = map.put(CLAZZ, CLAZZ); + Class value = map.get(CLAZZ); + } + } + + public void testIdentityHashMapClassObject() { + Map map = new IdentityHashMap(); + for (int i = 0; i < COUNT; i++) { + Class oldValue = map.put(CLAZZ, CLAZZ); + Class value = map.get(CLAZZ); + } + } + + public void testHashMapClassName() { + Map map = new HashMap(); + for (int i = 0; i < COUNT; i++) { + Class oldValue = map.put(CLAZZ.getName(), CLAZZ); + Class value = map.get(CLAZZ.getName()); + } + } + +} From af056ad10958ddff921e43442bee187396754ff5 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 2 Dec 2015 21:27:53 +0100 Subject: [PATCH 095/288] methodCache uses Class as key type --- .../src/de/greenrobot/event/SubscriberMethodFinder.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 4fa4543d..08eb766b 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -37,7 +37,7 @@ class SubscriberMethodFinder { private static final int SYNTHETIC = 0x1000; private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC; - private static final Map> methodCache = new HashMap>(); + private static final Map, List> methodCache = new HashMap, List>(); private final Map, Class> skipMethodVerificationForClasses; @@ -51,10 +51,9 @@ class SubscriberMethodFinder { } List findSubscriberMethods(Class subscriberClass) { - String key = subscriberClass.getName(); List subscriberMethods; synchronized (methodCache) { - subscriberMethods = methodCache.get(key); + subscriberMethods = methodCache.get(subscriberClass); } if (subscriberMethods != null) { return subscriberMethods; @@ -90,7 +89,7 @@ List findSubscriberMethods(Class subscriberClass) { + ON_EVENT_METHOD_NAME); } else { synchronized (methodCache) { - methodCache.put(key, subscriberMethods); + methodCache.put(subscriberClass, subscriberMethods); } return subscriberMethods; } From ec8a1c2742cdb9f5c01a1d654c9a67a73ebc9dad Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 2 Dec 2015 21:32:01 +0100 Subject: [PATCH 096/288] methodCache uses Class as key type --- .../src/de/greenrobot/event/SubscriberMethodFinder.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index b8124e1e..b6e6779d 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -32,7 +32,7 @@ class SubscriberMethodFinder { private static final int SYNTHETIC = 0x1000; private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC; - private static final Map> METHOD_CACHE = new HashMap>(); + private static final Map, List> METHOD_CACHE = new HashMap, List>(); private final boolean strictMethodVerification; private final boolean ignoreGeneratedIndex; @@ -46,10 +46,9 @@ class SubscriberMethodFinder { } List findSubscriberMethods(Class subscriberClass, boolean forceReflection) { - String key = subscriberClass.getName(); List subscriberMethods; synchronized (METHOD_CACHE) { - subscriberMethods = METHOD_CACHE.get(key); + subscriberMethods = METHOD_CACHE.get(subscriberClass); } if (subscriberMethods != null) { return subscriberMethods; @@ -64,7 +63,7 @@ List findSubscriberMethods(Class subscriberClass, boolean f + " and its super classes have no public methods with the @Subscribe annotation"); } else { synchronized (METHOD_CACHE) { - METHOD_CACHE.put(key, subscriberMethods); + METHOD_CACHE.put(subscriberClass, subscriberMethods); } return subscriberMethods; } From 75543c42e087cf9c92ae71ffe38f7040494c6ea3 Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 3 Dec 2015 18:23:38 +0100 Subject: [PATCH 097/288] checkAdd optimization: added faster 1st level check --- .../event/SubscriberMethodFinder.java | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index b6e6779d..45d0a29b 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -201,8 +201,9 @@ static void clearCaches() { } static class FindState { - final List subscriberMethods = new ArrayList(); - final Map eventTypesFound = new HashMap(); + final List subscriberMethods = new ArrayList<>(); + final Map anyMethodByEventType = new HashMap<>(); + final Map subscriberClassByMethodKey = new HashMap<>(); final StringBuilder methodKeyBuilder = new StringBuilder(128); Class subscriberClass; @@ -217,7 +218,8 @@ void initForSubscriber(Class subscriberClass) { void recycle() { subscriberMethods.clear(); - eventTypesFound.clear(); + anyMethodByEventType.clear(); + subscriberClassByMethodKey.clear(); methodKeyBuilder.setLength(0); subscriberClass = null; clazz = null; @@ -226,19 +228,38 @@ void recycle() { } boolean checkAdd(Method method, Class eventType) { + // 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required. + // Usually a subscriber doesn't have methods listening to the same event type. + Object existing = anyMethodByEventType.put(eventType, method); + if (existing == null) { + return true; + } else { + if(existing instanceof Method) { + if(!checkAddWithMethodSignature((Method) existing, eventType)) { + // Paranoia check + throw new IllegalStateException(); + } + // Put any non-Method object to "consume" the existing Method + anyMethodByEventType.put(eventType, this); + } + return checkAddWithMethodSignature(method, eventType); + } + } + + private boolean checkAddWithMethodSignature(Method method, Class eventType) { methodKeyBuilder.setLength(0); methodKeyBuilder.append(method.getName()); methodKeyBuilder.append('>').append(eventType.getName()); String methodKey = methodKeyBuilder.toString(); Class methodClass = method.getDeclaringClass(); - Class methodClassOld = eventTypesFound.put(methodKey, methodClass); + Class methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass); if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) { // Only add if not already found in a sub class return true; } else { // Revert the put, old class is further down the class hierarchy - eventTypesFound.put(methodKey, methodClassOld); + subscriberClassByMethodKey.put(methodKey, methodClassOld); return false; } } From 351d99084eb0ba7aacd51dfa1a379ba222df7576 Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 3 Dec 2015 21:58:20 +0100 Subject: [PATCH 098/288] fix problem with generic event types, added test for it --- .../EventBusAnnotationProcessor.java | 36 ++++++++++++------- .../event/test/EventBusGenericsTest.java | 26 ++++++++++++++ 2 files changed, 49 insertions(+), 13 deletions(-) create mode 100644 EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index b92492e2..7b22887f 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -22,6 +22,7 @@ import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; @@ -31,6 +32,8 @@ @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") public class EventBusAnnotationProcessor extends AbstractProcessor { public static final String CLASS_POSTFIX = "_EventBusInfo"; + public static final String JAVA_LANG_PREFIX = "java.lang."; + public static final int JAVA_LANG_PREFIX_LENGTH = JAVA_LANG_PREFIX.length(); /** Found subscriber methods for a class (without superclasses). */ private final Map> methodsByClass = @@ -220,7 +223,7 @@ private void writeSources() { writer.write(" protected SubscriberMethod[] createSubscriberMethods() {\n"); writer.write(" return new SubscriberMethod[] {\n"); Set methodSignatures = new HashSet(); - writeMethods(writer, entry.getValue(), methodSignatures); + writeMethods(writer, entry.getValue(), methodSignatures, myPackage); writer.write(" };\n"); writer.write(" }\n}\n"); } catch (IOException e) { @@ -269,10 +272,15 @@ private String getNextValue(String myPackage, TypeElement nextEntry) throws IOEx return nextValue; } - private String getClassString(TypeElement subscriberClass, String subscriberPackage) { - String className = subscriberClass.getQualifiedName().toString(); - if (!subscriberPackage.isEmpty() && className.startsWith(subscriberPackage)) { - className = className.substring(subscriberPackage.length() + 1); + private String getClassString(TypeElement typeElement, String myPackage) { + String className = typeElement.getQualifiedName().toString(); + int lastPeriod = className.lastIndexOf('.'); + if (!myPackage.isEmpty() && className.startsWith(myPackage) && lastPeriod == myPackage.length()) { + // TODO detect nested types also + + className = className.substring(myPackage.length() + 1); + } else if (className.startsWith(JAVA_LANG_PREFIX) && lastPeriod == JAVA_LANG_PREFIX_LENGTH - 1) { + className = className.substring(JAVA_LANG_PREFIX_LENGTH); } return className; } @@ -302,14 +310,16 @@ private TypeElement nextEntry(List methods, Set methodSignatures) throws IOException { + private void writeMethods(BufferedWriter writer, List methods, Set methodSignatures, + String myPackage) throws IOException { for (ExecutableElement method : methods) { List parameters = method.getParameters(); - VariableElement param = parameters.get(0); - DeclaredType paramType = (DeclaredType) param.asType(); + TypeMirror paramType = parameters.get(0).asType(); + TypeElement paramElement = (TypeElement) processingEnv.getTypeUtils().asElement(paramType); + String eventClass = getClassString(paramElement, myPackage) + ".class"; - String methodSignature = method + ">" + paramType; + String methodSignature = method + ">" + paramElement.getQualifiedName(); if (!methodSignatures.add(methodSignature)) { continue; } @@ -322,13 +332,13 @@ private void writeMethods(BufferedWriter writer, List methods String lineEnd = "),"; if (subscribe.priority() == 0 && !subscribe.sticky()) { if (subscribe.threadMode() == ThreadMode.POSTING) { - parts.add(paramType.toString() + ".class" + lineEnd); + parts.add(eventClass + lineEnd); } else { - parts.add(paramType.toString() + ".class,"); + parts.add(eventClass + ","); parts.add("ThreadMode." + subscribe.threadMode().name() + lineEnd); } } else { - parts.add(paramType.toString() + ".class,"); + parts.add(eventClass + ","); parts.add("ThreadMode." + subscribe.threadMode().name() + ","); parts.add(subscribe.priority() + ","); parts.add(subscribe.sticky() + lineEnd); @@ -337,7 +347,7 @@ private void writeMethods(BufferedWriter writer, List methods processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Indexed @Subscribe at " + method.getEnclosingElement().getSimpleName() + "." + methodName + - "(" + paramType.asElement().getSimpleName() + ")"); + "(" + paramElement.getSimpleName() + ")"); } } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java new file mode 100644 index 00000000..a8a31284 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java @@ -0,0 +1,26 @@ +package de.greenrobot.event.test; + +import de.greenrobot.event.EventBus; +import de.greenrobot.event.Subscribe; + +public class EventBusGenericsTest extends AbstractEventBusTest { + public static class GenericEvent { + T value; + } + + public class GenericSubscriber { + @Subscribe + public void onGenericEvent(GenericEvent event) { + trackEvent(event); + } + } + + public void testGenericEventAndSubscriber() { + GenericSubscriber genericSubscriber = new GenericSubscriber(); + eventBus.register(genericSubscriber); + eventBus.post(new GenericEvent()); + eventBus.unregister(genericSubscriber); + + assertEventCount(1); + } +} From d9833fd3e3a3149b50244421eacde2ac729b0c5a Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 10:18:54 +0100 Subject: [PATCH 099/288] update perf to otto 1.3.8 --- EventBusPerformance/build.gradle | 2 +- .../src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index b7a42f28..54801afa 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -17,7 +17,7 @@ repositories { dependencies { compile project(':EventBus') provided project(':EventBusAnnotationProcessor') - compile 'com.squareup:otto:1.3.7' + compile 'com.squareup:otto:1.3.8' } android { diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java index 6e1cb890..0d191aeb 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java @@ -4,6 +4,7 @@ import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; import android.app.Activity; import android.content.Context; @@ -117,7 +118,7 @@ public void runTest() { for (Object subscriber : super.subscribers) { if (cacheField != null) { try { - cacheField.set(null, new HashMap()); + cacheField.set(null, new ConcurrentHashMap()); } catch (Exception e) { throw new RuntimeException(e); } From 966fa3ef5149db72f478be37509e489c0bfbf742 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 10:20:30 +0100 Subject: [PATCH 100/288] update test to android-apt 1.8 --- EventBusTest/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 4583d580..62ed11a5 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -5,7 +5,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:1.3.1' - classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4' + classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } From d3e87d825422d4e3e24ce1ca28e1c4638fa61cd6 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 10:23:07 +0100 Subject: [PATCH 101/288] fix cutting the package for getClassString --- .../EventBusAnnotationProcessor.java | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 7b22887f..0b59da79 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -32,8 +32,6 @@ @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") public class EventBusAnnotationProcessor extends AbstractProcessor { public static final String CLASS_POSTFIX = "_EventBusInfo"; - public static final String JAVA_LANG_PREFIX = "java.lang."; - public static final int JAVA_LANG_PREFIX_LENGTH = JAVA_LANG_PREFIX.length(); /** Found subscriber methods for a class (without superclasses). */ private final Map> methodsByClass = @@ -273,18 +271,29 @@ private String getNextValue(String myPackage, TypeElement nextEntry) throws IOEx } private String getClassString(TypeElement typeElement, String myPackage) { + PackageElement packageElement = getPackageElement(typeElement); + String packageString = packageElement.getQualifiedName().toString(); String className = typeElement.getQualifiedName().toString(); - int lastPeriod = className.lastIndexOf('.'); - if (!myPackage.isEmpty() && className.startsWith(myPackage) && lastPeriod == myPackage.length()) { - // TODO detect nested types also - - className = className.substring(myPackage.length() + 1); - } else if (className.startsWith(JAVA_LANG_PREFIX) && lastPeriod == JAVA_LANG_PREFIX_LENGTH - 1) { - className = className.substring(JAVA_LANG_PREFIX_LENGTH); + if (packageString != null && !packageString.isEmpty()) { + if (packageString.equals(myPackage)) { + className = cutPackage(myPackage, className); + } else if (packageString.equals("java.lang")) { + className = typeElement.getSimpleName().toString(); + } } return className; } + private String cutPackage(String paket, String className) { + if (className.startsWith(paket + '.')) { + // Don't use TypeElement.getSimpleName, it doesn't work for us with inner classes + return className.substring(paket.length() + 1); + } else { + // Paranoia + throw new IllegalStateException("Mismatching " + paket + " vs. " + className); + } + } + private PackageElement getPackageElement(TypeElement subscriberClass) { Element candidate = subscriberClass.getEnclosingElement(); while (!(candidate instanceof PackageElement)) { From 8c328d3b0ab9d9c51b68f1f73c94d497c4f8bad6 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 11:03:11 +0100 Subject: [PATCH 102/288] move anonymous class detection after cache check --- .../src/de/greenrobot/event/EventBus.java | 10 +---- .../event/SubscriberMethodFinder.java | 41 +++++++++++++++---- .../src/de/greenrobot/eventperf/Test.java | 2 +- .../testsubject/PerfTestEventBus.java | 22 ---------- .../SubscribeClassEventBusDefault.java | 32 +++++++++++++++ 5 files changed, 68 insertions(+), 39 deletions(-) create mode 100644 EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index af47c7b9..1fab2e3e 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -130,16 +130,8 @@ public EventBus() { */ public void register(Object subscriber) { Class subscriberClass = subscriber.getClass(); - - // @Subscribe in anonymous classes is invisible to annotation processing, always fall back to reflection - // Note: Avoid Class.isAnonymousClass() because it is super slow (getSimpleName() is super slow, too) - String name = subscriberClass.getName(); - int dollarIndex = name.lastIndexOf('$'); - boolean forceReflection = dollarIndex != -1 && dollarIndex < name.length() - 1 && - Character.isDigit(name.charAt(dollarIndex + 1)); - List subscriberMethods = - subscriberMethodFinder.findSubscriberMethods(subscriberClass, forceReflection); + subscriberMethodFinder.findSubscriberMethods(subscriberClass); for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 45d0a29b..fa31afd3 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -45,7 +45,7 @@ class SubscriberMethodFinder { this.ignoreGeneratedIndex = ignoreGeneratedIndex; } - List findSubscriberMethods(Class subscriberClass, boolean forceReflection) { + List findSubscriberMethods(Class subscriberClass) { List subscriberMethods; synchronized (METHOD_CACHE) { subscriberMethods = METHOD_CACHE.get(subscriberClass); @@ -53,10 +53,12 @@ List findSubscriberMethods(Class subscriberClass, boolean f if (subscriberMethods != null) { return subscriberMethods; } - if (!ignoreGeneratedIndex && !forceReflection) { - subscriberMethods = findUsingInfo(subscriberClass); - } else { + + boolean forceReflection = isAnonymousClass(subscriberClass); + if (ignoreGeneratedIndex || forceReflection) { subscriberMethods = findUsingReflection(subscriberClass); + } else { + subscriberMethods = findUsingInfo(subscriberClass); } if (subscriberMethods.isEmpty()) { throw new EventBusException("Subscriber " + subscriberClass @@ -69,6 +71,15 @@ List findSubscriberMethods(Class subscriberClass, boolean f } } + private boolean isAnonymousClass(Class subscriberClass) { + // @Subscribe in anonymous classes is invisible to annotation processing, always fall back to reflection + // Note: Avoid Class.isAnonymousClass() because it is super slow (getSimpleName() is super slow, too) + String name = subscriberClass.getName(); + int dollarIndex = name.lastIndexOf('$'); + return dollarIndex != -1 && dollarIndex < name.length() - 1 && + Character.isDigit(name.charAt(dollarIndex + 1)); + } + private List findUsingInfo(Class subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); @@ -128,7 +139,7 @@ private SubscriberInfo getSubscriberInfo(FindState findState) { throw new EventBusException(e); } } - String infoClass = findState.clazz.getName().replace('$', '_') + "_EventBusInfo"; + String infoClass = getInfoClassName(findState); try { Class aClass = Class.forName(infoClass); Object object = aClass.newInstance(); @@ -143,6 +154,22 @@ private SubscriberInfo getSubscriberInfo(FindState findState) { return info; } + // A simple replace(char, char) is surprisingly slow + private String getInfoClassName(FindState findState) { + String className = findState.clazz.getName(); + for (int i = className.length() - 1; i >= 0; i--) { + char c = className.charAt(i); + if (c == '.') { + break; + } else if (c == '$') { + className = className.replace('$', '_'); + break; + } + } + return className + "_EventBusInfo"; +// return className.replace('$', '_')+ "_EventBusInfo"; + } + private List findUsingReflection(Class subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); @@ -234,8 +261,8 @@ boolean checkAdd(Method method, Class eventType) { if (existing == null) { return true; } else { - if(existing instanceof Method) { - if(!checkAddWithMethodSignature((Method) existing, eventType)) { + if (existing instanceof Method) { + if (!checkAddWithMethodSignature((Method) existing, eventType)) { // Paranoia check throw new IllegalStateException(); } diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/Test.java b/EventBusPerformance/src/de/greenrobot/eventperf/Test.java index 8c52d9aa..0c510d86 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/Test.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/Test.java @@ -7,7 +7,7 @@ public abstract class Test { protected final Context context; protected final TestParams params; - protected AtomicLong eventsReceivedCount = new AtomicLong(); + public final AtomicLong eventsReceivedCount = new AtomicLong(); protected long primaryResultMicros; protected int primaryResultCount; protected String otherTestResults; diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java index 70d4a8cd..4ad44afa 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java @@ -186,28 +186,6 @@ public String getDisplayName() { } - public class SubscribeClassEventBusDefault { - @Subscribe - public void onEvent(TestEvent event) { - eventsReceivedCount.incrementAndGet(); - } - - public void dummy() { - } - - public void dummy2() { - } - - public void dummy3() { - } - - public void dummy4() { - } - - public void dummy5() { - } - } - public class SubscribeClassEventBusMain { @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(TestEvent event) { diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java new file mode 100644 index 00000000..2deabf7d --- /dev/null +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java @@ -0,0 +1,32 @@ +package de.greenrobot.eventperf.testsubject; + +import de.greenrobot.event.Subscribe; +import de.greenrobot.eventperf.TestEvent; + +public class SubscribeClassEventBusDefault { + private PerfTestEventBus perfTestEventBus; + + public SubscribeClassEventBusDefault(PerfTestEventBus perfTestEventBus) { + this.perfTestEventBus = perfTestEventBus; + } + + @Subscribe + public void onEvent(TestEvent event) { + perfTestEventBus.eventsReceivedCount.incrementAndGet(); + } + + public void dummy() { + } + + public void dummy2() { + } + + public void dummy3() { + } + + public void dummy4() { + } + + public void dummy5() { + } +} From 254a27f411c374005f6b22de5d71d27dd60fb6ce Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 11:59:19 +0100 Subject: [PATCH 103/288] make METHOD_CACHE a ConcurrentHashMap --- .../greenrobot/event/SubscriberMethodFinder.java | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index fa31afd3..cd4e7187 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; class SubscriberMethodFinder { /* @@ -32,7 +33,7 @@ class SubscriberMethodFinder { private static final int SYNTHETIC = 0x1000; private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC; - private static final Map, List> METHOD_CACHE = new HashMap, List>(); + private static final Map, List> METHOD_CACHE = new ConcurrentHashMap<>(); private final boolean strictMethodVerification; private final boolean ignoreGeneratedIndex; @@ -46,10 +47,7 @@ class SubscriberMethodFinder { } List findSubscriberMethods(Class subscriberClass) { - List subscriberMethods; - synchronized (METHOD_CACHE) { - subscriberMethods = METHOD_CACHE.get(subscriberClass); - } + List subscriberMethods = METHOD_CACHE.get(subscriberClass); if (subscriberMethods != null) { return subscriberMethods; } @@ -64,9 +62,7 @@ List findSubscriberMethods(Class subscriberClass) { throw new EventBusException("Subscriber " + subscriberClass + " and its super classes have no public methods with the @Subscribe annotation"); } else { - synchronized (METHOD_CACHE) { - METHOD_CACHE.put(subscriberClass, subscriberMethods); - } + METHOD_CACHE.put(subscriberClass, subscriberMethods); return subscriberMethods; } } @@ -222,9 +218,7 @@ private void findUsingReflectionInSingleClass(FindState findState) { } static void clearCaches() { - synchronized (METHOD_CACHE) { - METHOD_CACHE.clear(); - } + METHOD_CACHE.clear(); } static class FindState { From 0a013ffcc55a96e8a5ce4d2ac862b33cf5e2cc00 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 12:05:20 +0100 Subject: [PATCH 104/288] some generic diamonds, minor --- EventBus/src/de/greenrobot/event/EventBus.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index 1fab2e3e..725d4178 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,7 +46,7 @@ public class EventBus { static volatile EventBus defaultInstance; private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder(); - private static final Map, List>> eventTypesCache = new HashMap, List>>(); + private static final Map, List>> eventTypesCache = new HashMap<>(); private final Map, CopyOnWriteArrayList> subscriptionsByEventType; private final Map>> typesBySubscriber; @@ -103,9 +103,9 @@ public EventBus() { } EventBus(EventBusBuilder builder) { - subscriptionsByEventType = new HashMap, CopyOnWriteArrayList>(); - typesBySubscriber = new HashMap>>(); - stickyEvents = new ConcurrentHashMap, Object>(); + subscriptionsByEventType = new HashMap<>(); + typesBySubscriber = new HashMap<>(); + stickyEvents = new ConcurrentHashMap<>(); mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); @@ -140,8 +140,8 @@ public void register(Object subscriber) { // Must be called in synchronized block private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { Class eventType = subscriberMethod.eventType; - CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType); Subscription newSubscription = new Subscription(subscriber, subscriberMethod); + CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions == null) { subscriptions = new CopyOnWriteArrayList(); subscriptionsByEventType.put(eventType, subscriptions); From b8dc2f648f85e97cea9ebe13975b245883941aa3 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 12:30:46 +0100 Subject: [PATCH 105/288] fixed synchronization (introduced in 7952c05234bb845552599fe86148112eb2bcf20c - annotation branch only), minor clean up --- .../src/de/greenrobot/event/EventBus.java | 52 ++++++++----------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index 725d4178..02548d34 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -130,10 +130,11 @@ public EventBus() { */ public void register(Object subscriber) { Class subscriberClass = subscriber.getClass(); - List subscriberMethods = - subscriberMethodFinder.findSubscriberMethods(subscriberClass); - for (SubscriberMethod subscriberMethod : subscriberMethods) { - subscribe(subscriber, subscriberMethod); + List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); + synchronized (this) { + for (SubscriberMethod subscriberMethod : subscriberMethods) { + subscribe(subscriber, subscriberMethod); + } } } @@ -143,7 +144,7 @@ private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { Subscription newSubscription = new Subscription(subscriber, subscriberMethod); CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions == null) { - subscriptions = new CopyOnWriteArrayList(); + subscriptions = new CopyOnWriteArrayList<>(); subscriptionsByEventType.put(eventType, subscriptions); } else { if (subscriptions.contains(newSubscription)) { @@ -152,23 +153,17 @@ private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { } } - // Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again) - // subscriberMethod.method.setAccessible(true); - - // Got to synchronize to avoid shifted positions when adding/removing concurrently - synchronized (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; - } + 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> subscribedEvents = typesBySubscriber.get(subscriber); if (subscribedEvents == null) { - subscribedEvents = new ArrayList>(); + subscribedEvents = new ArrayList<>(); typesBySubscriber.put(subscriber, subscribedEvents); } subscribedEvents.add(eventType); @@ -210,17 +205,14 @@ public synchronized boolean isRegistered(Object subscriber) { private void unsubscribeByEventType(Object subscriber, Class eventType) { List subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions != null) { - // Got to synchronize to avoid shifted positions when adding/removing concurrently - synchronized (subscriptions) { - int size = subscriptions.size(); - for (int i = 0; i < size; i++) { - Subscription subscription = subscriptions.get(i); - if (subscription.subscriber == subscriber) { - subscription.active = false; - subscriptions.remove(i); - i--; - size--; - } + int size = subscriptions.size(); + for (int i = 0; i < size; i++) { + Subscription subscription = subscriptions.get(i); + if (subscription.subscriber == subscriber) { + subscription.active = false; + subscriptions.remove(i); + i--; + size--; } } } @@ -443,11 +435,11 @@ private void postToSubscription(Subscription subscription, Object event, boolean } /** Looks up all Class objects including super classes and interfaces. Should also work for interfaces. */ - private List> lookupAllEventTypes(Class eventClass) { + private static List> lookupAllEventTypes(Class eventClass) { synchronized (eventTypesCache) { List> eventTypes = eventTypesCache.get(eventClass); if (eventTypes == null) { - eventTypes = new ArrayList>(); + eventTypes = new ArrayList<>(); Class clazz = eventClass; while (clazz != null) { eventTypes.add(clazz); From c7b43c7d78bc1d41f83a16662df5dd3ef94ba020 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 12:39:14 +0100 Subject: [PATCH 106/288] removed anonymous class detection (will fallback to reflection anyway) --- .../greenrobot/event/SubscriberMethodFinder.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index cd4e7187..dde68fc1 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -52,8 +52,7 @@ List findSubscriberMethods(Class subscriberClass) { return subscriberMethods; } - boolean forceReflection = isAnonymousClass(subscriberClass); - if (ignoreGeneratedIndex || forceReflection) { + if (ignoreGeneratedIndex) { subscriberMethods = findUsingReflection(subscriberClass); } else { subscriberMethods = findUsingInfo(subscriberClass); @@ -67,15 +66,6 @@ List findSubscriberMethods(Class subscriberClass) { } } - private boolean isAnonymousClass(Class subscriberClass) { - // @Subscribe in anonymous classes is invisible to annotation processing, always fall back to reflection - // Note: Avoid Class.isAnonymousClass() because it is super slow (getSimpleName() is super slow, too) - String name = subscriberClass.getName(); - int dollarIndex = name.lastIndexOf('$'); - return dollarIndex != -1 && dollarIndex < name.length() - 1 && - Character.isDigit(name.charAt(dollarIndex + 1)); - } - private List findUsingInfo(Class subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); From 637b27a89f754d1888c9a9c75f54319cf71eb064 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 13:19:37 +0100 Subject: [PATCH 107/288] prevent the compiler from introducing a new StringBuilder --- .../de/greenrobot/event/SubscriberMethodFinder.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index dde68fc1..99a5364f 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -140,7 +140,7 @@ private SubscriberInfo getSubscriberInfo(FindState findState) { return info; } - // A simple replace(char, char) is surprisingly slow + // A simple replace(char, char) is surprisingly slow, so we try to avoid it private String getInfoClassName(FindState findState) { String className = findState.clazz.getName(); for (int i = className.length() - 1; i >= 0; i--) { @@ -152,8 +152,7 @@ private String getInfoClassName(FindState findState) { break; } } - return className + "_EventBusInfo"; -// return className.replace('$', '_')+ "_EventBusInfo"; + return className.concat("_EventBusInfo"); } private List findUsingReflection(Class subscriberClass) { @@ -219,12 +218,13 @@ static class FindState { Class subscriberClass; Class clazz; - String clazzName; boolean skipSuperClasses; SubscriberInfo subscriberInfo; void initForSubscriber(Class subscriberClass) { this.subscriberClass = clazz = subscriberClass; + skipSuperClasses = false; + subscriberInfo = null; } void recycle() { @@ -278,14 +278,12 @@ private boolean checkAddWithMethodSignature(Method method, Class eventType) { void moveToSuperclass() { if (skipSuperClasses) { clazz = null; - clazzName = null; } else { clazz = clazz.getSuperclass(); - clazzName = clazz.getName(); + String clazzName = clazz.getName(); /** Skip system classes, this just degrades performance. */ if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) { clazz = null; - clazzName = null; } } } From d6229b1598d8b989cf4422bf861dbffdfa64fb25 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 13:20:10 +0100 Subject: [PATCH 108/288] minor typo --- .../src/de/greenrobot/event/test/AbstractEventBusTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java b/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java index 2d997620..7df0e202 100644 --- a/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,7 @@ * @author Markus Junginger, greenrobot */ public class AbstractEventBusTest extends TestCase { - /** Activates long(er) running tests e.g. testing multi-threading more throughly. */ + /** Activates long(er) running tests e.g. testing multi-threading more thoroughly. */ protected static final boolean LONG_TESTS = false; protected EventBus eventBus; From 808a4ef847d31c516c9ed692bd0c4506890decad Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 14:51:01 +0100 Subject: [PATCH 109/288] minor --- EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 99a5364f..e52cb996 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -87,7 +87,7 @@ private List findUsingInfo(Class subscriberClass) { } private List getMethodsAndRelease(FindState findState) { - ArrayList subscriberMethods = new ArrayList<>(findState.subscriberMethods); + List subscriberMethods = new ArrayList<>(findState.subscriberMethods); findState.recycle(); synchronized (FIND_STATE_POOL) { for (int i = 0; i < POOL_SIZE; i++) { @@ -168,7 +168,7 @@ private List findUsingReflection(Class subscriberClass) { private void findUsingReflectionInSingleClass(FindState findState) { Method[] methods; try { - // This is faster than getMethods, especially when subscribers a fat classes like Activities + // This is faster than getMethods, especially when subscribers are fat classes like Activities methods = findState.clazz.getDeclaredMethods(); } catch (Throwable th) { // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149 From 976ebbce1c5bd30c2faa8f62ec972ff580ca65d0 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 16:17:51 +0100 Subject: [PATCH 110/288] added SubscriberInfoIndex interface and generated implementation skeleton --- .../greenrobot/event/SubscriberInfoIndex.java | 8 +++ EventBusAnnotationProcessor/build.gradle | 2 +- .../EventBusAnnotationProcessor.java | 51 ++++++++++++++++++- EventBusPerformance/build.gradle | 14 +++-- 4 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java b/EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java new file mode 100644 index 00000000..9107fc3a --- /dev/null +++ b/EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java @@ -0,0 +1,8 @@ +package de.greenrobot.event; + +/** + * Interface for generated indexes. + */ +public interface SubscriberInfoIndex { + SubscriberInfo getSubscriberInfo(Class subscriberClass); +} diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index 3fb5d8fd..f8bf0b07 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -6,7 +6,7 @@ archivesBaseName = 'eventbus-annotation-processor' group = 'de.greenrobot' version = '3.0.0-beta2' -sourceCompatibility = 1.6 +sourceCompatibility = 1.7 def isSnapshot = version.endsWith('-SNAPSHOT') def sonatypeRepositoryUrl diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 0b59da79..37bebccc 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -73,6 +73,10 @@ public boolean process(Set annotations, RoundEnvironment if (!methodsByClass.isEmpty()) { writeSources(); + String index = processingEnv.getOptions().get("eventBusIndex"); + if (index != null) { + writeIndex(index); + } } else { messager.printMessage(Diagnostic.Kind.WARNING, "No @Subscribe annotations found"); } @@ -188,8 +192,7 @@ private TypeElement getSuperclass(TypeElement type) { } private void writeSources() { - List>> entries = - new ArrayList>>(methodsByClass.entrySet()); + List>> entries = new ArrayList<>(methodsByClass.entrySet()); for (int i = 0; i < entries.size(); i++) { Map.Entry> entry = entries.get(i); TypeElement subscriberClass = entry.getKey(); @@ -361,6 +364,50 @@ private void writeMethods(BufferedWriter writer, List methods } } + private void writeIndex(String index) { + BufferedWriter writer = null; + try { + JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(index); + int period = index.lastIndexOf('.'); + String myPackage = period > 0 ? index.substring(0, period) : null; + String clazz = index.substring(period + 1); + writer = new BufferedWriter(sourceFile.openWriter()); + if (myPackage != null) { + writer.write("package " + myPackage + ";\n\n"); + } + writer.write("import de.greenrobot.event.SubscriberInfo;\n"); + writer.write("import de.greenrobot.event.SubscriberInfoIndex;\n\n"); + writer.write("import java.util.HashMap;\n"); + writer.write("import java.util.Map;\n\n"); + writer.write("/** This class is generated by EventBus, do not edit. */\n"); + writer.write("public class " + clazz + " implements SubscriberInfoIndex {\n"); + writer.write(" private static final Map,Class> SUBSCRIBER_INDEX;\n\n"); + writer.write(" static {\n"); + writer.write(" SUBSCRIBER_INDEX = new HashMap,Class>();\n"); + writer.write(" }\n\n"); + writer.write(" @Override\n"); + writer.write(" public SubscriberInfo getSubscriberInfo(Class subscriberClass) {\n"); + writer.write(" Class infoClass = SUBSCRIBER_INDEX.get(subscriberClass);\n"); + writer.write(" try {\n"); + writer.write(" return infoClass != null? infoClass.newInstance(): null;\n"); + writer.write(" } catch(Exception ex) {\n"); + writer.write(" throw new RuntimeException(ex);\n"); + writer.write(" }\n"); + writer.write(" }\n"); + writer.write("}\n"); + } catch (IOException e) { + throw new RuntimeException("Could not write source for " + index, e); + } finally { + if (writer != null) { + try { + writer.close(); + } catch (IOException e) { + //Silent + } + } + } + } + private void writeLine(BufferedWriter writer, int indentLevel, String... parts) throws IOException { writeIndent(writer, indentLevel); int len = indentLevel * 4; diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 54801afa..12f19fb6 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -4,11 +4,13 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:1.3.1' + classpath 'com.android.tools.build:gradle:1.5.0' + classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } apply plugin: 'com.android.application' +apply plugin: 'com.neenbedankt.android-apt' repositories { jcenter() @@ -16,12 +18,18 @@ repositories { dependencies { compile project(':EventBus') - provided project(':EventBusAnnotationProcessor') + apt project(':EventBusAnnotationProcessor') compile 'com.squareup:otto:1.3.8' } +apt { + arguments { + eventBusIndex "de.greenrobot.eventperf.MyEventBusIndex" + } +} + android { - buildToolsVersion '23.0.1' + buildToolsVersion '23.0.2' compileSdkVersion 19 sourceSets { From 07969b2029d2499ae1d5eb575a047f7ff7b66af6 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 20:03:09 +0100 Subject: [PATCH 111/288] index setup code generation --- .../EventBusAnnotationProcessor.java | 77 +++++++++++++++---- 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 37bebccc..e1db0065 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -31,12 +31,12 @@ @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") public class EventBusAnnotationProcessor extends AbstractProcessor { - public static final String CLASS_POSTFIX = "_EventBusInfo"; + public static final String INFO_CLASS_POSTFIX = "_EventBusInfo"; /** Found subscriber methods for a class (without superclasses). */ - private final Map> methodsByClass = - new HashMap>(); - private final Set classesToSkip = new HashSet(); + private final Map> methodsByClass = new HashMap<>(); + private final Map infoByClass = new HashMap<>(); + private final Set classesToSkip = new HashSet<>(); private boolean writerRoundDone; private int round; @@ -72,10 +72,10 @@ public boolean process(Set annotations, RoundEnvironment checkForSubscribersToSkip(messager); if (!methodsByClass.isEmpty()) { - writeSources(); + createInfoFiles(); String index = processingEnv.getOptions().get("eventBusIndex"); if (index != null) { - writeIndex(index); + createInfoIndexFile(index); } } else { messager.printMessage(Diagnostic.Kind.WARNING, "No @Subscribe annotations found"); @@ -191,7 +191,7 @@ private TypeElement getSuperclass(TypeElement type) { } } - private void writeSources() { + private void createInfoFiles() { List>> entries = new ArrayList<>(methodsByClass.entrySet()); for (int i = 0; i < entries.size(); i++) { Map.Entry> entry = entries.get(i); @@ -207,6 +207,8 @@ private void writeSources() { String subscriberClassName = getClassString(subscriberClass, myPackage); String infoClassName = getInfoClass(subscriberClass, myPackage); + infoByClass.put(subscriberClass, myPackage + "." + infoClassName); + JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(myPackage + '.' + infoClassName); writer = new BufferedWriter(sourceFile.openWriter()); writer.write("package " + myPackage + ";\n\n"); @@ -254,7 +256,7 @@ private String getSuperclassInfoClass(TypeElement subscriberClass, String myPack private String getInfoClass(TypeElement subscriberClass, String myPackage) { String subscriberClassName = getClassString(subscriberClass, myPackage); - return subscriberClassName.replace('.', '_') + CLASS_POSTFIX; + return subscriberClassName.replace('.', '_') + INFO_CLASS_POSTFIX; } private String getNextValue(String myPackage, TypeElement nextEntry) throws IOException { @@ -364,7 +366,7 @@ private void writeMethods(BufferedWriter writer, List methods } } - private void writeIndex(String index) { + private void createInfoIndexFile(String index) { BufferedWriter writer = null; try { JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(index); @@ -381,17 +383,22 @@ private void writeIndex(String index) { writer.write("import java.util.Map;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); writer.write("public class " + clazz + " implements SubscriberInfoIndex {\n"); - writer.write(" private static final Map,Class> SUBSCRIBER_INDEX;\n\n"); + writer.write(" private static final Map, Class> SUBSCRIBER_INDEX;\n\n"); writer.write(" static {\n"); - writer.write(" SUBSCRIBER_INDEX = new HashMap,Class>();\n"); + writer.write(" SUBSCRIBER_INDEX = new HashMap, Class>();\n"); + writeIndexLines(writer, myPackage); writer.write(" }\n\n"); writer.write(" @Override\n"); writer.write(" public SubscriberInfo getSubscriberInfo(Class subscriberClass) {\n"); - writer.write(" Class infoClass = SUBSCRIBER_INDEX.get(subscriberClass);\n"); - writer.write(" try {\n"); - writer.write(" return infoClass != null? infoClass.newInstance(): null;\n"); - writer.write(" } catch(Exception ex) {\n"); - writer.write(" throw new RuntimeException(ex);\n"); + writer.write(" Class infoClass = SUBSCRIBER_INDEX.get(subscriberClass);\n"); + writer.write(" if (infoClass != null) {\n"); + writer.write(" try {\n"); + writer.write(" return infoClass.newInstance();\n"); + writer.write(" } catch (Exception ex) {\n"); + writer.write(" throw new RuntimeException(ex);\n"); + writer.write(" }\n"); + writer.write(" } else {\n"); + writer.write(" return null;\n"); writer.write(" }\n"); writer.write(" }\n"); writer.write("}\n"); @@ -408,6 +415,44 @@ private void writeIndex(String index) { } } + private void writeIndexLines(BufferedWriter writer, String myPackage) throws IOException { + for (Map.Entry entry : infoByClass.entrySet()) { + TypeElement subscriberTypeElement = entry.getKey(); + String infoClass = entry.getValue(); + if (!classesToSkip.contains(subscriberTypeElement)) { + int infoPeriod = infoClass.lastIndexOf('.'); + String infoPackage = infoPeriod > 0 ? infoClass.substring(0, infoPeriod) : null; + if (infoPackage.equals(myPackage)) { + infoClass = infoClass.substring(infoPeriod + 1); + } + String subscriberClass = getClassString(subscriberTypeElement, myPackage); + if (isVisible(myPackage, subscriberTypeElement)) { + writeLine(writer, 2, "SUBSCRIBER_INDEX.put(", subscriberClass + ".class,", infoClass + ".class);\n"); + } else { + writer.write(" // Subscriber not visible to index: " + subscriberClass + "\n"); + } + } + } + } + + private boolean isVisible(String myPackage, TypeElement typeElement) { + Set modifiers = typeElement.getModifiers(); + boolean visible; + if (modifiers.contains(Modifier.PUBLIC)) { + visible = true; + } else if (modifiers.contains(Modifier.PRIVATE) || modifiers.contains(Modifier.PROTECTED)) { + visible = false; + } else { + String subscriberPackage = getPackageElement(typeElement).getQualifiedName().toString(); + if (myPackage == null) { + visible = subscriberPackage.length() == 0; + } else { + visible = myPackage.equals(subscriberPackage); + } + } + return visible; + } + private void writeLine(BufferedWriter writer, int indentLevel, String... parts) throws IOException { writeIndent(writer, indentLevel); int len = indentLevel * 4; From 9f8106982ceeb3d7d36fe9320e96ce57627106b6 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 20:51:23 +0100 Subject: [PATCH 112/288] configure indexes using builder, using it in SubscriberMethodFinder --- .../src/de/greenrobot/event/EventBus.java | 4 ++-- .../de/greenrobot/event/EventBusBuilder.java | 21 +++++++++++++++++-- .../event/SubscriberMethodFinder.java | 18 ++++++++++++---- .../testsubject/PerfTestEventBus.java | 3 ++- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index 02548d34..cbdd10ef 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -109,7 +109,8 @@ public EventBus() { mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); - subscriberMethodFinder = new SubscriberMethodFinder(/* TODO */ false, builder.ignoreGeneratedIndex); + subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes, + builder.strictMethodVerification, builder.ignoreGeneratedIndex); logSubscriberExceptions = builder.logSubscriberExceptions; logNoSubscriberMessages = builder.logNoSubscriberMessages; sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent; @@ -119,7 +120,6 @@ public EventBus() { executorService = builder.executorService; } - /** * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they * are no longer interested in receiving events. diff --git a/EventBus/src/de/greenrobot/event/EventBusBuilder.java b/EventBus/src/de/greenrobot/event/EventBusBuilder.java index c8b75a6d..c51c69aa 100644 --- a/EventBus/src/de/greenrobot/event/EventBusBuilder.java +++ b/EventBus/src/de/greenrobot/event/EventBusBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2014-2015 Markus Junginger, greenrobot (http://greenrobot.de) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,8 +34,10 @@ public class EventBusBuilder { boolean throwSubscriberException; boolean eventInheritance = true; boolean ignoreGeneratedIndex; + boolean strictMethodVerification; ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE; List> skipMethodVerificationForClasses; + List subscriberInfoIndexes; EventBusBuilder() { } @@ -106,7 +108,7 @@ public EventBusBuilder executorService(ExecutorService executorService) { */ public EventBusBuilder skipMethodVerificationFor(Class clazz) { if (skipMethodVerificationForClasses == null) { - skipMethodVerificationForClasses = new ArrayList>(); + skipMethodVerificationForClasses = new ArrayList<>(); } skipMethodVerificationForClasses.add(clazz); return this; @@ -118,6 +120,21 @@ public EventBusBuilder ignoreGeneratedIndex(boolean ignoreGeneratedIndex) { return this; } + /** Enables strict method verification (default: false). */ + public EventBusBuilder strictMethodVerification(boolean strictMethodVerification) { + this.strictMethodVerification = strictMethodVerification; + return this; + } + + /** Adds an index generated by EventBus' annotation preprocessor. */ + public EventBusBuilder addIndex(SubscriberInfoIndex index) { + if(subscriberInfoIndexes == null) { + subscriberInfoIndexes = new ArrayList<>(); + } + subscriberInfoIndexes.add(index); + return this; + } + /** * Installs the default EventBus returned by {@link EventBus#getDefault()} using this builders' values. Must be * done only once before the first usage of the default EventBus. diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index e52cb996..bc0ee8fd 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -35,13 +35,16 @@ class SubscriberMethodFinder { private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC; private static final Map, List> METHOD_CACHE = new ConcurrentHashMap<>(); + private List subscriberInfoIndexes; private final boolean strictMethodVerification; private final boolean ignoreGeneratedIndex; private static final int POOL_SIZE = 4; private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE]; - SubscriberMethodFinder(boolean strictMethodVerification, boolean ignoreGeneratedIndex) { + SubscriberMethodFinder(List subscriberInfoIndexes, boolean strictMethodVerification, + boolean ignoreGeneratedIndex) { + this.subscriberInfoIndexes = subscriberInfoIndexes; this.strictMethodVerification = strictMethodVerification; this.ignoreGeneratedIndex = ignoreGeneratedIndex; } @@ -114,7 +117,6 @@ private FindState prepareFindState() { } private SubscriberInfo getSubscriberInfo(FindState findState) { - SubscriberInfo info = null; if (findState.subscriberInfo != null && findState.subscriberInfo.superSubscriberInfoClass != null) { try { SubscriberInfo superclassInfo = (SubscriberInfo) findState.subscriberInfo.superSubscriberInfoClass.newInstance(); @@ -125,19 +127,27 @@ private SubscriberInfo getSubscriberInfo(FindState findState) { throw new EventBusException(e); } } + if (subscriberInfoIndexes != null) { + for (SubscriberInfoIndex index : subscriberInfoIndexes) { + SubscriberInfo info = index.getSubscriberInfo(findState.clazz); + if (info != null) { + return info; + } + } + } String infoClass = getInfoClassName(findState); try { Class aClass = Class.forName(infoClass); Object object = aClass.newInstance(); if (object instanceof SubscriberInfo) { - info = (SubscriberInfo) object; + return (SubscriberInfo) object; } } catch (ClassNotFoundException e) { // TODO don't try again } catch (Exception e) { throw new EventBusException("Could not get infos for " + findState.clazz, e); } - return info; + return null; } // A simple replace(char, char) is surprisingly slow, so we try to avoid it diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java index 4ad44afa..cd0ae167 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java @@ -8,6 +8,7 @@ import de.greenrobot.event.EventBus; import de.greenrobot.event.ThreadMode; import de.greenrobot.event.Subscribe; +import de.greenrobot.eventperf.MyEventBusIndex; import de.greenrobot.eventperf.Test; import de.greenrobot.eventperf.TestEvent; import de.greenrobot.eventperf.TestParams; @@ -22,7 +23,7 @@ public abstract class PerfTestEventBus extends Test { public PerfTestEventBus(Context context, TestParams params) { super(context, params); - eventBus = EventBus.builder().eventInheritance(params.isEventInheritance()) + eventBus = EventBus.builder().eventInheritance(params.isEventInheritance()).addIndex(new MyEventBusIndex()) .ignoreGeneratedIndex(params.isIgnoreGeneratedIndex()).build(); subscribers = new ArrayList(); eventCount = params.getEventCount(); From d6e2a6ae8fc6f7cc55277c9afcb4082da732dfa8 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 21:47:23 +0100 Subject: [PATCH 113/288] made SubscriberInfo an interface, removed next subscriber info class, added shouldCheckSuperclass --- .../event/AbstractSubscriberInfo.java | 67 +++++++++++++++++++ .../de/greenrobot/event/SubscriberInfo.java | 52 ++++++-------- .../greenrobot/event/SubscriberInfoIndex.java | 15 +++++ .../event/SubscriberMethodFinder.java | 8 +-- .../EventBusAnnotationProcessor.java | 38 +++-------- 5 files changed, 115 insertions(+), 65 deletions(-) create mode 100644 EventBus/src/de/greenrobot/event/AbstractSubscriberInfo.java diff --git a/EventBus/src/de/greenrobot/event/AbstractSubscriberInfo.java b/EventBus/src/de/greenrobot/event/AbstractSubscriberInfo.java new file mode 100644 index 00000000..df36f136 --- /dev/null +++ b/EventBus/src/de/greenrobot/event/AbstractSubscriberInfo.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.greenrobot.event; + +import java.lang.reflect.Method; + +/** Base class for generated subscriber meta info classes created by annotation processing. */ +public abstract class AbstractSubscriberInfo implements SubscriberInfo { + private final Class subscriberClass; + private final Class superSubscriberInfoClass; + private final boolean shouldCheckSuperclass; + + protected AbstractSubscriberInfo(Class subscriberClass, Class superSubscriberInfoClass, + boolean shouldCheckSuperclass) { + this.subscriberClass = subscriberClass; + this.superSubscriberInfoClass = superSubscriberInfoClass; + this.shouldCheckSuperclass = shouldCheckSuperclass; + } + + @Override + public Class getSubscriberClass() { + return subscriberClass; + } + + @Override + public Class getSuperSubscriberInfoClass() { + return superSubscriberInfoClass; + } + + @Override + public boolean shouldCheckSuperclass() { + return shouldCheckSuperclass; + } + + protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType) { + return createSubscriberMethod(methodName, eventType, ThreadMode.POSTING, 0, false); + } + + protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType, ThreadMode threadMode) { + return createSubscriberMethod(methodName, eventType, threadMode, 0, false); + } + + protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType, ThreadMode threadMode, + int priority, boolean sticky) { + try { + Method method = subscriberClass.getDeclaredMethod(methodName, eventType); + return new SubscriberMethod(method, eventType, threadMode, priority, sticky); + } catch (NoSuchMethodException e) { + throw new EventBusException("Could not find subscriber method in " + subscriberClass + + ". Maybe a missing ProGuard rule?", e); + } + } + +} diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfo.java b/EventBus/src/de/greenrobot/event/SubscriberInfo.java index 43ed290c..635a4a0a 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberInfo.java +++ b/EventBus/src/de/greenrobot/event/SubscriberInfo.java @@ -1,39 +1,27 @@ +/* + * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package de.greenrobot.event; -import java.lang.reflect.Method; - /** Base class for generated index classes created by annotation processing. */ -public abstract class SubscriberInfo { - final Class subscriberClass; - final Class superSubscriberInfoClass; - final Class nextSubscriberInfoClass; - - protected SubscriberInfo(Class subscriberClass, Class superSubscriberInfoClass, Class nextSubscriberInfoClass) { - this.subscriberClass = subscriberClass; - this.superSubscriberInfoClass = superSubscriberInfoClass; - this.nextSubscriberInfoClass = nextSubscriberInfoClass; - } - - abstract protected SubscriberMethod[] createSubscriberMethods(); - - protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType) { - return createSubscriberMethod(methodName, eventType, ThreadMode.POSTING, 0, false); - - } +public interface SubscriberInfo { + Class getSubscriberClass(); - protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType, ThreadMode threadMode) { - return createSubscriberMethod(methodName, eventType, threadMode, 0, false); - } + SubscriberMethod[] getSubscriberMethods(); - protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType, ThreadMode threadMode, - int priority, boolean sticky) { - try { - Method method = subscriberClass.getDeclaredMethod(methodName, eventType); - return new SubscriberMethod(method, eventType, threadMode, priority, sticky); - } catch (NoSuchMethodException e) { - throw new EventBusException("Could not find subscriber method in " + subscriberClass + - ". Maybe a missing ProGuard rule?", e); - } - } + Class getSuperSubscriberInfoClass(); + boolean shouldCheckSuperclass(); } diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java b/EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java index 9107fc3a..f5772fb1 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java +++ b/EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java @@ -1,3 +1,18 @@ +/* + * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package de.greenrobot.event; /** diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index bc0ee8fd..8df6ae0b 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -75,7 +75,7 @@ private List findUsingInfo(Class subscriberClass) { while (findState.clazz != null) { findState.subscriberInfo = getSubscriberInfo(findState); if (findState.subscriberInfo != null) { - SubscriberMethod[] array = findState.subscriberInfo.createSubscriberMethods(); + SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods(); for (SubscriberMethod subscriberMethod : array) { if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) { findState.subscriberMethods.add(subscriberMethod); @@ -117,10 +117,10 @@ private FindState prepareFindState() { } private SubscriberInfo getSubscriberInfo(FindState findState) { - if (findState.subscriberInfo != null && findState.subscriberInfo.superSubscriberInfoClass != null) { + if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfoClass() != null) { try { - SubscriberInfo superclassInfo = (SubscriberInfo) findState.subscriberInfo.superSubscriberInfoClass.newInstance(); - if (findState.clazz == superclassInfo.subscriberClass) { + SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfoClass().newInstance(); + if (findState.clazz == superclassInfo.getSubscriberClass()) { return superclassInfo; } } catch (IllegalAccessException | InstantiationException e) { diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index e1db0065..b722a57b 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -212,21 +212,19 @@ private void createInfoFiles() { JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(myPackage + '.' + infoClassName); writer = new BufferedWriter(sourceFile.openWriter()); writer.write("package " + myPackage + ";\n\n"); - writer.write("import de.greenrobot.event.SubscriberInfo;\n"); + writer.write("import de.greenrobot.event.AbstractSubscriberInfo;\n"); writer.write("import de.greenrobot.event.SubscriberMethod;\n"); writer.write("import de.greenrobot.event.ThreadMode;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); - writer.write("public class " + infoClassName + " extends SubscriberInfo {\n"); + writer.write("public class " + infoClassName + " extends AbstractSubscriberInfo {\n"); writer.write(" public " + infoClassName + "() {\n"); - TypeElement nextEntry = nextEntry(entries, entry, i); - String next = getNextValue(myPackage, nextEntry); String infoSuperClass = getSuperclassInfoClass(subscriberClass, myPackage); - writeLine(writer, 2, "super(" + subscriberClassName + ".class,", infoSuperClass + ",", next + ");"); + writeLine(writer, 2, "super(" + subscriberClassName + ".class,", infoSuperClass + ",", "/* TODO */ true);"); writer.write(" }\n\n"); - writer.write(" protected SubscriberMethod[] createSubscriberMethods() {\n"); + writer.write(" public SubscriberMethod[] getSubscriberMethods() {\n"); writer.write(" return new SubscriberMethod[] {\n"); - Set methodSignatures = new HashSet(); - writeMethods(writer, entry.getValue(), methodSignatures, myPackage); + Set methodSignatures = new HashSet<>(); + writeCreateSubscriberMethods(writer, entry.getValue(), methodSignatures, myPackage); writer.write(" };\n"); writer.write(" }\n}\n"); } catch (IOException e) { @@ -307,27 +305,9 @@ private PackageElement getPackageElement(TypeElement subscriberClass) { return (PackageElement) candidate; } - private TypeElement nextEntry(List>> entries, - Map.Entry> current, int currentIdx) { - for (int i = currentIdx + 1; ; i++) { - if (i == entries.size()) { - i = 0; - } - if (i == currentIdx) { - return null; - } else { - Map.Entry> candidate = entries.get(i); - if (!classesToSkip.contains(candidate.getKey())) { - return candidate.getKey(); - } - } - } - } - - private void writeMethods(BufferedWriter writer, List methods, Set methodSignatures, - String myPackage) throws IOException { + private void writeCreateSubscriberMethods(BufferedWriter writer, List methods, Set methodSignatures, + String myPackage) throws IOException { for (ExecutableElement method : methods) { - List parameters = method.getParameters(); TypeMirror paramType = parameters.get(0).asType(); TypeElement paramElement = (TypeElement) processingEnv.getTypeUtils().asElement(paramType); @@ -341,7 +321,7 @@ private void writeMethods(BufferedWriter writer, List methods String methodName = method.getSimpleName().toString(); Subscribe subscribe = method.getAnnotation(Subscribe.class); - List parts = new ArrayList(); + List parts = new ArrayList<>(); parts.add("createSubscriberMethod(\"" + methodName + "\","); String lineEnd = "),"; if (subscribe.priority() == 0 && !subscribe.sticky()) { From 8fdd73d4e4600c7f1a69da8438d861c387b5b89c Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 21:54:08 +0100 Subject: [PATCH 114/288] moved subscriber info classes into new meta package --- EventBus/src/de/greenrobot/event/EventBusBuilder.java | 2 ++ EventBus/src/de/greenrobot/event/SubscriberMethod.java | 2 +- .../src/de/greenrobot/event/SubscriberMethodFinder.java | 3 +++ .../greenrobot/event/{ => meta}/AbstractSubscriberInfo.java | 6 +++++- .../src/de/greenrobot/event/{ => meta}/SubscriberInfo.java | 4 +++- .../de/greenrobot/event/{ => meta}/SubscriberInfoIndex.java | 2 +- .../annotationprocessor/EventBusAnnotationProcessor.java | 6 +++--- 7 files changed, 18 insertions(+), 7 deletions(-) rename EventBus/src/de/greenrobot/event/{ => meta}/AbstractSubscriberInfo.java (94%) rename EventBus/src/de/greenrobot/event/{ => meta}/SubscriberInfo.java (92%) rename EventBus/src/de/greenrobot/event/{ => meta}/SubscriberInfoIndex.java (95%) diff --git a/EventBus/src/de/greenrobot/event/EventBusBuilder.java b/EventBus/src/de/greenrobot/event/EventBusBuilder.java index c51c69aa..4ee59fc2 100644 --- a/EventBus/src/de/greenrobot/event/EventBusBuilder.java +++ b/EventBus/src/de/greenrobot/event/EventBusBuilder.java @@ -20,6 +20,8 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import de.greenrobot.event.meta.SubscriberInfoIndex; + /** * Creates EventBus instances with custom parameters and also allows to install a custom default EventBus instance. * Create a new builder using {@link EventBus#builder()}. diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethod.java b/EventBus/src/de/greenrobot/event/SubscriberMethod.java index 4d77446a..f1c86820 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethod.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethod.java @@ -27,7 +27,7 @@ public class SubscriberMethod { /** Used for efficient comparison */ String methodString; - SubscriberMethod(Method method, Class eventType, ThreadMode threadMode, int priority, boolean sticky) { + public SubscriberMethod(Method method, Class eventType, ThreadMode threadMode, int priority, boolean sticky) { this.method = method; this.threadMode = threadMode; this.eventType = eventType; diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 8df6ae0b..bf3e8c7b 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -23,6 +23,9 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import de.greenrobot.event.meta.SubscriberInfo; +import de.greenrobot.event.meta.SubscriberInfoIndex; + class SubscriberMethodFinder { /* * In newer class files, compilers may add methods. Those are called bridge or synthetic methods. diff --git a/EventBus/src/de/greenrobot/event/AbstractSubscriberInfo.java b/EventBus/src/de/greenrobot/event/meta/AbstractSubscriberInfo.java similarity index 94% rename from EventBus/src/de/greenrobot/event/AbstractSubscriberInfo.java rename to EventBus/src/de/greenrobot/event/meta/AbstractSubscriberInfo.java index df36f136..22a9ea0f 100644 --- a/EventBus/src/de/greenrobot/event/AbstractSubscriberInfo.java +++ b/EventBus/src/de/greenrobot/event/meta/AbstractSubscriberInfo.java @@ -13,10 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package de.greenrobot.event.meta; import java.lang.reflect.Method; +import de.greenrobot.event.EventBusException; +import de.greenrobot.event.SubscriberMethod; +import de.greenrobot.event.ThreadMode; + /** Base class for generated subscriber meta info classes created by annotation processing. */ public abstract class AbstractSubscriberInfo implements SubscriberInfo { private final Class subscriberClass; diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfo.java b/EventBus/src/de/greenrobot/event/meta/SubscriberInfo.java similarity index 92% rename from EventBus/src/de/greenrobot/event/SubscriberInfo.java rename to EventBus/src/de/greenrobot/event/meta/SubscriberInfo.java index 635a4a0a..51dda356 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberInfo.java +++ b/EventBus/src/de/greenrobot/event/meta/SubscriberInfo.java @@ -13,7 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package de.greenrobot.event.meta; + +import de.greenrobot.event.SubscriberMethod; /** Base class for generated index classes created by annotation processing. */ public interface SubscriberInfo { diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java b/EventBus/src/de/greenrobot/event/meta/SubscriberInfoIndex.java similarity index 95% rename from EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java rename to EventBus/src/de/greenrobot/event/meta/SubscriberInfoIndex.java index f5772fb1..f372c593 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java +++ b/EventBus/src/de/greenrobot/event/meta/SubscriberInfoIndex.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package de.greenrobot.event.meta; /** * Interface for generated indexes. diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index b722a57b..35300062 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -212,7 +212,7 @@ private void createInfoFiles() { JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(myPackage + '.' + infoClassName); writer = new BufferedWriter(sourceFile.openWriter()); writer.write("package " + myPackage + ";\n\n"); - writer.write("import de.greenrobot.event.AbstractSubscriberInfo;\n"); + writer.write("import de.greenrobot.event.meta.AbstractSubscriberInfo;\n"); writer.write("import de.greenrobot.event.SubscriberMethod;\n"); writer.write("import de.greenrobot.event.ThreadMode;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); @@ -357,8 +357,8 @@ private void createInfoIndexFile(String index) { if (myPackage != null) { writer.write("package " + myPackage + ";\n\n"); } - writer.write("import de.greenrobot.event.SubscriberInfo;\n"); - writer.write("import de.greenrobot.event.SubscriberInfoIndex;\n\n"); + writer.write("import de.greenrobot.event.meta.SubscriberInfo;\n"); + writer.write("import de.greenrobot.event.meta.SubscriberInfoIndex;\n\n"); writer.write("import java.util.HashMap;\n"); writer.write("import java.util.Map;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); From 880c0aea35bea562b6f99c1191e8a15149c89cfd Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 22:03:06 +0100 Subject: [PATCH 115/288] formatting improvements --- .../EventBusAnnotationProcessor.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 35300062..3c3d87a8 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -407,7 +407,7 @@ private void writeIndexLines(BufferedWriter writer, String myPackage) throws IOE } String subscriberClass = getClassString(subscriberTypeElement, myPackage); if (isVisible(myPackage, subscriberTypeElement)) { - writeLine(writer, 2, "SUBSCRIBER_INDEX.put(", subscriberClass + ".class,", infoClass + ".class);\n"); + writeLine(writer, 2, "SUBSCRIBER_INDEX.put(" + subscriberClass + ".class,", infoClass + ".class);"); } else { writer.write(" // Subscriber not visible to index: " + subscriberClass + "\n"); } @@ -438,15 +438,17 @@ private void writeLine(BufferedWriter writer, int indentLevel, String... parts) int len = indentLevel * 4; for (int i = 0; i < parts.length; i++) { String part = parts[i]; - if (len + part.length() > 118) { - writer.write("\n"); - if (indentLevel < 12) { - indentLevel += 2; + if (i != 0) { + if (len + part.length() > 118) { + writer.write("\n"); + if (indentLevel < 12) { + indentLevel += 2; + } + writeIndent(writer, indentLevel); + len = indentLevel * 4; + } else { + writer.write(" "); } - writeIndent(writer, indentLevel); - len = indentLevel * 4; - } else if (i != 0) { - writer.write(" "); } writer.write(part); len += part.length(); From e2b179b92f109703a1bdc9fa8d15af87f06bb15c Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 8 Dec 2015 21:36:49 +0100 Subject: [PATCH 116/288] index with SimpleSubscriberInfo objects --- .../event/meta/SimpleSubscriberInfo.java | 43 ++++++++++++++ .../event/meta/SubscriberMethodInfo.java | 44 ++++++++++++++ .../EventBusAnnotationProcessor.java | 59 +++++++++---------- 3 files changed, 116 insertions(+), 30 deletions(-) create mode 100644 EventBus/src/de/greenrobot/event/meta/SimpleSubscriberInfo.java create mode 100644 EventBus/src/de/greenrobot/event/meta/SubscriberMethodInfo.java diff --git a/EventBus/src/de/greenrobot/event/meta/SimpleSubscriberInfo.java b/EventBus/src/de/greenrobot/event/meta/SimpleSubscriberInfo.java new file mode 100644 index 00000000..39366a00 --- /dev/null +++ b/EventBus/src/de/greenrobot/event/meta/SimpleSubscriberInfo.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.greenrobot.event.meta; + +import de.greenrobot.event.SubscriberMethod; + +/** + * Uses {@link SubscriberMethodInfo} objects to create {@link SubscriberMethod} objects on demand. + */ +public class SimpleSubscriberInfo extends AbstractSubscriberInfo { + + private final SubscriberMethodInfo[] methodInfos; + + public SimpleSubscriberInfo(Class subscriberClass, boolean shouldCheckSuperclass, SubscriberMethodInfo[] methodInfos) { + super(subscriberClass, null, shouldCheckSuperclass); + this.methodInfos = methodInfos; + } + + @Override + public synchronized SubscriberMethod[] getSubscriberMethods() { + int length = methodInfos.length; + SubscriberMethod[] methods = new SubscriberMethod[length]; + for (int i = 0; i < length; i++) { + SubscriberMethodInfo info = methodInfos[i]; + methods[i] = createSubscriberMethod(info.methodName, info.eventType, info.threadMode, + info.priority, info.sticky); + } + return methods; + } +} \ No newline at end of file diff --git a/EventBus/src/de/greenrobot/event/meta/SubscriberMethodInfo.java b/EventBus/src/de/greenrobot/event/meta/SubscriberMethodInfo.java new file mode 100644 index 00000000..ed822f35 --- /dev/null +++ b/EventBus/src/de/greenrobot/event/meta/SubscriberMethodInfo.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.greenrobot.event.meta; + +import de.greenrobot.event.ThreadMode; + +public class SubscriberMethodInfo { + final String methodName; + final ThreadMode threadMode; + final Class eventType; + final int priority; + final boolean sticky; + + public SubscriberMethodInfo(String methodName, Class eventType, ThreadMode threadMode, + int priority, boolean sticky) { + this.methodName = methodName; + this.threadMode = threadMode; + this.eventType = eventType; + this.priority = priority; + this.sticky = sticky; + } + + public SubscriberMethodInfo(String methodName, Class eventType) { + this(methodName, eventType, ThreadMode.POSTING, 0, false); + } + + public SubscriberMethodInfo(String methodName, Class eventType, ThreadMode threadMode) { + this(methodName, eventType, threadMode, 0, false); + } + +} \ No newline at end of file diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 3c3d87a8..0210c370 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -99,7 +99,7 @@ private void collectSubscribers(Set annotations, RoundEnv Element classElement = method.getEnclosingElement(); List methods = methodsByClass.get(classElement); if (methods == null) { - methods = new ArrayList(); + methods = new ArrayList<>(); methodsByClass.put((TypeElement) classElement, methods); } methods.add(method); @@ -223,8 +223,7 @@ private void createInfoFiles() { writer.write(" }\n\n"); writer.write(" public SubscriberMethod[] getSubscriberMethods() {\n"); writer.write(" return new SubscriberMethod[] {\n"); - Set methodSignatures = new HashSet<>(); - writeCreateSubscriberMethods(writer, entry.getValue(), methodSignatures, myPackage); + writeCreateSubscriberMethods(writer, entry.getValue(), "createSubscriberMethod", myPackage); writer.write(" };\n"); writer.write(" }\n}\n"); } catch (IOException e) { @@ -305,24 +304,18 @@ private PackageElement getPackageElement(TypeElement subscriberClass) { return (PackageElement) candidate; } - private void writeCreateSubscriberMethods(BufferedWriter writer, List methods, Set methodSignatures, - String myPackage) throws IOException { + private void writeCreateSubscriberMethods(BufferedWriter writer, List methods, + String callPrefix, String myPackage) throws IOException { for (ExecutableElement method : methods) { List parameters = method.getParameters(); TypeMirror paramType = parameters.get(0).asType(); TypeElement paramElement = (TypeElement) processingEnv.getTypeUtils().asElement(paramType); - String eventClass = getClassString(paramElement, myPackage) + ".class"; - - String methodSignature = method + ">" + paramElement.getQualifiedName(); - if (!methodSignatures.add(methodSignature)) { - continue; - } - String methodName = method.getSimpleName().toString(); + String eventClass = getClassString(paramElement, myPackage) + ".class"; Subscribe subscribe = method.getAnnotation(Subscribe.class); List parts = new ArrayList<>(); - parts.add("createSubscriberMethod(\"" + methodName + "\","); + parts.add(callPrefix + "(\"" + methodName + "\","); String lineEnd = "),"; if (subscribe.priority() == 0 && !subscribe.sticky()) { if (subscribe.threadMode() == ThreadMode.POSTING) { @@ -357,26 +350,28 @@ private void createInfoIndexFile(String index) { if (myPackage != null) { writer.write("package " + myPackage + ";\n\n"); } + writer.write("import de.greenrobot.event.meta.SimpleSubscriberInfo;\n"); + writer.write("import de.greenrobot.event.meta.SubscriberMethodInfo;\n"); writer.write("import de.greenrobot.event.meta.SubscriberInfo;\n"); writer.write("import de.greenrobot.event.meta.SubscriberInfoIndex;\n\n"); + writer.write("import de.greenrobot.event.ThreadMode;\n\n"); writer.write("import java.util.HashMap;\n"); writer.write("import java.util.Map;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); writer.write("public class " + clazz + " implements SubscriberInfoIndex {\n"); - writer.write(" private static final Map, Class> SUBSCRIBER_INDEX;\n\n"); + writer.write(" private static final Map, SubscriberInfo> SUBSCRIBER_INDEX;\n\n"); writer.write(" static {\n"); - writer.write(" SUBSCRIBER_INDEX = new HashMap, Class>();\n"); + writer.write(" SUBSCRIBER_INDEX = new HashMap, SubscriberInfo>();\n\n"); writeIndexLines(writer, myPackage); writer.write(" }\n\n"); + writer.write(" private static void putIndex(SubscriberInfo info) {\n"); + writer.write(" SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);\n"); + writer.write(" }\n\n"); writer.write(" @Override\n"); writer.write(" public SubscriberInfo getSubscriberInfo(Class subscriberClass) {\n"); - writer.write(" Class infoClass = SUBSCRIBER_INDEX.get(subscriberClass);\n"); - writer.write(" if (infoClass != null) {\n"); - writer.write(" try {\n"); - writer.write(" return infoClass.newInstance();\n"); - writer.write(" } catch (Exception ex) {\n"); - writer.write(" throw new RuntimeException(ex);\n"); - writer.write(" }\n"); + writer.write(" SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);\n"); + writer.write(" if (info != null) {\n"); + writer.write(" return info;\n"); writer.write(" } else {\n"); writer.write(" return null;\n"); writer.write(" }\n"); @@ -398,16 +393,15 @@ private void createInfoIndexFile(String index) { private void writeIndexLines(BufferedWriter writer, String myPackage) throws IOException { for (Map.Entry entry : infoByClass.entrySet()) { TypeElement subscriberTypeElement = entry.getKey(); - String infoClass = entry.getValue(); if (!classesToSkip.contains(subscriberTypeElement)) { - int infoPeriod = infoClass.lastIndexOf('.'); - String infoPackage = infoPeriod > 0 ? infoClass.substring(0, infoPeriod) : null; - if (infoPackage.equals(myPackage)) { - infoClass = infoClass.substring(infoPeriod + 1); - } String subscriberClass = getClassString(subscriberTypeElement, myPackage); if (isVisible(myPackage, subscriberTypeElement)) { - writeLine(writer, 2, "SUBSCRIBER_INDEX.put(" + subscriberClass + ".class,", infoClass + ".class);"); + writeLine(writer, 2, + "putIndex(new SimpleSubscriberInfo(" + subscriberClass + ".class,", + "true,", "new SubscriberMethodInfo[] {"); + List methods = methodsByClass.get(subscriberTypeElement); + writeCreateSubscriberMethods(writer, methods, "new SubscriberMethodInfo", myPackage); + writer.write(" }));\n\n"); } else { writer.write(" // Subscriber not visible to index: " + subscriberClass + "\n"); } @@ -434,6 +428,11 @@ private boolean isVisible(String myPackage, TypeElement typeElement) { } private void writeLine(BufferedWriter writer, int indentLevel, String... parts) throws IOException { + writeLine(writer, indentLevel, 2, parts); + } + + private void writeLine(BufferedWriter writer, int indentLevel, int indentLevelIncrease, String... parts) + throws IOException { writeIndent(writer, indentLevel); int len = indentLevel * 4; for (int i = 0; i < parts.length; i++) { @@ -442,7 +441,7 @@ private void writeLine(BufferedWriter writer, int indentLevel, String... parts) if (len + part.length() > 118) { writer.write("\n"); if (indentLevel < 12) { - indentLevel += 2; + indentLevel += indentLevelIncrease; } writeIndent(writer, indentLevel); len = indentLevel * 4; From 2976f4824b1a45bdd18ca6f090d5e39409775e8e Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 8 Dec 2015 22:01:25 +0100 Subject: [PATCH 117/288] removed survey link --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 3b6c7a26..b0d001ec 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -**Please help us with this short survey: http://bit.ly/eventbus-survey Thanks for your support!** - EventBus ======== EventBus is publish/subscribe event bus optimized for Android.
From 030a852dd3a558f398af9b87ff745503c90751c9 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 16 Dec 2015 09:17:18 +0100 Subject: [PATCH 118/288] prepare CHANGELOG.md for version 3 --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index afe615df..413e86cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +### V3.0.0 (201?-??-??) Annotations +* Breaking change: switch subscriber methods to annotations +* Using annotations, each subscriber method can set sticky behavior and priority individually +* Annotation processor indexes annotation information for efficient subscriber registration on Android +* TODO: Renamed package and artifact id to allow co-existence with libs using EventBus 2 internally + +**Note:** This is a breaking change release: there is no inter-op between EventBus versions 2 and 3; they can run in parallel though. + ### V2.4.1 (2015-11-12) Bug fix release * Registering for sticky events now considers sticky events of subclasses, not just the exact same event type. This makes the semantic consistent to posting events. Note, that this may lead to subscribers being called more than once if matching sticky events of event type subclasses are available. * Workaround for an Android bug causing NoClassDefFoundError on some devices From 93e8ba6362f7757750a9ccd90d0fda2a91185d51 Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 17 Dec 2015 22:26:12 +0100 Subject: [PATCH 119/288] convert Android instrumentation tests to JUnit 4 --- EventBusTest/AndroidManifest.xml | 2 +- EventBusTest/build.gradle | 14 ++++++-- .../event/test/AbstractEventBusTest.java | 25 +++++++++----- .../event/test/ClassMapPerfTest.java | 2 -- .../test/EventBusBackgroundThreadTest.java | 10 +++++- .../event/test/EventBusBasicTest.java | 33 ++++++++++++++++--- .../event/test/EventBusBuilderTest.java | 11 ++++++- .../test/EventBusCancelEventDeliveryTest.java | 14 ++++++-- .../EventBusFallbackToReflectionTest.java | 8 +++++ .../event/test/EventBusGenericsTest.java | 3 +- .../test/EventBusInheritanceDisabledTest.java | 20 ++++++++--- .../event/test/EventBusInheritanceTest.java | 12 ++++--- .../test/EventBusMainThreadRacingTest.java | 10 +++--- .../event/test/EventBusMainThreadTest.java | 22 ++++++++----- .../test/EventBusMethodModifiersTest.java | 9 +++-- .../event/test/EventBusMultithreadedTest.java | 20 ++++++++--- .../test/EventBusNoSubscriberEventTest.java | 9 ++++- .../EventBusOrderedSubscriptionsTest.java | 9 +++++ .../test/EventBusRegistrationRacingTest.java | 4 +++ .../event/test/EventBusStickyEventTest.java | 16 +++++++++ .../test/EventBusSubscriberExceptionTest.java | 8 ++++- .../test/EventBusSubscriberInJarTest.java | 2 ++ .../test/EventBusSubscriberLegalTest.java | 5 ++- 23 files changed, 212 insertions(+), 56 deletions(-) diff --git a/EventBusTest/AndroidManifest.xml b/EventBusTest/AndroidManifest.xml index 9695813a..22aedee0 100644 --- a/EventBusTest/AndroidManifest.xml +++ b/EventBusTest/AndroidManifest.xml @@ -4,7 +4,7 @@ android:versionCode="1" android:versionName="1.0" > - + { @@ -15,6 +15,7 @@ public void onGenericEvent(GenericEvent event) { } } + @Test public void testGenericEventAndSubscriber() { GenericSubscriber genericSubscriber = new GenericSubscriber(); eventBus.register(genericSubscriber); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java index 70eb9bde..45376aea 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java @@ -15,14 +15,20 @@ */ package de.greenrobot.event.test; +import android.support.test.runner.AndroidJUnit4; import de.greenrobot.event.EventBus; import de.greenrobot.event.Subscribe; -import junit.framework.TestCase; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static junit.framework.Assert.assertEquals; /** * @author Markus Junginger, greenrobot */ -public class EventBusInheritanceDisabledTest extends TestCase { +@RunWith(AndroidJUnit4.class) +public class EventBusInheritanceDisabledTest { private EventBus eventBus; @@ -32,11 +38,12 @@ public class EventBusInheritanceDisabledTest extends TestCase { private int countMyEventInterface; private int countMyEventInterfaceExtended; - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() throws Exception { eventBus = EventBus.builder().eventInheritance(false).build(); } + @Test public void testEventClassHierarchy() { eventBus.register(this); @@ -53,6 +60,7 @@ public void testEventClassHierarchy() { assertEquals(1, countMyEventExtended); } + @Test public void testEventClassHierarchySticky() { eventBus.postSticky("Hello"); eventBus.postSticky(new MyEvent()); @@ -63,6 +71,7 @@ public void testEventClassHierarchySticky() { assertEquals(0, countObjectEvent); } + @Test public void testEventInterfaceHierarchy() { eventBus.register(this); @@ -74,6 +83,7 @@ public void testEventInterfaceHierarchy() { assertEquals(0, countMyEventInterfaceExtended); } + @Test public void testEventSuperInterfaceHierarchy() { eventBus.register(this); @@ -83,6 +93,7 @@ public void testEventSuperInterfaceHierarchy() { assertEquals(0, countMyEventInterfaceExtended); } + @Test public void testSubscriberClassHierarchy() { SubscriberExtended subscriber = new SubscriberExtended(); eventBus.register(subscriber); @@ -102,6 +113,7 @@ public void testSubscriberClassHierarchy() { assertEquals(1, subscriber.countMyEventOverwritten); } + @Test public void testSubscriberClassHierarchyWithoutNewSubscriberMethod() { SubscriberExtendedWithoutNewSubscriberMethod subscriber = new SubscriberExtendedWithoutNewSubscriberMethod(); eventBus.register(subscriber); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java index 183fe89d..fe594c54 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java @@ -15,12 +15,10 @@ */ package de.greenrobot.event.test; +import de.greenrobot.event.EventBus; import de.greenrobot.event.Subscribe; import junit.framework.TestCase; -import de.greenrobot.event.EventBus; - -import java.util.ArrayList; -import java.util.List; +import org.junit.Test; /** * @author Markus Junginger, greenrobot @@ -40,6 +38,7 @@ protected void setUp() throws Exception { eventBus = new EventBus(); } + @Test public void testEventClassHierarchy() { eventBus.register(this); @@ -56,6 +55,7 @@ public void testEventClassHierarchy() { assertEquals(1, countMyEventExtended); } + @Test public void testEventClassHierarchySticky() { eventBus.postSticky("Hello"); eventBus.postSticky(new MyEvent()); @@ -66,6 +66,7 @@ public void testEventClassHierarchySticky() { assertEquals(3, countObjectEvent); } + @Test public void testEventInterfaceHierarchy() { eventBus.register(this); @@ -77,6 +78,7 @@ public void testEventInterfaceHierarchy() { assertEquals(1, countMyEventInterfaceExtended); } + @Test public void testEventSuperInterfaceHierarchy() { eventBus.register(this); @@ -86,6 +88,7 @@ public void testEventSuperInterfaceHierarchy() { assertEquals(1, countMyEventInterfaceExtended); } + @Test public void testSubscriberClassHierarchy() { SubscriberExtended subscriber = new SubscriberExtended(); eventBus.register(subscriber); @@ -105,6 +108,7 @@ public void testSubscriberClassHierarchy() { assertEquals(2, subscriber.countMyEventOverwritten); } + @Test public void testSubscriberClassHierarchyWithoutNewSubscriberMethod() { SubscriberExtendedWithoutNewSubscriberMethod subscriber = new SubscriberExtendedWithoutNewSubscriberMethod(); eventBus.register(subscriber); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java index b7127db5..e9e6cdf3 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java @@ -15,13 +15,14 @@ */ package de.greenrobot.event.test; -import java.util.Random; -import java.util.concurrent.CountDownLatch; - import android.os.Handler; import android.os.Looper; -import de.greenrobot.event.ThreadMode; import de.greenrobot.event.Subscribe; +import de.greenrobot.event.ThreadMode; +import org.junit.Test; + +import java.util.Random; +import java.util.concurrent.CountDownLatch; /** * @author Markus Junginger, greenrobot @@ -34,6 +35,7 @@ public class EventBusMainThreadRacingTest extends AbstractEventBusTest { private CountDownLatch startLatch; private volatile RuntimeException failed; + @Test public void testRacingThreads() throws InterruptedException { Runnable register = new Runnable() { @Override diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java index 944dba21..3415467f 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java @@ -15,12 +15,17 @@ */ package de.greenrobot.event.test; +import android.os.Looper; +import de.greenrobot.event.Subscribe; +import de.greenrobot.event.ThreadMode; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + import java.util.ArrayList; import java.util.List; -import android.os.Looper; -import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.Subscribe; +import static org.junit.Assert.assertEquals; /** * @author Markus Junginger, greenrobot @@ -29,19 +34,19 @@ public class EventBusMainThreadTest extends AbstractEventBusTest { private BackgroundPoster backgroundPoster; - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() throws Exception { backgroundPoster = new BackgroundPoster(); backgroundPoster.start(); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { backgroundPoster.shutdown(); backgroundPoster.join(); - super.tearDown(); } + @Test public void testPost() throws InterruptedException { eventBus.register(this); eventBus.post("Hello"); @@ -51,6 +56,7 @@ public void testPost() throws InterruptedException { assertEquals(Looper.getMainLooper().getThread(), lastThread); } + @Test public void testPostInBackgroundThread() throws InterruptedException { eventBus.register(this); backgroundPoster.post("Hello"); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java index e3f6c9c5..094492e0 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java @@ -16,16 +16,19 @@ package de.greenrobot.event.test; import android.os.Looper; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.EventBusException; -import de.greenrobot.event.ThreadMode; import de.greenrobot.event.Subscribe; +import de.greenrobot.event.ThreadMode; +import org.junit.Test; + +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; /** * @author Markus Junginger, greenrobot */ public class EventBusMethodModifiersTest extends AbstractEventBusTest { + @Test public void testRegisterForEventTypeAndPost() throws InterruptedException { eventBus.register(this); String event = "Hello"; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java index 1efbcd92..c3c544da 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java @@ -15,16 +15,19 @@ */ package de.greenrobot.event.test; +import android.os.Looper; +import android.util.Log; +import de.greenrobot.event.EventBus; +import de.greenrobot.event.Subscribe; +import de.greenrobot.event.ThreadMode; +import org.junit.Test; + import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; -import android.os.Looper; -import android.util.Log; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.Subscribe; +import static org.junit.Assert.*; /** * @author Markus Junginger, greenrobot @@ -43,30 +46,37 @@ public class EventBusMultithreadedTest extends AbstractEventBusTest { private IntTestEvent lastIntTestEvent; + @Test public void testPost01Thread() throws InterruptedException { runThreadsSingleEventType(1); } + @Test public void testPost04Threads() throws InterruptedException { runThreadsSingleEventType(4); } + @Test public void testPost40Threads() throws InterruptedException { runThreadsSingleEventType(40); } + @Test public void testPostMixedEventType01Thread() throws InterruptedException { runThreadsMixedEventType(1); } + @Test public void testPostMixedEventType04Threads() throws InterruptedException { runThreadsMixedEventType(4); } + @Test public void testPostMixedEventType40Threads() throws InterruptedException { runThreadsMixedEventType(40); } + @Test public void testSubscribeUnSubscribeAndPostMixedEventType() throws InterruptedException { List threads = new ArrayList(); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java index f6d7516b..de638f22 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java @@ -17,14 +17,19 @@ import de.greenrobot.event.EventBus; import de.greenrobot.event.NoSubscriberEvent; -import de.greenrobot.event.SubscriberExceptionEvent; import de.greenrobot.event.Subscribe; +import de.greenrobot.event.SubscriberExceptionEvent; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; /** * @author Markus Junginger, greenrobot */ public class EventBusNoSubscriberEventTest extends AbstractEventBusTest { + @Test public void testNoSubscriberEvent() { eventBus.register(this); eventBus.post("Foo"); @@ -35,6 +40,7 @@ public void testNoSubscriberEvent() { assertSame(eventBus, noSub.eventBus); } + @Test public void testNoSubscriberEventAfterUnregister() { Object subscriber = new DummySubscriber(); eventBus.register(subscriber); @@ -42,6 +48,7 @@ public void testNoSubscriberEventAfterUnregister() { testNoSubscriberEvent(); } + @Test public void testBadNoSubscriberSubscriber() { eventBus = EventBus.builder().logNoSubscriberMessages(false).build(); eventBus.register(this); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java index 7630ea64..36a40890 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java @@ -19,10 +19,13 @@ import de.greenrobot.event.EventBus; import de.greenrobot.event.Subscribe; import de.greenrobot.event.ThreadMode; +import org.junit.Test; import java.util.ArrayList; import java.util.List; +import static org.junit.Assert.assertEquals; + /** * @author Markus Junginger, greenrobot */ @@ -32,26 +35,32 @@ public class EventBusOrderedSubscriptionsTest extends AbstractEventBusTest { final List registered = new ArrayList(); private String fail; + @Test public void testOrdered() { runTestOrdered("42", false, 5); } + @Test public void testOrderedMainThread() { runTestOrdered(new IntTestEvent(42), false, 3); } + @Test public void testOrderedBackgroundThread() { runTestOrdered(Integer.valueOf(42), false, 3); } + @Test public void testOrderedSticky() { runTestOrdered("42", true, 5); } + @Test public void testOrderedMainThreadSticky() { runTestOrdered(new IntTestEvent(42), true, 3); } + @Test public void testOrderedBackgroundThreadSticky() { runTestOrdered(Integer.valueOf(42), true, 3); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java index 7c4dbf9d..853cc5dd 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java @@ -16,6 +16,7 @@ package de.greenrobot.event.test; import de.greenrobot.event.Subscribe; +import org.junit.Test; import java.util.ArrayList; import java.util.List; @@ -23,6 +24,8 @@ import java.util.concurrent.Executor; import java.util.concurrent.Executors; +import static org.junit.Assert.fail; + /** * @author Markus Junginger, greenrobot */ @@ -40,6 +43,7 @@ public class EventBusRegistrationRacingTest extends AbstractEventBusTest { final Executor threadPool = Executors.newCachedThreadPool(); + @Test public void testRacingRegistrations() throws InterruptedException { for (int i = 0; i < ITERATIONS; i++) { startLatch = new CountDownLatch(THREAD_COUNT); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java index 6be32085..7694b185 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java @@ -16,12 +16,16 @@ package de.greenrobot.event.test; import de.greenrobot.event.Subscribe; +import org.junit.Test; + +import static org.junit.Assert.*; /** * @author Markus Junginger, greenrobot */ public class EventBusStickyEventTest extends AbstractEventBusTest { + @Test public void testPostSticky() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.register(this); @@ -29,6 +33,7 @@ public void testPostSticky() throws InterruptedException { assertEquals(Thread.currentThread(), lastThread); } + @Test public void testPostStickyTwoEvents() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.postSticky(new IntTestEvent(7)); @@ -36,6 +41,7 @@ public void testPostStickyTwoEvents() throws InterruptedException { assertEquals(2, eventCount.intValue()); } + @Test public void testPostStickyTwoSubscribers() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.postSticky(new IntTestEvent(7)); @@ -51,6 +57,7 @@ public void testPostStickyTwoSubscribers() throws InterruptedException { assertEquals(6, eventCount.intValue()); } + @Test public void testPostStickyRegisterNonSticky() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.register(new NonStickySubscriber()); @@ -58,6 +65,7 @@ public void testPostStickyRegisterNonSticky() throws InterruptedException { assertEquals(0, eventCount.intValue()); } + @Test public void testPostNonStickyRegisterSticky() throws InterruptedException { eventBus.post("NonSticky"); eventBus.register(this); @@ -65,6 +73,7 @@ public void testPostNonStickyRegisterSticky() throws InterruptedException { assertEquals(0, eventCount.intValue()); } + @Test public void testPostStickyTwice() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.postSticky("NewSticky"); @@ -72,6 +81,7 @@ public void testPostStickyTwice() throws InterruptedException { assertEquals("NewSticky", lastEvent); } + @Test public void testPostStickyThenPostNormal() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.post("NonSticky"); @@ -79,6 +89,7 @@ public void testPostStickyThenPostNormal() throws InterruptedException { assertEquals("Sticky", lastEvent); } + @Test public void testPostStickyWithRegisterAndUnregister() throws InterruptedException { eventBus.register(this); eventBus.postSticky("Sticky"); @@ -99,11 +110,13 @@ public void testPostStickyWithRegisterAndUnregister() throws InterruptedExceptio assertEquals("NewSticky", lastEvent); } + @Test public void testPostStickyAndGet() throws InterruptedException { eventBus.postSticky("Sticky"); assertEquals("Sticky", eventBus.getStickyEvent(String.class)); } + @Test public void testPostStickyRemoveClass() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.removeStickyEvent(String.class); @@ -113,6 +126,7 @@ public void testPostStickyRemoveClass() throws InterruptedException { assertEquals(0, eventCount.intValue()); } + @Test public void testPostStickyRemoveEvent() throws InterruptedException { eventBus.postSticky("Sticky"); assertTrue(eventBus.removeStickyEvent("Sticky")); @@ -122,6 +136,7 @@ public void testPostStickyRemoveEvent() throws InterruptedException { assertEquals(0, eventCount.intValue()); } + @Test public void testPostStickyRemoveAll() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.postSticky(new IntTestEvent(77)); @@ -133,6 +148,7 @@ public void testPostStickyRemoveAll() throws InterruptedException { assertEquals(0, eventCount.intValue()); } + @Test public void testRemoveStickyEventInSubscriber() throws InterruptedException { eventBus.register(new RemoveStickySubscriber()); eventBus.postSticky("Sticky"); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java index 21c79f95..2651b4b5 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java @@ -16,14 +16,19 @@ package de.greenrobot.event.test; import de.greenrobot.event.EventBus; -import de.greenrobot.event.SubscriberExceptionEvent; import de.greenrobot.event.Subscribe; +import de.greenrobot.event.SubscriberExceptionEvent; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; /** * @author Markus Junginger, greenrobot */ public class EventBusSubscriberExceptionTest extends AbstractEventBusTest { + @Test public void testSubscriberExceptionEvent() { eventBus = EventBus.builder().logSubscriberExceptions(false).build(); eventBus.register(this); @@ -36,6 +41,7 @@ public void testSubscriberExceptionEvent() { assertEquals("Bar", exEvent.throwable.getMessage()); } + @Test public void testBadExceptionSubscriber() { eventBus = EventBus.builder().logSubscriberExceptions(false).build(); eventBus.register(this); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java index 60882fc7..8eb5d281 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java @@ -3,8 +3,10 @@ import de.greenrobot.event.EventBus; import junit.framework.Assert; import junit.framework.TestCase; +import org.junit.Test; public class EventBusSubscriberInJarTest extends TestCase { + @Test public void testSubscriberInJar() { SubscriberInJar subscriber = new SubscriberInJar(); EventBus eventBus = EventBus.builder().build(); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java index 1c84dda6..c1c504a9 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java @@ -15,14 +15,17 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.EventBusException; import de.greenrobot.event.Subscribe; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; /** * @author Markus Junginger, greenrobot */ public class EventBusSubscriberLegalTest extends AbstractEventBusTest { + @Test public void testSubscriberLegal() { eventBus.register(this); eventBus.post("42"); From ddf19d24255c39a6f8d5a8fe7e79ab73b95fe6cd Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 17 Dec 2015 22:50:53 +0100 Subject: [PATCH 120/288] fixing @UiThreadTest --- EventBusTest/build.gradle | 1 + .../src/de/greenrobot/event/test/EventBusBasicTest.java | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 38d4583a..c3d66113 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -21,6 +21,7 @@ dependencies { androidTestCompile project(':EventBus') compile fileTree(dir: 'libs', include: '*.jar') androidTestCompile 'com.android.support.test:runner:0.4.1' + androidTestCompile 'com.android.support.test:rules:0.4.1' } android { diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java index 0d495112..784bf903 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java @@ -16,12 +16,14 @@ package de.greenrobot.event.test; import android.app.Activity; +import android.support.test.rule.UiThreadTestRule; import android.support.test.runner.AndroidJUnit4; -import android.test.UiThreadTest; +import android.support.test.annotation.UiThreadTest; import android.util.Log; import de.greenrobot.event.EventBus; import de.greenrobot.event.Subscribe; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -32,6 +34,8 @@ */ @RunWith(AndroidJUnit4.class) public class EventBusBasicTest { + @Rule + public final UiThreadTestRule uiThreadTestRule = new UiThreadTestRule(); private EventBus eventBus; private String lastStringEvent; From 479e83140d214b444a67e9e36a56b5759c5e114a Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 19 Jan 2016 17:44:20 +0100 Subject: [PATCH 121/288] test: Java 1.7, made test base class abstract, added EventBus.toString --- EventBus/src/de/greenrobot/event/EventBus.java | 7 +++++++ EventBusTest/build.gradle | 7 +++++++ .../src/de/greenrobot/event/test/AbstractEventBusTest.java | 3 +-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index cbdd10ef..7a966865 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -72,6 +72,8 @@ protected PostingThreadState initialValue() { private final boolean sendNoSubscriberEvent; private final boolean eventInheritance; + private final int indexCount; + /** Convenience singleton for apps using a process-wide EventBus instance. */ public static EventBus getDefault() { if (defaultInstance == null) { @@ -109,6 +111,7 @@ public EventBus() { mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); + indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0; subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes, builder.strictMethodVerification, builder.ignoreGeneratedIndex); logSubscriberExceptions = builder.logSubscriberExceptions; @@ -532,4 +535,8 @@ ExecutorService getExecutorService() { void onPostCompleted(List exceptionEvents); } + @Override + public String toString() { + return "EventBus[indexCount=" + indexCount + ", eventInheritance=" + eventInheritance + "]"; + } } diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index c3d66113..8e1d3abd 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -12,6 +12,8 @@ buildscript { apply plugin: 'com.android.application' apply plugin: 'com.neenbedankt.android-apt' +sourceCompatibility = 1.7 + repositories { jcenter() } @@ -28,6 +30,11 @@ android { buildToolsVersion '23.0.2' compileSdkVersion 19 + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_7 + targetCompatibility = JavaVersion.VERSION_1_7 + } + sourceSets { main { manifest.srcFile 'AndroidManifest.xml' diff --git a/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java b/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java index 766a54ea..641f586d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java @@ -37,8 +37,7 @@ * @author Markus Junginger, greenrobot */ @RunWith(AndroidJUnit4.class) -@Ignore("Base class") -public class AbstractEventBusTest { +public abstract class AbstractEventBusTest { /** Activates long(er) running tests e.g. testing multi-threading more thoroughly. */ protected static final boolean LONG_TESTS = false; From 591c618e71f12ff4accfa399dacb30e80973aff6 Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 19 Jan 2016 21:18:34 +0100 Subject: [PATCH 122/288] first bunch of test subclasses with EventBus using an index --- .../event/test/EventBusBasicTest.java | 9 +++++++- .../EventBusFallbackToReflectionTest.java | 1 - .../test/EventBusInheritanceDisabledTest.java | 2 +- .../event/test/EventBusInheritanceTest.java | 2 +- ...EventBusBackgroundThreadTestWithIndex.java | 21 +++++++++++++++++++ .../indexed/EventBusBasicTestWithIndex.java | 19 +++++++++++++++++ ...ntBusCancelEventDeliveryTestWithIndex.java | 11 ++++++++++ ...tBusFallbackToReflectionTestWithIndex.java | 12 +++++++++++ .../EventBusGenericsTestWithIndex.java | 11 ++++++++++ ...ntBusInheritanceDisabledTestWithIndex.java | 13 ++++++++++++ .../EventBusInheritanceTestWithIndex.java | 11 ++++++++++ ...EventBusMainThreadRacingTestWithIndex.java | 11 ++++++++++ .../EventBusMainThreadTestWithIndex.java | 11 ++++++++++ .../EventBusMethodModifiersTestWithIndex.java | 11 ++++++++++ .../EventBusMultithreadedTestWithIndex.java | 11 ++++++++++ .../event/test/indexed/Indexed.java | 10 +++++++++ 16 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java index 784bf903..10458512 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java @@ -34,10 +34,17 @@ */ @RunWith(AndroidJUnit4.class) public class EventBusBasicTest { + + public static class WithIndex extends EventBusBasicTest { + @Test + public void dummy() {} + + } + @Rule public final UiThreadTestRule uiThreadTestRule = new UiThreadTestRule(); - private EventBus eventBus; + protected EventBus eventBus; private String lastStringEvent; private int countStringEvent; private int countIntEvent; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java index d228995d..91969393 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java @@ -5,7 +5,6 @@ import static org.junit.Assert.assertEquals; -/** TODO */ public class EventBusFallbackToReflectionTest extends AbstractEventBusTest { private class PrivateEvent { } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java index 45376aea..74256dc1 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java @@ -30,7 +30,7 @@ @RunWith(AndroidJUnit4.class) public class EventBusInheritanceDisabledTest { - private EventBus eventBus; + protected EventBus eventBus; protected int countMyEventExtended; protected int countMyEvent; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java index fe594c54..04f2c3fc 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java @@ -25,7 +25,7 @@ */ public class EventBusInheritanceTest extends TestCase { - private EventBus eventBus; + protected EventBus eventBus; protected int countMyEventExtended; protected int countMyEvent; diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java new file mode 100644 index 00000000..07f61cc4 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java @@ -0,0 +1,21 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.EventBus; +import de.greenrobot.event.test.EventBusBackgroundThreadTest; +import org.greenrobot.eventbus.EventBusTestsIndex; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; + +public class EventBusBackgroundThreadTestWithIndex extends EventBusBackgroundThreadTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } + + @Test + public void testIndex() { + assertTrue(eventBus.toString().contains("indexCount=1")); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java new file mode 100644 index 00000000..3d2f83e9 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java @@ -0,0 +1,19 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusBasicTest; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; + +public class EventBusBasicTestWithIndex extends EventBusBasicTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } + + @Test + public void testIndex() { + assertTrue(eventBus.toString().contains("indexCount=1")); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java new file mode 100644 index 00000000..1456f760 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java @@ -0,0 +1,11 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusCancelEventDeliveryTest; +import org.junit.Before; + +public class EventBusCancelEventDeliveryTestWithIndex extends EventBusCancelEventDeliveryTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java new file mode 100644 index 00000000..7804b8b2 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java @@ -0,0 +1,12 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusFallbackToReflectionTest; +import org.junit.Before; + +public class EventBusFallbackToReflectionTestWithIndex extends EventBusFallbackToReflectionTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } + +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java new file mode 100644 index 00000000..dd00aa02 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java @@ -0,0 +1,11 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusGenericsTest; +import org.junit.Before; + +public class EventBusGenericsTestWithIndex extends EventBusGenericsTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java new file mode 100644 index 00000000..56613525 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java @@ -0,0 +1,13 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.EventBus; +import de.greenrobot.event.test.EventBusInheritanceDisabledTest; +import org.greenrobot.eventbus.EventBusTestsIndex; +import org.junit.Before; + +public class EventBusInheritanceDisabledTestWithIndex extends EventBusInheritanceDisabledTest { + @Before + public void setUp() throws Exception { + eventBus = EventBus.builder().eventInheritance(false).addIndex(new EventBusTestsIndex()).build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java new file mode 100644 index 00000000..54f2749b --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java @@ -0,0 +1,11 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusInheritanceTest; +import org.junit.Before; + +public class EventBusInheritanceTestWithIndex extends EventBusInheritanceTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java new file mode 100644 index 00000000..52bdb6e1 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java @@ -0,0 +1,11 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusMainThreadRacingTest; +import org.junit.Before; + +public class EventBusMainThreadRacingTestWithIndex extends EventBusMainThreadRacingTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java new file mode 100644 index 00000000..69fb22bc --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java @@ -0,0 +1,11 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusMainThreadTest; +import org.junit.Before; + +public class EventBusMainThreadTestWithIndex extends EventBusMainThreadTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java new file mode 100644 index 00000000..c66f0baf --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java @@ -0,0 +1,11 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusMethodModifiersTest; +import org.junit.Before; + +public class EventBusMethodModifiersTestWithIndex extends EventBusMethodModifiersTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java new file mode 100644 index 00000000..71329fe1 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java @@ -0,0 +1,11 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusMultithreadedTest; +import org.junit.Before; + +public class EventBusMultithreadedTestWithIndex extends EventBusMultithreadedTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java b/EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java new file mode 100644 index 00000000..64417e95 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java @@ -0,0 +1,10 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.EventBus; +import org.greenrobot.eventbus.EventBusTestsIndex; + +public class Indexed { + static EventBus build() { + return EventBus.builder().addIndex(new EventBusTestsIndex()).build(); + } +} From 8a319664c6d7b29c60508130e8fc7406b63e93ab Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 19 Jan 2016 21:34:04 +0100 Subject: [PATCH 123/288] remaining test subclasses with EventBus using an index --- .../event/test/EventBusSubscriberInJarTest.java | 3 ++- .../EventBusNoSubscriberEventTestWithIndex.java | 12 ++++++++++++ .../EventBusOrderedSubscriptionsTestWithIndex.java | 12 ++++++++++++ .../EventBusRegistrationRacingTestWithIndex.java | 12 ++++++++++++ .../indexed/EventBusStickyEventTestWithIndex.java | 12 ++++++++++++ .../EventBusSubscriberExceptionTestWithIndex.java | 12 ++++++++++++ .../EventBusSubscriberInJarTestWithIndex.java | 12 ++++++++++++ 7 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java index 8eb5d281..eaef374d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java @@ -6,10 +6,11 @@ import org.junit.Test; public class EventBusSubscriberInJarTest extends TestCase { + protected EventBus eventBus = EventBus.builder().build(); + @Test public void testSubscriberInJar() { SubscriberInJar subscriber = new SubscriberInJar(); - EventBus eventBus = EventBus.builder().build(); eventBus.register(subscriber); eventBus.post("Hi Jar"); eventBus.post(42); diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java new file mode 100644 index 00000000..26c48eb6 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java @@ -0,0 +1,12 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusNoSubscriberEventTest; +import org.junit.Before; + +/** TODO */ +public class EventBusNoSubscriberEventTestWithIndex extends EventBusNoSubscriberEventTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java new file mode 100644 index 00000000..21424186 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java @@ -0,0 +1,12 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusOrderedSubscriptionsTest; +import org.junit.Before; + +/** TODO */ +public class EventBusOrderedSubscriptionsTestWithIndex extends EventBusOrderedSubscriptionsTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java new file mode 100644 index 00000000..35840f72 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java @@ -0,0 +1,12 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusRegistrationRacingTest; +import org.junit.Before; + +/** TODO */ +public class EventBusRegistrationRacingTestWithIndex extends EventBusRegistrationRacingTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java new file mode 100644 index 00000000..c7b6413b --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java @@ -0,0 +1,12 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusStickyEventTest; +import org.junit.Before; + +/** TODO */ +public class EventBusStickyEventTestWithIndex extends EventBusStickyEventTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java new file mode 100644 index 00000000..31253cb5 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java @@ -0,0 +1,12 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusSubscriberExceptionTest; +import org.junit.Before; + +/** TODO */ +public class EventBusSubscriberExceptionTestWithIndex extends EventBusSubscriberExceptionTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java new file mode 100644 index 00000000..8899a546 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java @@ -0,0 +1,12 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusSubscriberInJarTest; +import org.junit.Before; + +/** TODO */ +public class EventBusSubscriberInJarTestWithIndex extends EventBusSubscriberInJarTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} From 80a9204f1cd352d122703469e73652067c3f6185 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 22 Jan 2016 12:03:43 +0100 Subject: [PATCH 124/288] main package is now org.greenrobot.eventbus --- .../greenrobot/eventbus}/AsyncPoster.java | 2 +- .../eventbus}/BackgroundPoster.java | 2 +- .../greenrobot/eventbus}/EventBus.java | 10 ++++---- .../greenrobot/eventbus}/EventBusBuilder.java | 6 ++--- .../eventbus}/EventBusException.java | 2 +- .../greenrobot/eventbus}/HandlerPoster.java | 2 +- .../eventbus}/NoSubscriberEvent.java | 2 +- .../greenrobot/eventbus}/PendingPost.java | 2 +- .../eventbus}/PendingPostQueue.java | 2 +- .../greenrobot/eventbus}/Subscribe.java | 4 ++-- .../eventbus}/SubscriberExceptionEvent.java | 2 +- .../eventbus}/SubscriberMethod.java | 2 +- .../eventbus}/SubscriberMethodFinder.java | 8 +++---- .../greenrobot/eventbus}/Subscription.java | 2 +- .../greenrobot/eventbus}/ThreadMode.java | 2 +- .../meta/AbstractSubscriberInfo.java | 10 ++++---- .../eventbus}/meta/SimpleSubscriberInfo.java | 6 ++--- .../eventbus}/meta/SubscriberInfo.java | 4 ++-- .../eventbus}/meta/SubscriberInfoIndex.java | 2 +- .../eventbus}/meta/SubscriberMethodInfo.java | 4 ++-- .../eventbus}/util/AsyncExecutor.java | 11 +++++---- .../eventbus}/util/ErrorDialogConfig.java | 5 ++-- .../util/ErrorDialogFragmentFactory.java | 2 +- .../eventbus}/util/ErrorDialogFragments.java | 5 ++-- .../eventbus}/util/ErrorDialogManager.java | 5 ++-- .../util/ExceptionToResourceMapping.java | 9 +++---- .../eventbus}/util/HasExecutionScope.java | 2 +- .../eventbus}/util/ThrowableFailureEvent.java | 2 +- .../EventBusAnnotationProcessor.java | 24 +++++++++---------- .../src/de/greenrobot/eventperf/Test.java | 4 ++-- .../de/greenrobot/eventperf/TestParams.java | 4 ++-- .../de/greenrobot/eventperf/TestRunner.java | 7 +++--- .../eventperf/TestRunnerActivity.java | 8 +++---- .../eventperf/TestSetupActivity.java | 8 ++++--- .../testsubject/PerfTestEventBus.java | 12 ++++++---- .../eventperf/testsubject/PerfTestOtto.java | 11 ++++----- .../SubscribeClassEventBusDefault.java | 3 ++- .../event/test/AbstractEventBusTest.java | 4 ++-- .../test/EventBusBackgroundThreadTest.java | 7 +++--- .../event/test/EventBusBasicTest.java | 7 +++--- .../event/test/EventBusBuilderTest.java | 12 +++++----- .../test/EventBusCancelEventDeliveryTest.java | 7 +++--- .../EventBusFallbackToReflectionTest.java | 2 +- .../event/test/EventBusGenericsTest.java | 2 +- .../test/EventBusInheritanceDisabledTest.java | 5 ++-- .../event/test/EventBusInheritanceTest.java | 5 ++-- .../test/EventBusMainThreadRacingTest.java | 5 ++-- .../event/test/EventBusMainThreadTest.java | 5 ++-- .../test/EventBusMethodModifiersTest.java | 5 ++-- .../event/test/EventBusMultithreadedTest.java | 7 +++--- .../test/EventBusNoSubscriberEventTest.java | 8 +++---- .../EventBusOrderedSubscriptionsTest.java | 7 +++--- .../test/EventBusRegistrationRacingTest.java | 2 +- .../event/test/EventBusStickyEventTest.java | 2 +- .../test/EventBusSubscriberExceptionTest.java | 6 ++--- .../test/EventBusSubscriberInJarTest.java | 3 ++- .../test/EventBusSubscriberLegalTest.java | 2 +- ...EventBusBackgroundThreadTestWithIndex.java | 5 ++-- .../indexed/EventBusBasicTestWithIndex.java | 3 ++- ...ntBusCancelEventDeliveryTestWithIndex.java | 3 ++- ...tBusFallbackToReflectionTestWithIndex.java | 3 ++- .../EventBusGenericsTestWithIndex.java | 3 ++- ...ntBusInheritanceDisabledTestWithIndex.java | 5 ++-- .../EventBusInheritanceTestWithIndex.java | 3 ++- ...EventBusMainThreadRacingTestWithIndex.java | 3 ++- .../EventBusMainThreadTestWithIndex.java | 3 ++- .../EventBusMethodModifiersTestWithIndex.java | 3 ++- .../EventBusMultithreadedTestWithIndex.java | 3 ++- ...ventBusNoSubscriberEventTestWithIndex.java | 3 ++- ...tBusOrderedSubscriptionsTestWithIndex.java | 3 ++- ...entBusRegistrationRacingTestWithIndex.java | 3 ++- .../EventBusStickyEventTestWithIndex.java | 3 ++- ...ntBusSubscriberExceptionTestWithIndex.java | 3 ++- .../EventBusSubscriberInJarTestWithIndex.java | 3 ++- .../event/test/indexed/Indexed.java | 2 +- .../event/test/SubscriberInJar.java | 2 +- 76 files changed, 197 insertions(+), 163 deletions(-) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/AsyncPoster.java (97%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/BackgroundPoster.java (98%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/EventBus.java (98%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/EventBusBuilder.java (98%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/EventBusException.java (97%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/HandlerPoster.java (98%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/NoSubscriberEvent.java (97%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/PendingPost.java (98%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/PendingPostQueue.java (96%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/Subscribe.java (86%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/SubscriberExceptionEvent.java (97%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/SubscriberMethod.java (98%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/SubscriberMethodFinder.java (98%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/Subscription.java (98%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/ThreadMode.java (98%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/meta/AbstractSubscriberInfo.java (93%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/meta/SimpleSubscriberInfo.java (87%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/meta/SubscriberInfo.java (91%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/meta/SubscriberInfoIndex.java (95%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/meta/SubscriberMethodInfo.java (94%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/util/AsyncExecutor.java (98%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/util/ErrorDialogConfig.java (96%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/util/ErrorDialogFragmentFactory.java (99%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/util/ErrorDialogFragments.java (97%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/util/ErrorDialogManager.java (99%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/util/ExceptionToResourceMapping.java (96%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/util/HasExecutionScope.java (76%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/util/ThrowableFailureEvent.java (97%) diff --git a/EventBus/src/de/greenrobot/event/AsyncPoster.java b/EventBus/src/org/greenrobot/eventbus/AsyncPoster.java similarity index 97% rename from EventBus/src/de/greenrobot/event/AsyncPoster.java rename to EventBus/src/org/greenrobot/eventbus/AsyncPoster.java index 936527b7..e3129dee 100644 --- a/EventBus/src/de/greenrobot/event/AsyncPoster.java +++ b/EventBus/src/org/greenrobot/eventbus/AsyncPoster.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; /** diff --git a/EventBus/src/de/greenrobot/event/BackgroundPoster.java b/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java similarity index 98% rename from EventBus/src/de/greenrobot/event/BackgroundPoster.java rename to EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java index 00e9ee54..c23e1575 100644 --- a/EventBus/src/de/greenrobot/event/BackgroundPoster.java +++ b/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; import android.util.Log; diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/org/greenrobot/eventbus/EventBus.java similarity index 98% rename from EventBus/src/de/greenrobot/event/EventBus.java rename to EventBus/src/org/greenrobot/eventbus/EventBus.java index 7a966865..3dd210b5 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBus.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; import android.os.Looper; import android.util.Log; @@ -33,7 +33,7 @@ * bus, which delivers it to subscribers that have a matching handler method for the event type. To receive events, * subscribers must register themselves to the bus using {@link #register(Object)}. Once registered, subscribers * receive events until {@link #unregister(Object)} is called. Event handling methods must be annotated by - * {@link de.greenrobot.event.Subscribe}, must be public, return nothing (void), and have exactly one parameter + * {@link Subscribe}, must be public, return nothing (void), and have exactly one parameter * (the event). * * @author Markus Junginger, greenrobot @@ -127,9 +127,9 @@ public EventBus() { * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they * are no longer interested in receiving events. *

- * Subscribers have event handling methods that must be annotated by {@link de.greenrobot.event.Subscribe}. - * The {@link de.greenrobot.event.Subscribe} annotation also allows configuration like {@link - * de.greenrobot.event.ThreadMode} and priority. + * Subscribers have event handling methods that must be annotated by {@link Subscribe}. + * The {@link Subscribe} annotation also allows configuration like {@link + * ThreadMode} and priority. */ public void register(Object subscriber) { Class subscriberClass = subscriber.getClass(); diff --git a/EventBus/src/de/greenrobot/event/EventBusBuilder.java b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java similarity index 98% rename from EventBus/src/de/greenrobot/event/EventBusBuilder.java rename to EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java index 4ee59fc2..9d003108 100644 --- a/EventBus/src/de/greenrobot/event/EventBusBuilder.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; + +import org.greenrobot.eventbus.meta.SubscriberInfoIndex; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import de.greenrobot.event.meta.SubscriberInfoIndex; - /** * Creates EventBus instances with custom parameters and also allows to install a custom default EventBus instance. * Create a new builder using {@link EventBus#builder()}. diff --git a/EventBus/src/de/greenrobot/event/EventBusException.java b/EventBus/src/org/greenrobot/eventbus/EventBusException.java similarity index 97% rename from EventBus/src/de/greenrobot/event/EventBusException.java rename to EventBus/src/org/greenrobot/eventbus/EventBusException.java index 80c51f86..9bbacf55 100644 --- a/EventBus/src/de/greenrobot/event/EventBusException.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBusException.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; /** * An {@link RuntimeException} thrown in cases something went wrong inside EventBus. diff --git a/EventBus/src/de/greenrobot/event/HandlerPoster.java b/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java similarity index 98% rename from EventBus/src/de/greenrobot/event/HandlerPoster.java rename to EventBus/src/org/greenrobot/eventbus/HandlerPoster.java index c1c44608..0571e1b2 100644 --- a/EventBus/src/de/greenrobot/event/HandlerPoster.java +++ b/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; import android.os.Handler; import android.os.Looper; diff --git a/EventBus/src/de/greenrobot/event/NoSubscriberEvent.java b/EventBus/src/org/greenrobot/eventbus/NoSubscriberEvent.java similarity index 97% rename from EventBus/src/de/greenrobot/event/NoSubscriberEvent.java rename to EventBus/src/org/greenrobot/eventbus/NoSubscriberEvent.java index a7378ae8..8a6d0c50 100644 --- a/EventBus/src/de/greenrobot/event/NoSubscriberEvent.java +++ b/EventBus/src/org/greenrobot/eventbus/NoSubscriberEvent.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; /** * This Event is posted by EventBus when no subscriber is found for a posted event. diff --git a/EventBus/src/de/greenrobot/event/PendingPost.java b/EventBus/src/org/greenrobot/eventbus/PendingPost.java similarity index 98% rename from EventBus/src/de/greenrobot/event/PendingPost.java rename to EventBus/src/org/greenrobot/eventbus/PendingPost.java index 0bd5a2ec..e6c3bf4f 100644 --- a/EventBus/src/de/greenrobot/event/PendingPost.java +++ b/EventBus/src/org/greenrobot/eventbus/PendingPost.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; import java.util.ArrayList; import java.util.List; diff --git a/EventBus/src/de/greenrobot/event/PendingPostQueue.java b/EventBus/src/org/greenrobot/eventbus/PendingPostQueue.java similarity index 96% rename from EventBus/src/de/greenrobot/event/PendingPostQueue.java rename to EventBus/src/org/greenrobot/eventbus/PendingPostQueue.java index 5440559b..048a841f 100644 --- a/EventBus/src/de/greenrobot/event/PendingPostQueue.java +++ b/EventBus/src/org/greenrobot/eventbus/PendingPostQueue.java @@ -1,4 +1,4 @@ -package de.greenrobot.event; +package org.greenrobot.eventbus; final class PendingPostQueue { private PendingPost head; diff --git a/EventBus/src/de/greenrobot/event/Subscribe.java b/EventBus/src/org/greenrobot/eventbus/Subscribe.java similarity index 86% rename from EventBus/src/de/greenrobot/event/Subscribe.java rename to EventBus/src/org/greenrobot/eventbus/Subscribe.java index 6532c6cd..b36496db 100644 --- a/EventBus/src/de/greenrobot/event/Subscribe.java +++ b/EventBus/src/org/greenrobot/eventbus/Subscribe.java @@ -1,4 +1,4 @@ -package de.greenrobot.event; +package org.greenrobot.eventbus; import java.lang.annotation.Documented; @@ -15,7 +15,7 @@ /** * If true, delivers the most recent sticky event (posted with - * {@link de.greenrobot.event.EventBus#postSticky(Object)}) to this subscriber (if event available). + * {@link EventBus#postSticky(Object)}) to this subscriber (if event available). */ boolean sticky() default false; diff --git a/EventBus/src/de/greenrobot/event/SubscriberExceptionEvent.java b/EventBus/src/org/greenrobot/eventbus/SubscriberExceptionEvent.java similarity index 97% rename from EventBus/src/de/greenrobot/event/SubscriberExceptionEvent.java rename to EventBus/src/org/greenrobot/eventbus/SubscriberExceptionEvent.java index 5d3b9b55..1302f777 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberExceptionEvent.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberExceptionEvent.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; /** * This Event is posted by EventBus when an exception occurs inside a subscriber's event handling method. diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethod.java b/EventBus/src/org/greenrobot/eventbus/SubscriberMethod.java similarity index 98% rename from EventBus/src/de/greenrobot/event/SubscriberMethod.java rename to EventBus/src/org/greenrobot/eventbus/SubscriberMethod.java index f1c86820..5bd751c4 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethod.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberMethod.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; import java.lang.reflect.Method; diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java similarity index 98% rename from EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java rename to EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java index bf3e8c7b..03974004 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java @@ -13,7 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; + +import org.greenrobot.eventbus.meta.SubscriberInfo; +import org.greenrobot.eventbus.meta.SubscriberInfoIndex; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -23,9 +26,6 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import de.greenrobot.event.meta.SubscriberInfo; -import de.greenrobot.event.meta.SubscriberInfoIndex; - class SubscriberMethodFinder { /* * In newer class files, compilers may add methods. Those are called bridge or synthetic methods. diff --git a/EventBus/src/de/greenrobot/event/Subscription.java b/EventBus/src/org/greenrobot/eventbus/Subscription.java similarity index 98% rename from EventBus/src/de/greenrobot/event/Subscription.java rename to EventBus/src/org/greenrobot/eventbus/Subscription.java index 868cbebe..1f529c92 100644 --- a/EventBus/src/de/greenrobot/event/Subscription.java +++ b/EventBus/src/org/greenrobot/eventbus/Subscription.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; final class Subscription { final Object subscriber; diff --git a/EventBus/src/de/greenrobot/event/ThreadMode.java b/EventBus/src/org/greenrobot/eventbus/ThreadMode.java similarity index 98% rename from EventBus/src/de/greenrobot/event/ThreadMode.java rename to EventBus/src/org/greenrobot/eventbus/ThreadMode.java index bbe060cd..9292d4e9 100644 --- a/EventBus/src/de/greenrobot/event/ThreadMode.java +++ b/EventBus/src/org/greenrobot/eventbus/ThreadMode.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; /** * Each event handler method has a thread mode, which determines in which thread the method is to be called by EventBus. diff --git a/EventBus/src/de/greenrobot/event/meta/AbstractSubscriberInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java similarity index 93% rename from EventBus/src/de/greenrobot/event/meta/AbstractSubscriberInfo.java rename to EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java index 22a9ea0f..9156ea25 100644 --- a/EventBus/src/de/greenrobot/event/meta/AbstractSubscriberInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.meta; +package org.greenrobot.eventbus.meta; -import java.lang.reflect.Method; +import org.greenrobot.eventbus.EventBusException; +import org.greenrobot.eventbus.SubscriberMethod; +import org.greenrobot.eventbus.ThreadMode; -import de.greenrobot.event.EventBusException; -import de.greenrobot.event.SubscriberMethod; -import de.greenrobot.event.ThreadMode; +import java.lang.reflect.Method; /** Base class for generated subscriber meta info classes created by annotation processing. */ public abstract class AbstractSubscriberInfo implements SubscriberInfo { diff --git a/EventBus/src/de/greenrobot/event/meta/SimpleSubscriberInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/SimpleSubscriberInfo.java similarity index 87% rename from EventBus/src/de/greenrobot/event/meta/SimpleSubscriberInfo.java rename to EventBus/src/org/greenrobot/eventbus/meta/SimpleSubscriberInfo.java index 39366a00..957d058d 100644 --- a/EventBus/src/de/greenrobot/event/meta/SimpleSubscriberInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/SimpleSubscriberInfo.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.meta; +package org.greenrobot.eventbus.meta; -import de.greenrobot.event.SubscriberMethod; +import org.greenrobot.eventbus.SubscriberMethod; /** - * Uses {@link SubscriberMethodInfo} objects to create {@link SubscriberMethod} objects on demand. + * Uses {@link SubscriberMethodInfo} objects to create {@link org.greenrobot.eventbus.SubscriberMethod} objects on demand. */ public class SimpleSubscriberInfo extends AbstractSubscriberInfo { diff --git a/EventBus/src/de/greenrobot/event/meta/SubscriberInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java similarity index 91% rename from EventBus/src/de/greenrobot/event/meta/SubscriberInfo.java rename to EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java index 51dda356..7cd445a8 100644 --- a/EventBus/src/de/greenrobot/event/meta/SubscriberInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.meta; +package org.greenrobot.eventbus.meta; -import de.greenrobot.event.SubscriberMethod; +import org.greenrobot.eventbus.SubscriberMethod; /** Base class for generated index classes created by annotation processing. */ public interface SubscriberInfo { diff --git a/EventBus/src/de/greenrobot/event/meta/SubscriberInfoIndex.java b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfoIndex.java similarity index 95% rename from EventBus/src/de/greenrobot/event/meta/SubscriberInfoIndex.java rename to EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfoIndex.java index f372c593..5e27d4e8 100644 --- a/EventBus/src/de/greenrobot/event/meta/SubscriberInfoIndex.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfoIndex.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.meta; +package org.greenrobot.eventbus.meta; /** * Interface for generated indexes. diff --git a/EventBus/src/de/greenrobot/event/meta/SubscriberMethodInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberMethodInfo.java similarity index 94% rename from EventBus/src/de/greenrobot/event/meta/SubscriberMethodInfo.java rename to EventBus/src/org/greenrobot/eventbus/meta/SubscriberMethodInfo.java index ed822f35..9d0782ed 100644 --- a/EventBus/src/de/greenrobot/event/meta/SubscriberMethodInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberMethodInfo.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.meta; +package org.greenrobot.eventbus.meta; -import de.greenrobot.event.ThreadMode; +import org.greenrobot.eventbus.ThreadMode; public class SubscriberMethodInfo { final String methodName; diff --git a/EventBus/src/de/greenrobot/event/util/AsyncExecutor.java b/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java similarity index 98% rename from EventBus/src/de/greenrobot/event/util/AsyncExecutor.java rename to EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java index 71048a43..c1b49c1b 100644 --- a/EventBus/src/de/greenrobot/event/util/AsyncExecutor.java +++ b/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java @@ -13,16 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.util; +package org.greenrobot.eventbus.util; + +import android.app.Activity; +import android.util.Log; + +import org.greenrobot.eventbus.EventBus; import java.lang.reflect.Constructor; import java.util.concurrent.Executor; import java.util.concurrent.Executors; -import android.app.Activity; -import android.util.Log; -import de.greenrobot.event.EventBus; - /** * Executes an {@link RunnableEx} using a thread pool. Thrown exceptions are propagated by posting failure events of any * given type (default is {@link ThrowableFailureEvent}). diff --git a/EventBus/src/de/greenrobot/event/util/ErrorDialogConfig.java b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogConfig.java similarity index 96% rename from EventBus/src/de/greenrobot/event/util/ErrorDialogConfig.java rename to EventBus/src/org/greenrobot/eventbus/util/ErrorDialogConfig.java index 25432631..3378ba4d 100644 --- a/EventBus/src/de/greenrobot/event/util/ErrorDialogConfig.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogConfig.java @@ -1,8 +1,9 @@ -package de.greenrobot.event.util; +package org.greenrobot.eventbus.util; import android.content.res.Resources; import android.util.Log; -import de.greenrobot.event.EventBus; + +import org.greenrobot.eventbus.EventBus; public class ErrorDialogConfig { final Resources resources; diff --git a/EventBus/src/de/greenrobot/event/util/ErrorDialogFragmentFactory.java b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragmentFactory.java similarity index 99% rename from EventBus/src/de/greenrobot/event/util/ErrorDialogFragmentFactory.java rename to EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragmentFactory.java index 47b693b6..ca6a8b4d 100644 --- a/EventBus/src/de/greenrobot/event/util/ErrorDialogFragmentFactory.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragmentFactory.java @@ -1,4 +1,4 @@ -package de.greenrobot.event.util; +package org.greenrobot.eventbus.util; import android.annotation.TargetApi; import android.os.Build; diff --git a/EventBus/src/de/greenrobot/event/util/ErrorDialogFragments.java b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragments.java similarity index 97% rename from EventBus/src/de/greenrobot/event/util/ErrorDialogFragments.java rename to EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragments.java index 04002df2..79833b42 100644 --- a/EventBus/src/de/greenrobot/event/util/ErrorDialogFragments.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragments.java @@ -1,4 +1,4 @@ -package de.greenrobot.event.util; +package org.greenrobot.eventbus.util; import android.annotation.TargetApi; import android.app.Activity; @@ -10,7 +10,8 @@ import android.os.Build; import android.os.Bundle; import android.support.v4.app.DialogFragment; -import de.greenrobot.event.EventBus; + +import org.greenrobot.eventbus.EventBus; public class ErrorDialogFragments { /** TODO Use config: Icon res ID to use for all error dialogs. May be configured by each app (optional). */ diff --git a/EventBus/src/de/greenrobot/event/util/ErrorDialogManager.java b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogManager.java similarity index 99% rename from EventBus/src/de/greenrobot/event/util/ErrorDialogManager.java rename to EventBus/src/org/greenrobot/eventbus/util/ErrorDialogManager.java index cee7c6a5..34cb82da 100644 --- a/EventBus/src/de/greenrobot/event/util/ErrorDialogManager.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogManager.java @@ -1,4 +1,4 @@ -package de.greenrobot.event.util; +package org.greenrobot.eventbus.util; import android.annotation.TargetApi; import android.app.Activity; @@ -10,7 +10,8 @@ import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.util.Log; -import de.greenrobot.event.EventBus; + +import org.greenrobot.eventbus.EventBus; /** * Central class for app that want to use event based error dialogs.
diff --git a/EventBus/src/de/greenrobot/event/util/ExceptionToResourceMapping.java b/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java similarity index 96% rename from EventBus/src/de/greenrobot/event/util/ExceptionToResourceMapping.java rename to EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java index d3286175..d45159b1 100644 --- a/EventBus/src/de/greenrobot/event/util/ExceptionToResourceMapping.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java @@ -1,13 +1,14 @@ -package de.greenrobot.event.util; +package org.greenrobot.eventbus.util; + +import android.util.Log; + +import org.greenrobot.eventbus.EventBus; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import android.util.Log; -import de.greenrobot.event.EventBus; - /** * Maps throwables to texts for error dialogs. Use Config to configure the mapping. diff --git a/EventBus/src/de/greenrobot/event/util/HasExecutionScope.java b/EventBus/src/org/greenrobot/eventbus/util/HasExecutionScope.java similarity index 76% rename from EventBus/src/de/greenrobot/event/util/HasExecutionScope.java rename to EventBus/src/org/greenrobot/eventbus/util/HasExecutionScope.java index d759d2c2..67613b4d 100644 --- a/EventBus/src/de/greenrobot/event/util/HasExecutionScope.java +++ b/EventBus/src/org/greenrobot/eventbus/util/HasExecutionScope.java @@ -1,4 +1,4 @@ -package de.greenrobot.event.util; +package org.greenrobot.eventbus.util; public interface HasExecutionScope { Object getExecutionScope(); diff --git a/EventBus/src/de/greenrobot/event/util/ThrowableFailureEvent.java b/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java similarity index 97% rename from EventBus/src/de/greenrobot/event/util/ThrowableFailureEvent.java rename to EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java index 7c6c07fa..abc37db9 100644 --- a/EventBus/src/de/greenrobot/event/util/ThrowableFailureEvent.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.util; +package org.greenrobot.eventbus.util; /** * A generic failure event, which can be used by apps to propagate thrown exceptions. Also used in conjunction with diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 0210c370..69731f5b 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -1,5 +1,8 @@ package de.greenrobot.event.annotationprocessor; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + import java.io.BufferedWriter; import java.io.IOException; import java.util.ArrayList; @@ -26,10 +29,7 @@ import javax.tools.Diagnostic; import javax.tools.JavaFileObject; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.ThreadMode; - -@SupportedAnnotationTypes("de.greenrobot.event.Subscribe") +@SupportedAnnotationTypes("org.greenrobot.eventbus.Subscribe") public class EventBusAnnotationProcessor extends AbstractProcessor { public static final String INFO_CLASS_POSTFIX = "_EventBusInfo"; @@ -212,9 +212,9 @@ private void createInfoFiles() { JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(myPackage + '.' + infoClassName); writer = new BufferedWriter(sourceFile.openWriter()); writer.write("package " + myPackage + ";\n\n"); - writer.write("import de.greenrobot.event.meta.AbstractSubscriberInfo;\n"); - writer.write("import de.greenrobot.event.SubscriberMethod;\n"); - writer.write("import de.greenrobot.event.ThreadMode;\n\n"); + writer.write("import org.greenrobot.eventbus.meta.AbstractSubscriberInfo;\n"); + writer.write("import org.greenrobot.eventbus.SubscriberMethod;\n"); + writer.write("import org.greenrobot.eventbus.ThreadMode;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); writer.write("public class " + infoClassName + " extends AbstractSubscriberInfo {\n"); writer.write(" public " + infoClassName + "() {\n"); @@ -350,11 +350,11 @@ private void createInfoIndexFile(String index) { if (myPackage != null) { writer.write("package " + myPackage + ";\n\n"); } - writer.write("import de.greenrobot.event.meta.SimpleSubscriberInfo;\n"); - writer.write("import de.greenrobot.event.meta.SubscriberMethodInfo;\n"); - writer.write("import de.greenrobot.event.meta.SubscriberInfo;\n"); - writer.write("import de.greenrobot.event.meta.SubscriberInfoIndex;\n\n"); - writer.write("import de.greenrobot.event.ThreadMode;\n\n"); + writer.write("import org.greenrobot.eventbus.meta.SimpleSubscriberInfo;\n"); + writer.write("import org.greenrobot.eventbus.meta.SubscriberMethodInfo;\n"); + writer.write("import org.greenrobot.eventbus.meta.SubscriberInfo;\n"); + writer.write("import org.greenrobot.eventbus.meta.SubscriberInfoIndex;\n\n"); + writer.write("import org.greenrobot.eventbus.ThreadMode;\n\n"); writer.write("import java.util.HashMap;\n"); writer.write("import java.util.Map;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/Test.java b/EventBusPerformance/src/de/greenrobot/eventperf/Test.java index 0c510d86..8177f9cd 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/Test.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/Test.java @@ -1,9 +1,9 @@ package de.greenrobot.eventperf; -import java.util.concurrent.atomic.AtomicLong; - import android.content.Context; +import java.util.concurrent.atomic.AtomicLong; + public abstract class Test { protected final Context context; protected final TestParams params; diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java b/EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java index 0776bd53..7d567191 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java @@ -1,10 +1,10 @@ package de.greenrobot.eventperf; +import org.greenrobot.eventbus.ThreadMode; + import java.io.Serializable; import java.util.ArrayList; -import de.greenrobot.event.ThreadMode; - public class TestParams implements Serializable { private static final long serialVersionUID = -2739435088947740809L; diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunner.java b/EventBusPerformance/src/de/greenrobot/eventperf/TestRunner.java index e593c8e3..a04f77ca 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunner.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/TestRunner.java @@ -1,12 +1,13 @@ package de.greenrobot.eventperf; +import android.content.Context; + +import org.greenrobot.eventbus.EventBus; + import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.List; -import android.content.Context; -import de.greenrobot.event.EventBus; - /** * This thread initialize all selected tests and runs them through. Also the thread skips the tests, when it is canceled */ diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java b/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java index 8ff7ff9f..91048797 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java @@ -1,15 +1,15 @@ package de.greenrobot.eventperf; -import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.Subscribe; - import android.app.Activity; import android.os.Bundle; import android.os.Process; import android.text.Html; import android.view.View; import android.widget.TextView; -import de.greenrobot.event.EventBus; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; /** * This activity gets the information from the activity before, sets up the test and starts the test. After it watchs diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java b/EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java index 6b760baf..51917286 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java @@ -8,12 +8,14 @@ import android.widget.CheckBox; import android.widget.EditText; import android.widget.Spinner; -import de.greenrobot.event.ThreadMode; -import de.greenrobot.eventperf.testsubject.PerfTestEventBus; -import de.greenrobot.eventperf.testsubject.PerfTestOtto; + +import org.greenrobot.eventbus.ThreadMode; import java.util.ArrayList; +import de.greenrobot.eventperf.testsubject.PerfTestEventBus; +import de.greenrobot.eventperf.testsubject.PerfTestOtto; + public class TestSetupActivity extends Activity { @SuppressWarnings("rawtypes") diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java index cd0ae167..54fe6f71 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java @@ -1,13 +1,15 @@ package de.greenrobot.eventperf.testsubject; +import android.content.Context; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.ArrayList; -import android.content.Context; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.Subscribe; import de.greenrobot.eventperf.MyEventBusIndex; import de.greenrobot.eventperf.Test; import de.greenrobot.eventperf.TestEvent; @@ -172,7 +174,7 @@ public static class RegisterFirstTime extends RegisterOneByOne { public RegisterFirstTime(Context context, TestParams params) { super(context, params); try { - Class clazz = Class.forName("de.greenrobot.event.SubscriberMethodFinder"); + Class clazz = Class.forName("org.greenrobot.eventbus.SubscriberMethodFinder"); clearCachesMethod = clazz.getDeclaredMethod("clearCaches"); clearCachesMethod.setAccessible(true); } catch (Exception e) { diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java index 0d191aeb..f46988af 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java @@ -1,11 +1,5 @@ package de.greenrobot.eventperf.testsubject; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.concurrent.ConcurrentHashMap; - import android.app.Activity; import android.content.Context; import android.os.Looper; @@ -14,6 +8,11 @@ import com.squareup.otto.Subscribe; import com.squareup.otto.ThreadEnforcer; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.concurrent.ConcurrentHashMap; + import de.greenrobot.eventperf.Test; import de.greenrobot.eventperf.TestEvent; import de.greenrobot.eventperf.TestParams; diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java index 2deabf7d..c64b54b1 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java @@ -1,6 +1,7 @@ package de.greenrobot.eventperf.testsubject; -import de.greenrobot.event.Subscribe; +import org.greenrobot.eventbus.Subscribe; + import de.greenrobot.eventperf.TestEvent; public class SubscribeClassEventBusDefault { diff --git a/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java b/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java index 641f586d..822d6a20 100644 --- a/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java @@ -20,9 +20,9 @@ import android.os.Looper; import android.os.Message; import android.support.test.runner.AndroidJUnit4; -import de.greenrobot.event.EventBus; + +import org.greenrobot.eventbus.EventBus; import org.junit.Before; -import org.junit.Ignore; import org.junit.runner.RunWith; import java.util.List; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java index fc090302..7ac54ec0 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java @@ -16,11 +16,10 @@ package de.greenrobot.event.test; import android.os.Looper; -import android.support.test.runner.AndroidJUnit4; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.ThreadMode; + +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; -import org.junit.runner.RunWith; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java index 10458512..f89e778b 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java @@ -16,12 +16,13 @@ package de.greenrobot.event.test; import android.app.Activity; +import android.support.test.annotation.UiThreadTest; import android.support.test.rule.UiThreadTestRule; import android.support.test.runner.AndroidJUnit4; -import android.support.test.annotation.UiThreadTest; import android.util.Log; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.Subscribe; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; import org.junit.Before; import org.junit.Rule; import org.junit.Test; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java index c85c2b06..14ae6dd7 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java @@ -15,12 +15,12 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.EventBusBuilder; -import de.greenrobot.event.EventBusException; -import de.greenrobot.event.NoSubscriberEvent; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.SubscriberExceptionEvent; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.EventBusBuilder; +import org.greenrobot.eventbus.EventBusException; +import org.greenrobot.eventbus.NoSubscriberEvent; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.SubscriberExceptionEvent; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java index dd28e614..1139d012 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java @@ -16,9 +16,10 @@ package de.greenrobot.event.test; import android.test.UiThreadTest; -import de.greenrobot.event.EventBusException; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.ThreadMode; + +import org.greenrobot.eventbus.EventBusException; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import java.util.concurrent.CountDownLatch; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java index 91969393..cc4c5952 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java @@ -1,6 +1,6 @@ package de.greenrobot.event.test; -import de.greenrobot.event.Subscribe; +import org.greenrobot.eventbus.Subscribe; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java index ee3b78a1..84f3d460 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java @@ -1,6 +1,6 @@ package de.greenrobot.event.test; -import de.greenrobot.event.Subscribe; +import org.greenrobot.eventbus.Subscribe; import org.junit.Test; public class EventBusGenericsTest extends AbstractEventBusTest { diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java index 74256dc1..cf6609ff 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java @@ -16,8 +16,9 @@ package de.greenrobot.event.test; import android.support.test.runner.AndroidJUnit4; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.Subscribe; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java index 04f2c3fc..e5b072b3 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java @@ -15,9 +15,10 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.Subscribe; import junit.framework.TestCase; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; import org.junit.Test; /** diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java index e9e6cdf3..0bd64f27 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java @@ -17,8 +17,9 @@ import android.os.Handler; import android.os.Looper; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.ThreadMode; + +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import java.util.Random; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java index 3415467f..5fe3e14f 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java @@ -16,8 +16,9 @@ package de.greenrobot.event.test; import android.os.Looper; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.ThreadMode; + +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; import org.junit.After; import org.junit.Before; import org.junit.Test; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java index 094492e0..485fdf5b 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java @@ -16,8 +16,9 @@ package de.greenrobot.event.test; import android.os.Looper; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.ThreadMode; + +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import static org.junit.Assert.assertNotSame; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java index c3c544da..4e4767cf 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java @@ -17,9 +17,10 @@ import android.os.Looper; import android.util.Log; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.ThreadMode; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import java.util.ArrayList; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java index de638f22..9fe94a59 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java @@ -15,10 +15,10 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.NoSubscriberEvent; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.SubscriberExceptionEvent; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.NoSubscriberEvent; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.SubscriberExceptionEvent; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java index 36a40890..e09b2c2f 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java @@ -16,9 +16,10 @@ package de.greenrobot.event.test; import android.util.Log; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.ThreadMode; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import java.util.ArrayList; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java index 853cc5dd..d143d08d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java @@ -15,7 +15,7 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.Subscribe; +import org.greenrobot.eventbus.Subscribe; import org.junit.Test; import java.util.ArrayList; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java index 7694b185..ba902f89 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java @@ -15,7 +15,7 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.Subscribe; +import org.greenrobot.eventbus.Subscribe; import org.junit.Test; import static org.junit.Assert.*; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java index 2651b4b5..a2b660dc 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java @@ -15,9 +15,9 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.SubscriberExceptionEvent; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.SubscriberExceptionEvent; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java index eaef374d..39eb12ce 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test; -import de.greenrobot.event.EventBus; import junit.framework.Assert; import junit.framework.TestCase; + +import org.greenrobot.eventbus.EventBus; import org.junit.Test; public class EventBusSubscriberInJarTest extends TestCase { diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java index c1c504a9..61f543b8 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java @@ -15,7 +15,7 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.Subscribe; +import org.greenrobot.eventbus.Subscribe; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java index 07f61cc4..946f1bc1 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java @@ -1,11 +1,10 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.test.EventBusBackgroundThreadTest; -import org.greenrobot.eventbus.EventBusTestsIndex; import org.junit.Before; import org.junit.Test; +import de.greenrobot.event.test.EventBusBackgroundThreadTest; + import static org.junit.Assert.assertTrue; public class EventBusBackgroundThreadTestWithIndex extends EventBusBackgroundThreadTest { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java index 3d2f83e9..a386fd99 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java @@ -1,9 +1,10 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusBasicTest; import org.junit.Before; import org.junit.Test; +import de.greenrobot.event.test.EventBusBasicTest; + import static org.junit.Assert.assertTrue; public class EventBusBasicTestWithIndex extends EventBusBasicTest { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java index 1456f760..f0eecd92 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusCancelEventDeliveryTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusCancelEventDeliveryTest; + public class EventBusCancelEventDeliveryTestWithIndex extends EventBusCancelEventDeliveryTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java index 7804b8b2..c51ef5ad 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusFallbackToReflectionTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusFallbackToReflectionTest; + public class EventBusFallbackToReflectionTestWithIndex extends EventBusFallbackToReflectionTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java index dd00aa02..86fd4d2e 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusGenericsTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusGenericsTest; + public class EventBusGenericsTestWithIndex extends EventBusGenericsTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java index 56613525..1c33a00d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java @@ -1,10 +1,11 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.test.EventBusInheritanceDisabledTest; +import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBusTestsIndex; import org.junit.Before; +import de.greenrobot.event.test.EventBusInheritanceDisabledTest; + public class EventBusInheritanceDisabledTestWithIndex extends EventBusInheritanceDisabledTest { @Before public void setUp() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java index 54f2749b..0d770661 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusInheritanceTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusInheritanceTest; + public class EventBusInheritanceTestWithIndex extends EventBusInheritanceTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java index 52bdb6e1..24e9cc4d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusMainThreadRacingTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusMainThreadRacingTest; + public class EventBusMainThreadRacingTestWithIndex extends EventBusMainThreadRacingTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java index 69fb22bc..e462d03f 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusMainThreadTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusMainThreadTest; + public class EventBusMainThreadTestWithIndex extends EventBusMainThreadTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java index c66f0baf..3f237739 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusMethodModifiersTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusMethodModifiersTest; + public class EventBusMethodModifiersTestWithIndex extends EventBusMethodModifiersTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java index 71329fe1..2a0705b4 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusMultithreadedTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusMultithreadedTest; + public class EventBusMultithreadedTestWithIndex extends EventBusMultithreadedTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java index 26c48eb6..b3961da5 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusNoSubscriberEventTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusNoSubscriberEventTest; + /** TODO */ public class EventBusNoSubscriberEventTestWithIndex extends EventBusNoSubscriberEventTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java index 21424186..54369cdd 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusOrderedSubscriptionsTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusOrderedSubscriptionsTest; + /** TODO */ public class EventBusOrderedSubscriptionsTestWithIndex extends EventBusOrderedSubscriptionsTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java index 35840f72..a06efd92 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusRegistrationRacingTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusRegistrationRacingTest; + /** TODO */ public class EventBusRegistrationRacingTestWithIndex extends EventBusRegistrationRacingTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java index c7b6413b..0d947f05 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusStickyEventTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusStickyEventTest; + /** TODO */ public class EventBusStickyEventTestWithIndex extends EventBusStickyEventTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java index 31253cb5..18a0f76a 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusSubscriberExceptionTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusSubscriberExceptionTest; + /** TODO */ public class EventBusSubscriberExceptionTestWithIndex extends EventBusSubscriberExceptionTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java index 8899a546..1cb842e8 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusSubscriberInJarTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusSubscriberInJarTest; + /** TODO */ public class EventBusSubscriberInJarTestWithIndex extends EventBusSubscriberInJarTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java b/EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java index 64417e95..a202ea5a 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java @@ -1,6 +1,6 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.EventBus; +import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBusTestsIndex; public class Indexed { diff --git a/EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java b/EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java index ea3bba4e..d79d0d80 100644 --- a/EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java +++ b/EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java @@ -1,6 +1,6 @@ package de.greenrobot.event.test; -import de.greenrobot.event.Subscribe; +import org.greenrobot.eventbus.Subscribe; import java.util.ArrayList; import java.util.List; From 97de666bac477bda74f64f220de09632bda8f4c7 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 22 Jan 2016 12:11:27 +0100 Subject: [PATCH 125/288] moved tests to org.greenrobot.eventbus --- .../greenrobot/eventbus}/AbstractEventBusTest.java | 2 +- .../greenrobot/eventbus}/ClassMapPerfTest.java | 2 +- .../eventbus}/EventBusBackgroundThreadTest.java | 4 +--- .../greenrobot/eventbus}/EventBusBasicTest.java | 4 +--- .../greenrobot/eventbus}/EventBusBuilderTest.java | 8 +------- .../eventbus}/EventBusCancelEventDeliveryTest.java | 5 +---- .../eventbus}/EventBusFallbackToReflectionTest.java | 3 +-- .../greenrobot/eventbus}/EventBusGenericsTest.java | 3 +-- .../eventbus}/EventBusInheritanceDisabledTest.java | 4 +--- .../greenrobot/eventbus}/EventBusInheritanceTest.java | 4 +--- .../eventbus}/EventBusMainThreadRacingTest.java | 4 +--- .../greenrobot/eventbus}/EventBusMainThreadTest.java | 4 +--- .../greenrobot/eventbus}/EventBusMethodModifiersTest.java | 4 +--- .../greenrobot/eventbus}/EventBusMultithreadedTest.java | 5 +---- .../eventbus}/EventBusNoSubscriberEventTest.java | 6 +----- .../eventbus}/EventBusOrderedSubscriptionsTest.java | 5 +---- .../eventbus}/EventBusRegistrationRacingTest.java | 3 +-- .../greenrobot/eventbus}/EventBusStickyEventTest.java | 3 +-- .../eventbus}/EventBusSubscriberExceptionTest.java | 5 +---- .../greenrobot/eventbus}/EventBusSubscriberInJarTest.java | 4 +++- .../greenrobot/eventbus}/EventBusSubscriberLegalTest.java | 3 +-- .../test => org/greenrobot/eventbus}/IntTestEvent.java | 2 +- .../indexed/EventBusBackgroundThreadTestWithIndex.java | 5 ++--- .../eventbus}/indexed/EventBusBasicTestWithIndex.java | 5 ++--- .../indexed/EventBusCancelEventDeliveryTestWithIndex.java | 5 ++--- .../EventBusFallbackToReflectionTestWithIndex.java | 4 ++-- .../eventbus}/indexed/EventBusGenericsTestWithIndex.java | 4 ++-- .../indexed/EventBusInheritanceDisabledTestWithIndex.java | 4 ++-- .../indexed/EventBusInheritanceTestWithIndex.java | 5 ++--- .../indexed/EventBusMainThreadRacingTestWithIndex.java | 4 ++-- .../indexed/EventBusMainThreadTestWithIndex.java | 4 ++-- .../indexed/EventBusMethodModifiersTestWithIndex.java | 5 ++--- .../indexed/EventBusMultithreadedTestWithIndex.java | 5 ++--- .../indexed/EventBusNoSubscriberEventTestWithIndex.java | 5 ++--- .../EventBusOrderedSubscriptionsTestWithIndex.java | 5 ++--- .../indexed/EventBusRegistrationRacingTestWithIndex.java | 4 ++-- .../indexed/EventBusStickyEventTestWithIndex.java | 5 ++--- .../indexed/EventBusSubscriberExceptionTestWithIndex.java | 4 ++-- .../indexed/EventBusSubscriberInJarTestWithIndex.java | 5 ++--- .../test => org/greenrobot/eventbus}/indexed/Indexed.java | 2 +- 40 files changed, 59 insertions(+), 108 deletions(-) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/AbstractEventBusTest.java (99%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/ClassMapPerfTest.java (97%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusBackgroundThreadTest.java (93%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusBasicTest.java (98%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusBuilderTest.java (90%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusCancelEventDeliveryTest.java (96%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusFallbackToReflectionTest.java (97%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusGenericsTest.java (89%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusInheritanceDisabledTest.java (98%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusInheritanceTest.java (98%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusMainThreadRacingTest.java (96%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusMainThreadTest.java (97%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusMethodModifiersTest.java (94%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusMultithreadedTest.java (98%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusNoSubscriberEventTest.java (92%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusOrderedSubscriptionsTest.java (97%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusRegistrationRacingTest.java (97%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusStickyEventTest.java (98%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusSubscriberExceptionTest.java (92%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusSubscriberInJarTest.java (88%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusSubscriberLegalTest.java (97%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/IntTestEvent.java (96%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusBackgroundThreadTestWithIndex.java (79%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusBasicTestWithIndex.java (80%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusCancelEventDeliveryTestWithIndex.java (68%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusFallbackToReflectionTestWithIndex.java (68%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusGenericsTestWithIndex.java (68%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusInheritanceDisabledTestWithIndex.java (78%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusInheritanceTestWithIndex.java (68%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusMainThreadRacingTestWithIndex.java (68%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusMainThreadTestWithIndex.java (68%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusMethodModifiersTestWithIndex.java (68%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusMultithreadedTestWithIndex.java (68%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusNoSubscriberEventTestWithIndex.java (69%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusOrderedSubscriptionsTestWithIndex.java (69%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusRegistrationRacingTestWithIndex.java (69%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusStickyEventTestWithIndex.java (69%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusSubscriberExceptionTestWithIndex.java (69%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusSubscriberInJarTestWithIndex.java (69%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/Indexed.java (84%) diff --git a/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java b/EventBusTest/src/org/greenrobot/eventbus/AbstractEventBusTest.java similarity index 99% rename from EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java rename to EventBusTest/src/org/greenrobot/eventbus/AbstractEventBusTest.java index 822d6a20..f313071a 100644 --- a/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/AbstractEventBusTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import android.annotation.SuppressLint; import android.os.Handler; diff --git a/EventBusTest/src/de/greenrobot/event/test/ClassMapPerfTest.java b/EventBusTest/src/org/greenrobot/eventbus/ClassMapPerfTest.java similarity index 97% rename from EventBusTest/src/de/greenrobot/event/test/ClassMapPerfTest.java rename to EventBusTest/src/org/greenrobot/eventbus/ClassMapPerfTest.java index ac6d9ada..60f7a66c 100644 --- a/EventBusTest/src/de/greenrobot/event/test/ClassMapPerfTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/ClassMapPerfTest.java @@ -1,4 +1,4 @@ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import java.util.HashMap; import java.util.IdentityHashMap; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusBackgroundThreadTest.java similarity index 93% rename from EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusBackgroundThreadTest.java index 7ac54ec0..32ce3b3f 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusBackgroundThreadTest.java @@ -13,12 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import android.os.Looper; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusBasicTest.java similarity index 98% rename from EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusBasicTest.java index f89e778b..f50c4108 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusBasicTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import android.app.Activity; import android.support.test.annotation.UiThreadTest; @@ -21,8 +21,6 @@ import android.support.test.runner.AndroidJUnit4; import android.util.Log; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; import org.junit.Before; import org.junit.Rule; import org.junit.Test; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java similarity index 90% rename from EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java index 14ae6dd7..354d78e2 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java @@ -13,14 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.EventBusBuilder; -import org.greenrobot.eventbus.EventBusException; -import org.greenrobot.eventbus.NoSubscriberEvent; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.SubscriberExceptionEvent; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java similarity index 96% rename from EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java index 1139d012..5c9966d6 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java @@ -13,13 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import android.test.UiThreadTest; -import org.greenrobot.eventbus.EventBusException; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import java.util.concurrent.CountDownLatch; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java similarity index 97% rename from EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java index cc4c5952..ce102566 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java @@ -1,6 +1,5 @@ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; -import org.greenrobot.eventbus.Subscribe; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java similarity index 89% rename from EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java index 84f3d460..06db3002 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java @@ -1,6 +1,5 @@ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; -import org.greenrobot.eventbus.Subscribe; import org.junit.Test; public class EventBusGenericsTest extends AbstractEventBusTest { diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java similarity index 98% rename from EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java index cf6609ff..4a767204 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java @@ -13,12 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import android.support.test.runner.AndroidJUnit4; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceTest.java similarity index 98% rename from EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceTest.java index e5b072b3..d4a4d0f7 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceTest.java @@ -13,12 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import junit.framework.TestCase; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; import org.junit.Test; /** diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadRacingTest.java similarity index 96% rename from EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadRacingTest.java index 0bd64f27..79fdfc92 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadRacingTest.java @@ -13,13 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import android.os.Handler; import android.os.Looper; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import java.util.Random; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java similarity index 97% rename from EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java index 5fe3e14f..55c6fc57 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java @@ -13,12 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import android.os.Looper; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; import org.junit.After; import org.junit.Before; import org.junit.Test; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMethodModifiersTest.java similarity index 94% rename from EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusMethodModifiersTest.java index 485fdf5b..8eb00cf2 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMethodModifiersTest.java @@ -13,12 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import android.os.Looper; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import static org.junit.Assert.assertNotSame; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMultithreadedTest.java similarity index 98% rename from EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusMultithreadedTest.java index 4e4767cf..eec9103b 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMultithreadedTest.java @@ -13,14 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import android.os.Looper; import android.util.Log; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import java.util.ArrayList; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java similarity index 92% rename from EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java index 9fe94a59..ad12d64f 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java @@ -13,12 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.NoSubscriberEvent; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.SubscriberExceptionEvent; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java similarity index 97% rename from EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java index e09b2c2f..463f11bf 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java @@ -13,13 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import android.util.Log; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import java.util.ArrayList; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java similarity index 97% rename from EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java index d143d08d..c4f405ee 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java @@ -13,9 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; -import org.greenrobot.eventbus.Subscribe; import org.junit.Test; import java.util.ArrayList; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java similarity index 98% rename from EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java index ba902f89..be23b4ab 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java @@ -13,9 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; -import org.greenrobot.eventbus.Subscribe; import org.junit.Test; import static org.junit.Assert.*; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java similarity index 92% rename from EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java index a2b660dc..2d227c94 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java @@ -13,11 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.SubscriberExceptionEvent; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberInJarTest.java similarity index 88% rename from EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberInJarTest.java index 39eb12ce..9f815583 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberInJarTest.java @@ -1,4 +1,4 @@ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import junit.framework.Assert; import junit.framework.TestCase; @@ -6,6 +6,8 @@ import org.greenrobot.eventbus.EventBus; import org.junit.Test; +import de.greenrobot.event.test.SubscriberInJar; + public class EventBusSubscriberInJarTest extends TestCase { protected EventBus eventBus = EventBus.builder().build(); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java similarity index 97% rename from EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java index 61f543b8..c70a1e6b 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java @@ -13,9 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; -import org.greenrobot.eventbus.Subscribe; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/IntTestEvent.java b/EventBusTest/src/org/greenrobot/eventbus/IntTestEvent.java similarity index 96% rename from EventBusTest/src/de/greenrobot/event/test/IntTestEvent.java rename to EventBusTest/src/org/greenrobot/eventbus/IntTestEvent.java index dc829b89..5874ae17 100644 --- a/EventBusTest/src/de/greenrobot/event/test/IntTestEvent.java +++ b/EventBusTest/src/org/greenrobot/eventbus/IntTestEvent.java @@ -17,7 +17,7 @@ /** * Simple event storing an int value. More efficient than Integer because of the its flat hierarchy. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; public class IntTestEvent { public final int value; diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBackgroundThreadTestWithIndex.java similarity index 79% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBackgroundThreadTestWithIndex.java index 946f1bc1..8771358a 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBackgroundThreadTestWithIndex.java @@ -1,10 +1,9 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; +import org.greenrobot.eventbus.EventBusBackgroundThreadTest; import org.junit.Before; import org.junit.Test; -import de.greenrobot.event.test.EventBusBackgroundThreadTest; - import static org.junit.Assert.assertTrue; public class EventBusBackgroundThreadTestWithIndex extends EventBusBackgroundThreadTest { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBasicTestWithIndex.java similarity index 80% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBasicTestWithIndex.java index a386fd99..d5e6d1fd 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBasicTestWithIndex.java @@ -1,10 +1,9 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; +import org.greenrobot.eventbus.EventBusBasicTest; import org.junit.Before; import org.junit.Test; -import de.greenrobot.event.test.EventBusBasicTest; - import static org.junit.Assert.assertTrue; public class EventBusBasicTestWithIndex extends EventBusBasicTest { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusCancelEventDeliveryTestWithIndex.java similarity index 68% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusCancelEventDeliveryTestWithIndex.java index f0eecd92..7c3d670c 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusCancelEventDeliveryTestWithIndex.java @@ -1,9 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; +import org.greenrobot.eventbus.EventBusCancelEventDeliveryTest; import org.junit.Before; -import de.greenrobot.event.test.EventBusCancelEventDeliveryTest; - public class EventBusCancelEventDeliveryTestWithIndex extends EventBusCancelEventDeliveryTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusFallbackToReflectionTestWithIndex.java similarity index 68% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusFallbackToReflectionTestWithIndex.java index c51ef5ad..74c2b44e 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusFallbackToReflectionTestWithIndex.java @@ -1,8 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; import org.junit.Before; -import de.greenrobot.event.test.EventBusFallbackToReflectionTest; +import org.greenrobot.eventbus.EventBusFallbackToReflectionTest; public class EventBusFallbackToReflectionTestWithIndex extends EventBusFallbackToReflectionTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusGenericsTestWithIndex.java similarity index 68% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusGenericsTestWithIndex.java index 86fd4d2e..eeca3a92 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusGenericsTestWithIndex.java @@ -1,8 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; import org.junit.Before; -import de.greenrobot.event.test.EventBusGenericsTest; +import org.greenrobot.eventbus.EventBusGenericsTest; public class EventBusGenericsTestWithIndex extends EventBusGenericsTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceDisabledTestWithIndex.java similarity index 78% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceDisabledTestWithIndex.java index 1c33a00d..b0c85a0b 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceDisabledTestWithIndex.java @@ -1,10 +1,10 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBusTestsIndex; import org.junit.Before; -import de.greenrobot.event.test.EventBusInheritanceDisabledTest; +import org.greenrobot.eventbus.EventBusInheritanceDisabledTest; public class EventBusInheritanceDisabledTestWithIndex extends EventBusInheritanceDisabledTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceTestWithIndex.java similarity index 68% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceTestWithIndex.java index 0d770661..6d8963b6 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceTestWithIndex.java @@ -1,9 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; +import org.greenrobot.eventbus.EventBusInheritanceTest; import org.junit.Before; -import de.greenrobot.event.test.EventBusInheritanceTest; - public class EventBusInheritanceTestWithIndex extends EventBusInheritanceTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadRacingTestWithIndex.java similarity index 68% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadRacingTestWithIndex.java index 24e9cc4d..f6a90873 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadRacingTestWithIndex.java @@ -1,8 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; import org.junit.Before; -import de.greenrobot.event.test.EventBusMainThreadRacingTest; +import org.greenrobot.eventbus.EventBusMainThreadRacingTest; public class EventBusMainThreadRacingTestWithIndex extends EventBusMainThreadRacingTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadTestWithIndex.java similarity index 68% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadTestWithIndex.java index e462d03f..99248950 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadTestWithIndex.java @@ -1,8 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; import org.junit.Before; -import de.greenrobot.event.test.EventBusMainThreadTest; +import org.greenrobot.eventbus.EventBusMainThreadTest; public class EventBusMainThreadTestWithIndex extends EventBusMainThreadTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMethodModifiersTestWithIndex.java similarity index 68% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMethodModifiersTestWithIndex.java index 3f237739..0a9d34ae 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMethodModifiersTestWithIndex.java @@ -1,9 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; +import org.greenrobot.eventbus.EventBusMethodModifiersTest; import org.junit.Before; -import de.greenrobot.event.test.EventBusMethodModifiersTest; - public class EventBusMethodModifiersTestWithIndex extends EventBusMethodModifiersTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMultithreadedTestWithIndex.java similarity index 68% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMultithreadedTestWithIndex.java index 2a0705b4..b0c06a67 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMultithreadedTestWithIndex.java @@ -1,9 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; +import org.greenrobot.eventbus.EventBusMultithreadedTest; import org.junit.Before; -import de.greenrobot.event.test.EventBusMultithreadedTest; - public class EventBusMultithreadedTestWithIndex extends EventBusMultithreadedTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java similarity index 69% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java index b3961da5..937af651 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java @@ -1,9 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; +import org.greenrobot.eventbus.EventBusNoSubscriberEventTest; import org.junit.Before; -import de.greenrobot.event.test.EventBusNoSubscriberEventTest; - /** TODO */ public class EventBusNoSubscriberEventTestWithIndex extends EventBusNoSubscriberEventTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java similarity index 69% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java index 54369cdd..71389239 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java @@ -1,9 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; +import org.greenrobot.eventbus.EventBusOrderedSubscriptionsTest; import org.junit.Before; -import de.greenrobot.event.test.EventBusOrderedSubscriptionsTest; - /** TODO */ public class EventBusOrderedSubscriptionsTestWithIndex extends EventBusOrderedSubscriptionsTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java similarity index 69% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java index a06efd92..bbd40a9c 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java @@ -1,8 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; import org.junit.Before; -import de.greenrobot.event.test.EventBusRegistrationRacingTest; +import org.greenrobot.eventbus.EventBusRegistrationRacingTest; /** TODO */ public class EventBusRegistrationRacingTestWithIndex extends EventBusRegistrationRacingTest { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java similarity index 69% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java index 0d947f05..6fab88f5 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java @@ -1,9 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; +import org.greenrobot.eventbus.EventBusStickyEventTest; import org.junit.Before; -import de.greenrobot.event.test.EventBusStickyEventTest; - /** TODO */ public class EventBusStickyEventTestWithIndex extends EventBusStickyEventTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java similarity index 69% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java index 18a0f76a..42bcce98 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java @@ -1,8 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; import org.junit.Before; -import de.greenrobot.event.test.EventBusSubscriberExceptionTest; +import org.greenrobot.eventbus.EventBusSubscriberExceptionTest; /** TODO */ public class EventBusSubscriberExceptionTestWithIndex extends EventBusSubscriberExceptionTest { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java similarity index 69% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java index 1cb842e8..4f721e2f 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java @@ -1,9 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; +import org.greenrobot.eventbus.EventBusSubscriberInJarTest; import org.junit.Before; -import de.greenrobot.event.test.EventBusSubscriberInJarTest; - /** TODO */ public class EventBusSubscriberInJarTestWithIndex extends EventBusSubscriberInJarTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java similarity index 84% rename from EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java index a202ea5a..f86e7872 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java @@ -1,4 +1,4 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBusTestsIndex; From 3f6f45019b3196da0405902b45d0c2d0da733694 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 22 Jan 2016 12:34:27 +0100 Subject: [PATCH 126/288] moved perf to org.greenrobot.eventbusperf package --- EventBusPerformance/AndroidManifest.xml | 11 ++++----- EventBusPerformance/build.gradle | 2 +- EventBusPerformance/res/values/strings.xml | 2 +- .../greenrobot/eventbusperf}/Test.java | 2 +- .../greenrobot/eventbusperf}/TestEvent.java | 2 +- .../eventbusperf}/TestFinishedEvent.java | 24 +++++++++---------- .../greenrobot/eventbusperf}/TestParams.java | 2 +- .../greenrobot/eventbusperf}/TestRunner.java | 2 +- .../eventbusperf}/TestRunnerActivity.java | 2 +- .../eventbusperf}/TestSetupActivity.java | 6 ++--- .../testsubject/PerfTestEventBus.java | 10 ++++---- .../testsubject/PerfTestOtto.java | 8 +++---- .../SubscribeClassEventBusDefault.java | 4 ++-- 13 files changed, 38 insertions(+), 39 deletions(-) rename EventBusPerformance/src/{de/greenrobot/eventperf => org/greenrobot/eventbusperf}/Test.java (97%) rename EventBusPerformance/src/{de/greenrobot/eventperf => org/greenrobot/eventbusperf}/TestEvent.java (62%) rename EventBusPerformance/src/{de/greenrobot/eventperf => org/greenrobot/eventbusperf}/TestFinishedEvent.java (84%) rename EventBusPerformance/src/{de/greenrobot/eventperf => org/greenrobot/eventbusperf}/TestParams.java (98%) rename EventBusPerformance/src/{de/greenrobot/eventperf => org/greenrobot/eventbusperf}/TestRunner.java (98%) rename EventBusPerformance/src/{de/greenrobot/eventperf => org/greenrobot/eventbusperf}/TestRunnerActivity.java (98%) rename EventBusPerformance/src/{de/greenrobot/eventperf => org/greenrobot/eventbusperf}/TestSetupActivity.java (96%) rename EventBusPerformance/src/{de/greenrobot/eventperf => org/greenrobot/eventbusperf}/testsubject/PerfTestEventBus.java (97%) rename EventBusPerformance/src/{de/greenrobot/eventperf => org/greenrobot/eventbusperf}/testsubject/PerfTestOtto.java (97%) rename EventBusPerformance/src/{de/greenrobot/eventperf => org/greenrobot/eventbusperf}/testsubject/SubscribeClassEventBusDefault.java (85%) diff --git a/EventBusPerformance/AndroidManifest.xml b/EventBusPerformance/AndroidManifest.xml index 4967dc56..af353b5d 100644 --- a/EventBusPerformance/AndroidManifest.xml +++ b/EventBusPerformance/AndroidManifest.xml @@ -1,8 +1,8 @@ + package="org.greenrobot.eventbusperf" + android:versionCode="1" + android:versionName="2.0.0" > - diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 12f19fb6..401b9afb 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -24,7 +24,7 @@ dependencies { apt { arguments { - eventBusIndex "de.greenrobot.eventperf.MyEventBusIndex" + eventBusIndex "org.greenrobot.eventbusperf.MyEventBusIndex" } } diff --git a/EventBusPerformance/res/values/strings.xml b/EventBusPerformance/res/values/strings.xml index c7af6a88..feed5953 100644 --- a/EventBusPerformance/res/values/strings.xml +++ b/EventBusPerformance/res/values/strings.xml @@ -1,7 +1,7 @@ - Event Performance + EventBus Performance EventBus Event Inheritance Ignore generated index diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/Test.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/Test.java similarity index 97% rename from EventBusPerformance/src/de/greenrobot/eventperf/Test.java rename to EventBusPerformance/src/org/greenrobot/eventbusperf/Test.java index 8177f9cd..35d20471 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/Test.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/Test.java @@ -1,4 +1,4 @@ -package de.greenrobot.eventperf; +package org.greenrobot.eventbusperf; import android.content.Context; diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestEvent.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestEvent.java similarity index 62% rename from EventBusPerformance/src/de/greenrobot/eventperf/TestEvent.java rename to EventBusPerformance/src/org/greenrobot/eventbusperf/TestEvent.java index b90be773..d0edba31 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestEvent.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestEvent.java @@ -1,4 +1,4 @@ -package de.greenrobot.eventperf; +package org.greenrobot.eventbusperf; /** Used by otto and EventBus */ public class TestEvent { diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestFinishedEvent.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestFinishedEvent.java similarity index 84% rename from EventBusPerformance/src/de/greenrobot/eventperf/TestFinishedEvent.java rename to EventBusPerformance/src/org/greenrobot/eventbusperf/TestFinishedEvent.java index 1e301c9b..7bc72ed8 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestFinishedEvent.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestFinishedEvent.java @@ -1,12 +1,12 @@ -package de.greenrobot.eventperf; - -public class TestFinishedEvent { - - public final Test test; - public final boolean isLastEvent; - - public TestFinishedEvent(Test test, boolean isLastEvent) { - this.test = test; - this.isLastEvent = isLastEvent; - } -} +package org.greenrobot.eventbusperf; + +public class TestFinishedEvent { + + public final Test test; + public final boolean isLastEvent; + + public TestFinishedEvent(Test test, boolean isLastEvent) { + this.test = test; + this.isLastEvent = isLastEvent; + } +} diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestParams.java similarity index 98% rename from EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java rename to EventBusPerformance/src/org/greenrobot/eventbusperf/TestParams.java index 7d567191..79af650a 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestParams.java @@ -1,4 +1,4 @@ -package de.greenrobot.eventperf; +package org.greenrobot.eventbusperf; import org.greenrobot.eventbus.ThreadMode; diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunner.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunner.java similarity index 98% rename from EventBusPerformance/src/de/greenrobot/eventperf/TestRunner.java rename to EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunner.java index a04f77ca..3107289a 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunner.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunner.java @@ -1,4 +1,4 @@ -package de.greenrobot.eventperf; +package org.greenrobot.eventbusperf; import android.content.Context; diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunnerActivity.java similarity index 98% rename from EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java rename to EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunnerActivity.java index 91048797..9c718597 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunnerActivity.java @@ -1,4 +1,4 @@ -package de.greenrobot.eventperf; +package org.greenrobot.eventbusperf; import android.app.Activity; import android.os.Bundle; diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestSetupActivity.java similarity index 96% rename from EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java rename to EventBusPerformance/src/org/greenrobot/eventbusperf/TestSetupActivity.java index 51917286..0837bd4a 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestSetupActivity.java @@ -1,4 +1,4 @@ -package de.greenrobot.eventperf; +package org.greenrobot.eventbusperf; import android.app.Activity; import android.content.Intent; @@ -13,8 +13,8 @@ import java.util.ArrayList; -import de.greenrobot.eventperf.testsubject.PerfTestEventBus; -import de.greenrobot.eventperf.testsubject.PerfTestOtto; +import org.greenrobot.eventbusperf.testsubject.PerfTestEventBus; +import org.greenrobot.eventbusperf.testsubject.PerfTestOtto; public class TestSetupActivity extends Activity { diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestEventBus.java similarity index 97% rename from EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java rename to EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestEventBus.java index 54fe6f71..5f43601a 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestEventBus.java @@ -1,4 +1,4 @@ -package de.greenrobot.eventperf.testsubject; +package org.greenrobot.eventbusperf.testsubject; import android.content.Context; @@ -10,10 +10,10 @@ import java.lang.reflect.Method; import java.util.ArrayList; -import de.greenrobot.eventperf.MyEventBusIndex; -import de.greenrobot.eventperf.Test; -import de.greenrobot.eventperf.TestEvent; -import de.greenrobot.eventperf.TestParams; +import org.greenrobot.eventbusperf.MyEventBusIndex; +import org.greenrobot.eventbusperf.Test; +import org.greenrobot.eventbusperf.TestEvent; +import org.greenrobot.eventbusperf.TestParams; public abstract class PerfTestEventBus extends Test { diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestOtto.java similarity index 97% rename from EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java rename to EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestOtto.java index f46988af..1a9fb24c 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestOtto.java @@ -1,4 +1,4 @@ -package de.greenrobot.eventperf.testsubject; +package org.greenrobot.eventbusperf.testsubject; import android.app.Activity; import android.content.Context; @@ -13,9 +13,9 @@ import java.util.ArrayList; import java.util.concurrent.ConcurrentHashMap; -import de.greenrobot.eventperf.Test; -import de.greenrobot.eventperf.TestEvent; -import de.greenrobot.eventperf.TestParams; +import org.greenrobot.eventbusperf.Test; +import org.greenrobot.eventbusperf.TestEvent; +import org.greenrobot.eventbusperf.TestParams; public abstract class PerfTestOtto extends Test { diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/SubscribeClassEventBusDefault.java similarity index 85% rename from EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java rename to EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/SubscribeClassEventBusDefault.java index c64b54b1..2244a0a3 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/SubscribeClassEventBusDefault.java @@ -1,8 +1,8 @@ -package de.greenrobot.eventperf.testsubject; +package org.greenrobot.eventbusperf.testsubject; import org.greenrobot.eventbus.Subscribe; -import de.greenrobot.eventperf.TestEvent; +import org.greenrobot.eventbusperf.TestEvent; public class SubscribeClassEventBusDefault { private PerfTestEventBus perfTestEventBus; From 633073e819e5563ce10e2364801260b7c25fc118 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 22 Jan 2016 13:06:50 +0100 Subject: [PATCH 127/288] moved processor and inJar to org.greenrobot.eventbus --- .../META-INF/services/javax.annotation.processing.Processor | 2 +- .../annotationprocessor/EventBusAnnotationProcessor.java | 2 +- .../test => org/greenrobot/eventbus}/SubscriberInJar.java | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) rename EventBusAnnotationProcessor/src/{de/greenrobot/event => org/greenrobot/eventbus}/annotationprocessor/EventBusAnnotationProcessor.java (99%) rename EventBusTestSubscriberInJar/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/SubscriberInJar.java (83%) diff --git a/EventBusAnnotationProcessor/res/META-INF/services/javax.annotation.processing.Processor b/EventBusAnnotationProcessor/res/META-INF/services/javax.annotation.processing.Processor index ec7e34b6..e6e7aa55 100644 --- a/EventBusAnnotationProcessor/res/META-INF/services/javax.annotation.processing.Processor +++ b/EventBusAnnotationProcessor/res/META-INF/services/javax.annotation.processing.Processor @@ -1 +1 @@ -de.greenrobot.event.annotationprocessor.EventBusAnnotationProcessor +org.greenrobot.eventbus.annotationprocessor.EventBusAnnotationProcessor diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java similarity index 99% rename from EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java rename to EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java index 69731f5b..6455233e 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java @@ -1,4 +1,4 @@ -package de.greenrobot.event.annotationprocessor; +package org.greenrobot.eventbus.annotationprocessor; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; diff --git a/EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java b/EventBusTestSubscriberInJar/src/org/greenrobot/eventbus/SubscriberInJar.java similarity index 83% rename from EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java rename to EventBusTestSubscriberInJar/src/org/greenrobot/eventbus/SubscriberInJar.java index d79d0d80..9d185207 100644 --- a/EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java +++ b/EventBusTestSubscriberInJar/src/org/greenrobot/eventbus/SubscriberInJar.java @@ -1,6 +1,4 @@ -package de.greenrobot.event.test; - -import org.greenrobot.eventbus.Subscribe; +package org.greenrobot.eventbus; import java.util.ArrayList; import java.util.List; From ce943759dfbbde0361b53e26657ebec44004bac7 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 22 Jan 2016 14:49:35 +0100 Subject: [PATCH 128/288] updating subscriber-in-jar and using an index for it --- .../EventBusAnnotationProcessor.java | 2 ++ .../EventBusTestSubscriberInJar-3.0.0-beta1.jar | Bin 1351 -> 0 bytes .../EventBusTestSubscriberInJar-3.0.0-beta2.jar | Bin 0 -> 3800 bytes .../eventbus/EventBusSubscriberInJarTest.java | 2 +- .../EventBusSubscriberInJarTestWithIndex.java | 4 +++- EventBusTestSubscriberInJar/build.gradle | 5 +++++ 6 files changed, 11 insertions(+), 2 deletions(-) delete mode 100644 EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta1.jar create mode 100644 EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta2.jar diff --git a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java index 6455233e..51ffc232 100644 --- a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java @@ -16,6 +16,7 @@ import javax.annotation.processing.Messager; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedOptions; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; @@ -30,6 +31,7 @@ import javax.tools.JavaFileObject; @SupportedAnnotationTypes("org.greenrobot.eventbus.Subscribe") +@SupportedOptions("eventBusIndex") public class EventBusAnnotationProcessor extends AbstractProcessor { public static final String INFO_CLASS_POSTFIX = "_EventBusInfo"; diff --git a/EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta1.jar b/EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta1.jar deleted file mode 100644 index bdfeab2124918adea44f041f85c5d9586c515c7c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1351 zcmWIWW@h1HVBp|jxNd#ajR6RlKm-tQ0iYh?4Z8)YQD9{G|L6ysAO20~&~=I<+h{55FFeudwMUNiD|IXn8&3)H6l~hUq}3 z>*3QFT$)szT$GuVTI8AMl~|;goRe5w+#8geeZ@hb?pvJD`&swqUJqNVzxGo0CwT2S};(iG;UL5F*NL{HxQw|Wk@>Xf}= z+{HUgF8oW_VRLD(>IeDe9RJHP?T=<|X^xD4@q451#|Md1yW%g&W}Lkr?Z+Q}q3Gj* z!*X&)Jpan)ZDF0B6nEBtg<{*e`Bg8kf6|DOD3P?5+qYP?IO8jWn|$Yj-M(SG+AAje zcD;NfV5C{Iz}$*my4LyaTgzATFaC&dDSx?THFr|RgsaM@wI3IX{%xw~eJzr>bKa%g zWwP2_4FH@7WzoyVv7Ld@p+sT*C#qoi95W7Kai{OxvdU*~Mm-Tw2|-r4d-UN2)V z)0_WlYa;`v@!nT@Q_B)Ls5=cDi~uk+ Bqmuvt diff --git a/EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta2.jar b/EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta2.jar new file mode 100644 index 0000000000000000000000000000000000000000..abecd8bea32d336a7f861e95ba13e073f154d1fa GIT binary patch literal 3800 zcmbVP2{e>_7awcG*t3lxQq0(fghE-eWQOrt(~PBTNtVG-Lbht`5(&eIEG299h+a*$ zFeD*S$VeozSLmBLeQ(RWU!Bf(pYuG=f6lqT-#v5x_kZv2F*9ajW(NR(KtQ9vnh}6% zjI;;U*r+$kz)DvEVQQ$z1Tg!_u`-PDJ%s82rr!KNI-+z<5rzhqR&bQzGOD}F#8?6T zgwt3-mfYQ2WuY{%f1EN&VWcCY;=e^@rmnGmZvP7SqYw9gecb$9UA_IVPFVlnx(ol? z-Sw=ix4%;W?q4{Up5*+UOaOrT4gdi58yvzL>F9^>c5w}aJ9|3faH-Z_mVD;?p>PQh zC^~#3t|>iZ>3VS!hKF!FCb!23Js5SWg>z`o{uDav)4+-TPdd{BD@EK}g@te59g&Cx zcl-2CjN)$K-s8ykHaE8@kZ?#~_a0zN0zmq(kJDql+RSOcIFc9Fxj-MDgQFCso{4PG zy87P0z@({(Hl}QH!NG2ybjo5k0FCG>}yZPkTpgK+Tj}<(7%ynK%V3{2qi7u6pox2Io zd@yGibyq44Z1`6^!92|%wnnBY&#cU%wZb3Y>0=Xv$>_}AXSXmbp_c;#mm1=qFZ#~% zU4=VtQShydIXYhH92ZOTn-sUC${twG3x}xd$=@#+!FUf?alEayLk)R94UhsMo5&%i z#WO7K=4#7}2S6&0_z#ovtgFQW+06 zG{vq7rb9n^J-n5@5ZR=GtSC4?mmtV~RHK?uPVvg|Ep&8F*BUuoqt7>g-Ka4J08=9! z-w~epULjF+ns46H5SQgH-kesxT}RAJ-6L<8E2Ii^y43upr%+1WNU?^~ZCrvF^n8SY zIXT|tuWI&M>^+Vrv(@oU^*Y6M)8TRT`pE}8?6nUuHP#4i0Bu(QXIU{~XAfZ+KkU`T zi0i7hFkYJgBJjn+QrtV=F(EWN85rZla@z3=K4p)>a-hxaYo|$$46KMqsj`20@x4wvyp;_IhB`$`4*0tcwn zHAYP6GJaJ%{TdKlu zcHJ_-3FqwR?&M1Csno{$wWlT|dwJ~CQuotP7s5;tum^*ma8aQZK1@UM!x^>`m(PaFQ2^sA-y525)mz4KA9)!4{Es2iJP_XRxetu))pRY3^D_47o-v033K-X zCB3k<$IgVEF5g&uQqZ1O?_ByZxNF6i&5L{eg6MeC#G5?3*>B&kslBs}=#nz448 zqM%$89M?{&Q#l3a6#si>4`=ncjx#4YQI!a#(mDPNeyu);eRx81?uTi{o?ag#cKt-lLpysRG0Ra8In6x4_a;Tc;LX{qR)x`I+= z73vr$S2}hP`q24v1lfJNe80{6878UY@04F1`lN(1d#ffC$#5lV_p*y#ti%!o)~?2@TW4z7^bEpltXOxqfr7FL+4lzrZhzLIh?<#e z1vv4rsNTWkZJ>&Fzp#@N!FFW1T}K*%n|eFccG*@8C=Ij9*6I`#7H_ir+zdvuMb$yn z?RB9lO!fbFduc=Aa#EKmNr%H={UdvE@!nWz@gxDDpoF!3pV*PpyQE_XWc^*-+_{^Y zDQX2gEVHSuW6rPU9A=3nyrR!;O6wb&staz!UbkMfPOkp^lJ|=gPq2$j*)_Lhf_UT- z0dv{k?Sx%G%;Bz~j)eU}5ng(*o)K_-+v7t~UQdJih%39CEb|PK<5>rGj3)L4EV2mi z7~GfRj@EIIzF=lw41ITt5{&4DdU60Z$fpycC?Sg(IwkI7VR8MQ{fQL4E7!|S`u?lYz@5}3 z9r&Btr)Qy8`~UFdM=((9^j9qO+Mk}4Ug~^j#ZWWz2duOjrzfSKq~A%+Sbt6WKj$hv zHGSLtP8|yTW9t9Wgz4kZpa1W1?5PF(tGv+tg`eYm%@hkY0{{R!^ Date: Mon, 25 Jan 2016 18:05:18 +0100 Subject: [PATCH 129/288] annotation processor only generates a single index class (at least for now) --- .../EventBusAnnotationProcessor.java | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java index 51ffc232..36d006ca 100644 --- a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java @@ -34,10 +34,10 @@ @SupportedOptions("eventBusIndex") public class EventBusAnnotationProcessor extends AbstractProcessor { public static final String INFO_CLASS_POSTFIX = "_EventBusInfo"; + public static final String OPTION_EVENT_BUS_INDEX = "eventBusIndex"; /** Found subscriber methods for a class (without superclasses). */ private final Map> methodsByClass = new HashMap<>(); - private final Map infoByClass = new HashMap<>(); private final Set classesToSkip = new HashSet<>(); private boolean writerRoundDone; @@ -74,10 +74,14 @@ public boolean process(Set annotations, RoundEnvironment checkForSubscribersToSkip(messager); if (!methodsByClass.isEmpty()) { - createInfoFiles(); - String index = processingEnv.getOptions().get("eventBusIndex"); + // Nor now, we just use a single index and skip individual files: createInfoFiles(); + + String index = processingEnv.getOptions().get(OPTION_EVENT_BUS_INDEX); if (index != null) { createInfoIndexFile(index); + } else { + messager.printMessage(Diagnostic.Kind.ERROR, "No option " + OPTION_EVENT_BUS_INDEX + + " passed to annotation processor."); } } else { messager.printMessage(Diagnostic.Kind.WARNING, "No @Subscribe annotations found"); @@ -193,10 +197,9 @@ private TypeElement getSuperclass(TypeElement type) { } } + // Currently unused in favor of single index files private void createInfoFiles() { - List>> entries = new ArrayList<>(methodsByClass.entrySet()); - for (int i = 0; i < entries.size(); i++) { - Map.Entry> entry = entries.get(i); + for (Map.Entry> entry : methodsByClass.entrySet()) { TypeElement subscriberClass = entry.getKey(); if (classesToSkip.contains(subscriberClass)) { continue; @@ -209,8 +212,6 @@ private void createInfoFiles() { String subscriberClassName = getClassString(subscriberClass, myPackage); String infoClassName = getInfoClass(subscriberClass, myPackage); - infoByClass.put(subscriberClass, myPackage + "." + infoClassName); - JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(myPackage + '.' + infoClassName); writer = new BufferedWriter(sourceFile.openWriter()); writer.write("package " + myPackage + ";\n\n"); @@ -393,20 +394,22 @@ private void createInfoIndexFile(String index) { } private void writeIndexLines(BufferedWriter writer, String myPackage) throws IOException { - for (Map.Entry entry : infoByClass.entrySet()) { + for (Map.Entry> entry : methodsByClass.entrySet()) { TypeElement subscriberTypeElement = entry.getKey(); - if (!classesToSkip.contains(subscriberTypeElement)) { - String subscriberClass = getClassString(subscriberTypeElement, myPackage); - if (isVisible(myPackage, subscriberTypeElement)) { - writeLine(writer, 2, - "putIndex(new SimpleSubscriberInfo(" + subscriberClass + ".class,", - "true,", "new SubscriberMethodInfo[] {"); - List methods = methodsByClass.get(subscriberTypeElement); - writeCreateSubscriberMethods(writer, methods, "new SubscriberMethodInfo", myPackage); - writer.write(" }));\n\n"); - } else { - writer.write(" // Subscriber not visible to index: " + subscriberClass + "\n"); - } + if (classesToSkip.contains(subscriberTypeElement)) { + continue; + } + + String subscriberClass = getClassString(subscriberTypeElement, myPackage); + if (isVisible(myPackage, subscriberTypeElement)) { + writeLine(writer, 2, + "putIndex(new SimpleSubscriberInfo(" + subscriberClass + ".class,", + "true,", "new SubscriberMethodInfo[] {"); + List methods = methodsByClass.get(subscriberTypeElement); + writeCreateSubscriberMethods(writer, methods, "new SubscriberMethodInfo", myPackage); + writer.write(" }));\n\n"); + } else { + writer.write(" // Subscriber not visible to index: " + subscriberClass + "\n"); } } } From e96bb42a93edcd8ac2cf45c35015b0d540d8afa1 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 25 Jan 2016 18:08:18 +0100 Subject: [PATCH 130/288] annotation processor: removed now unused methods getNextValue and createInfoFiles --- .../EventBusAnnotationProcessor.java | 78 ------------------- 1 file changed, 78 deletions(-) diff --git a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java index 36d006ca..9985228d 100644 --- a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java @@ -197,84 +197,6 @@ private TypeElement getSuperclass(TypeElement type) { } } - // Currently unused in favor of single index files - private void createInfoFiles() { - for (Map.Entry> entry : methodsByClass.entrySet()) { - TypeElement subscriberClass = entry.getKey(); - if (classesToSkip.contains(subscriberClass)) { - continue; - } - - BufferedWriter writer = null; - try { - PackageElement packageElement = getPackageElement(subscriberClass); - String myPackage = packageElement.getQualifiedName().toString(); - String subscriberClassName = getClassString(subscriberClass, myPackage); - String infoClassName = getInfoClass(subscriberClass, myPackage); - - JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(myPackage + '.' + infoClassName); - writer = new BufferedWriter(sourceFile.openWriter()); - writer.write("package " + myPackage + ";\n\n"); - writer.write("import org.greenrobot.eventbus.meta.AbstractSubscriberInfo;\n"); - writer.write("import org.greenrobot.eventbus.SubscriberMethod;\n"); - writer.write("import org.greenrobot.eventbus.ThreadMode;\n\n"); - writer.write("/** This class is generated by EventBus, do not edit. */\n"); - writer.write("public class " + infoClassName + " extends AbstractSubscriberInfo {\n"); - writer.write(" public " + infoClassName + "() {\n"); - String infoSuperClass = getSuperclassInfoClass(subscriberClass, myPackage); - writeLine(writer, 2, "super(" + subscriberClassName + ".class,", infoSuperClass + ",", "/* TODO */ true);"); - writer.write(" }\n\n"); - writer.write(" public SubscriberMethod[] getSubscriberMethods() {\n"); - writer.write(" return new SubscriberMethod[] {\n"); - writeCreateSubscriberMethods(writer, entry.getValue(), "createSubscriberMethod", myPackage); - writer.write(" };\n"); - writer.write(" }\n}\n"); - } catch (IOException e) { - throw new RuntimeException("Could not write source for " + subscriberClass.getQualifiedName(), e); - } finally { - if (writer != null) { - try { - writer.close(); - } catch (IOException e) { - //Silent - } - } - } - } - } - - private String getSuperclassInfoClass(TypeElement subscriberClass, String myPackage) { - DeclaredType superclassType = (DeclaredType) subscriberClass.getSuperclass(); - if (superclassType != null) { - TypeElement superclass = (TypeElement) superclassType.asElement(); - if (methodsByClass.containsKey(superclass) && !classesToSkip.contains(superclass)) { - return getInfoClass(superclass, myPackage) + ".class"; - } - } - return "null"; - } - - private String getInfoClass(TypeElement subscriberClass, String myPackage) { - String subscriberClassName = getClassString(subscriberClass, myPackage); - return subscriberClassName.replace('.', '_') + INFO_CLASS_POSTFIX; - } - - private String getNextValue(String myPackage, TypeElement nextEntry) throws IOException { - String nextValue; - if (nextEntry != null) { - PackageElement nextPackageElement = getPackageElement(nextEntry); - String nextPackage = nextPackageElement.getQualifiedName().toString(); - String nextInfoClassName = getInfoClass(nextEntry, nextPackage); - if (!myPackage.equals(nextPackage)) { - nextInfoClassName = nextPackage + "." + nextInfoClassName; - } - nextValue = nextInfoClassName + ".class"; - } else { - nextValue = "null"; - } - return nextValue; - } - private String getClassString(TypeElement typeElement, String myPackage) { PackageElement packageElement = getPackageElement(typeElement); String packageString = packageElement.getQualifiedName().toString(); From 6372ee9bdf133fa50a92985b055170bc9e02ff21 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 27 Jan 2016 08:20:28 +0100 Subject: [PATCH 131/288] allow package protected classes along with index --- .../EventBusAnnotationProcessor.java | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java index 9985228d..018bffca 100644 --- a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java @@ -33,7 +33,6 @@ @SupportedAnnotationTypes("org.greenrobot.eventbus.Subscribe") @SupportedOptions("eventBusIndex") public class EventBusAnnotationProcessor extends AbstractProcessor { - public static final String INFO_CLASS_POSTFIX = "_EventBusInfo"; public static final String OPTION_EVENT_BUS_INDEX = "eventBusIndex"; /** Found subscriber methods for a class (without superclasses). */ @@ -52,6 +51,15 @@ public SourceVersion getSupportedSourceVersion() { public boolean process(Set annotations, RoundEnvironment env) { Messager messager = processingEnv.getMessager(); try { + String index = processingEnv.getOptions().get(OPTION_EVENT_BUS_INDEX); + if (index == null) { + messager.printMessage(Diagnostic.Kind.ERROR, "No option " + OPTION_EVENT_BUS_INDEX + + " passed to annotation processor"); + return false; + } + int lastPeriod = index.lastIndexOf('.'); + String indexPackage = lastPeriod != -1 ? index.substring(0, lastPeriod) : null; + round++; messager.printMessage(Diagnostic.Kind.NOTE, "Processing round " + round + ", new annotations: " + !annotations.isEmpty() + ", processingOver: " + env.processingOver()); @@ -71,18 +79,10 @@ public boolean process(Set annotations, RoundEnvironment "Unexpected processing state: annotations still available after writing."); } collectSubscribers(annotations, env, messager); - checkForSubscribersToSkip(messager); + checkForSubscribersToSkip(messager, indexPackage); if (!methodsByClass.isEmpty()) { - // Nor now, we just use a single index and skip individual files: createInfoFiles(); - - String index = processingEnv.getOptions().get(OPTION_EVENT_BUS_INDEX); - if (index != null) { - createInfoIndexFile(index); - } else { - messager.printMessage(Diagnostic.Kind.ERROR, "No option " + OPTION_EVENT_BUS_INDEX + - " passed to annotation processor."); - } + createInfoIndexFile(index); } else { messager.printMessage(Diagnostic.Kind.WARNING, "No @Subscribe annotations found"); } @@ -136,12 +136,12 @@ private boolean checkHasNoErrors(ExecutableElement element, Messager messager) { return true; } - private void checkForSubscribersToSkip(Messager messager) { + private void checkForSubscribersToSkip(Messager messager, String myPackage) { for (Map.Entry> entry : methodsByClass.entrySet()) { TypeElement skipCandidate = entry.getKey(); TypeElement subscriberClass = skipCandidate; while (subscriberClass != null) { - if (!subscriberClass.getModifiers().contains(Modifier.PUBLIC)) { + if (!isVisible(myPackage, subscriberClass)) { boolean added = classesToSkip.add(skipCandidate); if (added) { String msg; @@ -159,9 +159,8 @@ private void checkForSubscribersToSkip(Messager messager) { if (methods != null) { for (ExecutableElement method : methods) { VariableElement param = method.getParameters().get(0); - DeclaredType paramType = (DeclaredType) param.asType(); - Set eventClassModifiers = paramType.asElement().getModifiers(); - if (!eventClassModifiers.contains(Modifier.PUBLIC)) { + TypeElement eventTypeElement = (TypeElement) ((DeclaredType) param.asType()).asElement(); + if (!isVisible(myPackage, eventTypeElement)) { boolean added = classesToSkip.add(skipCandidate); if (added) { String msg; From e880e35e7f5a6ab2a4ec1074fed2c846342bf76b Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 27 Jan 2016 08:20:58 +0100 Subject: [PATCH 132/288] removed empty TODO comments from tests --- .../eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java | 1 - .../indexed/EventBusOrderedSubscriptionsTestWithIndex.java | 1 - .../indexed/EventBusRegistrationRacingTestWithIndex.java | 1 - .../eventbus/indexed/EventBusStickyEventTestWithIndex.java | 1 - .../indexed/EventBusSubscriberExceptionTestWithIndex.java | 1 - .../eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java | 1 - 6 files changed, 6 deletions(-) diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java index 937af651..3365157e 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java @@ -3,7 +3,6 @@ import org.greenrobot.eventbus.EventBusNoSubscriberEventTest; import org.junit.Before; -/** TODO */ public class EventBusNoSubscriberEventTestWithIndex extends EventBusNoSubscriberEventTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java index 71389239..68fdd9db 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java @@ -3,7 +3,6 @@ import org.greenrobot.eventbus.EventBusOrderedSubscriptionsTest; import org.junit.Before; -/** TODO */ public class EventBusOrderedSubscriptionsTestWithIndex extends EventBusOrderedSubscriptionsTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java index bbd40a9c..ecfb2cba 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java @@ -4,7 +4,6 @@ import org.greenrobot.eventbus.EventBusRegistrationRacingTest; -/** TODO */ public class EventBusRegistrationRacingTestWithIndex extends EventBusRegistrationRacingTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java index 6fab88f5..8a3f8b4b 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java @@ -3,7 +3,6 @@ import org.greenrobot.eventbus.EventBusStickyEventTest; import org.junit.Before; -/** TODO */ public class EventBusStickyEventTestWithIndex extends EventBusStickyEventTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java index 42bcce98..a1e91b07 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java @@ -4,7 +4,6 @@ import org.greenrobot.eventbus.EventBusSubscriberExceptionTest; -/** TODO */ public class EventBusSubscriberExceptionTestWithIndex extends EventBusSubscriberExceptionTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java index 27938dce..8a3d5967 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java @@ -5,7 +5,6 @@ import org.greenrobot.eventbus.InJarIndex; import org.junit.Before; -/** TODO */ public class EventBusSubscriberInJarTestWithIndex extends EventBusSubscriberInJarTest { @Before public void overwriteEventBus() throws Exception { From 8f9629eed5420dbea063cf54d2d7c9667518d9c7 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 29 Jan 2016 22:02:39 +0100 Subject: [PATCH 133/288] using ListMap, org.greenrobot:eventbus-annotation-processor:3.0.0-rc --- EventBusAnnotationProcessor/build.gradle | 5 +-- .../EventBusAnnotationProcessor.java | 36 +++++++++++-------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index f8bf0b07..ddb9d53d 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -3,8 +3,8 @@ apply plugin: 'maven' apply plugin: 'signing' archivesBaseName = 'eventbus-annotation-processor' -group = 'de.greenrobot' -version = '3.0.0-beta2' +group = 'org.greenrobot' +version = '3.0.0-rc' sourceCompatibility = 1.7 @@ -29,6 +29,7 @@ configurations { dependencies { compile project(':EventBus') + compile 'de.greenrobot:java-common:2.3.1' deployerJars 'org.apache.maven.wagon:wagon-webdav:1.0-beta-2' } diff --git a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java index 018bffca..8fc5888e 100644 --- a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java @@ -1,3 +1,18 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.greenrobot.eventbus.annotationprocessor; import org.greenrobot.eventbus.Subscribe; @@ -6,10 +21,8 @@ import java.io.BufferedWriter; import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; import javax.annotation.processing.AbstractProcessor; @@ -30,13 +43,15 @@ import javax.tools.Diagnostic; import javax.tools.JavaFileObject; +import de.greenrobot.common.ListMap; + @SupportedAnnotationTypes("org.greenrobot.eventbus.Subscribe") @SupportedOptions("eventBusIndex") public class EventBusAnnotationProcessor extends AbstractProcessor { public static final String OPTION_EVENT_BUS_INDEX = "eventBusIndex"; /** Found subscriber methods for a class (without superclasses). */ - private final Map> methodsByClass = new HashMap<>(); + private final ListMap methodsByClass = new ListMap<>(); private final Set classesToSkip = new HashSet<>(); private boolean writerRoundDone; @@ -102,13 +117,8 @@ private void collectSubscribers(Set annotations, RoundEnv if (element instanceof ExecutableElement) { ExecutableElement method = (ExecutableElement) element; if (checkHasNoErrors(method, messager)) { - Element classElement = method.getEnclosingElement(); - List methods = methodsByClass.get(classElement); - if (methods == null) { - methods = new ArrayList<>(); - methodsByClass.put((TypeElement) classElement, methods); - } - methods.add(method); + TypeElement classElement = (TypeElement) method.getEnclosingElement(); + methodsByClass.putElement(classElement, method); } } else { messager.printMessage(Diagnostic.Kind.ERROR, "@Subscribe is only valid for methods", element); @@ -137,8 +147,7 @@ private boolean checkHasNoErrors(ExecutableElement element, Messager messager) { } private void checkForSubscribersToSkip(Messager messager, String myPackage) { - for (Map.Entry> entry : methodsByClass.entrySet()) { - TypeElement skipCandidate = entry.getKey(); + for (TypeElement skipCandidate : methodsByClass.keySet()) { TypeElement subscriberClass = skipCandidate; while (subscriberClass != null) { if (!isVisible(myPackage, subscriberClass)) { @@ -315,8 +324,7 @@ private void createInfoIndexFile(String index) { } private void writeIndexLines(BufferedWriter writer, String myPackage) throws IOException { - for (Map.Entry> entry : methodsByClass.entrySet()) { - TypeElement subscriberTypeElement = entry.getKey(); + for (TypeElement subscriberTypeElement : methodsByClass.keySet()) { if (classesToSkip.contains(subscriberTypeElement)) { continue; } From d3398723b3089cac311ac2145d5b3242f19f05a4 Mon Sep 17 00:00:00 2001 From: Markus Date: Sat, 30 Jan 2016 09:34:06 +0100 Subject: [PATCH 134/288] updated copyright headers --- .../src/org/greenrobot/eventbus/AsyncPoster.java | 2 +- .../greenrobot/eventbus/BackgroundPoster.java | 2 +- .../src/org/greenrobot/eventbus/EventBus.java | 2 +- .../org/greenrobot/eventbus/EventBusBuilder.java | 2 +- .../greenrobot/eventbus/EventBusException.java | 2 +- .../org/greenrobot/eventbus/HandlerPoster.java | 2 +- .../greenrobot/eventbus/NoSubscriberEvent.java | 2 +- .../src/org/greenrobot/eventbus/PendingPost.java | 2 +- .../greenrobot/eventbus/PendingPostQueue.java | 16 ++++++++++++++++ .../src/org/greenrobot/eventbus/Subscribe.java | 16 ++++++++++++++++ .../eventbus/SubscriberExceptionEvent.java | 2 +- .../greenrobot/eventbus/SubscriberMethod.java | 2 +- .../eventbus/SubscriberMethodFinder.java | 2 +- .../org/greenrobot/eventbus/Subscription.java | 2 +- .../src/org/greenrobot/eventbus/ThreadMode.java | 2 +- .../eventbus/meta/AbstractSubscriberInfo.java | 2 +- .../eventbus/meta/SimpleSubscriberInfo.java | 2 +- .../greenrobot/eventbus/meta/SubscriberInfo.java | 2 +- .../eventbus/meta/SubscriberInfoIndex.java | 2 +- .../eventbus/meta/SubscriberMethodInfo.java | 2 +- .../greenrobot/eventbus/util/AsyncExecutor.java | 2 +- .../eventbus/util/ErrorDialogConfig.java | 16 ++++++++++++++++ .../util/ErrorDialogFragmentFactory.java | 16 ++++++++++++++++ .../eventbus/util/ErrorDialogFragments.java | 16 ++++++++++++++++ .../eventbus/util/ErrorDialogManager.java | 16 ++++++++++++++++ .../util/ExceptionToResourceMapping.java | 16 ++++++++++++++++ .../eventbus/util/HasExecutionScope.java | 16 ++++++++++++++++ .../eventbus/util/ThrowableFailureEvent.java | 2 +- .../src/org/greenrobot/eventbusperf/Test.java | 16 ++++++++++++++++ .../org/greenrobot/eventbusperf/TestEvent.java | 16 ++++++++++++++++ .../eventbusperf/TestFinishedEvent.java | 16 ++++++++++++++++ .../org/greenrobot/eventbusperf/TestParams.java | 16 ++++++++++++++++ .../org/greenrobot/eventbusperf/TestRunner.java | 16 ++++++++++++++++ .../eventbusperf/TestRunnerActivity.java | 16 ++++++++++++++++ .../eventbusperf/TestSetupActivity.java | 16 ++++++++++++++++ .../testsubject/PerfTestEventBus.java | 16 ++++++++++++++++ .../eventbusperf/testsubject/PerfTestOtto.java | 16 ++++++++++++++++ .../SubscribeClassEventBusDefault.java | 16 ++++++++++++++++ .../eventbus/AbstractEventBusTest.java | 2 +- .../greenrobot/eventbus/ClassMapPerfTest.java | 16 ++++++++++++++++ .../eventbus/EventBusBackgroundThreadTest.java | 2 +- .../greenrobot/eventbus/EventBusBasicTest.java | 2 +- .../greenrobot/eventbus/EventBusBuilderTest.java | 2 +- .../EventBusCancelEventDeliveryTest.java | 2 +- .../EventBusFallbackToReflectionTest.java | 16 ++++++++++++++++ .../eventbus/EventBusGenericsTest.java | 16 ++++++++++++++++ .../EventBusInheritanceDisabledTest.java | 2 +- .../eventbus/EventBusInheritanceTest.java | 2 +- .../eventbus/EventBusMainThreadRacingTest.java | 2 +- .../eventbus/EventBusMainThreadTest.java | 2 +- .../eventbus/EventBusMethodModifiersTest.java | 2 +- .../eventbus/EventBusMultithreadedTest.java | 2 +- .../eventbus/EventBusNoSubscriberEventTest.java | 2 +- .../EventBusOrderedSubscriptionsTest.java | 2 +- .../eventbus/EventBusRegistrationRacingTest.java | 2 +- .../eventbus/EventBusStickyEventTest.java | 2 +- .../EventBusSubscriberExceptionTest.java | 2 +- .../eventbus/EventBusSubscriberInJarTest.java | 16 ++++++++++++++++ .../eventbus/EventBusSubscriberLegalTest.java | 2 +- .../org/greenrobot/eventbus/IntTestEvent.java | 2 +- .../EventBusBackgroundThreadTestWithIndex.java | 16 ++++++++++++++++ .../indexed/EventBusBasicTestWithIndex.java | 16 ++++++++++++++++ ...EventBusCancelEventDeliveryTestWithIndex.java | 16 ++++++++++++++++ ...ventBusFallbackToReflectionTestWithIndex.java | 16 ++++++++++++++++ .../indexed/EventBusGenericsTestWithIndex.java | 16 ++++++++++++++++ ...EventBusInheritanceDisabledTestWithIndex.java | 16 ++++++++++++++++ .../EventBusInheritanceTestWithIndex.java | 16 ++++++++++++++++ .../EventBusMainThreadRacingTestWithIndex.java | 16 ++++++++++++++++ .../indexed/EventBusMainThreadTestWithIndex.java | 16 ++++++++++++++++ .../EventBusMethodModifiersTestWithIndex.java | 16 ++++++++++++++++ .../EventBusMultithreadedTestWithIndex.java | 16 ++++++++++++++++ .../EventBusNoSubscriberEventTestWithIndex.java | 16 ++++++++++++++++ ...ventBusOrderedSubscriptionsTestWithIndex.java | 16 ++++++++++++++++ .../EventBusRegistrationRacingTestWithIndex.java | 16 ++++++++++++++++ .../EventBusStickyEventTestWithIndex.java | 16 ++++++++++++++++ ...EventBusSubscriberExceptionTestWithIndex.java | 16 ++++++++++++++++ .../EventBusSubscriberInJarTestWithIndex.java | 16 ++++++++++++++++ .../org/greenrobot/eventbus/indexed/Indexed.java | 16 ++++++++++++++++ 78 files changed, 678 insertions(+), 38 deletions(-) diff --git a/EventBus/src/org/greenrobot/eventbus/AsyncPoster.java b/EventBus/src/org/greenrobot/eventbus/AsyncPoster.java index e3129dee..a56f4ebf 100644 --- a/EventBus/src/org/greenrobot/eventbus/AsyncPoster.java +++ b/EventBus/src/org/greenrobot/eventbus/AsyncPoster.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java b/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java index c23e1575..2a5319d0 100644 --- a/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java +++ b/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/EventBus.java b/EventBus/src/org/greenrobot/eventbus/EventBus.java index 3dd210b5..1cd57e32 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBus.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBus.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java index 9d003108..e212750e 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/EventBusException.java b/EventBus/src/org/greenrobot/eventbus/EventBusException.java index 9bbacf55..20d50e6b 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBusException.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBusException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java b/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java index 0571e1b2..3247be53 100644 --- a/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java +++ b/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/NoSubscriberEvent.java b/EventBus/src/org/greenrobot/eventbus/NoSubscriberEvent.java index 8a6d0c50..e4da4757 100644 --- a/EventBus/src/org/greenrobot/eventbus/NoSubscriberEvent.java +++ b/EventBus/src/org/greenrobot/eventbus/NoSubscriberEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/PendingPost.java b/EventBus/src/org/greenrobot/eventbus/PendingPost.java index e6c3bf4f..01f474c2 100644 --- a/EventBus/src/org/greenrobot/eventbus/PendingPost.java +++ b/EventBus/src/org/greenrobot/eventbus/PendingPost.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/PendingPostQueue.java b/EventBus/src/org/greenrobot/eventbus/PendingPostQueue.java index 048a841f..55db529a 100644 --- a/EventBus/src/org/greenrobot/eventbus/PendingPostQueue.java +++ b/EventBus/src/org/greenrobot/eventbus/PendingPostQueue.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus; final class PendingPostQueue { diff --git a/EventBus/src/org/greenrobot/eventbus/Subscribe.java b/EventBus/src/org/greenrobot/eventbus/Subscribe.java index b36496db..ed0b8c82 100644 --- a/EventBus/src/org/greenrobot/eventbus/Subscribe.java +++ b/EventBus/src/org/greenrobot/eventbus/Subscribe.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus; diff --git a/EventBus/src/org/greenrobot/eventbus/SubscriberExceptionEvent.java b/EventBus/src/org/greenrobot/eventbus/SubscriberExceptionEvent.java index 1302f777..ff69f05a 100644 --- a/EventBus/src/org/greenrobot/eventbus/SubscriberExceptionEvent.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberExceptionEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/SubscriberMethod.java b/EventBus/src/org/greenrobot/eventbus/SubscriberMethod.java index 5bd751c4..1d78d479 100644 --- a/EventBus/src/org/greenrobot/eventbus/SubscriberMethod.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java index 03974004..3cf28a42 100644 --- a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/Subscription.java b/EventBus/src/org/greenrobot/eventbus/Subscription.java index 1f529c92..cc0de1e3 100644 --- a/EventBus/src/org/greenrobot/eventbus/Subscription.java +++ b/EventBus/src/org/greenrobot/eventbus/Subscription.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/ThreadMode.java b/EventBus/src/org/greenrobot/eventbus/ThreadMode.java index 9292d4e9..79d5dc43 100644 --- a/EventBus/src/org/greenrobot/eventbus/ThreadMode.java +++ b/EventBus/src/org/greenrobot/eventbus/ThreadMode.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java index 9156ea25..75e309d2 100644 --- a/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/meta/SimpleSubscriberInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/SimpleSubscriberInfo.java index 957d058d..3ee4442d 100644 --- a/EventBus/src/org/greenrobot/eventbus/meta/SimpleSubscriberInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/SimpleSubscriberInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java index 7cd445a8..bd7cd5c0 100644 --- a/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfoIndex.java b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfoIndex.java index 5e27d4e8..9fc65f6f 100644 --- a/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfoIndex.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfoIndex.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/meta/SubscriberMethodInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberMethodInfo.java index 9d0782ed..2152554c 100644 --- a/EventBus/src/org/greenrobot/eventbus/meta/SubscriberMethodInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberMethodInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java b/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java index c1b49c1b..c44c1366 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java +++ b/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogConfig.java b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogConfig.java index 3378ba4d..95e84c72 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogConfig.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogConfig.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.util; import android.content.res.Resources; diff --git a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragmentFactory.java b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragmentFactory.java index ca6a8b4d..27ab963d 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragmentFactory.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragmentFactory.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.util; import android.annotation.TargetApi; diff --git a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragments.java b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragments.java index 79833b42..49174766 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragments.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragments.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.util; import android.annotation.TargetApi; diff --git a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogManager.java b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogManager.java index 34cb82da..9d5ccf2c 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogManager.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogManager.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.util; import android.annotation.TargetApi; diff --git a/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java b/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java index d45159b1..9ab0d006 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.util; import android.util.Log; diff --git a/EventBus/src/org/greenrobot/eventbus/util/HasExecutionScope.java b/EventBus/src/org/greenrobot/eventbus/util/HasExecutionScope.java index 67613b4d..fd20a0dc 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/HasExecutionScope.java +++ b/EventBus/src/org/greenrobot/eventbus/util/HasExecutionScope.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.util; public interface HasExecutionScope { diff --git a/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java b/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java index abc37db9..9b7b80b6 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/Test.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/Test.java index 35d20471..ee2d405d 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/Test.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/Test.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbusperf; import android.content.Context; diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestEvent.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestEvent.java index d0edba31..8db0db9f 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestEvent.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestEvent.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbusperf; /** Used by otto and EventBus */ diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestFinishedEvent.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestFinishedEvent.java index 7bc72ed8..9e1a5594 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestFinishedEvent.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestFinishedEvent.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbusperf; public class TestFinishedEvent { diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestParams.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestParams.java index 79af650a..85ee4f13 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestParams.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestParams.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbusperf; import org.greenrobot.eventbus.ThreadMode; diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunner.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunner.java index 3107289a..4c0f941f 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunner.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunner.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbusperf; import android.content.Context; diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunnerActivity.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunnerActivity.java index 9c718597..e22631c1 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunnerActivity.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunnerActivity.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbusperf; import android.app.Activity; diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestSetupActivity.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestSetupActivity.java index 0837bd4a..3488b8da 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestSetupActivity.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestSetupActivity.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbusperf; import android.app.Activity; diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestEventBus.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestEventBus.java index 5f43601a..7ceb8e6d 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestEventBus.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestEventBus.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbusperf.testsubject; import android.content.Context; diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestOtto.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestOtto.java index 1a9fb24c..646256ed 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestOtto.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestOtto.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbusperf.testsubject; import android.app.Activity; diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/SubscribeClassEventBusDefault.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/SubscribeClassEventBusDefault.java index 2244a0a3..54a11423 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/SubscribeClassEventBusDefault.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/SubscribeClassEventBusDefault.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbusperf.testsubject; import org.greenrobot.eventbus.Subscribe; diff --git a/EventBusTest/src/org/greenrobot/eventbus/AbstractEventBusTest.java b/EventBusTest/src/org/greenrobot/eventbus/AbstractEventBusTest.java index f313071a..867cada1 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/AbstractEventBusTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/AbstractEventBusTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/ClassMapPerfTest.java b/EventBusTest/src/org/greenrobot/eventbus/ClassMapPerfTest.java index 60f7a66c..6c1e9b51 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/ClassMapPerfTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/ClassMapPerfTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus; import java.util.HashMap; diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusBackgroundThreadTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusBackgroundThreadTest.java index 32ce3b3f..5a57f744 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusBackgroundThreadTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusBackgroundThreadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusBasicTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusBasicTest.java index f50c4108..d6af1eb4 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusBasicTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusBasicTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java index 354d78e2..42d919de 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java index 5c9966d6..869da70e 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java index ce102566..59e8d68c 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus; import org.junit.Test; diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java index 06db3002..2e218a37 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus; import org.junit.Test; diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java index 4a767204..80638e8b 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceTest.java index d4a4d0f7..f9619bed 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadRacingTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadRacingTest.java index 79fdfc92..a598220e 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadRacingTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadRacingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java index 55c6fc57..2195d10f 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusMethodModifiersTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMethodModifiersTest.java index 8eb00cf2..e974e73a 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusMethodModifiersTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMethodModifiersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusMultithreadedTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMultithreadedTest.java index eec9103b..f3e7bd50 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusMultithreadedTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMultithreadedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java index ad12d64f..b358f8c3 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java index 463f11bf..f6f97201 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java index c4f405ee..7d09d7ad 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java index be23b4ab..ec426745 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java index 2d227c94..f0dea680 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberInJarTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberInJarTest.java index 45c21a42..5b013eb9 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberInJarTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberInJarTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus; import junit.framework.Assert; diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java index c70a1e6b..c362e900 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/IntTestEvent.java b/EventBusTest/src/org/greenrobot/eventbus/IntTestEvent.java index 5874ae17..db6fa83f 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/IntTestEvent.java +++ b/EventBusTest/src/org/greenrobot/eventbus/IntTestEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBackgroundThreadTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBackgroundThreadTestWithIndex.java index 8771358a..00e38203 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBackgroundThreadTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBackgroundThreadTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBusBackgroundThreadTest; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBasicTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBasicTestWithIndex.java index d5e6d1fd..4237ce8e 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBasicTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBasicTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBusBasicTest; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusCancelEventDeliveryTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusCancelEventDeliveryTestWithIndex.java index 7c3d670c..76418689 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusCancelEventDeliveryTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusCancelEventDeliveryTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBusCancelEventDeliveryTest; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusFallbackToReflectionTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusFallbackToReflectionTestWithIndex.java index 74c2b44e..d6a2df27 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusFallbackToReflectionTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusFallbackToReflectionTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.junit.Before; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusGenericsTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusGenericsTestWithIndex.java index eeca3a92..ca74fdfa 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusGenericsTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusGenericsTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.junit.Before; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceDisabledTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceDisabledTestWithIndex.java index b0c85a0b..2443e9e1 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceDisabledTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceDisabledTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBus; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceTestWithIndex.java index 6d8963b6..151195a0 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBusInheritanceTest; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadRacingTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadRacingTestWithIndex.java index f6a90873..b73c2d85 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadRacingTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadRacingTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.junit.Before; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadTestWithIndex.java index 99248950..630d1d72 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.junit.Before; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMethodModifiersTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMethodModifiersTestWithIndex.java index 0a9d34ae..6034354f 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMethodModifiersTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMethodModifiersTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBusMethodModifiersTest; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMultithreadedTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMultithreadedTestWithIndex.java index b0c06a67..e56a8020 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMultithreadedTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMultithreadedTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBusMultithreadedTest; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java index 3365157e..20b0d08e 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBusNoSubscriberEventTest; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java index 68fdd9db..840e8bad 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBusOrderedSubscriptionsTest; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java index ecfb2cba..55c43bfa 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.junit.Before; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java index 8a3f8b4b..4e5c63d5 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBusStickyEventTest; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java index a1e91b07..2b9e3a17 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.junit.Before; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java index 8a3d5967..9df9c7dd 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBus; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java index f86e7872..1fcda4e3 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBus; From 0c224c4660f771100137cb5251caed1f68094dd2 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 1 Feb 2016 08:56:02 +0100 Subject: [PATCH 135/288] removed individual subscriberInfo look-ups via reflection --- .../eventbus/SubscriberMethodFinder.java | 41 +++---------------- .../eventbus/meta/AbstractSubscriberInfo.java | 11 ++++- .../eventbus/meta/SubscriberInfo.java | 2 +- 3 files changed, 15 insertions(+), 39 deletions(-) diff --git a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java index 3cf28a42..79c6addd 100644 --- a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java @@ -120,14 +120,10 @@ private FindState prepareFindState() { } private SubscriberInfo getSubscriberInfo(FindState findState) { - if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfoClass() != null) { - try { - SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfoClass().newInstance(); - if (findState.clazz == superclassInfo.getSubscriberClass()) { - return superclassInfo; - } - } catch (IllegalAccessException | InstantiationException e) { - throw new EventBusException(e); + if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) { + SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo(); + if (findState.clazz == superclassInfo.getSubscriberClass()) { + return superclassInfo; } } if (subscriberInfoIndexes != null) { @@ -138,36 +134,9 @@ private SubscriberInfo getSubscriberInfo(FindState findState) { } } } - String infoClass = getInfoClassName(findState); - try { - Class aClass = Class.forName(infoClass); - Object object = aClass.newInstance(); - if (object instanceof SubscriberInfo) { - return (SubscriberInfo) object; - } - } catch (ClassNotFoundException e) { - // TODO don't try again - } catch (Exception e) { - throw new EventBusException("Could not get infos for " + findState.clazz, e); - } return null; } - // A simple replace(char, char) is surprisingly slow, so we try to avoid it - private String getInfoClassName(FindState findState) { - String className = findState.clazz.getName(); - for (int i = className.length() - 1; i >= 0; i--) { - char c = className.charAt(i); - if (c == '.') { - break; - } else if (c == '$') { - className = className.replace('$', '_'); - break; - } - } - return className.concat("_EventBusInfo"); - } - private List findUsingReflection(Class subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); @@ -277,7 +246,7 @@ private boolean checkAddWithMethodSignature(Method method, Class eventType) { String methodKey = methodKeyBuilder.toString(); Class methodClass = method.getDeclaringClass(); - Class methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass); + Class methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass); if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) { // Only add if not already found in a sub class return true; diff --git a/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java index 75e309d2..b68de63a 100644 --- a/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java @@ -40,8 +40,15 @@ public Class getSubscriberClass() { } @Override - public Class getSuperSubscriberInfoClass() { - return superSubscriberInfoClass; + public SubscriberInfo getSuperSubscriberInfo() { + if(superSubscriberInfoClass == null) { + return null; + } + try { + return superSubscriberInfoClass.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e); + } } @Override diff --git a/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java index bd7cd5c0..83c1e741 100644 --- a/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java @@ -23,7 +23,7 @@ public interface SubscriberInfo { SubscriberMethod[] getSubscriberMethods(); - Class getSuperSubscriberInfoClass(); + SubscriberInfo getSuperSubscriberInfo(); boolean shouldCheckSuperclass(); } From 5871bd9c05e81e01ba6752cc3feaa9b2042cda4b Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 1 Feb 2016 09:10:31 +0100 Subject: [PATCH 136/288] added testManualIndexWithoutAnnotation --- .../eventbus/EventBusIndexTest.java | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 EventBusTest/src/org/greenrobot/eventbus/EventBusIndexTest.java diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusIndexTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusIndexTest.java new file mode 100644 index 00000000..d5acc814 --- /dev/null +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusIndexTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.greenrobot.eventbus; + +import org.greenrobot.eventbus.meta.SimpleSubscriberInfo; +import org.greenrobot.eventbus.meta.SubscriberInfo; +import org.greenrobot.eventbus.meta.SubscriberInfoIndex; +import org.greenrobot.eventbus.meta.SubscriberMethodInfo; +import org.junit.Assert; +import org.junit.Test; + +public class EventBusIndexTest { + private String value; + + @Test + /** Ensures the index is actually used and no reflection fall-back kicks in. */ + public void testManualIndexWithoutAnnotation() { + SubscriberInfoIndex index = new SubscriberInfoIndex() { + + @Override + public SubscriberInfo getSubscriberInfo(Class subscriberClass) { + Assert.assertEquals(EventBusIndexTest.class, subscriberClass); + SubscriberMethodInfo[] methodInfos = { + new SubscriberMethodInfo("someMethodWithoutAnnotation", String.class) + }; + return new SimpleSubscriberInfo(EventBusIndexTest.class, false, methodInfos); + } + }; + + EventBus eventBus = EventBus.builder().addIndex(index).build(); + eventBus.register(this); + eventBus.post("Yepp"); + eventBus.unregister(this); + Assert.assertEquals("Yepp", value); + } + + public void someMethodWithoutAnnotation(String value) { + this.value = value; + } +} From 245990474bf10b15850124fe856f81b20d5be946 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 1 Feb 2016 22:04:39 +0100 Subject: [PATCH 137/288] prepping v3.0.0 --- CHANGELOG.md | 6 ++--- COMPARISON.md | 2 ++ EventBus/build.gradle | 10 ++++---- EventBusAnnotationProcessor/build.gradle | 8 +++--- ...ventBusTestSubscriberInJar-3.0.0-beta2.jar | Bin 3800 -> 0 bytes .../EventBusTestSubscriberInJar-3.0.0.jar | Bin 0 -> 2761 bytes EventBusTestSubscriberInJar/build.gradle | 15 +++++++++--- README.md | 23 +++++++++--------- 8 files changed, 37 insertions(+), 27 deletions(-) delete mode 100644 EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta2.jar create mode 100644 EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0.jar diff --git a/CHANGELOG.md b/CHANGELOG.md index 413e86cf..7ddb539f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ -### V3.0.0 (201?-??-??) Annotations -* Breaking change: switch subscriber methods to annotations +### V3.0.0 (2016-02-??) Annotations +* Breaking change: switch subscriber method name conventions to annotations * Using annotations, each subscriber method can set sticky behavior and priority individually * Annotation processor indexes annotation information for efficient subscriber registration on Android -* TODO: Renamed package and artifact id to allow co-existence with libs using EventBus 2 internally +* Renamed package and artifact id to allow co-existence with libs using EventBus 2 internally **Note:** This is a breaking change release: there is no inter-op between EventBus versions 2 and 3; they can run in parallel though. diff --git a/COMPARISON.md b/COMPARISON.md index 31fadc03..2e0493cc 100644 --- a/COMPARISON.md +++ b/COMPARISON.md @@ -61,6 +61,8 @@ _**Note:** the following information is outdated, preprocessed annotations are m Besides features, performance is another differentiator. To compare performance, we created an Android application, which is also part of this repository (EventBusPerformance). You can also run the app on your phone to benchmark different scenarios. +TODO: Update for EventBus 3 with and without index. + Benchmark results indicate that EventBus is significantly faster in almost every scenario: diff --git a/EventBus/build.gradle b/EventBus/build.gradle index b1e8224f..a953f022 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -3,8 +3,8 @@ apply plugin: 'maven' apply plugin: 'signing' archivesBaseName = 'eventbus' -group = 'de.greenrobot' -version = '3.0.0-beta2' +group = 'org.greenrobot' +version = '3.0.0' sourceCompatibility = 1.7 def isSnapshot = version.endsWith('-SNAPSHOT') @@ -49,7 +49,7 @@ javadoc { failOnError = false classpath += configurations.provided title = "EventBus ${version} API" - options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2012-2015 greenrobot.de. All Rights Reserved.' + options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2012-2016 greenrobot.org. All Rights Reserved.' } task javadocJar(type: Jar, dependsOn: javadoc) { @@ -98,7 +98,7 @@ uploadArchives { name 'EventBus' packaging 'jar' description 'EventBus is a publish/subscribe event bus optimized for Android .' - url 'https://github.com/greenrobot/EventBus' + url 'http://greenrobot.org/eventbus/' scm { url 'https://github.com/greenrobot/EventBus' @@ -128,7 +128,7 @@ uploadArchives { organization { name 'greenrobot' - url 'http://greenrobot.de' + url 'http://greenrobot.org' } } } diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index ddb9d53d..d3434bb2 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -4,7 +4,7 @@ apply plugin: 'signing' archivesBaseName = 'eventbus-annotation-processor' group = 'org.greenrobot' -version = '3.0.0-rc' +version = '3.0.0' sourceCompatibility = 1.7 @@ -48,7 +48,7 @@ sourceSets { javadoc { classpath += configurations.provided title = "EventBus Annotation Processor ${version} API" - options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2015 greenrobot.de. All Rights Reserved.' + options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2015-2016 greenrobot.org. All Rights Reserved.' } task javadocJar(type: Jar, dependsOn: javadoc) { @@ -98,7 +98,7 @@ uploadArchives { name 'EventBus Annotation Processor' packaging 'jar' description 'Precompiler for EventBus Annotations.' - url 'https://github.com/greenrobot/EventBus' + url 'http://greenrobot.org/eventbus/' scm { url 'https://github.com/greenrobot/EventBus' @@ -128,7 +128,7 @@ uploadArchives { organization { name 'greenrobot' - url 'http://greenrobot.de' + url 'http://greenrobot.org' } } } diff --git a/EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta2.jar b/EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta2.jar deleted file mode 100644 index abecd8bea32d336a7f861e95ba13e073f154d1fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3800 zcmbVP2{e>_7awcG*t3lxQq0(fghE-eWQOrt(~PBTNtVG-Lbht`5(&eIEG299h+a*$ zFeD*S$VeozSLmBLeQ(RWU!Bf(pYuG=f6lqT-#v5x_kZv2F*9ajW(NR(KtQ9vnh}6% zjI;;U*r+$kz)DvEVQQ$z1Tg!_u`-PDJ%s82rr!KNI-+z<5rzhqR&bQzGOD}F#8?6T zgwt3-mfYQ2WuY{%f1EN&VWcCY;=e^@rmnGmZvP7SqYw9gecb$9UA_IVPFVlnx(ol? z-Sw=ix4%;W?q4{Up5*+UOaOrT4gdi58yvzL>F9^>c5w}aJ9|3faH-Z_mVD;?p>PQh zC^~#3t|>iZ>3VS!hKF!FCb!23Js5SWg>z`o{uDav)4+-TPdd{BD@EK}g@te59g&Cx zcl-2CjN)$K-s8ykHaE8@kZ?#~_a0zN0zmq(kJDql+RSOcIFc9Fxj-MDgQFCso{4PG zy87P0z@({(Hl}QH!NG2ybjo5k0FCG>}yZPkTpgK+Tj}<(7%ynK%V3{2qi7u6pox2Io zd@yGibyq44Z1`6^!92|%wnnBY&#cU%wZb3Y>0=Xv$>_}AXSXmbp_c;#mm1=qFZ#~% zU4=VtQShydIXYhH92ZOTn-sUC${twG3x}xd$=@#+!FUf?alEayLk)R94UhsMo5&%i z#WO7K=4#7}2S6&0_z#ovtgFQW+06 zG{vq7rb9n^J-n5@5ZR=GtSC4?mmtV~RHK?uPVvg|Ep&8F*BUuoqt7>g-Ka4J08=9! z-w~epULjF+ns46H5SQgH-kesxT}RAJ-6L<8E2Ii^y43upr%+1WNU?^~ZCrvF^n8SY zIXT|tuWI&M>^+Vrv(@oU^*Y6M)8TRT`pE}8?6nUuHP#4i0Bu(QXIU{~XAfZ+KkU`T zi0i7hFkYJgBJjn+QrtV=F(EWN85rZla@z3=K4p)>a-hxaYo|$$46KMqsj`20@x4wvyp;_IhB`$`4*0tcwn zHAYP6GJaJ%{TdKlu zcHJ_-3FqwR?&M1Csno{$wWlT|dwJ~CQuotP7s5;tum^*ma8aQZK1@UM!x^>`m(PaFQ2^sA-y525)mz4KA9)!4{Es2iJP_XRxetu))pRY3^D_47o-v033K-X zCB3k<$IgVEF5g&uQqZ1O?_ByZxNF6i&5L{eg6MeC#G5?3*>B&kslBs}=#nz448 zqM%$89M?{&Q#l3a6#si>4`=ncjx#4YQI!a#(mDPNeyu);eRx81?uTi{o?ag#cKt-lLpysRG0Ra8In6x4_a;Tc;LX{qR)x`I+= z73vr$S2}hP`q24v1lfJNe80{6878UY@04F1`lN(1d#ffC$#5lV_p*y#ti%!o)~?2@TW4z7^bEpltXOxqfr7FL+4lzrZhzLIh?<#e z1vv4rsNTWkZJ>&Fzp#@N!FFW1T}K*%n|eFccG*@8C=Ij9*6I`#7H_ir+zdvuMb$yn z?RB9lO!fbFduc=Aa#EKmNr%H={UdvE@!nWz@gxDDpoF!3pV*PpyQE_XWc^*-+_{^Y zDQX2gEVHSuW6rPU9A=3nyrR!;O6wb&staz!UbkMfPOkp^lJ|=gPq2$j*)_Lhf_UT- z0dv{k?Sx%G%;Bz~j)eU}5ng(*o)K_-+v7t~UQdJih%39CEb|PK<5>rGj3)L4EV2mi z7~GfRj@EIIzF=lw41ITt5{&4DdU60Z$fpycC?Sg(IwkI7VR8MQ{fQL4E7!|S`u?lYz@5}3 z9r&Btr)Qy8`~UFdM=((9^j9qO+Mk}4Ug~^j#ZWWz2duOjrzfSKq~A%+Sbt6WKj$hv zHGSLtP8|yTW9t9Wgz4kZpa1W1?5PF(tGv+tg`eYm%@hkY0{{R!^%jHO`Q^R&v*nNK0tB)C{?dC6r;D6^6Ow-q0k`(O8&EG90-}TGNe1 zuA`I~6-ukWzjPwxRL;An|LN5F*K@w_^ZwrN`#hh|=l4AC_x*jIj}ux%bS(%ZApxqW zM(zgzCCp!dk_2uC8w?VTar1-GW`A&a#R6 zo50}I6Woj&dHHW?)uS0=rRfDQ?wK5X!mk^~LxUgVX&qGuK5EoT`8zt4tPB#57I5@M z)$-cbEh%%%mk>M)USaRR(<3*9^4k4WkrE-IhLdC&s_OWioNMD#p>(#2szF6&OiFpFOE5o3Ktn<3ZeTxqf@KG1P}FU`kY?^F-# z_udzCtb4eiZagJhrYztAKHE3gZcaO=8nbO{5l(H~?V@{t5n-JvYgd=Fww-NtHf~3J zAElhS8qFlK9xaHPS+sur4(iJTP+jvcx(7UA8U>{7qI zWJos_c_^oU_lJJrOgirR&b0Z%3#Csp5DY|LT;mBF165r5=3yHrHO6Qy+BYU6q{Hw% zQ8cEKvHxyZr{gZtgY1wn-B@;ljZsT;zap#tg3f7-VK_y<+NPjKbIgQ_LUnr4ZZMNK zQznP#H^g3`66tTMc&$G5SoH1C2xQ}ALu^d#NZ@Y3w2U#Z(zOn%G-$EU($L1rSg5VK-a^6_(< zYR_LN@Db_>%~NNaocS$Ha*@m^^0y>+KnDHT(L1qImV+`+{ojB1)x9_O|$Wxjssx?QxQU{h`zd`4NNEoz^p=9bHi3Ahq05XI{oq^s4j8 z8JVE8P-5zBGvyF$YgYpoUVF+bH7{TGRG7yk!?GREHp}^akowj! zG&<#!8ihchtH24@`gbSmC@uu|n*WsxUp8xsCp8qwmqOl_5a zo>lPf+>X&#C2vevh5Zv@{p&HwiXxw!%B&sWM%qd2i==!rs<7*(TrvM~Xr8xirk+^+ znnU_?Rgjp?XJVgutkL9>Eq_@)YD~N#21D1%dxW9HmiJ&yi^d>ZmfUbvl#Ly&>)d%<3Yyezm^QyA%t)IO&!I5G_7!o9m)|^Ga%@+2Y2e}% z*H!M|jV+~I@GcVRl+T3<>v)n1m<3Gc-e6q~5nu=_fOykatWZd=3 z4bp1IO0STk6LkuuyI<}yK2(X9eoAdQ(LQ0^B!k!kDI2j(68d)PK5vKGp8-?P2Rs%2 zlc~E#`jY&@3BGv1Q~_uGY^s^(f{)1{rSGoNyNmS zTf?pJc+83BBg-7>S z+y=MJsp}|EsGe{G(F`!6GM*o-dJwwB)#m8pr&@{xz0pwXO7WsNI~FT-wC&bH({=}vx%>gf zZ2z#`tkkUBMhn)$GBmozB#D@BpRzw!5QQO61%fJoyOpTv-U3jm+xvLhJ;%;_* z6V0kn)gv+gZ0}3?4-P@j6uf!G;}R$@QEKbwPla@0h^$=)6?OKlw@hQHh;F)0qC$x~TtjLc82=L1QB@LQI@}FPg zh#*Zcj_|?!Vvu!!^$YE*a3ZL{NB^CC_!;DL@i&eFT7Dw=8H1llJ{O-+0JMC@SNY^; zWPU#RTzqmj&hq!mFG!L;(X4udQNoVg#V2xb>SRY9lzN7WPfGXFxA@7sc+f=2L< csPmd1i~e6*a6*d#6d @@ -19,13 +17,13 @@ EventBus... [![Build Status](https://travis-ci.org/greenrobot/EventBus.svg?branch=master)](https://travis-ci.org/greenrobot/EventBus) -Limitations of the SNAPSHOT version ------------------------------------ -The "subscriber index" is an optional optimization to speed up initial subscriber registration. The subscriber index is created during build time using an annotation processor. There are a couple of limitations of the current implementation: +Index and its Limitations +------------------------- +The "subscriber index" is a new feature of EventBus 3. It is an optional optimization to speed up initial subscriber registration. The subscriber index can be created during build time using EventBus' annotation processor. It is not required to use the index, but it's recommended on Android because of its poor reflection speed regarding annotations. + +Note that only those @Subscribers methods can be indexed for which the subscriber AND event class are public. Non-indexed methods have to be looked-up at runtime using reflection. - * Subscriber classes must be public - * Event classes must be public - * @Subscribe seems to be not recognized when inside of anonymous classes +Also, @Subscribe annotations are not recognized when inside of anonymous classes EventBus in 4 steps ------------------- @@ -47,16 +45,15 @@ Note: This SNAPSHOT version is only available on Sonatype's snapshot repository Gradle: ``` - compile 'de.greenrobot:eventbus:3.0.0-SNAPSHOT' - provided 'de.greenrobot:eventbus-annotation-processor:3.0.0-SNAPSHOT' + compile 'org.greenrobot:eventbus:3.0.0' ``` Maven: ``` - de.greenrobot + org.greenrobot eventbus - 3.0.0-SNAPSHOT + 3.0.0 ``` @@ -88,6 +85,8 @@ Release History, License ------------------------ [CHANGELOG](CHANGELOG.md) +Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + EventBus binaries and source code can be used according to the [Apache License, Version 2.0](LICENSE). More Open Source by greenrobot From 0ec23c3cd912efc7470e247fadc77a575d480c28 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 1 Feb 2016 22:12:32 +0100 Subject: [PATCH 138/288] pruning some old files --- EventBus/.classpath | 9 ----- EventBus/.project | 33 ----------------- EventBus/AndroidManifest.xml | 12 ------- EventBus/libs/android-support-v4.jar | Bin 385685 -> 0 bytes EventBus/mybuild.xml | 13 ------- EventBus/project.properties | 15 -------- EventBus/res/values/strings.xml | 2 -- EventBusPerformance/.classpath | 9 ----- EventBusPerformance/.project | 33 ----------------- .../.settings/org.eclipse.jdt.core.prefs | 4 --- EventBusTest/.classpath | 10 ------ EventBusTest/.project | 34 ------------------ EventBusTest/project.properties | 15 -------- 13 files changed, 189 deletions(-) delete mode 100644 EventBus/.classpath delete mode 100644 EventBus/.project delete mode 100644 EventBus/AndroidManifest.xml delete mode 100644 EventBus/libs/android-support-v4.jar delete mode 100644 EventBus/mybuild.xml delete mode 100644 EventBus/project.properties delete mode 100644 EventBus/res/values/strings.xml delete mode 100644 EventBusPerformance/.classpath delete mode 100644 EventBusPerformance/.project delete mode 100644 EventBusPerformance/.settings/org.eclipse.jdt.core.prefs delete mode 100644 EventBusTest/.classpath delete mode 100644 EventBusTest/.project delete mode 100644 EventBusTest/project.properties diff --git a/EventBus/.classpath b/EventBus/.classpath deleted file mode 100644 index 7bc01d9a..00000000 --- a/EventBus/.classpath +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/EventBus/.project b/EventBus/.project deleted file mode 100644 index 3321bf38..00000000 --- a/EventBus/.project +++ /dev/null @@ -1,33 +0,0 @@ - - - EventBus - - - - - - com.android.ide.eclipse.adt.ResourceManagerBuilder - - - - - com.android.ide.eclipse.adt.PreCompilerBuilder - - - - - org.eclipse.jdt.core.javabuilder - - - - - com.android.ide.eclipse.adt.ApkBuilder - - - - - - com.android.ide.eclipse.adt.AndroidNature - org.eclipse.jdt.core.javanature - - diff --git a/EventBus/AndroidManifest.xml b/EventBus/AndroidManifest.xml deleted file mode 100644 index 2ad17bbd..00000000 --- a/EventBus/AndroidManifest.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - diff --git a/EventBus/libs/android-support-v4.jar b/EventBus/libs/android-support-v4.jar deleted file mode 100644 index 6080877d4ade158f24ad7ccd9a10db2ac9060b47..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 385685 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

6HPQhY&mkuc_8%Q=4KIb)@wP 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%0A03X%h@VcJLH+gJm3sMzG=X1S%0K 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 - - - - - - - - - - - - diff --git a/EventBus/project.properties b/EventBus/project.properties deleted file mode 100644 index 484dab07..00000000 --- a/EventBus/project.properties +++ /dev/null @@ -1,15 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system edit -# "ant.properties", and override values to adapt the script to your -# project structure. -# -# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): -#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt - -# Project target. -target=android-17 -android.library=true diff --git a/EventBus/res/values/strings.xml b/EventBus/res/values/strings.xml deleted file mode 100644 index 85420055..00000000 --- a/EventBus/res/values/strings.xml +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/EventBusPerformance/.classpath b/EventBusPerformance/.classpath deleted file mode 100644 index 7bc01d9a..00000000 --- a/EventBusPerformance/.classpath +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/EventBusPerformance/.project b/EventBusPerformance/.project deleted file mode 100644 index b29334b1..00000000 --- a/EventBusPerformance/.project +++ /dev/null @@ -1,33 +0,0 @@ - - - EventBusPerformance - - - - - - com.android.ide.eclipse.adt.ResourceManagerBuilder - - - - - com.android.ide.eclipse.adt.PreCompilerBuilder - - - - - org.eclipse.jdt.core.javabuilder - - - - - com.android.ide.eclipse.adt.ApkBuilder - - - - - - com.android.ide.eclipse.adt.AndroidNature - org.eclipse.jdt.core.javanature - - diff --git a/EventBusPerformance/.settings/org.eclipse.jdt.core.prefs b/EventBusPerformance/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index f77b31c2..00000000 --- a/EventBusPerformance/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -org.eclipse.jdt.core.compiler.compliance=1.5 -org.eclipse.jdt.core.compiler.source=1.5 diff --git a/EventBusTest/.classpath b/EventBusTest/.classpath deleted file mode 100644 index 2b16fe8e..00000000 --- a/EventBusTest/.classpath +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/EventBusTest/.project b/EventBusTest/.project deleted file mode 100644 index 49b077d3..00000000 --- a/EventBusTest/.project +++ /dev/null @@ -1,34 +0,0 @@ - - - EventBusTest - - - greenBus - - - - com.android.ide.eclipse.adt.ResourceManagerBuilder - - - - - com.android.ide.eclipse.adt.PreCompilerBuilder - - - - - org.eclipse.jdt.core.javabuilder - - - - - com.android.ide.eclipse.adt.ApkBuilder - - - - - - com.android.ide.eclipse.adt.AndroidNature - org.eclipse.jdt.core.javanature - - diff --git a/EventBusTest/project.properties b/EventBusTest/project.properties deleted file mode 100644 index 4655e969..00000000 --- a/EventBusTest/project.properties +++ /dev/null @@ -1,15 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system edit -# "ant.properties", and override values to adapt the script to your -# project structure. -# -# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): -#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt - -# Project target. -target=android-17 -android.library.reference.1=../EventBus From b064e61d1c977981ed15f6e0728547454c38bf27 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 1 Feb 2016 22:24:42 +0100 Subject: [PATCH 139/288] upgraded to gradle wrapper 2.10 --- build.gradle | 6 +++++- gradle/wrapper/gradle-wrapper.jar | Bin 53637 -> 53636 bytes gradle/wrapper/gradle-wrapper.properties | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 760a32ad..c8d56ea1 100644 --- a/build.gradle +++ b/build.gradle @@ -4,4 +4,8 @@ if (JavaVersion.current().isJava8Compatible()) { options.addStringOption('Xdoclint:none', '-quiet') } } -} \ No newline at end of file +} + +task wrapper(type: Wrapper) { + gradleVersion = '2.10' +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 05ef575b0cd0173fc735f2857ce4bd594ce4f6bd..13372aef5e24af05341d49695ee84e5f9b594659 100644 GIT binary patch delta 1915 zcmZWp3rtg27(Tr%g+V)>*5Oroilt5{MV$^`3?}1IR^*{Ur+_d!WoV`YHzrWTU>FAF zh|y>=kq#EeEYQLRf+_MW6iQ`=88e3lP!}{pR5nNE&i${IRc~_h{pY*?_rK0L_h=Qj zsER98M00ue2-(>oNkhd+p`VaI#7M=N%^MIxi6=M4ySYjvcT4V{Avt#hJ^k+kR@vuIp}i zC|R>=Ufe#X;+Bx_{yD8wSMN?(*|`7PX5Mt|@_pj!@a#{Whj{_{{N(B7$)a`F&$~a; zncu6KOdArv@0G7EJfkW8yW{B7ocWr(C3P;-zg`;dRN>${^`YJIPkcD#U*+-lPCUuq z7^HKYU-Ynk?1Qt7F5;b|4^|I(%N!DVsA3knQRH zhHvh$4KU9Oo^!yMDZIftn@Y?qQ&svSn}t(;<+$Ldkm7_MpJ!Kcz%E*DB^ z($^h0Lm_mDZz-jqkB@1SNIR;z$cm0Oe8OfJ*M_oc|6hh!X0|zj^@(rATo+~@pWQx; zHj!C`lh*^`ShE*)*Sm$jdDLWzH;>x5)dAyBZroSb5NGLESl>ge(XV9AJHDq61axm- z1-Q9=Js@t61srSN2bgqC4p@C{D~BBA{zG8+TXtE?677V_v&#-aX+$W;k=#C#MYZ$psP>1)|hU9V^gw6^P^0PP))TuJDIfh9O$r zN-J3ro*H~Pe-lmRG{Cs(8XRBs7iJbs{7FXj4avCHN;;y2%12B~AuVT!=FoW2&_^(q z<@1z delta 1838 zcmZWpdrVVT7(cz`Q65DLqJ}XU z9KpfZA`x1%7A{oS z(vw_%l9X#^jS!EAZ2aYwd@-LuOo2}96^0O!S8hrXemI#wmCr$ohA;i(m1=h`14bW! zrxFIRFK3uR4WBBYfG9D$55z9>Mj$joo`VH2tL$#EjD#5z2XYRSsWwxsg-B#W41nePuJks=cDqn#U5?0gea zClmdXC4os2$%Vjxi-Ex@d0+DFIMyz8`HsSSnN8y3!rxWS-m1~Yaq)dczGL-RwPH+l z+obdf;`j5hl2v`guPgrg6ZidBayulpQM+g31j;?nE5oHNR8)=AcAHR_7^U~Js+@nG zJX~#cvB+SQ-VW}bZHtyhsq1-EjDSwW6b* z>q~d|s$b+z=0*yCbXgy=%JZn#wE3CV7KO)WiF9U4z&>$}(X3&gSo3T4w%ix#V{v&w zKTNAWh>+E3l*3D`4gcX&R+lRU)gTJ5PePzFj@X ztqYpT8#xzRQy=f`ck}s;#17f)|1OzSig%~I!zHLur5&M|1rAU=0AhK@91t2&)&q87 zlZ`oW)Q}_M!J?y3#D&GZ-632%rg0v7IzOs1N2r#MIVFxbufj$nD>`KkM$-pgu==OP zgOLOqa{q$VnBa>_IToFvT(xjd$6_4Rwnd z9DQ?|%jQyfc9K0hcz!z@Z&VY`+W1`RXPKE+IR$~ETX@exxd?SxAru0ED|*ba?SP}^ zr?wcbJ(HU*%y%@J%t93Ti4aa0aK|oMVfdTFwnqNuu$hh+hZ1rZ9wOeQU2Xaj@fmF} zGx2y#`!1kM`x?OH_Kkp5?J~fT_AdZauOiTz3a6&z|3pO zfLE?b0j;jHc8cpMu)lmg70_PCx=q)83VVYt{>aJlWP}ZF^<&cG^ zdVO(Hr-z7%_opZS?-&k3QZg$6X53U?0u5*c;`EQ*6nw7V(wo3+5fsv-1i%6nwSXN|< zTXn3oKIh{;HOWjxhH34*j$pI$FRV1ifYeB&4tuKvg)8eetM0>6A^ zDd?psotoTC=)$e+A=LiUBt8Fys#>(?3ce=|`Pt(2UY6p?-dDZsqp7dXLqpD+SuQznns#5lT*^dJ=T^z7xBKH){nX5}3mKM-iKQ_FDw0jC(TDgXcg diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c1823e9a..47511d78 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Nov 04 17:33:28 SGT 2015 +#Mon Feb 01 22:19:59 CET 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip From 07d28bcef371430d15e891275bc2e1d8ad7914a1 Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 2 Feb 2016 14:25:16 +0100 Subject: [PATCH 140/288] minor --- .../eventbus/SubscriberMethodFinder.java | 18 +++++++----------- README.md | 6 ++---- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java index 79c6addd..db5e0ad3 100644 --- a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java @@ -171,19 +171,15 @@ private void findUsingReflectionInSingleClass(FindState findState) { subscribeAnnotation.priority(), subscribeAnnotation.sticky())); } } - } else if (strictMethodVerification) { - if (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) { - if (method.isAnnotationPresent(Subscribe.class)) { + } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { String methodName = method.getDeclaringClass().getName() + "." + method.getName(); - throw new EventBusException(methodName + - " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); + 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(methodName + + " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); } } } diff --git a/README.md b/README.md index d5e6cca9..23fd66c1 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ EventBus... * avoids complex and error-prone dependencies and life cycle issues * makes your code simpler * is fast - * is tiny (<50k jar) + * is tiny (~50k jar) * is proven in practice by apps with 100,000,000+ installs * has advanced features like delivery threads, subscriber priorities, etc. @@ -41,8 +41,6 @@ Add EventBus to your project ---------------------------- EventBus is available on Maven Central. Please ensure that you are using the latest version by [checking here](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22de.greenrobot%22%20AND%20a%3A%22eventbus%22) -Note: This SNAPSHOT version is only available on Sonatype's snapshot repository (https://oss.sonatype.org/content/repositories/snapshots). - Gradle: ``` compile 'org.greenrobot:eventbus:3.0.0' @@ -79,7 +77,7 @@ FAQ **A:** Unlike Android's BroadcastReceiver/Intent system, EventBus uses standard Java classes as events and offers a more convenient API. EventBus is intended for a lot more uses cases where you wouldn't want to go through the hassle of setting up Intents, preparing Intent extras, implementing broadcast receivers, and extracting Intent extras again. Also, EventBus comes with a much lower overhead. **Q:** How to do pull requests?
-**A:** Ensure good code quality and consistent formatting. EventBus has a good test coverage: if you propose a new feature or fix a bug, please add a unit test. +**A:** Ensure good code quality and consistent formatting. EventBus has good test coverage: if you propose a new feature or fix a bug, please add a unit test. Release History, License ------------------------ From 89f8e970be607e646b756b6596de8424c2b0c96a Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 3 Feb 2016 18:39:21 +0100 Subject: [PATCH 141/288] added a test for subscribers having methods for public and private event classes --- .../EventBusAnnotationProcessor.java | 3 +++ .../EventBusFallbackToReflectionTest.java | 26 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java index 8fc5888e..78b2ab62 100644 --- a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java @@ -146,6 +146,9 @@ private boolean checkHasNoErrors(ExecutableElement element, Messager messager) { return true; } + /** + * Subscriber classes should be skipped if their class or any involved event class are not visible to the index. + */ private void checkForSubscribersToSkip(Messager messager, String myPackage) { for (TypeElement skipCandidate : methodsByClass.keySet()) { TypeElement subscriberClass = skipCandidate; diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java index 59e8d68c..4b884ef4 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java @@ -52,6 +52,18 @@ public void onEvent(PrivateEvent any) { } } + public class PublicClassWithPublicAndPrivateEvent { + @Subscribe + public void onEvent(String any) { + trackEvent(any); + } + + @Subscribe + public void onEvent(PrivateEvent any) { + trackEvent(any); + } + } + public class PublicWithPrivateEventInSuperclass extends PublicClassWithPrivateEvent { @Subscribe public void onEvent(Object any) { @@ -110,6 +122,20 @@ public void testSubscriberClassWithPrivateEvent() { assertEquals(1, eventsReceived.size()); } + @Test + public void testSubscriberClassWithPublicAndPrivateEvent() { + eventBus.register(new PublicClassWithPublicAndPrivateEvent()); + + eventBus.post("Hello"); + assertEquals("Hello", lastEvent); + assertEquals(1, eventsReceived.size()); + + PrivateEvent privateEvent = new PrivateEvent(); + eventBus.post(privateEvent); + assertEquals(privateEvent, lastEvent); + assertEquals(2, eventsReceived.size()); + } + @Test public void testSubscriberExtendingClassWithPrivateEvent() { eventBus.register(new PublicWithPrivateEventInSuperclass()); From a3045b448275c4251f08cbcc8f52bd67f7fe7a82 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 3 Feb 2016 19:04:50 +0100 Subject: [PATCH 142/288] Updated readme, removed embedded changelog, FAQ, and other redundant docs --- CHANGELOG.md | 78 ---------------------------------------------------- README.md | 29 ++++++------------- 2 files changed, 9 insertions(+), 98 deletions(-) delete mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 7ddb539f..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,78 +0,0 @@ -### V3.0.0 (2016-02-??) Annotations -* Breaking change: switch subscriber method name conventions to annotations -* Using annotations, each subscriber method can set sticky behavior and priority individually -* Annotation processor indexes annotation information for efficient subscriber registration on Android -* Renamed package and artifact id to allow co-existence with libs using EventBus 2 internally - -**Note:** This is a breaking change release: there is no inter-op between EventBus versions 2 and 3; they can run in parallel though. - -### V2.4.1 (2015-11-12) Bug fix release -* Registering for sticky events now considers sticky events of subclasses, not just the exact same event type. This makes the semantic consistent to posting events. Note, that this may lead to subscribers being called more than once if matching sticky events of event type subclasses are available. -* Workaround for an Android bug causing NoClassDefFoundError on some devices - -### V2.4.0 (2014-11-11) Clean up release -* Removed deprecated APIs: A year ago in Version 2.2.0, a couple of EventBus methods were deprecated and flagged to be removed in a future release. Well, version 2.4.0 is that release. Clean ups like this one keep the API concise and simple. - -**Note:** No new feature were added since 2.3.0. Use this release if you do not rely on deprecated APIs. - -### V2.3.0 (2014-11-11) Feature release: EventBusBuilder and performance fix -* New EventBusBuilder to configure EventBus instances (including the getDefault() instance, #124) -* Added configuration to disable "No subscribers registered for event" logs (EventBusBuilder, #107, #117) -* Added configuration to disable sending SubscriberExceptionEvent and NoSubscriberEvent (EventBusBuilder) -* Added configuration to fail when subscribers throw exceptions (EventBusBuilder, #55) -* Added configuration to use an existing thread pool (EventBusBuilder, #115) -* Added configuration to disable event inheritance improving performance for apps with high event rates (EventBusBuilder) -* Fixed performance regression sneaked into V2.2.x affecting (first time) registration of subscribers -* Updated to Gradle 2.1, using wrapper -* EventBusTest and EventBusPerformance use Gradle to build -* Added hasSubscriberForEvent to check if currently subscribers exist registered to a given event type -* Improved README.md and extracted an extended HOWTO.md and CHANGELOG.md from it -* Ignore compiler generated methods (#76) -* Various small code improvements (#120 among many others) - -**Note:** This is your last chance to use APIs that were deprecated in V2.2.0. It's recommended to switch to Version 2.4.0 (or above) at your earliest convenience. - -### V2.2.1 (2014-05-21) Bug fix release -* Fixed an issue with AsyncExecutor and execution scope - -### V2.2.0 (2013-11-18) Feature release, subscriber priority -* Register subscribers with a priority to to influence the order of event delivery (per delivery thread) -* Event delivery can be canceled by subscribers so subsequent subscribers will not receive the event -* Added "isRegistered" and "removeAllStickyEvents" methods -* Deprecated registration methods with custom method names and event class filters -* Starting with EventBus 2.2 we enforced methods to be public -* Fixed a race conditions with subscriber registration -* Fixed NoSubscriberEvent delivery after unregister - -### V2.1.0 (2013-11-15) Bug fix release, experimental util package -* Experimental: AsyncExecutor executes RunnableEx and wraps exceptions into FailureEvents -* Experimental: exception to UI mapping (for now based on dialogs) -* Fixed race condition with queued events that were delivered after subscription was unregistered. This is important for main thread events tied to application life cycle. -* Fixed typos and improved readme (#17, #22, #37, #39) -* Make getStickyEvent and removeStickyEvent generic (#45) -* Fixed bug in SubscriberMethod.equals() (#38) - -### V2.0.2 (2013-03-02) Bug fix release -* Fixed build dependencies, are "provided" now - -### V2.0.1 (2013-02-25) Bug fix release, Gradle and Maven Central -* Fixed #15: removeStickyEvent(...) does not remove event the first time -* Introduced Gradle build scripts for main project -* Maven artifacts are pushed to Maven Central starting with this version -* Added Travis CI - -### V2.0.0 (2012-10-23) Major feature release -* Event methods define for themselves in which thread they get called. This is done by providing "modifiers" to the method name, e.g. onEventMainThread is called by the main thread without further configuration. Have a look at the JavaDoc of the enum ThreadMode for all available thread modes. -* The event method modifiers replace registerForMainThread methods. Moving this information to the method itself should make things clearer. -* Using event method modifiers, subscribers can receive the same event type in different threads if they choose to. -* New "BackgroundThread" modifier for onEvent handler methods ensures that event handler methods are called in a background thread. If an event is posted from a non-main thread, handler methods will be called directly. If posted from the main thread, EventBus will use a background thread to call the handler methods. -* New "Async" modifier for onEvent handler methods ensures that each event handler method is called completely asynchronously. -* Better performance: Delivery of multiple events in the main thread got significantly faster. -* Added sticky events, which are inspired by sticky broadcasts of the Android system. EventBus keeps the most recent sticky events in memory. Subscribers registering with the new method registerSticky, will receive sticky events right away. You can also query and remove sticky events (methods getStickyEvent and removeStickyEvent). -* By listening to SubscriberExceptionEvent, it is possible to react to Exceptions occuring in subscribers. -* Bug fixes, and internal refactorings - -### V1.0.1 (2012-07-31): Important bug fix release -Please update! Now, EventBus.unregister releases all internal references to the subscriber. - -### V1.0.0 (2012-07-16): First public release diff --git a/README.md b/README.md index 23fd66c1..d273dff6 100644 --- a/README.md +++ b/README.md @@ -17,14 +17,6 @@ EventBus... [![Build Status](https://travis-ci.org/greenrobot/EventBus.svg?branch=master)](https://travis-ci.org/greenrobot/EventBus) -Index and its Limitations -------------------------- -The "subscriber index" is a new feature of EventBus 3. It is an optional optimization to speed up initial subscriber registration. The subscriber index can be created during build time using EventBus' annotation processor. It is not required to use the index, but it's recommended on Android because of its poor reflection speed regarding annotations. - -Note that only those @Subscribers methods can be indexed for which the subscriber AND event class are public. Non-indexed methods have to be looked-up at runtime using reflection. - -Also, @Subscribe annotations are not recognized when inside of anonymous classes - EventBus in 4 steps ------------------- 1. Define events:
@@ -39,7 +31,7 @@ EventBus in 4 steps Add EventBus to your project ---------------------------- -EventBus is available on Maven Central. Please ensure that you are using the latest version by [checking here](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22de.greenrobot%22%20AND%20a%3A%22eventbus%22) +EventBus is available on Maven Central. Please ensure that you are using the latest version by [checking here](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.greenrobot%22%20AND%20a%3A%22eventbus%22) Gradle: ``` @@ -61,28 +53,25 @@ How-to, Developer Documentation ------------------------------- Details on EventBus and its API are available in the [HOWTO document](HOWTO.md). -How does EventBus compare to other solutions, like Otto from Square? Check this [comparison](COMPARISON.md). - Additional Features and Notes ----------------------------- +Link: [Features](http://greenrobot.org/eventbus/features/) * **Based on annotations:** Event handling methods can be named however you want, and only need to be annotated with **@Subscribe**. * **Performance optimized:** It's probably the fastest event bus for Android. * **Convenience singleton:** You can get a process wide event bus instance by calling EventBus.getDefault(). You can still call new EventBus() to create any number of local busses. * **Subscriber and event inheritance:** Event handler methods may be defined in super classes, and events are posted to handlers of the event's super classes including any implemented interfaces. For example, subscriber may register to events of the type Object to receive all events posted on the event bus. -FAQ ---- -**Q:** How is EventBus different to Android's BroadcastReceiver/Intent system?
-**A:** Unlike Android's BroadcastReceiver/Intent system, EventBus uses standard Java classes as events and offers a more convenient API. EventBus is intended for a lot more uses cases where you wouldn't want to go through the hassle of setting up Intents, preparing Intent extras, implementing broadcast receivers, and extracting Intent extras again. Also, EventBus comes with a much lower overhead. +Links +----- +[CHANGELOG](http://greenrobot.org/eventbus/changelog/) -**Q:** How to do pull requests?
-**A:** Ensure good code quality and consistent formatting. EventBus has good test coverage: if you propose a new feature or fix a bug, please add a unit test. +[FAQ](http://greenrobot.org/eventbus/documentation/faq/) -Release History, License ------------------------- -[CHANGELOG](CHANGELOG.md) +How does EventBus compare to other solutions, like Otto from Square? Check this [comparison](COMPARISON.md). +License +------- Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) EventBus binaries and source code can be used according to the [Apache License, Version 2.0](LICENSE). From 8cba55264db6dd13d4aca72bb3cf360e3779eeea Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 3 Feb 2016 21:51:09 +0100 Subject: [PATCH 143/288] Updated readme --- README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d273dff6..e9688985 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ EventBus ======== -EventBus is publish/subscribe event bus optimized for Android.
+EventBus is a publish/subscribe event bus optimized for Android.
EventBus... @@ -17,21 +17,24 @@ EventBus... [![Build Status](https://travis-ci.org/greenrobot/EventBus.svg?branch=master)](https://travis-ci.org/greenrobot/EventBus) -EventBus in 4 steps +EventBus in 3 steps ------------------- 1. Define events:
public class MessageEvent { /* Additional fields if needed */ }

-2. Register your subscriber (in your onCreate or in a constructor):
+2. Prepare subscribers
+Register your subscriber (in your onCreate or in a constructor):
eventBus.register(this);

-3. Declare your subscribing method
+Declare your subscribing method:
@Subscribe
public void onEvent(AnyEventType event) {/* Do something */};

-4. Post events:
+3. Post events:
eventBus.post(event); +This [getting started guide](http://greenrobot.org/eventbus/documentation/how-to-get-started/) shows these 3 steps in more detail. + Add EventBus to your project ---------------------------- -EventBus is available on Maven Central. Please ensure that you are using the latest version by [checking here](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.greenrobot%22%20AND%20a%3A%22eventbus%22) +Please ensure that you are using the latest version by [checking here](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.greenrobot%22%20AND%20a%3A%22eventbus%22) Gradle: ``` From 875f4aa4b46a001e33d93d5d32e5ac9d9692f8e0 Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 4 Feb 2016 17:49:26 +0100 Subject: [PATCH 144/288] Updated readme, removed obsolete HOWTO.md --- HOWTO.md | 263 ------------------------------------------------------ README.md | 21 ++--- 2 files changed, 7 insertions(+), 277 deletions(-) delete mode 100644 HOWTO.md diff --git a/HOWTO.md b/HOWTO.md deleted file mode 100644 index d630f7a7..00000000 --- a/HOWTO.md +++ /dev/null @@ -1,263 +0,0 @@ -EventBus How-To -=============== -In the [README file](README.md), you got to know EventBus, and some of its basic principles. You also saw how to add EventBus to your project using Maven Central. Great, now let's dive deeper! - -General usage and API ---------------------- -Here we pick up on the 3 steps of the README and expand a bit on the code. -### 1: Define events ### -Events are POJO (plain old Java object) without any specific requirements. - -```java -public class MessageEvent { - public final String message; - - public MessageEvent(String message) { - this.message = message; - } -} -``` -### 2: Prepare subscribers ### - -Subscribers implement event handling methods that will be called when an event is received. These are defined with the ``@Subscribe`` annotation. They also need to register and unregister themselves to the bus. - -```java - @Override - public void onStart() { - super.onStart(); - EventBus.getDefault().register(this); - } - - @Override - public void onStop() { - EventBus.getDefault().unregister(this); - super.onStop(); - } - - // This method will be called when a MessageEvent is posted - @Subscribe - public void onMessageEvent(MessageEvent event){ - Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show(); - } - - // This method will be called when a SomeOtherEvent is posted - @Subscribe - public void onEvent(SomeOtherEvent event){ - doSomethingWith(event); - } - -``` -### 3: Post events ### -Post an event from any part of your code. All subscribers matching the event type will receive it. - -```java - EventBus.getDefault().post(new MessageEvent("Hello everyone!")); -``` - -Delivery threads and ThreadModes --------------------------------- -EventBus can handle threading for you: events can be posted in threads different from the posting thread. - -A common use case is dealing with UI changes. In Android, UI changes must be done in the UI (main) thread. On the other hand, networking, or any time consuming task, must not run on the main thread. EventBus helps you to deal with those tasks and synchronize with the UI thread (without having to delve into thread transitions, using AsyncTask, etc). - -In EventBus, you may define the thread that will call the event handling method `onEvent` by using a **ThreadMode**: -* **PostThread:** Subscriber will be called in the same thread, which is posting the event. This is the default. Event delivery implies the least overhead because it avoids thread switching completely. Thus this is the recommended mode for simple tasks that are known to complete is a very short time without requiring the main thread. Event handlers using this mode should return quickly to avoid blocking the posting thread, which may be the main thread. -Example: -```java - // Called in the same thread (default) - @Subscribe(threadMode = ThreadMode.PostThread) // ThreadMode is optional here - public void onEvent(MessageEvent event) { - log(event.message); - } -``` -* **MainThread:** Subscriber will be called in Android's main thread (sometimes referred to as UI thread). If the posting thread is the main thread, event handler methods will be called directly. Event handlers using this mode must return quickly to avoid blocking the main thread. -Example: -```java - // Called in Android UI's main thread - @Subscribe(threadMode = ThreadMode.MainThread) - public void onEventMainThread(MessageEvent event) { - textField.setText(event.message); - } -``` -* **BackgroundThread:** Subscriber will be called in a background thread. If posting thread is not the main thread, event handler methods will be called directly in the posting thread. If the posting thread is the main thread, EventBus uses a single background thread that will deliver all its events sequentially. Event handlers using this mode should try to return quickly to avoid blocking the background thread. -```java - // Called in the background thread - @Subscribe(threadMode = ThreadMode.BackgroundThread) - public void onEventBackgroundThread(MessageEvent event){ - saveToDisk(event.message); - } -``` -* **Async:** Event handler methods are called in a separate thread. This is always independent from the posting thread and the main thread. Posting events never wait for event handler methods using this mode. Event handler methods should use this mode if their execution might take some time, e.g. for network access. Avoid triggering a large number of long running asynchronous handler methods at the same time to limit the number of concurrent threads. EventBus uses a thread pool to efficiently reuse threads from completed asynchronous event handler notifications. -```java - // Called in a separate thread - @Subscribe(threadMode = ThreadMode.Async) - public void onEventAsync(MessageEvent event){ - backend.send(event.message); - } -``` - -*Note:* EventBus takes care of calling the `onEvent` method in the proper thread depending on its annotation. - -Subscriber priorities and ordered event delivery ------------------------------------------------- -You may change the order of event delivery by providing a priority to the subscriber during registration. - -```java - @Subscribe(priority = 1); - public void onEvent(MessageEvent event) { - ... - } -``` - -Within the same delivery thread (ThreadMode), higher priority subscribers will receive events before others with a lower priority. The default priority is 0. - -*Note*: the priority does *NOT* affect the order of delivery among subscribers with different [ThreadModes](#delivery-threads-and-threadmodes)! - -Configure EventBus using EventBusBuilder ----------------------------------------- -EventBus 2.3 added EventBusBuilder to configure various aspects of EventBus. For example, here's how to build an EventBus that keeps quiet in case a posted event has no subscribers: - -```java - EventBus eventBus = EventBus.builder().logNoSubscriberMessages(false).sendNoSubscriberEvent(false).build(); -``` - -Another example is to fail when a subscriber throws an exception. Note: by default, EventBus catches exceptions thrown from onEvent methods and sends a SubscriberExceptionEvent that may but do not have to be handled. - -```java - EventBus eventBus = EventBus.builder().throwSubscriberException(true).build(); -``` - -Check the EventBusBuilder class and its JavaDoc for all possible configuration possibilities. - -### Configure the default EventBus instance ### -Using EventBus.getDefault() is a simple way to get a shared EventBus instance. EventBusBuilder also allows to configure this default instance using the method installDefaultEventBus(). - -For example, it's possible to configure the default EventBus instance to rethrow exceptions, which occurred in onEvent methods. But let's to this only for DEBUG builds, because this will likely crash the app on exceptions: - -```java -EventBus.builder().throwSubscriberException(BuildConfig.DEBUG).installDefaultEventBus(); -``` - -Note: this can be done only once before the default EventBus instance is used the first time. This ensures consistent behavior in your app. Your Application class is a good place to configure the default EventBus instance before its used. - -Cancelling event delivery -------------------------- -You may cancel the event delivery process by calling `cancelEventDelivery(Object event)` from a subscriber's event handling method. -Any further event delivery will be cancelled: subsequent subscribers won't receive the event. -```java - // Called in the same thread (default) - @Subscribe - public void onEvent(MessageEvent event){ - // Process the event - ... - - EventBus.getDefault().cancelEventDelivery(event) ; - } -``` - -Events are usually cancelled by higher priority subscribers. Cancelling is restricted to event handling methods running in posting thread [ThreadMode.PostThread](#delivery-threads-and-threadmodes). - -Sticky Events -------------- -Some events carry information that is of interest after the event is posted. For example, this could be an event signalizing that some initialization is complete. Or if you have some sensor or location data and you want to hold on the most recent values. Instead of implementing your own caching, you can use sticky events. EventBus keeps the last sticky event of a certain type in memory. The sticky event can be delivered to subscribers or queried explicitly. Thus, you don't need any special logic to consider already available data. - -Let's say, a sticky event was posted some time ago: -```java - EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!")); -``` - -After that, a new Activity gets started. During registration, and sticky Subscriber methods will immediately get the previously posted sticky event: -```java - @Override - public void onStart() { - super.onStart(); - EventBus.getDefault().register(this); - } - - @Subscribe(sticky = true, threadMode = ThreadMode.MainThread) - public void onEvent(MessageEvent event) { - // UI updates must run on MainThread - textField.setText(event.message); - } - - @Override - public void onStop() { - EventBus.getDefault().unregister(this); - super.onStop(); - } -``` - -You may also get the last sticky event of a certain type with: -```java - EventBus.getDefault().getStickyEvent(Class eventType) -``` - -ProGuard configuration ----------------------- -ProGuard obfuscates method names and may remove "unused" methods, including Subscriber methods. Use the following snip in your ProGuard configuration file (proguard.cfg) to prevent Subscribers from being removed: - -``` --keepattributes *Annotation* --keepclassmembers class ** { - @de.greenrobot.event.Subscribe public *; -} - -# EventBus 3.0 annotation --keepclassmembers class * { - @de.greenrobot.event.Subscribe ; -} --keep enum de.greenrobot.event.ThreadMode { *; } - -# Only required if you use AsyncExecutor --keepclassmembers class * extends de.greenrobot.event.util.ThrowableFailureEvent { - (java.lang.Throwable); -} -``` - - -AsyncExecutor -------------- -_Disclaimer:_ AsyncExecutor is a non-core utility class. It might save you some code with error handling in background threads, but it's not a core EventBus class. - -AsyncExecutor is like a thread pool, but with failure handling. Failures are thrown exceptions, which get are wrapped inside an event, which is posted automatically by AsyncExecutor. - -Usually, you call AsyncExecutor.create() to create an instance and keep it in Application scope. To execute something, implement the RunnableEx interface and pass it to the execute method of the AsyncExecutor. Unlike Runnable, RunnableEx may throw an Exception. - -If the RunnableEx implementation throws an exception, it will be catched and wrapped into a ThrowableFailureEvent, which will be posted. - -Code example for execution: - -```java -AsyncExecutor.create().execute( - new RunnableEx { - public void run throws LoginException { - remote.login(); - EventBus.getDefault().postSticky(new LoggedInEvent()); - // No need to catch Exception - } - } -} -``` - -Code example for the receiving part: - -```java -public void onEventMainThread(LoggedInEvent event) { - // Change some UI -} - -public void onEventMainThread(ThrowableFailureEvent event) { - // Show error in UI -} -``` - -AsyncExecutor Builder ---------------------- -If you want to customize your AsyncExecutor instance, call the static method AsyncExecutor.builder(). It will return a builder which lets you customize the EventBus instance, the thread pool, and the class of the failure event. - -Another customization options is the execution scope, which gives failure events context information. For example, a failure event may be relevant only to a specific Activity instance or class. If your custom failure event class implements the HasExecutionScope interface, AsyncExecutor will set the execution scope automatically. Like this, your subscriber can query the failure event for its execution scope and react depending on it. - - -Comparison with Square's Otto ------------------------------ -Check the [COMPARISON.md](COMPARISON.md) \ No newline at end of file diff --git a/README.md b/README.md index e9688985..bcc0f4be 100644 --- a/README.md +++ b/README.md @@ -52,22 +52,15 @@ Maven: [Or download EventBus from Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22de.greenrobot%22%20AND%20a%3A%22eventbus%22) -How-to, Developer Documentation -------------------------------- -Details on EventBus and its API are available in the [HOWTO document](HOWTO.md). +Homepage, Documentation, Links +------------------------------ +For more details on EventBus please check [EventBus' website](http://greenrobot.org/eventbus). Here are some direct links you may find useful: -Additional Features and Notes ------------------------------ -Link: [Features](http://greenrobot.org/eventbus/features/) +[Features](http://greenrobot.org/eventbus/features/) -* **Based on annotations:** Event handling methods can be named however you want, and only need to be annotated with **@Subscribe**. -* **Performance optimized:** It's probably the fastest event bus for Android. -* **Convenience singleton:** You can get a process wide event bus instance by calling EventBus.getDefault(). You can still call new EventBus() to create any number of local busses. -* **Subscriber and event inheritance:** Event handler methods may be defined in super classes, and events are posted to handlers of the event's super classes including any implemented interfaces. For example, subscriber may register to events of the type Object to receive all events posted on the event bus. +[Documentation](http://greenrobot.org/eventbus/documentation/) -Links ------ -[CHANGELOG](http://greenrobot.org/eventbus/changelog/) +[Changelog](http://greenrobot.org/eventbus/changelog/) [FAQ](http://greenrobot.org/eventbus/documentation/faq/) @@ -85,4 +78,4 @@ More Open Source by greenrobot [__greenDAO__](https://github.com/greenrobot/greenDAO) is an ORM optimized for Android: it maps database tables to Java objects and uses code generation for optimal speed. -[Follow us on Google+](https://plus.google.com/b/114381455741141514652/+GreenrobotDe/posts) to stay up to date. \ No newline at end of file +[Follow us on Google+](https://plus.google.com/b/114381455741141514652/+GreenrobotDe/posts) or check our [homepage](http://greenrobot.org/) to stay up to date. \ No newline at end of file From 5b5aec0a2ab27540478265cc2986b2f8257bdef8 Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 4 Feb 2016 21:33:02 +0100 Subject: [PATCH 145/288] travis: build-tools-23.0.2, JavaDoc css --- .travis.yml | 2 +- EventBusPerformance/build.gradle | 2 +- EventBusTest/build.gradle | 2 +- javadoc-style/stylesheet.css | 574 +++++++++++++++++++++++++++++++ 4 files changed, 577 insertions(+), 3 deletions(-) create mode 100644 javadoc-style/stylesheet.css diff --git a/.travis.yml b/.travis.yml index 07706ece..977bf686 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ jdk: # http://docs.travis-ci.com/user/languages/android/ android: components: - - build-tools-23.0.1 + - build-tools-23.0.2 - android-10 before_script: diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 401b9afb..3d554a84 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -29,7 +29,7 @@ apt { } android { - buildToolsVersion '23.0.2' + buildToolsVersion '23.0.2' // When updating, don't forget to adjust .travis.yml compileSdkVersion 19 sourceSets { diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 8e1d3abd..990fb0c4 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -27,7 +27,7 @@ dependencies { } android { - buildToolsVersion '23.0.2' + buildToolsVersion '23.0.2' // When updating, don't forget to adjust .travis.yml compileSdkVersion 19 compileOptions { diff --git a/javadoc-style/stylesheet.css b/javadoc-style/stylesheet.css new file mode 100644 index 00000000..c12603af --- /dev/null +++ b/javadoc-style/stylesheet.css @@ -0,0 +1,574 @@ +/* Javadoc style sheet */ +/* +Overall document style +*/ + +@import url('resources/fonts/dejavu.css'); + +body { + background-color:#ffffff; + color:#353833; + font-family:'DejaVu Sans', Arial, Helvetica, sans-serif; + font-size:14px; + margin:0; +} +a:link, a:visited { + text-decoration:none; + color:#4A6782; +} +a:hover, a:focus { + text-decoration:none; + color:#bb7a2a; +} +a:active { + text-decoration:none; + color:#4A6782; +} +a[name] { + color:#353833; +} +a[name]:hover { + text-decoration:none; + color:#353833; +} +pre { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; +} +h1 { + font-size:20px; +} +h2 { + font-size:18px; +} +h3 { + font-size:16px; + font-style:italic; +} +h4 { + font-size:13px; +} +h5 { + font-size:12px; +} +h6 { + font-size:11px; +} +ul { + list-style-type:disc; +} +code, tt { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; + padding-top:4px; + margin-top:8px; + line-height:1.4em; +} +dt code { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; + padding-top:4px; +} +table tr td dt code { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; + vertical-align:top; + padding-top:4px; +} +sup { + font-size:8px; +} +/* +Document title and Copyright styles +*/ +.clear { + clear:both; + height:0px; + overflow:hidden; +} +.aboutLanguage { + float:right; + padding:0px 21px; + font-size:11px; + z-index:200; + margin-top:-9px; +} +.legalCopy { + margin-left:.5em; +} +.bar a, .bar a:link, .bar a:visited, .bar a:active { + color:#FFFFFF; + text-decoration:none; +} +.bar a:hover, .bar a:focus { + color:#bb7a2a; +} +.tab { + background-color:#0066FF; + color:#ffffff; + padding:8px; + width:5em; + font-weight:bold; +} +/* +Navigation bar styles +*/ +.bar { + background-color:#4D974D; + color:#FFFFFF; + padding:.8em .5em .4em .8em; + height:auto;/*height:1.8em;*/ + font-size:11px; + margin:0; +} +.topNav { + background-color:#4D974D; + color:#FFFFFF; + float:left; + padding:0; + width:100%; + clear:right; + height:2.8em; + padding-top:10px; + overflow:hidden; + font-size:12px; +} +.bottomNav { + margin-top:10px; + background-color:#4D974D; + color:#FFFFFF; + float:left; + padding:0; + width:100%; + clear:right; + height:2.8em; + padding-top:10px; + overflow:hidden; + font-size:12px; +} +.subNav { + background-color:#dee3e9; + float:left; + width:100%; + overflow:hidden; + font-size:12px; +} +.subNav div { + clear:left; + float:left; + padding:0 0 5px 6px; + text-transform:uppercase; +} +ul.navList, ul.subNavList { + float:left; + margin:0 25px 0 0; + padding:0; +} +ul.navList li{ + list-style:none; + float:left; + padding: 5px 6px; + text-transform:uppercase; +} +ul.subNavList li{ + list-style:none; + float:left; +} +.topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited { + color:#FFFFFF; + text-decoration:none; + text-transform:uppercase; +} +.topNav a:hover, .bottomNav a:hover { + text-decoration:none; + color:#bb7a2a; + text-transform:uppercase; +} +.navBarCell1Rev { + background-color:#F8981D; + color:#253441; + margin: auto 5px; +} +.skipNav { + position:absolute; + top:auto; + left:-9999px; + overflow:hidden; +} +/* +Page header and footer styles +*/ +.header, .footer { + clear:both; + margin:0 20px; + padding:5px 0 0 0; +} +.indexHeader { + margin:10px; + position:relative; +} +.indexHeader span{ + margin-right:15px; +} +.indexHeader h1 { + font-size:13px; +} +.title { + color:#2c4557; + margin:10px 0; +} +.subTitle { + margin:5px 0 0 0; +} +.header ul { + margin:0 0 15px 0; + padding:0; +} +.footer ul { + margin:20px 0 5px 0; +} +.header ul li, .footer ul li { + list-style:none; + font-size:13px; +} +/* +Heading styles +*/ +div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 { + background-color:#dee3e9; + border:1px solid #d0d9e0; + margin:0 0 6px -8px; + padding:7px 5px; +} +ul.blockList ul.blockList ul.blockList li.blockList h3 { + background-color:#dee3e9; + border:1px solid #d0d9e0; + margin:0 0 6px -8px; + padding:7px 5px; +} +ul.blockList ul.blockList li.blockList h3 { + padding:0; + margin:15px 0; +} +ul.blockList li.blockList h2 { + padding:0px 0 20px 0; +} +/* +Page layout container styles +*/ +.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer { + clear:both; + padding:10px 20px; + position:relative; +} +.indexContainer { + margin:10px; + position:relative; + font-size:12px; +} +.indexContainer h2 { + font-size:13px; + padding:0 0 3px 0; +} +.indexContainer ul { + margin:0; + padding:0; +} +.indexContainer ul li { + list-style:none; + padding-top:2px; +} +.contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt { + font-size:12px; + font-weight:bold; + margin:10px 0 0 0; + color:#4E4E4E; +} +.contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd { + margin:5px 0 10px 0px; + font-size:14px; + font-family:'DejaVu Sans Mono',monospace; +} +.serializedFormContainer dl.nameValue dt { + margin-left:1px; + font-size:1.1em; + display:inline; + font-weight:bold; +} +.serializedFormContainer dl.nameValue dd { + margin:0 0 0 1px; + font-size:1.1em; + display:inline; +} +/* +List styles +*/ +ul.horizontal li { + display:inline; + font-size:0.9em; +} +ul.inheritance { + margin:0; + padding:0; +} +ul.inheritance li { + display:inline; + list-style:none; +} +ul.inheritance li ul.inheritance { + margin-left:15px; + padding-left:15px; + padding-top:1px; +} +ul.blockList, ul.blockListLast { + margin:10px 0 10px 0; + padding:0; +} +ul.blockList li.blockList, ul.blockListLast li.blockList { + list-style:none; + margin-bottom:15px; + line-height:1.4; +} +ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList { + padding:0px 20px 5px 10px; + border:1px solid #ededed; + background-color:#f8f8f8; +} +ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList { + padding:0 0 5px 8px; + background-color:#ffffff; + border:none; +} +ul.blockList ul.blockList ul.blockList ul.blockList li.blockList { + margin-left:0; + padding-left:0; + padding-bottom:15px; + border:none; +} +ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast { + list-style:none; + border-bottom:none; + padding-bottom:0; +} +table tr td dl, table tr td dl dt, table tr td dl dd { + margin-top:0; + margin-bottom:1px; +} +/* +Table styles +*/ +.overviewSummary, .memberSummary, .typeSummary, .useSummary, .constantsSummary, .deprecatedSummary { + width:100%; + border-left:1px solid #EEE; + border-right:1px solid #EEE; + border-bottom:1px solid #EEE; +} +.overviewSummary, .memberSummary { + padding:0px; +} +.overviewSummary caption, .memberSummary caption, .typeSummary caption, +.useSummary caption, .constantsSummary caption, .deprecatedSummary caption { + position:relative; + text-align:left; + background-repeat:no-repeat; + color:#253441; + font-weight:bold; + clear:none; + overflow:hidden; + padding:0px; + padding-top:10px; + padding-left:1px; + margin:0px; + white-space:pre; +} +.overviewSummary caption a:link, .memberSummary caption a:link, .typeSummary caption a:link, +.useSummary caption a:link, .constantsSummary caption a:link, .deprecatedSummary caption a:link, +.overviewSummary caption a:hover, .memberSummary caption a:hover, .typeSummary caption a:hover, +.useSummary caption a:hover, .constantsSummary caption a:hover, .deprecatedSummary caption a:hover, +.overviewSummary caption a:active, .memberSummary caption a:active, .typeSummary caption a:active, +.useSummary caption a:active, .constantsSummary caption a:active, .deprecatedSummary caption a:active, +.overviewSummary caption a:visited, .memberSummary caption a:visited, .typeSummary caption a:visited, +.useSummary caption a:visited, .constantsSummary caption a:visited, .deprecatedSummary caption a:visited { + color:#FFFFFF; +} +.overviewSummary caption span, .memberSummary caption span, .typeSummary caption span, +.useSummary caption span, .constantsSummary caption span, .deprecatedSummary caption span { + white-space:nowrap; + padding-top:5px; + padding-left:12px; + padding-right:12px; + padding-bottom:7px; + display:inline-block; + float:left; + background-color:#F8981D; + border: none; + height:16px; +} +.memberSummary caption span.activeTableTab span { + white-space:nowrap; + padding-top:5px; + padding-left:12px; + padding-right:12px; + margin-right:3px; + display:inline-block; + float:left; + background-color:#F8981D; + height:16px; +} +.memberSummary caption span.tableTab span { + white-space:nowrap; + padding-top:5px; + padding-left:12px; + padding-right:12px; + margin-right:3px; + display:inline-block; + float:left; + background-color:#4D974D; + height:16px; +} +.memberSummary caption span.tableTab, .memberSummary caption span.activeTableTab { + padding-top:0px; + padding-left:0px; + padding-right:0px; + background-image:none; + float:none; + display:inline; +} +.overviewSummary .tabEnd, .memberSummary .tabEnd, .typeSummary .tabEnd, +.useSummary .tabEnd, .constantsSummary .tabEnd, .deprecatedSummary .tabEnd { + display:none; + width:5px; + position:relative; + float:left; + background-color:#F8981D; +} +.memberSummary .activeTableTab .tabEnd { + display:none; + width:5px; + margin-right:3px; + position:relative; + float:left; + background-color:#F8981D; +} +.memberSummary .tableTab .tabEnd { + display:none; + width:5px; + margin-right:3px; + position:relative; + background-color:#4D974D; + float:left; + +} +.overviewSummary td, .memberSummary td, .typeSummary td, +.useSummary td, .constantsSummary td, .deprecatedSummary td { + text-align:left; + padding:0px 0px 12px 10px; + width:100%; +} +th.colOne, th.colFirst, th.colLast, .useSummary th, .constantsSummary th, +td.colOne, td.colFirst, td.colLast, .useSummary td, .constantsSummary td{ + vertical-align:top; + padding-right:0px; + padding-top:8px; + padding-bottom:3px; +} +th.colFirst, th.colLast, th.colOne, .constantsSummary th { + background:#dee3e9; + text-align:left; + padding:8px 3px 3px 7px; +} +td.colFirst, th.colFirst { + white-space:nowrap; + font-size:13px; +} +td.colLast, th.colLast { + font-size:13px; +} +td.colOne, th.colOne { + font-size:13px; +} +.overviewSummary td.colFirst, .overviewSummary th.colFirst, +.overviewSummary td.colOne, .overviewSummary th.colOne, +.memberSummary td.colFirst, .memberSummary th.colFirst, +.memberSummary td.colOne, .memberSummary th.colOne, +.typeSummary td.colFirst{ + width:25%; + vertical-align:top; +} +td.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover { + font-weight:bold; +} +.tableSubHeadingColor { + background-color:#EEEEFF; +} +.altColor { + background-color:#FFFFFF; +} +.rowColor { + background-color:#EEEEEF; +} +/* +Content styles +*/ +.description pre { + margin-top:0; +} +.deprecatedContent { + margin:0; + padding:10px 0; +} +.docSummary { + padding:0; +} + +ul.blockList ul.blockList ul.blockList li.blockList h3 { + font-style:normal; +} + +div.block { + font-size:14px; + font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; +} + +td.colLast div { + padding-top:0px; +} + + +td.colLast a { + padding-bottom:3px; +} +/* +Formatting effect styles +*/ +.sourceLineNo { + color:green; + padding:0 30px 0 0; +} +h1.hidden { + visibility:hidden; + overflow:hidden; + font-size:10px; +} +.block { + display:block; + margin:3px 10px 2px 0px; + color:#474747; +} +.deprecatedLabel, .descfrmTypeLabel, .memberNameLabel, .memberNameLink, +.overrideSpecifyLabel, .packageHierarchyLabel, .paramLabel, .returnLabel, +.seeLabel, .simpleTagLabel, .throwsLabel, .typeNameLabel, .typeNameLink { + font-weight:bold; +} +.deprecationComment, .emphasizedPhrase, .interfaceName { + font-style:italic; +} + +div.block div.block span.deprecationComment, div.block div.block span.emphasizedPhrase, +div.block div.block span.interfaceName { + font-style:normal; +} + +div.contentContainer ul.blockList li.blockList h2{ + padding-bottom:0px; +} From dc11a2d7b1a85da5bb372633929f1b273eb469d2 Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 4 Feb 2016 21:42:24 +0100 Subject: [PATCH 146/288] travis: adding tools component --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 977bf686..54b0253c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ jdk: # http://docs.travis-ci.com/user/languages/android/ android: components: + - tools - build-tools-23.0.2 - android-10 From 4395b6612d44c4450742725162b9ae5956c23027 Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 4 Feb 2016 21:53:11 +0100 Subject: [PATCH 147/288] travis: adding extra-android-m2repository component --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 54b0253c..5f3aa2fd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ android: - tools - build-tools-23.0.2 - android-10 + - extra-android-m2repository before_script: - chmod +x gradlew From 39d2ec5a97fb901e955c63ac6d53d1b440a7a179 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 8 Feb 2016 20:11:05 +0100 Subject: [PATCH 148/288] EventBusAnnotationProcessor now skips fully generic event classes (#249) --- .../EventBusAnnotationProcessor.java | 26 +++++---- .../eventbus/EventBusGenericsTest.java | 54 +++++++++++++++++-- 2 files changed, 67 insertions(+), 13 deletions(-) diff --git a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java index 78b2ab62..3a9f76c4 100644 --- a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java @@ -171,18 +171,26 @@ private void checkForSubscribersToSkip(Messager messager, String myPackage) { if (methods != null) { for (ExecutableElement method : methods) { VariableElement param = method.getParameters().get(0); - TypeElement eventTypeElement = (TypeElement) ((DeclaredType) param.asType()).asElement(); - if (!isVisible(myPackage, eventTypeElement)) { + TypeMirror typeMirror = param.asType(); + String skipReason = null; + if (!(typeMirror instanceof DeclaredType) || + !(((DeclaredType) typeMirror).asElement() instanceof TypeElement)) { + skipReason = "event type is not a standard class e.g. generics"; + } + if (skipReason == null) { + TypeElement eventTypeElement = (TypeElement) ((DeclaredType) typeMirror).asElement(); + if (!isVisible(myPackage, eventTypeElement)) { + skipReason = "event type is not public"; + } + } + if (skipReason != null) { boolean added = classesToSkip.add(skipCandidate); if (added) { - String msg; - if (subscriberClass.equals(skipCandidate)) { - msg = "Falling back to reflection because event type is not public"; - } else { - msg = "Falling back to reflection because " + skipCandidate + - " has a super class using a non-public event type"; + String msg = "Falling back to reflection because " + skipReason; + if (!subscriberClass.equals(skipCandidate)) { + msg += " (found in super class for " + skipCandidate + ")"; } - messager.printMessage(Diagnostic.Kind.NOTE, msg, subscriberClass); + messager.printMessage(Diagnostic.Kind.NOTE, msg, method); } break; } diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java index 2e218a37..59f8a37b 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java @@ -23,20 +23,66 @@ public static class GenericEvent { T value; } - public class GenericSubscriber { + public class GenericEventSubscriber { @Subscribe public void onGenericEvent(GenericEvent event) { trackEvent(event); } } + public class FullGenericEventSubscriber { + @Subscribe + public void onGenericEvent(T event) { + trackEvent(event); + } + } + + public class GenericNumberEventSubscriber { + @Subscribe + public void onGenericEvent(T event) { + trackEvent(event); + } + } + + public class GenericFloatEventSubscriber extends GenericNumberEventSubscriber { + } + @Test public void testGenericEventAndSubscriber() { - GenericSubscriber genericSubscriber = new GenericSubscriber(); + GenericEventSubscriber genericSubscriber = new GenericEventSubscriber(); eventBus.register(genericSubscriber); eventBus.post(new GenericEvent()); - eventBus.unregister(genericSubscriber); - assertEventCount(1); } + + @Test + public void testGenericEventAndSubscriber_TypeErasure() { + FullGenericEventSubscriber genericSubscriber = new FullGenericEventSubscriber(); + eventBus.register(genericSubscriber); + eventBus.post(new IntTestEvent(42)); + eventBus.post("Type erasure!"); + assertEventCount(2); + } + + @Test + public void testGenericEventAndSubscriber_BaseType() { + GenericNumberEventSubscriber genericSubscriber = new GenericNumberEventSubscriber<>(); + eventBus.register(genericSubscriber); + eventBus.post(new Float(42)); + eventBus.post(new Double(23)); + assertEventCount(2); + eventBus.post("Not the same base type"); + assertEventCount(2); + } + + @Test + public void testGenericEventAndSubscriber_Subclass() { + GenericFloatEventSubscriber genericSubscriber = new GenericFloatEventSubscriber(); + eventBus.register(genericSubscriber); + eventBus.post(new Float(42)); + eventBus.post(new Double(77)); + assertEventCount(2); + eventBus.post("Not the same base type"); + assertEventCount(2); + } } From db043167c46b4fd07e5e0013d6bc68f218534c55 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 10 Feb 2016 18:37:45 +0100 Subject: [PATCH 149/288] EventBusAnnotationProcessor: uses upper bound type for generic event classes (#249), added verbose option --- .../EventBusAnnotationProcessor.java | 46 ++++++++++++++----- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java index 3a9f76c4..c37c18a5 100644 --- a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java @@ -40,15 +40,17 @@ import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeVariable; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; import de.greenrobot.common.ListMap; @SupportedAnnotationTypes("org.greenrobot.eventbus.Subscribe") -@SupportedOptions("eventBusIndex") +@SupportedOptions(value = {"eventBusIndex", "verbose"}) public class EventBusAnnotationProcessor extends AbstractProcessor { public static final String OPTION_EVENT_BUS_INDEX = "eventBusIndex"; + public static final String OPTION_VERBOSE = "verbose"; /** Found subscriber methods for a class (without superclasses). */ private final ListMap methodsByClass = new ListMap<>(); @@ -56,6 +58,7 @@ public class EventBusAnnotationProcessor extends AbstractProcessor { private boolean writerRoundDone; private int round; + private boolean verbose; @Override public SourceVersion getSupportedSourceVersion() { @@ -72,12 +75,15 @@ public boolean process(Set annotations, RoundEnvironment " passed to annotation processor"); return false; } + verbose = Boolean.parseBoolean(processingEnv.getOptions().get(OPTION_VERBOSE)); int lastPeriod = index.lastIndexOf('.'); String indexPackage = lastPeriod != -1 ? index.substring(0, lastPeriod) : null; round++; - messager.printMessage(Diagnostic.Kind.NOTE, "Processing round " + round + ", new annotations: " + - !annotations.isEmpty() + ", processingOver: " + env.processingOver()); + if (verbose) { + messager.printMessage(Diagnostic.Kind.NOTE, "Processing round " + round + ", new annotations: " + + !annotations.isEmpty() + ", processingOver: " + env.processingOver()); + } if (env.processingOver()) { if (!annotations.isEmpty()) { messager.printMessage(Diagnostic.Kind.ERROR, @@ -170,12 +176,12 @@ private void checkForSubscribersToSkip(Messager messager, String myPackage) { List methods = methodsByClass.get(subscriberClass); if (methods != null) { for (ExecutableElement method : methods) { - VariableElement param = method.getParameters().get(0); - TypeMirror typeMirror = param.asType(); String skipReason = null; + VariableElement param = method.getParameters().get(0); + TypeMirror typeMirror = getParamTypeMirror(param, messager); if (!(typeMirror instanceof DeclaredType) || !(((DeclaredType) typeMirror).asElement() instanceof TypeElement)) { - skipReason = "event type is not a standard class e.g. generics"; + skipReason = "event type cannot be processed"; } if (skipReason == null) { TypeElement eventTypeElement = (TypeElement) ((DeclaredType) typeMirror).asElement(); @@ -190,7 +196,7 @@ private void checkForSubscribersToSkip(Messager messager, String myPackage) { if (!subscriberClass.equals(skipCandidate)) { msg += " (found in super class for " + skipCandidate + ")"; } - messager.printMessage(Diagnostic.Kind.NOTE, msg, method); + messager.printMessage(Diagnostic.Kind.NOTE, msg, param); } break; } @@ -201,6 +207,22 @@ private void checkForSubscribersToSkip(Messager messager, String myPackage) { } } + private TypeMirror getParamTypeMirror(VariableElement param, Messager messager) { + TypeMirror typeMirror = param.asType(); + // Check for generic type + if (typeMirror instanceof TypeVariable) { + TypeMirror upperBound = ((TypeVariable) typeMirror).getUpperBound(); + if (upperBound instanceof DeclaredType) { + if (messager != null) { + messager.printMessage(Diagnostic.Kind.NOTE, "Using upper bound type " + upperBound + + " for generic parameter", param); + } + typeMirror = upperBound; + } + } + return typeMirror; + } + private TypeElement getSuperclass(TypeElement type) { if (type.getSuperclass().getKind() == TypeKind.DECLARED) { TypeElement superclass = (TypeElement) processingEnv.getTypeUtils().asElement(type.getSuperclass()); @@ -252,7 +274,7 @@ private void writeCreateSubscriberMethods(BufferedWriter writer, List parameters = method.getParameters(); - TypeMirror paramType = parameters.get(0).asType(); + TypeMirror paramType = getParamTypeMirror(parameters.get(0), null); TypeElement paramElement = (TypeElement) processingEnv.getTypeUtils().asElement(paramType); String methodName = method.getSimpleName().toString(); String eventClass = getClassString(paramElement, myPackage) + ".class"; @@ -276,9 +298,11 @@ private void writeCreateSubscriberMethods(BufferedWriter writer, List Date: Wed, 10 Feb 2016 21:52:43 +0100 Subject: [PATCH 150/288] eventbus-annotation-processor 3.0.1 --- EventBusAnnotationProcessor/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index d3434bb2..4dfa5eca 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -4,7 +4,7 @@ apply plugin: 'signing' archivesBaseName = 'eventbus-annotation-processor' group = 'org.greenrobot' -version = '3.0.0' +version = '3.0.1' sourceCompatibility = 1.7 From 513f466fee9eec849d4c6a900b7fc1bf6bdc8fba Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 12 Feb 2016 17:05:59 +0100 Subject: [PATCH 151/288] minor changes to CONTRIBUTING.md --- CONTRIBUTING.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8e7aee90..b656e1a5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,11 +3,12 @@ Before you create an Issue... There are better Places for Support ----------------------------------- -Please be aware that an issue tracker is not the best place to ask for support. An issue tracker is used to track issues (bugs or feature requests). +We want your question to be answered, so it is important that you ask at the right place. Be aware that an issue tracker is not the best place to ask for support. An issue tracker is used to track issues (bugs or feature requests). Instead, please use [stackoverflow.com](http://stackoverflow.com/questions/tagged/greenrobot-eventbus?sort=frequent) and use the tag [greenrobot-eventbus](http://stackoverflow.com/tags/greenrobot-eventbus/info) for your question. -If you want professional support, you can contact the main author and maintainer [Markus Junginger via Google+](https://plus.google.com/+MarkusJunginger/posts). -Examples for support questions better asked elsewhere: +If you want professional support, check http://greenrobot.org/contact-support/. + +Examples for support questions that are more likely to be answered on StackOverflow: * Asking how something works * Asking how to use EventBus in a specific scenario @@ -35,7 +36,7 @@ Requesting features: A Note on Pull Requests ======================= -Pull requests (and issue) may queue up up a bit. Usually, pull requests and issues are checked when new releases are planned. +Pull requests (and issues) may queue up up a bit. Usually, pull requests and issues are checked when new releases are planned. For bigger pull requests, it's a good idea to check with the maintainer upfront about the idea and the implementation outline. From 2fd3f58682673ac8796cd1c1ed4a421a87a2d3f8 Mon Sep 17 00:00:00 2001 From: greenrobot-team Date: Thu, 17 Mar 2016 11:52:14 +0100 Subject: [PATCH 152/288] make Android Studio and IntelliJ Idea happy --- EventBus/build.gradle | 7 +++++++ EventBus/settings.gradle | 1 - 2 files changed, 7 insertions(+), 1 deletion(-) delete mode 100644 EventBus/settings.gradle diff --git a/EventBus/build.gradle b/EventBus/build.gradle index a953f022..50637de7 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'java' apply plugin: 'maven' apply plugin: 'signing' +apply plugin: 'idea' archivesBaseName = 'eventbus' group = 'org.greenrobot' @@ -45,6 +46,12 @@ sourceSets { } } +idea { + module { + scopes.PROVIDED.plus += [configurations.provided] + } +} + javadoc { failOnError = false classpath += configurations.provided diff --git a/EventBus/settings.gradle b/EventBus/settings.gradle deleted file mode 100644 index 4d211e40..00000000 --- a/EventBus/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'eventbus' \ No newline at end of file From c418ad982602b3888af3ff8af17dcb14b536571c Mon Sep 17 00:00:00 2001 From: Markus Date: Sun, 17 Apr 2016 21:12:52 +0200 Subject: [PATCH 153/288] com.android.tools.build:gradle:2.0.0 --- EventBusPerformance/build.gradle | 2 +- EventBusTest/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 3d554a84..28de4ac5 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:1.5.0' + classpath 'com.android.tools.build:gradle:2.0.0' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 990fb0c4..bc806f91 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:1.5.0' + classpath 'com.android.tools.build:gradle:2.0.0' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } From 13846f362bbe3b5fb0491afdc9ea011c10a1eee6 Mon Sep 17 00:00:00 2001 From: chthai64 Date: Tue, 3 May 2016 14:38:01 -0400 Subject: [PATCH 154/288] com.android.tools.build:gradle:2.1.0 --- EventBusPerformance/build.gradle | 2 +- EventBusTest/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 28de4ac5..fa9029dc 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:2.0.0' + classpath 'com.android.tools.build:gradle:2.1.0' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index bc806f91..bb877369 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:2.0.0' + classpath 'com.android.tools.build:gradle:2.1.0' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } From d16add527620cb6fc0715c3824b31ffccc124f7b Mon Sep 17 00:00:00 2001 From: Frieder Bluemle Date: Mon, 29 Feb 2016 16:06:25 +0700 Subject: [PATCH 155/288] Update Gradle wrapper to 2.14 --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 53636 -> 53319 bytes gradle/wrapper/gradle-wrapper.properties | 4 +- gradlew | 46 ++++++++++++----------- gradlew.bat | 8 ++-- 5 files changed, 32 insertions(+), 28 deletions(-) diff --git a/build.gradle b/build.gradle index c8d56ea1..d0f0925f 100644 --- a/build.gradle +++ b/build.gradle @@ -7,5 +7,5 @@ if (JavaVersion.current().isJava8Compatible()) { } task wrapper(type: Wrapper) { - gradleVersion = '2.10' + gradleVersion = '2.14' } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 13372aef5e24af05341d49695ee84e5f9b594659..d3b83982b9b1bccad955349d702be9b884c6e049 100644 GIT binary patch delta 5470 zcmaJ_2{=@3`yYcS`!be^#=h?%YbyI1l6^OpvSbU9CKTD@Buj{pP{a&MB*s`KYh_7x zlBGl?>&yR`@zyurcU}K;UFSOYx##!0x9558^E`8_h`ghKoZi%soZ=V+LQM@(Gw9Vz zqZd4S@MJ&9QF;lV#HVlU{FEo62~RpT%owwpqVaxvMcM`woY80OEFjIdzE@WWXg0VMQ-Sp zO`7n{4dIbBzel|zBfix(*AAQPZSSONkTu@961jjYjuu5M$t+^88i{AEweTlj*(z|h zG~qLURXF8~q6|7VAL-Rv%xPBpRu7&UQ&b({o!~HUvV@nQtFd8X&?_IZ+$oxobHZ_gB zv5iOjfRU%Rq5IXS?W0)vTyJRQn>PtJBk-dIwby!O)=^#|-VXJdwd?n!Vr&8=Yae}# z&1Fya6TXC`i2Wj=%49Gys$;<5`^i@2*{8x0zxIK8Hs3^+j{cMA9R2zp)=`#*3yUx% zgh;Wsbs;BzNgUO&_fOr5&;7K`S#FH&a$6X^f3unPxa@nI(kVV8nd)AC6w)PJxU!TR zE4LUl{yr4NsfT9yC^;UCSGKjD{4h&zcC}qQDkc3N{uDp&6hS~E<22sJ&sg)?C^T8S zO$vSA$npd>Q%ZS#k$FS*xXYr*Y{aR55MPQulL?n6+WWq2zey*{?{e8>$RladGbnN< z>vdK}?QD3|o%~V@HIdBn7kAhxY*RO~2j%ovN_Z+=QRMcMW{F3mDoZVFbs8)9qKc1c zw)<6?1xBsRwq@2lcJo;j?5)IKF!o6P5bH-{pH=7kc4gdT$>R$Co#Mi>dZpcWhxx#Z zIH48&H1lf83qr^;y;*+Bx&&G-N*mZlVZ}&0y|m8!oq~dB2N+_O1@>^}B<$gARD$$s zNpzLPbyV^diX-PI%%PGQnbv0{OOk#4SgXW8?J6#tUL!*;zYRK;s~nQ?J3}jMMpT?X zrYqRURTnzA;aY&V5Kyp>lCJxNUUlpc%L-G44xZsV;*B(QwJ{kTs{8uj`ri82y{wha z+02QsoH?wu$K5L9>cx+V?yKn?1Kzrpp^tSq^a!7VO`zahywpDoJG$8l8BIs*d%b!5OWJ?1 zP`3S4>O;ug%uEbNbkO7uw)9oqWg!17XnT%}QnzpFbldl9dK&JL6AQXG%_Si+H_xWf zakR>y%>F0$R94K6ZdmLIM60IeKfAp56m)*;#OVflO%2ymT^*Bz zHSctt2rr5=9i|`9`c+mp&t=Q;NFlB+EfS-_*;_aZ$%780k>|37-CDM2plBbz5lZhl zx~m+l(YiV?_mV5TUHt|_?ZbZMxs5po&qeh&$|!crjXhL*xQ~}Bw+p@6% z^6&T=5ZbDrZNdWRd*-S$Xt%qZ5H`zSJnvvAlvB)(3ro5%qZ61$FsFHn7&zCd_FT3o ztEQ}y=JoAeF{gu>VRKS0zZgTaM>T_4KI(@1HYQ}Q%83s8$B64L3f5v$0)EYS+P8R1 z+!jVm1`W#?%9u%*w1j4i)?O!bD*dhF81d7Iv=5?H*ixZP2mQ-+^OE?&5eNiM4}k~) zX%uY0DhC_N>G&|yzLcJ=%~M|qH&tgncOw>FvhwkEU*nnk;&sdv_r!4~=h!f8%Xczr zUey#@g}*fZF0THrVIvY4N*n7x|1)C$N!{c}2g8CpLR)9Q_eA8J`kD8=`$7HwUf=RQ z)SrGoX<98w^Im0#=^LG-bWtoFXTFu$y>G@g)?x;-Z7AnX6Psf8N6+0uTurC(A=VXGm|JQuxifg z#Qa(M?J7+6*TuBgY`9_fJssA`q!~Ne>&GXVzDVn?jf=b%7Iv~+i-c*I`uj9sD%pjN zJ8FAs6TDIPB`9r&YG@-KJyA`W7E!u-?S@Za_~omYTrS^O$NTtQzUmTiS~bY#?Dg%~ z8yEUmuU6c(DIlwmDW6)^>I$?U56oP5#hLme{cik@FN?=*m+@2D^|2=lc08}Tr>KoR z<#t~#^?`Pb5MOG}{Y6Lf{(LTbOU4|L&t)OOqnM;@JZe72MS96wTXUCY(|uggo!cjN zj1G9RQ)(E(JNpVhRcT&8x+K<7ah_kNdJH$^$dp za}GD89U8nU*+kzM??3GmSp}n%?7;*-;c0lR+MXn(rSnsMIgvZ0tWCxTRf0#@Q@*>1 ze(J2aHIMq*6r*H^bbK~~6K_DDjpy2arzzQpQM(@Y-k+<<*(iq+8vy&YWsp+sSZy4t z3Vhl*wT|`vRB7S)sWyP}n44O4$I^$P1~dB2c%^(Ap&>;@!&Av+lEcrrQs?h}t}ePu zCurCk-My2$PSq)i?UCs5WT3WLu&+s6=X+gcJnN2n>~JoeyXz;MAyu?nE9e;YFD+&zj{p^);uH=V>7WdHpee^ zqi7mcznPaX>Agw5_hkC~COTS*VMM6My}jq$P+)R&!FHlZ(o9vfmu|}%TefBY`;ojV z>&lmxzHXsIA6babvsiW+`#hInd3>?*#nEPYownZ>XC-B?F!FyvF^SBdyQbM`4Iyb=aS}3Zm z><(ykZb{=ELFt?{m2D=8h=oscf(&<08~TdYR|fC;z{peAC(bH00e;_~&5YAI&N#}S zm%H#DlgmGg&fmXQ*=`U8*oACx>BHfLBs6Ffxmo=tLQuANOX+cj590P>Q-(SEK=N!;o36F6;{bBSYA0gC>)f{d@;YaD z7j*qF0v4}`lypMltd{- z2}VPdN;Q8UBT9uPV~0nAsEbDqj|quZ7SwbHAJ^I2{Z1z!5C|9W)k#cITm;`|U@RqC zXDn@C)TKXY+}kxLCe|a~)ool$`5ys@f=nafRf=Gc84m$&I3rM<)%2}AjFA4OW>?o0 zk#n5ZWA^sHs8W`h^bIbBfA~I}wb`DTQq$dMuB|#K2|q(cFBukGq|q|`=GoA@D?xKw znG&~niy*2{XL@JhlW8n<(F+}C;^Q8rW++D1o;WEfhP4Zk^leHvkoUywzd$H-?Nu=R z-7tt6KzsFoFc)!(gUHaOE^$z%14+)wJ@qjd;{te#00Y4SfE%)&h&kcD2PH~8UJHj3 zt#>*Zfv3UlwckMnfyA+Z$0h=g70-qK?lV9|q_hQ}ASX)mp(^C`2d?eYXx5$XnM)Ze68+{4=L}zk7R&@qY2!sM;>kyoEbPJ-lk}M9R zGD|IGCX#mxR}Xco#gm89`_ftp;;%_hq2z?<>)t#M$^s3RgPW#<=*0kd9~*kI>d_(P zc8&dEG@sFD4#}b~`VMuwFE0>_r&CA0p-v8g;EzHes)V>wdnf_g0T?>JQJ0+gAZdnu ztQ9L*TW0V^Kmg+bUV%ST=<|P095N^?`QMW;;P>X_-=i>44(>`1<|1eW0)|bv!1L;q7~66h&yYWUaCe=}(QB|r`s&4&!nKo_Ks`~OP>#~5-*K42~#Y%wMN+mlx` z(xV6j4uUs7c>jB0qPWR`C>#u^w4w&OTUdDx!op459%2PE@dvZe`WFd4F;QgDKVa@w z1;hdP%UA25a`4Ab;LS$@4g~^QWeFIHvhZJZ+;T8fgTLWFrXrZ*81J-7y>-`a_POQ^g4pQr8=* z7kCd&9exgQ36mHl18(9@5qYmb9$b^a`-8JI5R1bSWIfNCc#QE%7@hjO|B)k*w7LMIDRR|x7Tkp$gTr!Y}R(*=i8c>-&_ zqJU`^A0dzhe!3sJU@Z*6IV1ZgjDyMh^Abqr0xG-s2|$u2Ndk=b2G+U^i5|}2;n0d8 zf`^@8M&N5VG2J=WLE&l8gCE#sHAu)kAwUb>nBd`WPX$kYBp{k_LMSE?w7|=DqQzVv z`@T{z?#KT#hSMm5`--=RMeBYGhfYKRIZye3W8K8o3h;Epp>^@Vc!JtN5eeQ&`Z9_4 zghbH0-a#(J9CtyoQVOW!15|nr4Vw1Ap|b^mOQQ&IuZNR}s|Iz$MTgZs0_^rM6C8yJ z%~&{tD;o}WAypDb4UfU0RsTDz5xsC|Pz4yd)St9Tnmq~mS|#Y|-%;p;Lw%|VHLI#& z_>-dM0NeZ$Sg-4#XEhRXcMS;U2Zs6%Ckk0V9LiV^aQEvHLY9PiMN@&p_X-SKj)XY- uf`VO8p))zV)5&`_J#WuDR~}I``*%&N=se?(@ufu(_wApPiyH)ICK^0fCT{Lxii+ zHB)HL{&hT#rav^kkaFIV3A+2mhY0cq#C!}Y<{`$7{et-MKms=cB1AK|37Qt_1I3GC zh!^o9Pm*VN5t^BtffO$jrTGA*KV~ut<8)adhCtXrPb2}!7G^+%o*T95%V@^*>t?1y zdqCeaLmizMa;VF0xMRphMbWpyP8XDyf)fz%A(X@X(qXB6o1`S4wsE^?wCNK!RSFkaVSFD26j^u!qY0DI#1t_dBu${zT4SY#85m>M z61@i4rP+MOyVmkk9w9hPp7iPEWXkPOgkaqTVY=tK+%-BDIr&f-jF&_!9|o%LRom~( zJmy6WRlo!0DCCNwuZWmcNFxHq>Kr@tl;rFjFE-TsiPkv^$a#EnW|4Ury-Lnk!ed&X zcfg zX_hlbPqeyh6^hkR=9V5c89k5scvp<49GY@%bz`E8EEHnhbSHLSE%@Dd=V0nonp;p> z*&Tg@-j)815A62MmvrS2A?Y4AanBm|8$KBRc-@^Bk>ZO_nEi9VjXw>k_lA>uVwq7UAwZeq6Za}myFY9K8I-N?&_Lw)~hbdznt_P>P8g>XT*yrB5a4BV zKd9Q$@o)D{T)0C+7OZW}Nn#BU^^1IXXcIeYhswV&{?bkr%d7Ino0I#+ffg29_jHbt zGbhq2GQ?b>%rNUon%kK!=b zaN!i6Hz2F<97yxuE8?hcIro8!?WSeSy_)lLsr2T(`nRa%bsnc4ZXV@)lUOn$%96jG zId+GFMqbheKq1c$PK$Rp3&4F;QZ{CVy3A%jC#yt%sTZ8mW#4)@QJHKiA;c5uQMO8_ zPFv$#dj2-8>X)CEYQtZVGRf)*TSrjT;L+KG9`Zy9)$GEhnTwt_^s5KuAEQ*3fz11x zJ<8F74{{A8o~DnlPRKD;rijbI-j3|kW#&}h436HrJB8w{RndrxRJG~eXPsc0Z2jvM zWy-=PljbdbqRcqyE7@SvrnJI1sxjPr3-O^sb^*F ze6r?!F}i}<7PwIB;XV1WOLekSx6YuSOkpiTk?ipLyGwm4Q_Pwy>voeLH3Y@>cZOF5 zl(}+m+-@RuR&HU)_ok2-PB4hPWKix!JtsfK<&>g!07ELY%~{Xwj~F%Rpvu!JEr&v~ z>+P?lB>M)oO;G*wH+JW*Cx^PEC_8&_7RF$bwf zhfpIA(kONTt~XZeP|47l;N5{Ty3cuqUy#&d(U`+%GHv||qEw@j8LJw~pOoB-a@sbg z;!c>G_YQ^TB+i<6hqC9SbULYHI6Iddeui>jx2mXY?#v|^g$l(=VBf}+cWjv%{d`Pi z!;(2ow~{Fps=Mfk-O6TdI*r}m3TyQijOFgwLY@m2jIXDlNwiG3?A?v>vYxPnzlyyf zZ0K89JQ1bd@9n4AnxYFFA^F;Oq)pm^oeZpI+)`1Yps#%f6TgOsvwV%aku>F)5W6Jh z5^RmLS`YhPFVI}%fgj0t0Re0d2UpgVVokZN+hLx{{PNxnH!GP?>DctJHuz^5`rt`P z>ixXPF4O(e$Tzv^MdPTS^zHAkI(?KF<(Fbi{@W5WPO=mC{VUjfGN|%4I4alFMgr3t zZ@7twV6wB{OcsP|)adDFCeh>vV3<9>Q)23+xp#^~YM*R7Y25k*L7!i~zs2G` zQXE?Cz#`!`z;Jf)O$Jxle8I+SV;^STnIxxELe8ac`ndneOueczg790a9{KHAKo6~Ks2twU&p4}4@CBUKetMC zKNFLg{pj^NLshS=F z(#G%EL3aG~JZ;0lGi0*Hwk8bKmSa{rZw5oP+Q6!VG#{*pE7>yn6qc|M@4DrA5tUQU zRYgYmKg`X2iBYmbT(!5F-gEk%YbLx16fOv4Xier{FH4)uH^^40yn0;&KG{BPI*E;q zZ`Re=NT^>NCq)&{Q8#G&5N9W|pgSB#GvwFcT+a{Un3kbGwLK`L2hM6Y=Fjr$E>afy zC)lQXX4sJwP0i|`#h3<)$ zvoAcogi`M6=8fkYdJ{W#B$rx5i>jAJ|Fl?S&=F2V6Z}B?t8QC#nxfXUtEdT zhHOM#)QeDEQ;w14Yo)`F=Rfy_GYGmTFnNsz5Frxge@rR%de&=H&m9F(l?q!>cYB3- zOkgrD1eo_qZB)MX`N3n6>}9SHHw=T9hrHmPV_l;1VLpY7h!A`( zgz=WTKhTgA`yxFonuOnFL18a<8146Alt%O}e+4nBL-OXK+%H`Nqk(^hA0gO9$nO>2 z5++YBxFrp{I1nR8mkl)A!Pdt94lRomD0_$46WH^1ruK&0qe%Lf+A=X@0m}jb%OS=F zyM_*@$d-m)&W>o2h^=0ktv=Hx)oF;S{($Ull$oQ2TK!to6veunxOcL3t8RBC zGxd3Y6r+K$>nAI~VBB7>pJ!L|VWi~xS|_}KT=sC1q^GVGrIwXkaJQl|5eehq(&hN8 zIpUe`y+_5b3^(5?SC@^ZZOG^bbRpCC3_PDIE}k(wue~K}C>`NVYZleu6fs?YUQqBm z!_EDzH*jD?Wn}n@29`9bKjzMYGK@ddAk8~84CQy~s_$LK(ziWiPZs7y1D29XcYQhj zW|Wcv6thJGSo*{c1`ti;<5G8po;ce%7D^#SuckR|C$i{IGk;SF{eYb2u^}NEa(l;| zSL47yo8kRg?fcbe>D5PFdkEwA4g3wxPweh#I0vV_;@bZqc!a*fb=j+PhpwQ@?ELE6 z%$zf*2#L&byP|uC%UtX9i&>Zts&UGz%A8M^`m`*Rxf~sAO|NU@BMKe60G^+&X5+OD zwb!`@hc#K_a)Ygng2OtRO=G4NB7S8AUqT?#wCPj_IXi~RpI%o6mUqqj)%Gt=D?5k; zZDP{S&Vn_hZBitAEbd0g*T6G0&6ryvl8lh-g6;Lyp6)-h`$!V^(hn37W;6Sc6ZbQwY* zkW0W#8)0XYfqny_er+=?ZT-I2eWE?D2j`9V`Ug$CwDrv;5vG!eDufIgA!XzhKy4(6 zkd#>vhW8HY=!*;0>PzV8^=QA>AL#icEZi^B^IE@V0s3FDQGmAi#~$1m0Bvy)0sS`I zsN_bEc1fz}z$P7f)iji}bB}p$_fVdjs&4hOmQ*Tjxo-zGnb8wrpSHWN`=cAn!e{c4 zR8;LmO<7CU-4d6z-3^6I@7yb${&dYYZ@;YJ%1cZ@MOW3j@Hsh{ktbaoMk(j}1Lyog zCsWxPuY^~`UrNP1;e{6i9O;LN#Zjb}zgUYgD-UI{ZB)ONFIuyE16MqQ%8z_l9(ULt zvm3}#9)7lh;mf-h!yOTTbVYuUlgU>;qSWAUQn$sgsK2GEX<4GzD?h0{s$qcJ%&aK9 z;r{c_=r~m1rmYC^@dTY^8wbVB073g@yok}^CzR%Rv7uBSkphK4qDX+0GBLECQzagX zCUQ+B!ecYsxXAIdSH4_e3w%sD5ukW7V+$D~!OJ#LhbJ0q5%0+GvW~lNPGk=gUYsy% zBo#5>SGRMwPGk$urcY+wg*C+Z)rb=4iH*3j&6CxTO6wE8@v6U1a9sZkp2)WAOiplG z^{J;Ajy-jm3WI2X2YwO!aYF#QH)qWMe;I}_{C9>e5abmRlI7Y zbGS4IUNp0_J_e0@`Z!4#>i*F=&U|39nO(8zWYNjzx`X?Te__B?2zWlYhw)^DKo#-TiK)!*yCQSe)BgcWyk@Eno9aOlOUQ=JwI8Mw%u*48Da{_<2 zoyQRpd<-EVJfy=BiqLZc18r3JlbC8_hl(=ec;x|5nZX&S%yXL*&~su2%KPvhE%Q--(FET>x*(Ah0m)BSP=Nywab*G6 zdhy^3EY82MVAmK2UNB_>aGE=gz1xigK%Ia&+?Xr-LDmV-J$V9ft>14~wtVS+yYk8I zz2GdU-~n2=K%np;5T`&D$n~3@H>BrsDtJd8QG*RE0hsv~u-zkr+o3FX>%k&0xWePt zD*g?F9VJsK~>g06eOSo2^0wkTH}FVy;^uh-9C0` zdLoW6zE27-YX)V=WKhNn9QEPJY-m-6o`LZRf$y4*4W#iXeIIEg(9oJGpU=|o3 zA#g7L#BEZ5BcDq2zw6|29tH`_nc9LChMf`uQ6g}+vj|KlZMO-v?XU zQsMg$wD \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,26 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -85,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then diff --git a/gradlew.bat b/gradlew.bat index aec99730..f6d5974e 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,7 +46,7 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args if "%@eval[2+2]" == "4" goto 4NT_args From 041928c5aabcd53aaed29c1751dcbae7b3480ab4 Mon Sep 17 00:00:00 2001 From: Heinrich Reimer Date: Thu, 14 Jul 2016 18:42:57 +0200 Subject: [PATCH 156/288] Fixed code highlighting --- README.md | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 1ce34029..49ac7e26 100644 --- a/README.md +++ b/README.md @@ -19,16 +19,31 @@ EventBus... EventBus in 3 steps ------------------- -1. Define events:
-public class MessageEvent { /* Additional fields if needed */ }

-2. Prepare subscribers
-Register your subscriber (in your onCreate or in a constructor):
-eventBus.register(this);

-Declare your subscribing method:
-@Subscribe
-public void onEvent(AnyEventType event) {/* Do something */};

-3. Post events:
-eventBus.post(event); +1. Define events: + + ```java +public class MessageEvent { /* Additional fields if needed */ } +``` + +2. Prepare subscribers: + Register your subscriber (in your onCreate or in a constructor): + + ```java +eventBus.register(this); +``` + + Declare your subscribing method: + + ```java +@Subscribe +public void onEvent(AnyEventType event) {/* Do something */}; +``` + +3. Post events: + + ```java +eventBus.post(event); +``` This [getting started guide](http://greenrobot.org/eventbus/documentation/how-to-get-started/) shows these 3 steps in more detail. @@ -37,12 +52,12 @@ Add EventBus to your project Please ensure that you are using the latest version by [checking here](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.greenrobot%22%20AND%20a%3A%22eventbus%22) Gradle: -``` - compile 'org.greenrobot:eventbus:3.0.0' +```gradle +compile 'org.greenrobot:eventbus:3.0.0' ``` Maven: -``` +```xml org.greenrobot eventbus From fd2c5715be0081ab52305c7484f26831d538230f Mon Sep 17 00:00:00 2001 From: greenrobot Date: Tue, 16 Aug 2016 21:55:52 +0200 Subject: [PATCH 157/288] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 49ac7e26..21975d0a 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ Maven: ``` -[Or download EventBus from Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22de.greenrobot%22%20AND%20a%3A%22eventbus%22) +[Or download EventBus from Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.greenrobot%22%20AND%20a%3A%22eventbus%22) Homepage, Documentation, Links ------------------------------ From 8bfdfe8dd2840393b260c93df3bf2bcc664dfe9d Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 17 Oct 2016 09:58:42 +0200 Subject: [PATCH 158/288] Line-up quick-steps with getting started guide. - Hopefully this will make it easier to use EventBus correctly and avoid support requests. --- README.md | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 21975d0a..100cdcc1 100644 --- a/README.md +++ b/README.md @@ -22,30 +22,39 @@ EventBus in 3 steps 1. Define events: ```java -public class MessageEvent { /* Additional fields if needed */ } +public static class MessageEvent { /* Additional fields if needed */ } ``` 2. Prepare subscribers: - Register your subscriber (in your onCreate or in a constructor): - - ```java -eventBus.register(this); -``` - - Declare your subscribing method: + Declare and annotate your subscribing method, optionally specify a [thread mode](http://greenrobot.org/eventbus/documentation/delivery-threads-threadmode/): ```java -@Subscribe +@Subscribe(threadMode = ThreadMode.MAIN) public void onEvent(AnyEventType event) {/* Do something */}; +``` + Register and unregister your subscriber. For example on Android, activities and fragments should usually register according to their life cycle: + + ```java +@Override +public void onStart() { + super.onStart(); + EventBus.getDefault().register(this); +} + +@Override +public void onStop() { + super.onStop(); + EventBus.getDefault().unregister(this); +} ``` 3. Post events: ```java -eventBus.post(event); +EventBus.getDefault().post(new MessageEvent()); ``` -This [getting started guide](http://greenrobot.org/eventbus/documentation/how-to-get-started/) shows these 3 steps in more detail. +Read the full [getting started guide](http://greenrobot.org/eventbus/documentation/how-to-get-started/). Add EventBus to your project ---------------------------- From 7fddba86c1b79157c879cd523fdb8c389c72a7ec Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 17 Oct 2016 10:40:37 +0200 Subject: [PATCH 159/288] Fix formatting, rename example method. - Markup is great, or is it? --- README.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 100cdcc1..1f193bd9 100644 --- a/README.md +++ b/README.md @@ -22,39 +22,39 @@ EventBus in 3 steps 1. Define events: ```java -public static class MessageEvent { /* Additional fields if needed */ } -``` + public static class MessageEvent { /* Additional fields if needed */ } + ``` 2. Prepare subscribers: Declare and annotate your subscribing method, optionally specify a [thread mode](http://greenrobot.org/eventbus/documentation/delivery-threads-threadmode/): ```java -@Subscribe(threadMode = ThreadMode.MAIN) -public void onEvent(AnyEventType event) {/* Do something */}; -``` + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageEvent(MessageEvent event) {/* Do something */}; + ``` Register and unregister your subscriber. For example on Android, activities and fragments should usually register according to their life cycle: ```java -@Override -public void onStart() { - super.onStart(); - EventBus.getDefault().register(this); -} + @Override + public void onStart() { + super.onStart(); + EventBus.getDefault().register(this); + } -@Override -public void onStop() { - super.onStop(); - EventBus.getDefault().unregister(this); -} -``` + @Override + public void onStop() { + super.onStop(); + EventBus.getDefault().unregister(this); + } + ``` 3. Post events: ```java -EventBus.getDefault().post(new MessageEvent()); -``` + EventBus.getDefault().post(new MessageEvent()); + ``` -Read the full [getting started guide](http://greenrobot.org/eventbus/documentation/how-to-get-started/). +**Read the full [getting started guide](http://greenrobot.org/eventbus/documentation/how-to-get-started/).** Add EventBus to your project ---------------------------- From 7504c43a9beb3771f5863c51426354ea22698d0f Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 19 Oct 2016 12:33:50 +0200 Subject: [PATCH 160/288] com.android.tools.build:gradle:2.2.1, gradle-2.14.1 --- EventBusPerformance/build.gradle | 2 +- EventBusTest/build.gradle | 2 +- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index fa9029dc..53180e6e 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:2.1.0' + classpath 'com.android.tools.build:gradle:2.2.1' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index bb877369..a1d04468 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:2.1.0' + classpath 'com.android.tools.build:gradle:2.2.1' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } diff --git a/build.gradle b/build.gradle index d0f0925f..9c519b5c 100644 --- a/build.gradle +++ b/build.gradle @@ -7,5 +7,5 @@ if (JavaVersion.current().isJava8Compatible()) { } task wrapper(type: Wrapper) { - gradleVersion = '2.14' + gradleVersion = '2.14.1' } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f3b61425..4fde35c7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip From d47baf2208e1e7a70d57dc4bfa9fa6507d9a13e1 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 10 Apr 2017 10:48:03 +0200 Subject: [PATCH 161/288] fix lint error: Multi-catch with these reflection exceptions requires API level 19 (current min is 7) --- .../org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java index b68de63a..9020c24b 100644 --- a/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java @@ -46,7 +46,9 @@ public SubscriberInfo getSuperSubscriberInfo() { } try { return superSubscriberInfoClass.newInstance(); - } catch (InstantiationException | IllegalAccessException e) { + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { throw new RuntimeException(e); } } From a4c613e58ea1fd90f46a75f39dc95297d4759971 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 10 Apr 2017 10:51:35 +0200 Subject: [PATCH 162/288] Gradle 3.4.1 --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 53319 -> 54212 bytes gradle/wrapper/gradle-wrapper.properties | 4 ++-- gradlew | 22 +++++++++++++++------- gradlew.bat | 6 ------ 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/build.gradle b/build.gradle index 9c519b5c..958c35ba 100644 --- a/build.gradle +++ b/build.gradle @@ -7,5 +7,5 @@ if (JavaVersion.current().isJava8Compatible()) { } task wrapper(type: Wrapper) { - gradleVersion = '2.14.1' + gradleVersion = '3.4.1' } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d3b83982b9b1bccad955349d702be9b884c6e049..90ae8dfd9ca83141cd5b1fc8cf52c663bce33bc5 100644 GIT binary patch delta 21905 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 Date: Mon, 10 Apr 2017 10:52:25 +0200 Subject: [PATCH 163/288] updated Android versions --- .travis.yml | 2 +- EventBusPerformance/build.gradle | 4 ++-- EventBusTest/build.gradle | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5f3aa2fd..4c8fcf6b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ jdk: android: components: - tools - - build-tools-23.0.2 + - build-tools-25.0.2 - android-10 - extra-android-m2repository diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 53180e6e..23fd53b6 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:2.2.1' + classpath 'com.android.tools.build:gradle:2.3.1' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } @@ -29,7 +29,7 @@ apt { } android { - buildToolsVersion '23.0.2' // When updating, don't forget to adjust .travis.yml + buildToolsVersion '25.0.2' // When updating, don't forget to adjust .travis.yml compileSdkVersion 19 sourceSets { diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index a1d04468..b65a4bdd 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:2.2.1' + classpath 'com.android.tools.build:gradle:2.3.1' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } @@ -22,13 +22,13 @@ dependencies { androidTestApt project(':EventBusAnnotationProcessor') androidTestCompile project(':EventBus') compile fileTree(dir: 'libs', include: '*.jar') - androidTestCompile 'com.android.support.test:runner:0.4.1' - androidTestCompile 'com.android.support.test:rules:0.4.1' + androidTestCompile 'com.android.support.test:runner:0.5' + androidTestCompile 'com.android.support.test:rules:0.5' } android { - buildToolsVersion '23.0.2' // When updating, don't forget to adjust .travis.yml - compileSdkVersion 19 + buildToolsVersion '25.0.0' // When updating, don't forget to adjust .travis.yml + compileSdkVersion 25 compileOptions { sourceCompatibility = JavaVersion.VERSION_1_7 From 9d96410c6550bba9b9d49983a94b39f287382ff6 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 10 Apr 2017 11:00:20 +0200 Subject: [PATCH 164/288] travis: switch to Java 8 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4c8fcf6b..cf7a4bd4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ sudo: false language: android jdk: - - oraclejdk7 + - oraclejdk8 # http://docs.travis-ci.com/user/languages/android/ android: From 48ad4b924fda081930031bc33d757fe85ef00425 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 10 Apr 2017 11:16:20 +0200 Subject: [PATCH 165/288] travis: added android-25 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index cf7a4bd4..96aae900 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ android: - tools - build-tools-25.0.2 - android-10 + - android-25 - extra-android-m2repository before_script: From 60c5d3d0b465cb5708378767e21d01d1485da9e7 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 10 Apr 2017 12:55:44 +0200 Subject: [PATCH 166/288] buildToolsVersion 25.0.2 also for test --- EventBusTest/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index b65a4bdd..d9742aab 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -27,7 +27,7 @@ dependencies { } android { - buildToolsVersion '25.0.0' // When updating, don't forget to adjust .travis.yml + buildToolsVersion '25.0.2' // When updating, don't forget to adjust .travis.yml compileSdkVersion 25 compileOptions { From 18729a7df8959c1edc1c05bad8a0809d58c5c652 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 10 Apr 2017 13:16:41 +0200 Subject: [PATCH 167/288] show test lint problems in 'stdout' - debug an travis issue --- EventBusTest/build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index d9742aab..ed6296f2 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -49,6 +49,11 @@ android { testApplicationId "de.greenrobot.event.test" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } + + lintOptions { + // To see problems right away, also nice for Travis CI + textOutput 'stdout' + } } apt { From 16b043a11fc1afd59abba102f20bc2ba826f0cf2 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 10 Apr 2017 13:30:28 +0200 Subject: [PATCH 168/288] Travis only lint error in test: abortOnError false for now --- EventBusTest/build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index ed6296f2..34c45681 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -53,6 +53,9 @@ android { lintOptions { // To see problems right away, also nice for Travis CI textOutput 'stdout' + + // TODO FIXME: Travis only error + abortOnError false } } From 435d9b0f6c64ae4761b531046da1c482fadb1436 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 26 May 2017 21:50:15 +0200 Subject: [PATCH 169/288] com.android.tools.build:gradle:2.3.2, buildToolsVersion 25.0.3, Gradle 3.5 --- .travis.yml | 2 +- EventBusPerformance/build.gradle | 4 ++-- EventBusTest/build.gradle | 4 ++-- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 54212 -> 54783 bytes gradle/wrapper/gradle-wrapper.properties | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 96aae900..94fcd6f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ jdk: android: components: - tools - - build-tools-25.0.2 + - build-tools-25.0.3 - android-10 - android-25 - extra-android-m2repository diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 23fd53b6..cf5c647e 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:2.3.1' + classpath 'com.android.tools.build:gradle:2.3.2' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } @@ -29,7 +29,7 @@ apt { } android { - buildToolsVersion '25.0.2' // When updating, don't forget to adjust .travis.yml + buildToolsVersion '25.0.3' // When updating, don't forget to adjust .travis.yml compileSdkVersion 19 sourceSets { diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 34c45681..8751edbb 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:2.3.1' + classpath 'com.android.tools.build:gradle:2.3.2' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } @@ -27,7 +27,7 @@ dependencies { } android { - buildToolsVersion '25.0.2' // When updating, don't forget to adjust .travis.yml + buildToolsVersion '25.0.3' // When updating, don't forget to adjust .travis.yml compileSdkVersion 25 compileOptions { diff --git a/build.gradle b/build.gradle index 958c35ba..2243fd1d 100644 --- a/build.gradle +++ b/build.gradle @@ -7,5 +7,5 @@ if (JavaVersion.current().isJava8Compatible()) { } task wrapper(type: Wrapper) { - gradleVersion = '3.4.1' + gradleVersion = '3.5' } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 90ae8dfd9ca83141cd5b1fc8cf52c663bce33bc5..79eb0160bc80b1a4d113f3147ed7755989a9ad29 100644 GIT binary patch delta 6729 zcmaKR2{@E*_x~8#v+sNMootc4Y*~gFM0TP?7|L2EvJ>%S-?C@TE^F58Ldd?BeNBlH zzo(gb-*3L}|N7t8^_Vl~{+!P__qp%$Jf1Th`PgSg*d#Z#urE+SAo%zY2;>?hhJ=gw z&!-1LtB)e6F^Ewzp!({z?}i2W7qIZs1(d-c5Bl?11oc_z%6A0^B>{!P3n1w=NUw{G zJHX0#9cu0Z*fO#qC4vZwCwE?0zxW!V{dk0S`rZ=ho;v+5#PB-7*po!x)pYk=c~ASp z)i*ARkeB-tY7|!)N!)10Dc(BRGBXl5ahEyGm|m%IomQjrCYq+%x!jR)ocSh0T;(80 zKG+y`1*ctqmb7zoZqfgy%h5F@@>*d=xryaosb7f8dDDIgWk_bOXxy=M=ZKrXh)Z*A zTrGk!Z&p9`YzUCftv3*Qlj|i;W?{Lnqt3e{(y9bDCp20;HTLUdulDOSnFA5gB#5hN9VRmM!#h~2`Ankky_5z$;^sbx)h{Z zh=>vl?yMP4vq5%6p414u4Duxj-&s7Vy02PK?e8?)g*Gk`lg1fKLK} zFflk#OR_&N?1yd8~Y~=|#d>n5|snLk8 zf~C|rC#SE+aQ~j0RxTP-dqlW4AbYy``|QWruKfP7%aaXphzBw(0+-^gwH2MnSlJJU z$;WC}MEX{!>wXf+C^#b+ zh8;b?wmymSpYPo5`7)m{z`Ax6;IG)h+OraEcc6-G*_J_f1V2e~I&BOtY%X3Fxp=~L zs@Z<);YqcB$x#aO(r8A^>!>#jN2Vv{LZ>Wm=#TIo!@43B;4>^9MyeQ7!s?BSBJ5#RYc^^A zh;j>Ba&xB_Zc-x@hzQ{;>o%3b&SRw-j-dhyj1?u%))!nbGn`jXb8jx9!#7Aso65KL?Fn5(}+%(>r{lTBmM%zH8&(f}{6vNca6WmTg!@A?EsQk}-MtQ{f&Xg5FLVYz$7Ims<;{j>J_%09hUGZwS_Vc%3N zp0|{gT)i5#?HL_Sypqd3yVKtDvV`-#5jz`NK3@yr z*t+sp?nC!eza{Wg&(TCDWb)u$I7F|sv zvZpV$`;RIk&9UIWoz?i+x}#&lzv0wQeJ=D6Z&uP8o}i>hDlC5ts*zOR#v=S;KQ2-k z?!7btcjL) zd|Fn`&J4pk%#@t=UiHk7sRfaab~+CbS)SVPD^SYHyC5g$zHlagTb|O}+Q7>>OWlL@ z6eNbff{~+8@A1o)`C@#1wOtX;Z%f=H;&)Bz2K1=4Gx9sMO1nw|6T;vvRL0Y{^#a&d zxt(~}9GxFHzj)*27#|<*&L)*6kSOU~|FGgy3VZtV#FYI!rzBV)0;}CzKPpViOZ$q8 zglM$7w%3i6Jv*RPm2y5>YQ(d$S#e%cWbE*lU;yF_}uP)X-Kl-A<{=H$KSLQoXd% zFnqn|c`TogN~dh{Lf8@)k9cgJfJ}0Q2@9vGOwZ>q`*1>A^Nv)5Ri7U9gYWmuuP*%( z>v^g9{^p?EIhMI4q6ufbkIULt?nSJ-M_9i*&RdO; zTcI!+AHMYur4+yJ$ZWjzlSoU-@N`f{viH{E&_u44hgsuHsvFn4Y0Smxx+ST}Imhcp ztq`R}rriy%(v~)?s~29`OiW_^vI$pqmadh^u3IlPo0OO^z4D+yvj*W?@9QfwRWIM9 z`+M4CL^4Q3jMF5SyS&uEnAz<1T-EJs)2fTP8uX^Fk2l>kcr_7aEx%}p429Twkk@Zq zJq?hNGctTdvJjsYRZ&zMQ}bK-uqsYte`dnijYKFLF4jNtv-<=vGG=jbTYle`S^2Pw zaKQWqXH!-EWExxZlZ0E(D0*`p$CAh6JR5E}esLU%74r78r%zk_mM|lF-c9s z-sxyw_6;z8p&Y`$%WJojQQesM?X9?-NW<FAWM$-SxX9EloI^OI z@N!onSwa|CC4kC+U(>PJ@$yJ`tC)aok57*)E2T&ZmW-qp3 z4AS{N-)>E|-tphn_784BZmC@^auCGy5} z0nr#XdiAc6z|Y_)!HtU7inHT$<)OiD2v7YP^Q~Q@rL3#*OGXTP7v_qQ1`-Q|eos>s zyZxSu+ioeE+%$TWYJ4x}RA%n8Pr&x4;l$45^daKFWvL;m{H5xMdn{pr75CN&s;bqY z5ytAeZ+3^-{arb;?8@0Fx@~NAT?eAxCwyZuk8+;09o;G^nKY#(Q2Qo$rSr$AfqX>W z=0s{|39HIML}+mB9mF)T6Y_aTt&q*HKA}eglDCSR9tl-%m`>|A(A0hyYh0zTs(k_- zTO1ekNH+ow=WY)MI%~G zew*mO3zu$wDt<&UxYQ>d@@C=MZSpQD=^wCE>c>Q(msqH{1*uP^vZHDm18NsS=!RtX ztsCQv$6oIf`q8;?7_itQ1Ky?aStvh<*4xFgw~uVxZIRW}dY({M>#0wec@skJ>rGak zfUOtzy0c-QCE$TCBitsY_Axr78b$e|Uhc)3upXuVz760!Njam79z8mpAo?&zm3oYmkSkGvXu1S1(xL z&rj=^n|zZah6nkww$G9`@8TYI(IPHAM$+I-8yEQ;4`fA43yZLjY`d=KdCPRS%g9Ld zE^ObmHs-&B7f$c_DiMLVC&&y}-SOQcHn`BFUtT0gn$5S&i;>xve*aF?sJ_dv$IIZsRVFDr5*`j?N1piTKaM;q<^FDT!t0BL94zjNUi8M@mYYpZ z@eS}lMVwsl67V=f~)>e$TjP+P4q#A*IgIvoe%iDxo0XJyEsAZhrPMyDn00t zv&`*mXXMhap1ST=R?ZV4o>muX$)zwTY+b6#jJs>6GN%ro`!I5XmG|ugu1l$=^LU7itNgs1l!ANJyU3F z|Cuefo6g~+_#W6@zAvEej{BvSqRnBPY5f*Jeik^TnMm&od!Wh{pxj+3E}}UhQbC)O zD*txSBJ^d3L9$|y$s^I%Z4!=543CbH<~Q1oEYH7Aj_QcaW`bRcUhoqA@7v@}H@QK{|hUK@oYSc zbS<0xdChF+qBF_rcRx9-;>&vr-fNWH<%JPuJ?~3(^)RlxP_9riH5XN#E6TG>I?nR1CWObLA_y z2+5~Nj!g=D<|>Ymp`ecn-xxd={QlKosnn%t#znVOn#{AIKOK0X z*1KSiTX~}2M2POVTqRsVTbQwv;h`lj#aonUDM}<7ik8UfanXD>M-BpOxDW^f_(sl+ z;&bUFu7ndEVH`hZp1FWFxnnhfF&4xkAVBE=C0kRpkYOu;Mg_eK!JyQM@DZkb zKuZ8w8w^{jv>vc(lVQgJw+|10+t=n&$?pGa_$Si8jMx910KtEI z+V#1eunPt?MgV~bo%6(m1&9(+17F^AqtXVDb}>MWa8Wv?E~ZQWY5kFcaVmibiF3v> zco-l7FxSb60{>|a{kJ!C4xB=O0pkNJT@)zrxzaxeUZVXEnEU^IC;0aYf!PiQ=m;Ik zilkEzMSr2dXVwf1Tn`NV{HkBF0*m^Lz+^YN{|RVzGeBk8L7gCQqvs;Zcy-Izy%3CP z8ob!S>z~0Tgz{oWND6Fqp}}cIbVs9L4PGJrH<(ly1xB)ylKoG}Ct$8QBr)@NfJ8U? z=mJ)t-tPuVAJavL-WP>V1}M1}sAC5nV^V#t@c#)9lo(+kkQW%}Ku34Sr++>cq>%@A z|MEGYx&g{d1~c>jM)w=c36BYCUKa}wh_a#tl0Tpcr%pq#y1=&ZOYrdVo+HFI!x&Hl zd>HS`K|_`-AP8(0LO9NW$?O0fTP`4}=OS1==L-nT<6pzY4qZT)a2|={h$1>+oBa$>zIy=PfX1ai5<(g+6%$aCSw zMS2i;7X`Uuo< z0B`yzQJ&Ol@PEi-gAYD%TV&4}CwriPBxwwQ5+>!AqzWV1e?r28K*Z01FZ-at!M!Xf zR^?%ul?{;fF?dsuI|t-^0sgmp%v7jYBbNyORU1gXj>|hwZmwLDp0-_2-kJoqz%h^wOc+ zHx|RhVnEU#lrAg}>ko!B||jA^Jvc31r4{;e}xKOsfI^SM0#r2aN6}s1t7jb;7__ zFUD37Jj7R9fJ=|${v0_p-_t<`C~+H*I;f8RF7S~7y3h`=w6OvAK3=>8KFc)!eu9Dj eW&AZnI{=q92B7pKK8YB(P)qO`7vAw_{{H|+e466` delta 6082 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 76d36bb3..ee2c6b4d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Apr 10 10:49:50 CEST 2017 +#Fri May 26 21:49:46 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-all.zip From 88f3149112096e741cfefeac5e4245228da036e0 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 12 Jun 2017 08:02:33 +0200 Subject: [PATCH 170/288] Simplify add instructions, quick-link to ProGuard docs. --- README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 1f193bd9..0c154d32 100644 --- a/README.md +++ b/README.md @@ -54,18 +54,18 @@ EventBus in 3 steps EventBus.getDefault().post(new MessageEvent()); ``` -**Read the full [getting started guide](http://greenrobot.org/eventbus/documentation/how-to-get-started/).** +Read the full [getting started guide](http://greenrobot.org/eventbus/documentation/how-to-get-started/). Add EventBus to your project ---------------------------- -Please ensure that you are using the latest version by [checking here](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.greenrobot%22%20AND%20a%3A%22eventbus%22) +
-Gradle: +Via Gradle: ```gradle compile 'org.greenrobot:eventbus:3.0.0' ``` -Maven: +Via Maven: ```xml org.greenrobot @@ -74,16 +74,18 @@ Maven: ``` -[Or download EventBus from Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.greenrobot%22%20AND%20a%3A%22eventbus%22) +Or download [the latest JAR](https://search.maven.org/remote_content?g=org.greenrobot&a=eventbus&v=LATEST) from Maven Central. Homepage, Documentation, Links ------------------------------ -For more details on EventBus please check [EventBus' website](http://greenrobot.org/eventbus). Here are some direct links you may find useful: +For more details please check the [EventBus website](http://greenrobot.org/eventbus). Here are some direct links you may find useful: [Features](http://greenrobot.org/eventbus/features/) [Documentation](http://greenrobot.org/eventbus/documentation/) +[ProGuard](http://greenrobot.org/eventbus/documentation/proguard) + [Changelog](http://greenrobot.org/eventbus/changelog/) [FAQ](http://greenrobot.org/eventbus/documentation/faq/) From adda90cf11406785487b414433beb43e7d5a17c9 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 19 Jun 2017 07:44:45 +0200 Subject: [PATCH 171/288] Fix empty test suite error for EventBusTest module. - Closes https://github.com/greenrobot/EventBus/issues/439 - Remove outdated instrumentation tags from AndroidManifest.xml to stop overriding build.gradle config. Make sure to remove existing run configurations, sync your project, then right click class/method to run test. --- EventBusTest/AndroidManifest.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/EventBusTest/AndroidManifest.xml b/EventBusTest/AndroidManifest.xml index 22aedee0..03275fde 100644 --- a/EventBusTest/AndroidManifest.xml +++ b/EventBusTest/AndroidManifest.xml @@ -6,15 +6,11 @@ - - \ No newline at end of file From 4fd90e6e399f8166672d19a861236b7f112f5d2d Mon Sep 17 00:00:00 2001 From: Markus Date: Sat, 16 Sep 2017 11:17:55 +0100 Subject: [PATCH 172/288] com.android.tools.build:gradle:2.3.3 --- EventBusPerformance/build.gradle | 2 +- EventBusTest/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index cf5c647e..0aab22b0 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:2.3.2' + classpath 'com.android.tools.build:gradle:2.3.3' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 8751edbb..e92f19aa 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:2.3.2' + classpath 'com.android.tools.build:gradle:2.3.3' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } From 2c01ac0225ad31f1c28a274e1f48dd965f78ce44 Mon Sep 17 00:00:00 2001 From: Markus Date: Sun, 22 Feb 2015 14:07:06 +0100 Subject: [PATCH 173/288] prepared Logger, probably too many methods --- EventBus/src/de/greenrobot/event/Logger.java | 239 +++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 EventBus/src/de/greenrobot/event/Logger.java diff --git a/EventBus/src/de/greenrobot/event/Logger.java b/EventBus/src/de/greenrobot/event/Logger.java new file mode 100644 index 00000000..9d7cba85 --- /dev/null +++ b/EventBus/src/de/greenrobot/event/Logger.java @@ -0,0 +1,239 @@ +package de.greenrobot.event; + +import android.annotation.TargetApi; +import android.os.Build; +import android.util.Log; + +import java.util.logging.Level; + +public abstract class Logger { + private static final boolean useAndroidLog; + private static volatile Logger DEFAULT_LOGGER; + + + static { + boolean android = false; + try { + android = Class.forName("android.util.Log") != null; + } catch (ClassNotFoundException e) { + // OK + } + useAndroidLog = android; + } + + + public static synchronized Logger initDefaultLogger(String tag) { + if (DEFAULT_LOGGER != null) { + throw new IllegalStateException("Default logger already set up"); + } + DEFAULT_LOGGER = create(tag); + return DEFAULT_LOGGER; + } + + public static Logger get() { + if (DEFAULT_LOGGER == null) { + throw new IllegalStateException("Default logger must be initialized before"); + } + return DEFAULT_LOGGER; + } + + public static Logger create(String tag) { + if (useAndroidLog) { + return new AndroidLogger(tag); + } else { + return new JavaLogger(tag); + } + } + + + public abstract boolean isLoggable(int level); + + public abstract void v(String msg); + + public abstract void v(String msg, Throwable th); + + public abstract void d(String msg); + + public abstract void d(String msg, Throwable th); + + public abstract void i(String msg); + + public abstract void i(String msg, Throwable th); + + public abstract void w(String msg); + + public abstract void w(String msg, Throwable th); + + public abstract void w(Throwable th); + + public abstract void e(String msg); + + public abstract void e(String msg, Throwable th); + + public abstract void wtf(String msg); + + public abstract void wtf(String msg, Throwable th); + + public static class AndroidLogger extends Logger { + public static final int VERBOSE = 2; + public static final int DEBUG = 3; + public static final int INFO = 4; + public static final int WARN = 5; + public static final int ERROR = 6; + public static final int ASSERT = 7; + + private final String tag; + + public AndroidLogger(String tag) { + this.tag = tag; + } + + public boolean isLoggable(int level) { + return Log.isLoggable(tag, level); + } + + public void v(String msg) { + Log.v(tag, msg); + } + + public void v(String msg, Throwable th) { + Log.v(tag, msg, th); + } + + public void d(String msg) { + Log.d(tag, msg); + } + + public void d(String msg, Throwable th) { + Log.d(tag, msg, th); + } + + public void i(String msg) { + Log.i(tag, msg); + } + + public void i(String msg, Throwable th) { + Log.i(tag, msg, th); + } + + public void w(String msg) { + Log.w(tag, msg); + } + + public void w(String msg, Throwable th) { + Log.w(tag, msg, th); + } + + public void w(Throwable th) { + Log.w(tag, th); + } + + public void e(String msg) { + Log.e(tag, msg); + } + + public void e(String msg, Throwable th) { + Log.e(tag, msg, th); + } + + @TargetApi(Build.VERSION_CODES.FROYO) + @Override + public void wtf(String msg) { + Log.wtf(tag, msg); + } + + @TargetApi(Build.VERSION_CODES.FROYO) + @Override + public void wtf(String msg, Throwable th) { + Log.wtf(tag, msg, th); + } + } + + public static class JavaLogger extends Logger { + private static final Level[] LEVEL_MAP = { + Level.OFF, Level.OFF, Level.OFF, // Unused + Level.FINEST, // VERBOSE = 2 + Level.FINE, //DEBUG = 3 + Level.INFO, // INFO = 4 + Level.WARNING, // WARN = 5 + Level.SEVERE, //ERROR = 6 + Level.SEVERE, //ASSERT = 7 + }; + + java.util.logging.Logger logger = java.util.logging.Logger.getLogger(""); + + public JavaLogger(String tag) { + logger = java.util.logging.Logger.getLogger(tag); + } + + @Override + public boolean isLoggable(int level) { + return logger.isLoggable(LEVEL_MAP[level]); + } + + @Override + public void v(String msg) { + logger.finest(msg); + } + + @Override + public void v(String msg, Throwable th) { + logger.log(Level.FINEST, msg, th); + } + + @Override + public void d(String msg) { + logger.fine(msg); + } + + @Override + public void d(String msg, Throwable th) { + logger.log(Level.FINE, msg, th); + } + + @Override + public void i(String msg) { + logger.info(msg); + } + + @Override + public void i(String msg, Throwable th) { + logger.log(Level.INFO, msg, th); + } + + @Override + public void w(String msg) { + logger.warning(msg); + } + + @Override + public void w(String msg, Throwable th) { + logger.log(Level.WARNING, msg, th); + } + + @Override + public void w(Throwable th) { + logger.log(Level.WARNING, null, th); + } + + @Override + public void e(String msg) { + logger.severe(msg); + } + + @Override + public void e(String msg, Throwable th) { + logger.log(Level.SEVERE, msg, th); + } + + @Override + public void wtf(String msg) { + logger.severe(msg); + } + + @Override + public void wtf(String msg, Throwable th) { + logger.log(Level.SEVERE, msg, th); + } + } +} From 7a0949fcfbc60e37dfc7800baa28e3581ed1624d Mon Sep 17 00:00:00 2001 From: William Ferguson Date: Sun, 31 Jan 2016 00:49:47 +1000 Subject: [PATCH 174/288] Providing mechanisms to allow non Android use of the library. --- .../org/greenrobot/eventbus/AsyncPoster.java | 2 +- .../greenrobot/eventbus/BackgroundPoster.java | 6 +- .../src/org/greenrobot/eventbus/EventBus.java | 35 ++++-- .../greenrobot/eventbus/EventBusBuilder.java | 20 ++++ .../greenrobot/eventbus/HandlerPoster.java | 8 +- .../src/org/greenrobot/eventbus/Poster.java | 32 ++++++ .../org/greenrobot/eventbus/SyncPoster.java | 35 ++++++ .../greenrobot/eventbus/log/AndroidLog.java | 95 ++++++++++++++++ .../org/greenrobot/eventbus/log/EBLog.java | 79 ++++++++++++++ .../greenrobot/eventbus/log/GenericLog.java | 39 +++++++ .../greenrobot/eventbus/log/SystemOutLog.java | 103 ++++++++++++++++++ .../eventbus/util/AndroidMTCalculator.java | 16 +++ .../eventbus/util/AsyncExecutor.java | 8 +- .../util/ExceptionToResourceMapping.java | 8 +- .../eventbus/util/MainThreadCalculator.java | 14 +++ .../eventbus/util/NonAndroidMTCalculator.java | 12 ++ 16 files changed, 482 insertions(+), 30 deletions(-) create mode 100644 EventBus/src/org/greenrobot/eventbus/Poster.java create mode 100644 EventBus/src/org/greenrobot/eventbus/SyncPoster.java create mode 100644 EventBus/src/org/greenrobot/eventbus/log/AndroidLog.java create mode 100644 EventBus/src/org/greenrobot/eventbus/log/EBLog.java create mode 100644 EventBus/src/org/greenrobot/eventbus/log/GenericLog.java create mode 100644 EventBus/src/org/greenrobot/eventbus/log/SystemOutLog.java create mode 100644 EventBus/src/org/greenrobot/eventbus/util/AndroidMTCalculator.java create mode 100644 EventBus/src/org/greenrobot/eventbus/util/MainThreadCalculator.java create mode 100644 EventBus/src/org/greenrobot/eventbus/util/NonAndroidMTCalculator.java diff --git a/EventBus/src/org/greenrobot/eventbus/AsyncPoster.java b/EventBus/src/org/greenrobot/eventbus/AsyncPoster.java index a56f4ebf..90a30d1e 100644 --- a/EventBus/src/org/greenrobot/eventbus/AsyncPoster.java +++ b/EventBus/src/org/greenrobot/eventbus/AsyncPoster.java @@ -21,7 +21,7 @@ * * @author Markus */ -class AsyncPoster implements Runnable { +class AsyncPoster implements Runnable, Poster { private final PendingPostQueue queue; private final EventBus eventBus; diff --git a/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java b/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java index 2a5319d0..d2e5dcfb 100644 --- a/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java +++ b/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java @@ -15,14 +15,14 @@ */ package org.greenrobot.eventbus; -import android.util.Log; +import org.greenrobot.eventbus.log.EBLog; /** * Posts events in background. * * @author Markus */ -final class BackgroundPoster implements Runnable { +final class BackgroundPoster implements Runnable, Poster { private final PendingPostQueue queue; private final EventBus eventBus; @@ -64,7 +64,7 @@ public void run() { eventBus.invokeSubscriber(pendingPost); } } catch (InterruptedException e) { - Log.w("Event", Thread.currentThread().getName() + " was interruppted", e); + EBLog.w(Thread.currentThread().getName() + " was interruppted", e); } } finally { executorRunning = false; diff --git a/EventBus/src/org/greenrobot/eventbus/EventBus.java b/EventBus/src/org/greenrobot/eventbus/EventBus.java index 1cd57e32..ae2b5834 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBus.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBus.java @@ -15,8 +15,12 @@ */ package org.greenrobot.eventbus; -import android.os.Looper; -import android.util.Log; +import org.greenrobot.eventbus.log.AndroidLog; +import org.greenrobot.eventbus.log.EBLog; +import org.greenrobot.eventbus.log.SystemOutLog; +import org.greenrobot.eventbus.util.AndroidMTCalculator; +import org.greenrobot.eventbus.util.MainThreadCalculator; +import org.greenrobot.eventbus.util.NonAndroidMTCalculator; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; @@ -59,11 +63,12 @@ protected PostingThreadState initialValue() { } }; - private final HandlerPoster mainThreadPoster; + private final Poster mainThreadPoster; private final BackgroundPoster backgroundPoster; private final AsyncPoster asyncPoster; private final SubscriberMethodFinder subscriberMethodFinder; private final ExecutorService executorService; + private final MainThreadCalculator mtCalculator; private final boolean throwSubscriberException; private final boolean logSubscriberExceptions; @@ -105,10 +110,15 @@ public EventBus() { } EventBus(EventBusBuilder builder) { + if (builder.logTarget == null) { + EBLog.setLogTarget(builder.nonAndroidEnvironment ? new SystemOutLog() : new AndroidLog(TAG)); + } else { + EBLog.setLogTarget(builder.logTarget); + } subscriptionsByEventType = new HashMap<>(); typesBySubscriber = new HashMap<>(); stickyEvents = new ConcurrentHashMap<>(); - mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); + mainThreadPoster = (builder.nonAndroidEnvironment ? new SyncPoster(this) : new HandlerPoster(this, 10)); backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0; @@ -121,6 +131,7 @@ public EventBus() { throwSubscriberException = builder.throwSubscriberException; eventInheritance = builder.eventInheritance; executorService = builder.executorService; + mtCalculator = (builder.nonAndroidEnvironment ? new NonAndroidMTCalculator() : new AndroidMTCalculator()); } /** @@ -196,7 +207,7 @@ private void checkPostStickyEventToSubscription(Subscription newSubscription, Ob if (stickyEvent != null) { // If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state) // --> Strange corner case, which we don't take care of here. - postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper()); + postToSubscription(newSubscription, stickyEvent, mtCalculator.isMainThread()); } } @@ -230,7 +241,7 @@ public synchronized void unregister(Object subscriber) { } typesBySubscriber.remove(subscriber); } else { - Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass()); + EBLog.w("Subscriber to unregister was not registered before: " + subscriber.getClass()); } } @@ -241,7 +252,7 @@ public void post(Object event) { eventQueue.add(event); if (!postingState.isPosting) { - postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper(); + postingState.isMainThread = mtCalculator.isMainThread(); postingState.isPosting = true; if (postingState.canceled) { throw new EventBusException("Internal error. Abort state was not reset"); @@ -374,7 +385,7 @@ private void postSingleEvent(Object event, PostingThreadState postingState) thro } if (!subscriptionFound) { if (logNoSubscriberMessages) { - Log.d(TAG, "No subscribers registered for event " + eventClass); + EBLog.d("No subscribers registered for event " + eventClass); } if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) { @@ -494,10 +505,10 @@ private void handleSubscriberException(Subscription subscription, Object event, if (event instanceof SubscriberExceptionEvent) { if (logSubscriberExceptions) { // Don't send another SubscriberExceptionEvent to avoid infinite event recursion, just log - Log.e(TAG, "SubscriberExceptionEvent subscriber " + subscription.subscriber.getClass() + EBLog.e("SubscriberExceptionEvent subscriber " + subscription.subscriber.getClass() + " threw an exception", cause); SubscriberExceptionEvent exEvent = (SubscriberExceptionEvent) event; - Log.e(TAG, "Initial event " + exEvent.causingEvent + " caused exception in " + EBLog.e("Initial event " + exEvent.causingEvent + " caused exception in " + exEvent.causingSubscriber, exEvent.throwable); } } else { @@ -505,7 +516,7 @@ private void handleSubscriberException(Subscription subscription, Object event, throw new EventBusException("Invoking subscriber failed", cause); } if (logSubscriberExceptions) { - Log.e(TAG, "Could not dispatch event: " + event.getClass() + " to subscribing class " + EBLog.e("Could not dispatch event: " + event.getClass() + " to subscribing class " + subscription.subscriber.getClass(), cause); } if (sendSubscriberExceptionEvent) { @@ -518,7 +529,7 @@ private void handleSubscriberException(Subscription subscription, Object event, /** For ThreadLocal, much faster to set (and get multiple values). */ final static class PostingThreadState { - final List eventQueue = new ArrayList(); + final List eventQueue = new ArrayList<>(); boolean isPosting; boolean isMainThread; Subscription subscription; diff --git a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java index e212750e..3a899a21 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java @@ -17,6 +17,8 @@ import org.greenrobot.eventbus.meta.SubscriberInfoIndex; +import org.greenrobot.eventbus.log.GenericLog; + import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; @@ -40,6 +42,8 @@ public class EventBusBuilder { ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE; List> skipMethodVerificationForClasses; List subscriberInfoIndexes; + GenericLog logTarget; + boolean nonAndroidEnvironment; EventBusBuilder() { } @@ -137,6 +141,22 @@ public EventBusBuilder addIndex(SubscriberInfoIndex index) { return this; } + /** + * Set a specific log handler for all EventBus logging. + * + * By default all logging is via {@link android.util.Log} but if you want to use EventBus + * outside the Android environment then you will need to provide another log target. + */ + public EventBusBuilder logger(GenericLog logTarget) { + this.logTarget = logTarget; + return this; + } + + public EventBusBuilder nonAndroidEnvironment(boolean nonAndroidEnvironment) { + this.nonAndroidEnvironment = nonAndroidEnvironment; + return this; + } + /** * Installs the default EventBus returned by {@link EventBus#getDefault()} using this builders' values. Must be * done only once before the first usage of the default EventBus. diff --git a/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java b/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java index 3247be53..3596c47a 100644 --- a/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java +++ b/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java @@ -20,21 +20,21 @@ import android.os.Message; import android.os.SystemClock; -final class HandlerPoster extends Handler { +final class HandlerPoster extends Handler implements Poster { private final PendingPostQueue queue; private final int maxMillisInsideHandleMessage; private final EventBus eventBus; private boolean handlerActive; - HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) { - super(looper); + HandlerPoster(EventBus eventBus, int maxMillisInsideHandleMessage) { + super(Looper.getMainLooper()); this.eventBus = eventBus; this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage; queue = new PendingPostQueue(); } - void enqueue(Subscription subscription, Object event) { + public void enqueue(Subscription subscription, Object event) { PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event); synchronized (this) { queue.enqueue(pendingPost); diff --git a/EventBus/src/org/greenrobot/eventbus/Poster.java b/EventBus/src/org/greenrobot/eventbus/Poster.java new file mode 100644 index 00000000..3ebe24f4 --- /dev/null +++ b/EventBus/src/org/greenrobot/eventbus/Poster.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.greenrobot.eventbus; + +/** + * Posts events. + * + * @author William Ferguson + */ +interface Poster { + + /** + * Enqueue an event to be posted for a particular subscription. + * + * @param subscription Subscription which will receive the event. + * @param event Event that will be posted to subscribers. + */ + void enqueue(Subscription subscription, Object event); +} diff --git a/EventBus/src/org/greenrobot/eventbus/SyncPoster.java b/EventBus/src/org/greenrobot/eventbus/SyncPoster.java new file mode 100644 index 00000000..29e5c0cf --- /dev/null +++ b/EventBus/src/org/greenrobot/eventbus/SyncPoster.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.greenrobot.eventbus; + + +/** + * Posts events in the current Thread. + * + * @author William Ferguson + */ +class SyncPoster implements Poster { + + private final EventBus eventBus; + + SyncPoster(EventBus eventBus) { + this.eventBus = eventBus; + } + + public void enqueue(Subscription subscription, Object event) { + eventBus.invokeSubscriber(subscription, event); + } +} diff --git a/EventBus/src/org/greenrobot/eventbus/log/AndroidLog.java b/EventBus/src/org/greenrobot/eventbus/log/AndroidLog.java new file mode 100644 index 00000000..c15def5a --- /dev/null +++ b/EventBus/src/org/greenrobot/eventbus/log/AndroidLog.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) Xandar IP 2013. + * + * All Rights Reserved + * No part of this application may be reproduced, copied, modified or adapted, without the prior written consent + * of the author, unless otherwise indicated for stand-alone materials. + * + * Contact support@xandar.com.au for copyright requests. + */ + +package org.greenrobot.eventbus.log; + +import android.util.Log; + +/** + * Logs to the Android log. + */ +public final class AndroidLog implements GenericLog { + + private final String tag; + + public AndroidLog(String tag) { + this.tag = tag; + } + + @Override + public void v(String msg) { + Log.v(tag, msg); + } + + @Override + public void v(String msg, Throwable tr) { + Log.v(tag, msg, tr); + } + + @Override + public void d(String msg) { + Log.d(tag, msg); + } + + @Override + public void d(String msg, Throwable tr) { + Log.d(tag, msg, tr); + } + + @Override + public void i(String msg) { + Log.i(tag, msg); + } + + @Override + public void i(String msg, Throwable tr) { + Log.i(tag, msg, tr); + } + + @Override + public void w(String msg) { + Log.w(tag, msg); + } + + @Override + public void w(String msg, Throwable tr) { + Log.w(tag, msg, tr); + } + + @Override + public void w(Throwable tr) { + Log.w(tag, tr); + } + + @Override + public void e(String msg) { + Log.e(tag, msg); + } + + @Override + public void e(String msg, Throwable tr) { + Log.e(tag, msg, tr); + } + + @Override + public void wtf(String msg) { + Log.wtf(tag, msg); + } + + @Override + public void wtf(Throwable tr) { + Log.wtf(tag, tr); + } + + @Override + public void wtf(String msg, Throwable tr) { + Log.wtf(tag, msg, tr); + } +} diff --git a/EventBus/src/org/greenrobot/eventbus/log/EBLog.java b/EventBus/src/org/greenrobot/eventbus/log/EBLog.java new file mode 100644 index 00000000..a321c9e5 --- /dev/null +++ b/EventBus/src/org/greenrobot/eventbus/log/EBLog.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) Xandar IP 2013. + * + * All Rights Reserved + * No part of this application may be reproduced, copied, modified or adapted, without the prior written consent + * of the author, unless otherwise indicated for stand-alone materials. + * + * Contact support@xandar.com.au for copyright requests. + */ + +package org.greenrobot.eventbus.log; + +/** + * Provides a platform neutral logging target for all EVentBus logging.. + */ +public final class EBLog { + + private static GenericLog log; + + public static void setLogTarget(GenericLog logTarget) { + log = logTarget; + } + + public static void v(String msg) { + log.v(msg); + } + + public static void v(String msg, Throwable tr) { + log.v(msg, tr); + } + + public static void d(String msg) { + log.d(msg); + } + + public static void d(String msg, Throwable tr) { + log.d(msg, tr); + } + + public static void i(String msg) { + log.i(msg); + } + + public static void i(String msg, Throwable tr) { + log.i(msg, tr); + } + + public static void w(String msg) { + log.w(msg); + } + + public static void w(String msg, Throwable tr) { + log.w(msg, tr); + } + + public static void w(Throwable tr) { + log.w(tr); + } + + public static void e(String msg) { + log.e(msg); + } + + public static void e(String msg, Throwable tr) { + log.e(msg, tr); + } + + public static void wtf(String msg) { + log.wtf(msg); + } + + public static void wtf(Throwable tr) { + log.wtf(tr); + } + + public static void wtf(String msg, Throwable tr) { + log.wtf(msg, tr); + } +} diff --git a/EventBus/src/org/greenrobot/eventbus/log/GenericLog.java b/EventBus/src/org/greenrobot/eventbus/log/GenericLog.java new file mode 100644 index 00000000..8ad08177 --- /dev/null +++ b/EventBus/src/org/greenrobot/eventbus/log/GenericLog.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) Xandar IP 2013. + * + * All Rights Reserved + * No part of this application may be reproduced, copied, modified or adapted, without the prior written consent + * of the author, unless otherwise indicated for stand-alone materials. + * + * Contact support@xandar.com.au for copyright requests. + */ + +package org.greenrobot.eventbus.log; + +/** + * Means of logging regardless of what platform you are on. + * + * @author William Ferguson + */ +public interface GenericLog { + + void v(String msg); + void v(String msg, Throwable tr); + + void d(String msg); + void d(String msg, Throwable tr); + + void i(String msg); + void i(String msg, Throwable tr); + + void w(String msg); + void w(String msg, Throwable tr); + void w(Throwable tr); + + void e(String msg); + void e(String msg, Throwable tr); + + void wtf(String msg); + void wtf(Throwable tr); + void wtf(String msg, Throwable tr); +} diff --git a/EventBus/src/org/greenrobot/eventbus/log/SystemOutLog.java b/EventBus/src/org/greenrobot/eventbus/log/SystemOutLog.java new file mode 100644 index 00000000..096af53f --- /dev/null +++ b/EventBus/src/org/greenrobot/eventbus/log/SystemOutLog.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) Xandar IP 2013. + * + * All Rights Reserved + * No part of this application may be reproduced, copied, modified or adapted, without the prior written consent + * of the author, unless otherwise indicated for stand-alone materials. + * + * Contact support@xandar.com.au for copyright requests. + */ + +package org.greenrobot.eventbus.log; + +/** + * Logs to SystemOut. + * + * @author William Ferguson + */ +public final class SystemOutLog implements GenericLog { + + @Override + public void v(String msg) { + System.out.println("VERBOSE: " + msg); + } + + @Override + public void v(String msg, Throwable tr) { + System.out.println("VERBOSE: " + msg); + System.out.println("VERBOSE: " + tr.getMessage()); + tr.printStackTrace(System.out); + } + + @Override + public void d(String msg) { + System.out.println("DEBUG: " + msg); + } + + @Override + public void d(String msg, Throwable tr) { + System.out.println("DEBUG: " + msg); + System.out.println("DEBUG: " + tr.getMessage()); + tr.printStackTrace(System.out); + } + + @Override + public void i(String msg) { + System.out.println("INFO: " + msg); + } + + @Override + public void i(String msg, Throwable tr) { + System.out.println("INFO: " + msg); + System.out.println("INFO: " + tr.getMessage()); + tr.printStackTrace(System.out); + } + + @Override + public void w(String msg) { + System.out.println("WARN: " + msg); + } + + @Override + public void w(String msg, Throwable tr) { + System.out.println("WARN: " + msg); + System.out.println("WARN: " + tr.getMessage()); + tr.printStackTrace(System.out); + } + + @Override + public void w(Throwable tr) { + System.out.println("WARN: " + tr.getMessage()); + tr.printStackTrace(System.out); + } + + @Override + public void e(String msg) { + System.out.println("ERROR: " + msg); + } + + @Override + public void e(String msg, Throwable tr) { + System.out.println("ERROR: " + msg); + System.out.println("ERROR: " + tr.getMessage()); + tr.printStackTrace(System.out); + } + + @Override + public void wtf(String msg) { + System.out.println("WTF: " + msg); + } + + @Override + public void wtf(Throwable tr) { + System.out.println("WTF: " + tr.getMessage()); + tr.printStackTrace(System.out); + } + + @Override + public void wtf(String msg, Throwable tr) { + System.out.println("WTF: " + msg); + System.out.println("WTF: " + tr.getMessage()); + tr.printStackTrace(System.out); + } +} diff --git a/EventBus/src/org/greenrobot/eventbus/util/AndroidMTCalculator.java b/EventBus/src/org/greenrobot/eventbus/util/AndroidMTCalculator.java new file mode 100644 index 00000000..23ce5753 --- /dev/null +++ b/EventBus/src/org/greenrobot/eventbus/util/AndroidMTCalculator.java @@ -0,0 +1,16 @@ +package org.greenrobot.eventbus.util; + +import android.os.Looper; + +/** + * Returns true if the current Thread is the Android Main Looper Thread. + * + * @author William Ferguson + */ +public class AndroidMTCalculator implements MainThreadCalculator { + + @Override + public boolean isMainThread() { + return Looper.getMainLooper() == Looper.myLooper(); + } +} diff --git a/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java b/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java index c44c1366..d989b361 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java +++ b/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java @@ -15,10 +15,8 @@ */ package org.greenrobot.eventbus.util; -import android.app.Activity; -import android.util.Log; - import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.log.EBLog; import java.lang.reflect.Constructor; import java.util.concurrent.Executor; @@ -59,7 +57,7 @@ public AsyncExecutor build() { return buildForScope(null); } - public AsyncExecutor buildForActivityScope(Activity activity) { + public AsyncExecutor buildForActivityScope(Object activity) { return buildForScope(activity.getClass()); } @@ -119,7 +117,7 @@ public void run() { try { event = failureEventConstructor.newInstance(e); } catch (Exception e1) { - Log.e(EventBus.TAG, "Original exception:", e); + EBLog.e("Original exception:", e); throw new RuntimeException("Could not create failure event", e1); } if (event instanceof HasExecutionScope) { diff --git a/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java b/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java index 9ab0d006..b334c13c 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java @@ -16,9 +16,7 @@ package org.greenrobot.eventbus.util; -import android.util.Log; - -import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.log.EBLog; import java.util.HashMap; import java.util.Map; @@ -36,7 +34,7 @@ public class ExceptionToResourceMapping { public final Map, Integer> throwableToMsgIdMap; public ExceptionToResourceMapping() { - throwableToMsgIdMap = new HashMap, Integer>(); + throwableToMsgIdMap = new HashMap<>(); } /** Looks at the exception and its causes trying to find an ID. */ @@ -52,7 +50,7 @@ public Integer mapThrowable(final Throwable throwable) { throwableToCheck = throwableToCheck.getCause(); depthToGo--; if (depthToGo <= 0 || throwableToCheck == throwable || throwableToCheck == null) { - Log.d(EventBus.TAG, "No specific message ressource ID found for " + throwable); + EBLog.d("No specific message resource ID found for " + throwable); // return config.defaultErrorMsgId; return null; } diff --git a/EventBus/src/org/greenrobot/eventbus/util/MainThreadCalculator.java b/EventBus/src/org/greenrobot/eventbus/util/MainThreadCalculator.java new file mode 100644 index 00000000..6feeb21d --- /dev/null +++ b/EventBus/src/org/greenrobot/eventbus/util/MainThreadCalculator.java @@ -0,0 +1,14 @@ +package org.greenrobot.eventbus.util; + +/** + * Determines whether the current Thread is the Android Main Looper Thread. + * + * @author William Ferguson + */ +public interface MainThreadCalculator { + + /** + * @return true if the current Thread is the Android Main Looper Thread. + */ + boolean isMainThread(); +} diff --git a/EventBus/src/org/greenrobot/eventbus/util/NonAndroidMTCalculator.java b/EventBus/src/org/greenrobot/eventbus/util/NonAndroidMTCalculator.java new file mode 100644 index 00000000..2a7897ee --- /dev/null +++ b/EventBus/src/org/greenrobot/eventbus/util/NonAndroidMTCalculator.java @@ -0,0 +1,12 @@ +package org.greenrobot.eventbus.util; + +/** + * Always returns false as the Main Looper Thread only occurs within Android. + */ +public class NonAndroidMTCalculator implements MainThreadCalculator { + + @Override + public boolean isMainThread() { + return false; + } +} From 5b3a8c47eb2f75a8b563ad7abe1aef1d7a349347 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 5 Feb 2016 19:24:14 +0100 Subject: [PATCH 175/288] simplified Logger to use java.util.logging.Level --- EventBus/src/de/greenrobot/event/Logger.java | 213 +++++-------------- 1 file changed, 50 insertions(+), 163 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/Logger.java b/EventBus/src/de/greenrobot/event/Logger.java index 9d7cba85..b2af3d40 100644 --- a/EventBus/src/de/greenrobot/event/Logger.java +++ b/EventBus/src/de/greenrobot/event/Logger.java @@ -1,7 +1,5 @@ package de.greenrobot.event; -import android.annotation.TargetApi; -import android.os.Build; import android.util.Log; import java.util.logging.Level; @@ -45,195 +43,84 @@ public static Logger create(String tag) { } } + public abstract boolean isLoggable(Level level); - public abstract boolean isLoggable(int level); + public abstract void log(Level level, String msg); - public abstract void v(String msg); - - public abstract void v(String msg, Throwable th); - - public abstract void d(String msg); - - public abstract void d(String msg, Throwable th); - - public abstract void i(String msg); - - public abstract void i(String msg, Throwable th); - - public abstract void w(String msg); - - public abstract void w(String msg, Throwable th); - - public abstract void w(Throwable th); - - public abstract void e(String msg); - - public abstract void e(String msg, Throwable th); - - public abstract void wtf(String msg); - - public abstract void wtf(String msg, Throwable th); + public abstract void log(Level level, String msg, Throwable th); public static class AndroidLogger extends Logger { - public static final int VERBOSE = 2; - public static final int DEBUG = 3; - public static final int INFO = 4; - public static final int WARN = 5; - public static final int ERROR = 6; - public static final int ASSERT = 7; - private final String tag; public AndroidLogger(String tag) { this.tag = tag; } - public boolean isLoggable(int level) { - return Log.isLoggable(tag, level); - } - - public void v(String msg) { - Log.v(tag, msg); - } - - public void v(String msg, Throwable th) { - Log.v(tag, msg, th); - } - - public void d(String msg) { - Log.d(tag, msg); - } - - public void d(String msg, Throwable th) { - Log.d(tag, msg, th); - } - - public void i(String msg) { - Log.i(tag, msg); - } - - public void i(String msg, Throwable th) { - Log.i(tag, msg, th); - } - - public void w(String msg) { - Log.w(tag, msg); - } - - public void w(String msg, Throwable th) { - Log.w(tag, msg, th); - } - - public void w(Throwable th) { - Log.w(tag, th); - } - - public void e(String msg) { - Log.e(tag, msg); - } - - public void e(String msg, Throwable th) { - Log.e(tag, msg, th); - } - - @TargetApi(Build.VERSION_CODES.FROYO) - @Override - public void wtf(String msg) { - Log.wtf(tag, msg); + public boolean isLoggable(Level level) { + if (level == Level.OFF) { + return false; + } else { + return Log.isLoggable(tag, mapLevel(level)); + } + } + + public void log(Level level, String msg) { + if (level != Level.OFF) { + Log.println(mapLevel(level), tag, msg); + } + } + + public void log(Level level, String msg, Throwable th) { + if (level != Level.OFF) { + // That's how Log does it internally + Log.println(mapLevel(level), tag, msg + "\n" + Log.getStackTraceString(th)); + } + } + + protected int mapLevel(Level level) { + if (level == Level.OFF) { + return 0; + } else if (level == Level.FINEST || level == Level.FINER) { + return Log.VERBOSE; + } else if (level == Level.FINE || level == Level.CONFIG) { + return Log.DEBUG; + } else if (level == Level.INFO) { + return Log.INFO; + } else if (level == Level.WARNING) { + return Log.WARN; + } else if (level == Level.SEVERE) { + return Log.ERROR; + } else if (level == Level.ALL) { + // Hmm, well.. + return Log.ASSERT; + } else { + throw new IllegalArgumentException("Unexpected level: " + level); + } } - @TargetApi(Build.VERSION_CODES.FROYO) - @Override - public void wtf(String msg, Throwable th) { - Log.wtf(tag, msg, th); - } } public static class JavaLogger extends Logger { - private static final Level[] LEVEL_MAP = { - Level.OFF, Level.OFF, Level.OFF, // Unused - Level.FINEST, // VERBOSE = 2 - Level.FINE, //DEBUG = 3 - Level.INFO, // INFO = 4 - Level.WARNING, // WARN = 5 - Level.SEVERE, //ERROR = 6 - Level.SEVERE, //ASSERT = 7 - }; - - java.util.logging.Logger logger = java.util.logging.Logger.getLogger(""); + protected final java.util.logging.Logger logger; public JavaLogger(String tag) { logger = java.util.logging.Logger.getLogger(tag); } @Override - public boolean isLoggable(int level) { - return logger.isLoggable(LEVEL_MAP[level]); - } - - @Override - public void v(String msg) { - logger.finest(msg); - } - - @Override - public void v(String msg, Throwable th) { - logger.log(Level.FINEST, msg, th); - } - - @Override - public void d(String msg) { - logger.fine(msg); - } - - @Override - public void d(String msg, Throwable th) { - logger.log(Level.FINE, msg, th); - } - - @Override - public void i(String msg) { - logger.info(msg); - } - - @Override - public void i(String msg, Throwable th) { - logger.log(Level.INFO, msg, th); - } - - @Override - public void w(String msg) { - logger.warning(msg); - } - - @Override - public void w(String msg, Throwable th) { - logger.log(Level.WARNING, msg, th); + public boolean isLoggable(Level level) { + return logger.isLoggable(level); } @Override - public void w(Throwable th) { - logger.log(Level.WARNING, null, th); + public void log(Level level, String msg) { + logger.log(level, msg); } @Override - public void e(String msg) { - logger.severe(msg); + public void log(Level level, String msg, Throwable th) { + logger.log(level, msg, th); } - @Override - public void e(String msg, Throwable th) { - logger.log(Level.SEVERE, msg, th); - } - - @Override - public void wtf(String msg) { - logger.severe(msg); - } - - @Override - public void wtf(String msg, Throwable th) { - logger.log(Level.SEVERE, msg, th); - } } } From b034e2c0ecf9e07013a559d1f57c229dc0ea66ff Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 8 Feb 2016 18:19:56 +0100 Subject: [PATCH 176/288] remove DEFAULT_LOGGER, map level based on intValue --- EventBus/src/de/greenrobot/event/Logger.java | 43 +++++--------------- 1 file changed, 10 insertions(+), 33 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/Logger.java b/EventBus/src/de/greenrobot/event/Logger.java index b2af3d40..10a11970 100644 --- a/EventBus/src/de/greenrobot/event/Logger.java +++ b/EventBus/src/de/greenrobot/event/Logger.java @@ -6,8 +6,6 @@ public abstract class Logger { private static final boolean useAndroidLog; - private static volatile Logger DEFAULT_LOGGER; - static { boolean android = false; @@ -19,22 +17,6 @@ public abstract class Logger { useAndroidLog = android; } - - public static synchronized Logger initDefaultLogger(String tag) { - if (DEFAULT_LOGGER != null) { - throw new IllegalStateException("Default logger already set up"); - } - DEFAULT_LOGGER = create(tag); - return DEFAULT_LOGGER; - } - - public static Logger get() { - if (DEFAULT_LOGGER == null) { - throw new IllegalStateException("Default logger must be initialized before"); - } - return DEFAULT_LOGGER; - } - public static Logger create(String tag) { if (useAndroidLog) { return new AndroidLogger(tag); @@ -78,26 +60,21 @@ public void log(Level level, String msg, Throwable th) { } protected int mapLevel(Level level) { - if (level == Level.OFF) { - return 0; - } else if (level == Level.FINEST || level == Level.FINER) { - return Log.VERBOSE; - } else if (level == Level.FINE || level == Level.CONFIG) { - return Log.DEBUG; - } else if (level == Level.INFO) { + int value = level.intValue(); + if (value < 800) { // below INFO + if (value < 500) { // below FINE + return Log.VERBOSE; + } else { + return Log.DEBUG; + } + } else if (value < 900) { // below WARNING return Log.INFO; - } else if (level == Level.WARNING) { + } else if (value < 1000) { // below ERROR return Log.WARN; - } else if (level == Level.SEVERE) { - return Log.ERROR; - } else if (level == Level.ALL) { - // Hmm, well.. - return Log.ASSERT; } else { - throw new IllegalArgumentException("Unexpected level: " + level); + return Log.ERROR; } } - } public static class JavaLogger extends Logger { From e4f7ea1d27b691ca0a08434c249483017d9a0cc2 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 15 Feb 2016 19:03:25 +0100 Subject: [PATCH 177/288] SystemOutLogger etc. --- EventBus/src/de/greenrobot/event/Logger.java | 35 +++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/Logger.java b/EventBus/src/de/greenrobot/event/Logger.java index 10a11970..897d437b 100644 --- a/EventBus/src/de/greenrobot/event/Logger.java +++ b/EventBus/src/de/greenrobot/event/Logger.java @@ -5,7 +5,7 @@ import java.util.logging.Level; public abstract class Logger { - private static final boolean useAndroidLog; + private static final boolean ANDROID_LOG_AVAILABLE; static { boolean android = false; @@ -14,14 +14,18 @@ public abstract class Logger { } catch (ClassNotFoundException e) { // OK } - useAndroidLog = android; + ANDROID_LOG_AVAILABLE = android; + } + + public static boolean isAndroidLogAvailable() { + return ANDROID_LOG_AVAILABLE; } public static Logger create(String tag) { - if (useAndroidLog) { + if (ANDROID_LOG_AVAILABLE) { return new AndroidLogger(tag); } else { - return new JavaLogger(tag); + return new SystemOutLogger(); } } @@ -91,13 +95,36 @@ public boolean isLoggable(Level level) { @Override public void log(Level level, String msg) { + // TODO Replace logged method with caller method logger.log(level, msg); } @Override public void log(Level level, String msg, Throwable th) { + // TODO Replace logged method with caller method logger.log(level, msg, th); } } + + public static class SystemOutLogger extends Logger { + + @Override + public boolean isLoggable(Level level) { + return true; + } + + @Override + public void log(Level level, String msg) { + System.out.println("[" + level + "] " + msg); + } + + @Override + public void log(Level level, String msg, Throwable th) { + System.out.println("[" + level + "] " + msg); + th.printStackTrace(System.out); + } + + } + } From 06dfe109da0261838f56a82cc407bf581ca83701 Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 25 Feb 2016 23:58:58 +0100 Subject: [PATCH 178/288] replaced logging with smaller Logger --- .../greenrobot/eventbus/BackgroundPoster.java | 6 +- .../src/org/greenrobot/eventbus/EventBus.java | 28 ++--- .../greenrobot/eventbus/EventBusBuilder.java | 22 ++-- .../greenrobot/eventbus}/Logger.java | 66 ++++------- .../greenrobot/eventbus/log/AndroidLog.java | 95 ---------------- .../org/greenrobot/eventbus/log/EBLog.java | 79 -------------- .../greenrobot/eventbus/log/GenericLog.java | 39 ------- .../greenrobot/eventbus/log/SystemOutLog.java | 103 ------------------ .../eventbus/util/AsyncExecutor.java | 4 +- .../util/ExceptionToResourceMapping.java | 4 +- 10 files changed, 54 insertions(+), 392 deletions(-) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/Logger.java (59%) delete mode 100644 EventBus/src/org/greenrobot/eventbus/log/AndroidLog.java delete mode 100644 EventBus/src/org/greenrobot/eventbus/log/EBLog.java delete mode 100644 EventBus/src/org/greenrobot/eventbus/log/GenericLog.java delete mode 100644 EventBus/src/org/greenrobot/eventbus/log/SystemOutLog.java diff --git a/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java b/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java index d2e5dcfb..624ddf6d 100644 --- a/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java +++ b/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java @@ -15,11 +15,11 @@ */ package org.greenrobot.eventbus; -import org.greenrobot.eventbus.log.EBLog; +import java.util.logging.Level; /** * Posts events in background. - * + * * @author Markus */ final class BackgroundPoster implements Runnable, Poster { @@ -64,7 +64,7 @@ public void run() { eventBus.invokeSubscriber(pendingPost); } } catch (InterruptedException e) { - EBLog.w(Thread.currentThread().getName() + " was interruppted", e); + eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e); } } finally { executorRunning = false; diff --git a/EventBus/src/org/greenrobot/eventbus/EventBus.java b/EventBus/src/org/greenrobot/eventbus/EventBus.java index ae2b5834..8312a983 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBus.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBus.java @@ -15,9 +15,6 @@ */ package org.greenrobot.eventbus; -import org.greenrobot.eventbus.log.AndroidLog; -import org.greenrobot.eventbus.log.EBLog; -import org.greenrobot.eventbus.log.SystemOutLog; import org.greenrobot.eventbus.util.AndroidMTCalculator; import org.greenrobot.eventbus.util.MainThreadCalculator; import org.greenrobot.eventbus.util.NonAndroidMTCalculator; @@ -31,6 +28,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; +import java.util.logging.Level; /** * EventBus is a central publish/subscribe event system for Android. Events are posted ({@link #post(Object)}) to the @@ -78,6 +76,7 @@ protected PostingThreadState initialValue() { private final boolean eventInheritance; private final int indexCount; + private final Logger logger; /** Convenience singleton for apps using a process-wide EventBus instance. */ public static EventBus getDefault() { @@ -110,11 +109,7 @@ public EventBus() { } EventBus(EventBusBuilder builder) { - if (builder.logTarget == null) { - EBLog.setLogTarget(builder.nonAndroidEnvironment ? new SystemOutLog() : new AndroidLog(TAG)); - } else { - EBLog.setLogTarget(builder.logTarget); - } + logger = builder.initLogger(); subscriptionsByEventType = new HashMap<>(); typesBySubscriber = new HashMap<>(); stickyEvents = new ConcurrentHashMap<>(); @@ -241,7 +236,7 @@ public synchronized void unregister(Object subscriber) { } typesBySubscriber.remove(subscriber); } else { - EBLog.w("Subscriber to unregister was not registered before: " + subscriber.getClass()); + logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass()); } } @@ -385,7 +380,7 @@ private void postSingleEvent(Object event, PostingThreadState postingState) thro } if (!subscriptionFound) { if (logNoSubscriberMessages) { - EBLog.d("No subscribers registered for event " + eventClass); + logger.log(Level.FINE, "No subscribers registered for event " + eventClass); } if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) { @@ -505,10 +500,10 @@ private void handleSubscriberException(Subscription subscription, Object event, if (event instanceof SubscriberExceptionEvent) { if (logSubscriberExceptions) { // Don't send another SubscriberExceptionEvent to avoid infinite event recursion, just log - EBLog.e("SubscriberExceptionEvent subscriber " + subscription.subscriber.getClass() + logger.log(Level.SEVERE, "SubscriberExceptionEvent subscriber " + subscription.subscriber.getClass() + " threw an exception", cause); SubscriberExceptionEvent exEvent = (SubscriberExceptionEvent) event; - EBLog.e("Initial event " + exEvent.causingEvent + " caused exception in " + logger.log(Level.SEVERE, "Initial event " + exEvent.causingEvent + " caused exception in " + exEvent.causingSubscriber, exEvent.throwable); } } else { @@ -516,7 +511,7 @@ private void handleSubscriberException(Subscription subscription, Object event, throw new EventBusException("Invoking subscriber failed", cause); } if (logSubscriberExceptions) { - EBLog.e("Could not dispatch event: " + event.getClass() + " to subscribing class " + logger.log(Level.SEVERE, "Could not dispatch event: " + event.getClass() + " to subscribing class " + subscription.subscriber.getClass(), cause); } if (sendSubscriberExceptionEvent) { @@ -541,6 +536,13 @@ ExecutorService getExecutorService() { return executorService; } + /** + * For internal use only. + */ + public Logger getLogger() { + return logger; + } + // Just an idea: we could provide a callback to post() to be notified, an alternative would be events, of course... /* public */interface PostCallback { void onPostCompleted(List exceptionEvents); diff --git a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java index 3a899a21..b12a7f38 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java @@ -17,8 +17,6 @@ import org.greenrobot.eventbus.meta.SubscriberInfoIndex; -import org.greenrobot.eventbus.log.GenericLog; - import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; @@ -42,7 +40,7 @@ public class EventBusBuilder { ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE; List> skipMethodVerificationForClasses; List subscriberInfoIndexes; - GenericLog logTarget; + Logger logger; boolean nonAndroidEnvironment; EventBusBuilder() { @@ -134,7 +132,7 @@ public EventBusBuilder strictMethodVerification(boolean strictMethodVerification /** Adds an index generated by EventBus' annotation preprocessor. */ public EventBusBuilder addIndex(SubscriberInfoIndex index) { - if(subscriberInfoIndexes == null) { + if (subscriberInfoIndexes == null) { subscriberInfoIndexes = new ArrayList<>(); } subscriberInfoIndexes.add(index); @@ -143,18 +141,22 @@ public EventBusBuilder addIndex(SubscriberInfoIndex index) { /** * Set a specific log handler for all EventBus logging. - * + *

* By default all logging is via {@link android.util.Log} but if you want to use EventBus * outside the Android environment then you will need to provide another log target. */ - public EventBusBuilder logger(GenericLog logTarget) { - this.logTarget = logTarget; + public EventBusBuilder logger(Logger logger) { + this.logger = logger; return this; } - public EventBusBuilder nonAndroidEnvironment(boolean nonAndroidEnvironment) { - this.nonAndroidEnvironment = nonAndroidEnvironment; - return this; + Logger initLogger() { + if (logger != null) { + return logger; + } else { + return Logger.AndroidLogger.isAndroidLogAvailable() ? new Logger.AndroidLogger("EventBus") : + new Logger.SystemOutLogger(); + } } /** diff --git a/EventBus/src/de/greenrobot/event/Logger.java b/EventBus/src/org/greenrobot/eventbus/Logger.java similarity index 59% rename from EventBus/src/de/greenrobot/event/Logger.java rename to EventBus/src/org/greenrobot/eventbus/Logger.java index 897d437b..7a1ad232 100644 --- a/EventBus/src/de/greenrobot/event/Logger.java +++ b/EventBus/src/org/greenrobot/eventbus/Logger.java @@ -1,55 +1,39 @@ -package de.greenrobot.event; +package org.greenrobot.eventbus; import android.util.Log; import java.util.logging.Level; -public abstract class Logger { - private static final boolean ANDROID_LOG_AVAILABLE; +public interface Logger { - static { - boolean android = false; - try { - android = Class.forName("android.util.Log") != null; - } catch (ClassNotFoundException e) { - // OK - } - ANDROID_LOG_AVAILABLE = android; - } + void log(Level level, String msg); - public static boolean isAndroidLogAvailable() { - return ANDROID_LOG_AVAILABLE; - } + void log(Level level, String msg, Throwable th); - public static Logger create(String tag) { - if (ANDROID_LOG_AVAILABLE) { - return new AndroidLogger(tag); - } else { - return new SystemOutLogger(); - } - } + public static class AndroidLogger implements Logger { + static final boolean ANDROID_LOG_AVAILABLE; - public abstract boolean isLoggable(Level level); + static { + boolean android = false; + try { + android = Class.forName("android.util.Log") != null; + } catch (ClassNotFoundException e) { + // OK + } + ANDROID_LOG_AVAILABLE = android; + } - public abstract void log(Level level, String msg); + public static boolean isAndroidLogAvailable() { + return ANDROID_LOG_AVAILABLE; + } - public abstract void log(Level level, String msg, Throwable th); - public static class AndroidLogger extends Logger { private final String tag; public AndroidLogger(String tag) { this.tag = tag; } - public boolean isLoggable(Level level) { - if (level == Level.OFF) { - return false; - } else { - return Log.isLoggable(tag, mapLevel(level)); - } - } - public void log(Level level, String msg) { if (level != Level.OFF) { Log.println(mapLevel(level), tag, msg); @@ -81,18 +65,13 @@ protected int mapLevel(Level level) { } } - public static class JavaLogger extends Logger { + public static class JavaLogger implements Logger { protected final java.util.logging.Logger logger; public JavaLogger(String tag) { logger = java.util.logging.Logger.getLogger(tag); } - @Override - public boolean isLoggable(Level level) { - return logger.isLoggable(level); - } - @Override public void log(Level level, String msg) { // TODO Replace logged method with caller method @@ -107,12 +86,7 @@ public void log(Level level, String msg, Throwable th) { } - public static class SystemOutLogger extends Logger { - - @Override - public boolean isLoggable(Level level) { - return true; - } + public static class SystemOutLogger implements Logger { @Override public void log(Level level, String msg) { diff --git a/EventBus/src/org/greenrobot/eventbus/log/AndroidLog.java b/EventBus/src/org/greenrobot/eventbus/log/AndroidLog.java deleted file mode 100644 index c15def5a..00000000 --- a/EventBus/src/org/greenrobot/eventbus/log/AndroidLog.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) Xandar IP 2013. - * - * All Rights Reserved - * No part of this application may be reproduced, copied, modified or adapted, without the prior written consent - * of the author, unless otherwise indicated for stand-alone materials. - * - * Contact support@xandar.com.au for copyright requests. - */ - -package org.greenrobot.eventbus.log; - -import android.util.Log; - -/** - * Logs to the Android log. - */ -public final class AndroidLog implements GenericLog { - - private final String tag; - - public AndroidLog(String tag) { - this.tag = tag; - } - - @Override - public void v(String msg) { - Log.v(tag, msg); - } - - @Override - public void v(String msg, Throwable tr) { - Log.v(tag, msg, tr); - } - - @Override - public void d(String msg) { - Log.d(tag, msg); - } - - @Override - public void d(String msg, Throwable tr) { - Log.d(tag, msg, tr); - } - - @Override - public void i(String msg) { - Log.i(tag, msg); - } - - @Override - public void i(String msg, Throwable tr) { - Log.i(tag, msg, tr); - } - - @Override - public void w(String msg) { - Log.w(tag, msg); - } - - @Override - public void w(String msg, Throwable tr) { - Log.w(tag, msg, tr); - } - - @Override - public void w(Throwable tr) { - Log.w(tag, tr); - } - - @Override - public void e(String msg) { - Log.e(tag, msg); - } - - @Override - public void e(String msg, Throwable tr) { - Log.e(tag, msg, tr); - } - - @Override - public void wtf(String msg) { - Log.wtf(tag, msg); - } - - @Override - public void wtf(Throwable tr) { - Log.wtf(tag, tr); - } - - @Override - public void wtf(String msg, Throwable tr) { - Log.wtf(tag, msg, tr); - } -} diff --git a/EventBus/src/org/greenrobot/eventbus/log/EBLog.java b/EventBus/src/org/greenrobot/eventbus/log/EBLog.java deleted file mode 100644 index a321c9e5..00000000 --- a/EventBus/src/org/greenrobot/eventbus/log/EBLog.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) Xandar IP 2013. - * - * All Rights Reserved - * No part of this application may be reproduced, copied, modified or adapted, without the prior written consent - * of the author, unless otherwise indicated for stand-alone materials. - * - * Contact support@xandar.com.au for copyright requests. - */ - -package org.greenrobot.eventbus.log; - -/** - * Provides a platform neutral logging target for all EVentBus logging.. - */ -public final class EBLog { - - private static GenericLog log; - - public static void setLogTarget(GenericLog logTarget) { - log = logTarget; - } - - public static void v(String msg) { - log.v(msg); - } - - public static void v(String msg, Throwable tr) { - log.v(msg, tr); - } - - public static void d(String msg) { - log.d(msg); - } - - public static void d(String msg, Throwable tr) { - log.d(msg, tr); - } - - public static void i(String msg) { - log.i(msg); - } - - public static void i(String msg, Throwable tr) { - log.i(msg, tr); - } - - public static void w(String msg) { - log.w(msg); - } - - public static void w(String msg, Throwable tr) { - log.w(msg, tr); - } - - public static void w(Throwable tr) { - log.w(tr); - } - - public static void e(String msg) { - log.e(msg); - } - - public static void e(String msg, Throwable tr) { - log.e(msg, tr); - } - - public static void wtf(String msg) { - log.wtf(msg); - } - - public static void wtf(Throwable tr) { - log.wtf(tr); - } - - public static void wtf(String msg, Throwable tr) { - log.wtf(msg, tr); - } -} diff --git a/EventBus/src/org/greenrobot/eventbus/log/GenericLog.java b/EventBus/src/org/greenrobot/eventbus/log/GenericLog.java deleted file mode 100644 index 8ad08177..00000000 --- a/EventBus/src/org/greenrobot/eventbus/log/GenericLog.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) Xandar IP 2013. - * - * All Rights Reserved - * No part of this application may be reproduced, copied, modified or adapted, without the prior written consent - * of the author, unless otherwise indicated for stand-alone materials. - * - * Contact support@xandar.com.au for copyright requests. - */ - -package org.greenrobot.eventbus.log; - -/** - * Means of logging regardless of what platform you are on. - * - * @author William Ferguson - */ -public interface GenericLog { - - void v(String msg); - void v(String msg, Throwable tr); - - void d(String msg); - void d(String msg, Throwable tr); - - void i(String msg); - void i(String msg, Throwable tr); - - void w(String msg); - void w(String msg, Throwable tr); - void w(Throwable tr); - - void e(String msg); - void e(String msg, Throwable tr); - - void wtf(String msg); - void wtf(Throwable tr); - void wtf(String msg, Throwable tr); -} diff --git a/EventBus/src/org/greenrobot/eventbus/log/SystemOutLog.java b/EventBus/src/org/greenrobot/eventbus/log/SystemOutLog.java deleted file mode 100644 index 096af53f..00000000 --- a/EventBus/src/org/greenrobot/eventbus/log/SystemOutLog.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) Xandar IP 2013. - * - * All Rights Reserved - * No part of this application may be reproduced, copied, modified or adapted, without the prior written consent - * of the author, unless otherwise indicated for stand-alone materials. - * - * Contact support@xandar.com.au for copyright requests. - */ - -package org.greenrobot.eventbus.log; - -/** - * Logs to SystemOut. - * - * @author William Ferguson - */ -public final class SystemOutLog implements GenericLog { - - @Override - public void v(String msg) { - System.out.println("VERBOSE: " + msg); - } - - @Override - public void v(String msg, Throwable tr) { - System.out.println("VERBOSE: " + msg); - System.out.println("VERBOSE: " + tr.getMessage()); - tr.printStackTrace(System.out); - } - - @Override - public void d(String msg) { - System.out.println("DEBUG: " + msg); - } - - @Override - public void d(String msg, Throwable tr) { - System.out.println("DEBUG: " + msg); - System.out.println("DEBUG: " + tr.getMessage()); - tr.printStackTrace(System.out); - } - - @Override - public void i(String msg) { - System.out.println("INFO: " + msg); - } - - @Override - public void i(String msg, Throwable tr) { - System.out.println("INFO: " + msg); - System.out.println("INFO: " + tr.getMessage()); - tr.printStackTrace(System.out); - } - - @Override - public void w(String msg) { - System.out.println("WARN: " + msg); - } - - @Override - public void w(String msg, Throwable tr) { - System.out.println("WARN: " + msg); - System.out.println("WARN: " + tr.getMessage()); - tr.printStackTrace(System.out); - } - - @Override - public void w(Throwable tr) { - System.out.println("WARN: " + tr.getMessage()); - tr.printStackTrace(System.out); - } - - @Override - public void e(String msg) { - System.out.println("ERROR: " + msg); - } - - @Override - public void e(String msg, Throwable tr) { - System.out.println("ERROR: " + msg); - System.out.println("ERROR: " + tr.getMessage()); - tr.printStackTrace(System.out); - } - - @Override - public void wtf(String msg) { - System.out.println("WTF: " + msg); - } - - @Override - public void wtf(Throwable tr) { - System.out.println("WTF: " + tr.getMessage()); - tr.printStackTrace(System.out); - } - - @Override - public void wtf(String msg, Throwable tr) { - System.out.println("WTF: " + msg); - System.out.println("WTF: " + tr.getMessage()); - tr.printStackTrace(System.out); - } -} diff --git a/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java b/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java index d989b361..ba5f263d 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java +++ b/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java @@ -16,11 +16,11 @@ package org.greenrobot.eventbus.util; import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.log.EBLog; import java.lang.reflect.Constructor; import java.util.concurrent.Executor; import java.util.concurrent.Executors; +import java.util.logging.Level; /** * Executes an {@link RunnableEx} using a thread pool. Thrown exceptions are propagated by posting failure events of any @@ -117,7 +117,7 @@ public void run() { try { event = failureEventConstructor.newInstance(e); } catch (Exception e1) { - EBLog.e("Original exception:", e); + eventBus.getLogger().log(Level.SEVERE, "Original exception:", e); throw new RuntimeException("Could not create failure event", e1); } if (event instanceof HasExecutionScope) { diff --git a/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java b/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java index b334c13c..a3bb67f3 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java @@ -16,7 +16,7 @@ package org.greenrobot.eventbus.util; -import org.greenrobot.eventbus.log.EBLog; +import android.util.Log; import java.util.HashMap; import java.util.Map; @@ -50,7 +50,7 @@ public Integer mapThrowable(final Throwable throwable) { throwableToCheck = throwableToCheck.getCause(); depthToGo--; if (depthToGo <= 0 || throwableToCheck == throwable || throwableToCheck == null) { - EBLog.d("No specific message resource ID found for " + throwable); + Log.d("EventBus", "No specific message resource ID found for " + throwable); // return config.defaultErrorMsgId; return null; } From 6fb7b67622c8d51e5085dffac5676adfe27b57ad Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 29 Feb 2016 18:17:06 +0100 Subject: [PATCH 179/288] MainThreadSupport interface as a single place for main thread support --- .../src/org/greenrobot/eventbus/EventBus.java | 28 ++++++++++----- .../greenrobot/eventbus/EventBusBuilder.java | 2 +- .../greenrobot/eventbus/HandlerPoster.java | 6 ++-- .../eventbus/MainThreadSupport.java | 33 +++++++++++++++++ .../org/greenrobot/eventbus/SyncPoster.java | 35 ------------------- .../eventbus/util/AndroidMTCalculator.java | 16 --------- .../eventbus/util/MainThreadCalculator.java | 14 -------- .../eventbus/util/NonAndroidMTCalculator.java | 12 ------- 8 files changed, 57 insertions(+), 89 deletions(-) create mode 100644 EventBus/src/org/greenrobot/eventbus/MainThreadSupport.java delete mode 100644 EventBus/src/org/greenrobot/eventbus/SyncPoster.java delete mode 100644 EventBus/src/org/greenrobot/eventbus/util/AndroidMTCalculator.java delete mode 100644 EventBus/src/org/greenrobot/eventbus/util/MainThreadCalculator.java delete mode 100644 EventBus/src/org/greenrobot/eventbus/util/NonAndroidMTCalculator.java diff --git a/EventBus/src/org/greenrobot/eventbus/EventBus.java b/EventBus/src/org/greenrobot/eventbus/EventBus.java index 8312a983..2518946b 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBus.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBus.java @@ -15,9 +15,7 @@ */ package org.greenrobot.eventbus; -import org.greenrobot.eventbus.util.AndroidMTCalculator; -import org.greenrobot.eventbus.util.MainThreadCalculator; -import org.greenrobot.eventbus.util.NonAndroidMTCalculator; +import android.os.Looper; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; @@ -61,12 +59,14 @@ protected PostingThreadState initialValue() { } }; + // @Nullable + private final MainThreadSupport mainThreadSupport; + // @Nullable private final Poster mainThreadPoster; private final BackgroundPoster backgroundPoster; private final AsyncPoster asyncPoster; private final SubscriberMethodFinder subscriberMethodFinder; private final ExecutorService executorService; - private final MainThreadCalculator mtCalculator; private final boolean throwSubscriberException; private final boolean logSubscriberExceptions; @@ -113,7 +113,10 @@ public EventBus() { subscriptionsByEventType = new HashMap<>(); typesBySubscriber = new HashMap<>(); stickyEvents = new ConcurrentHashMap<>(); - mainThreadPoster = (builder.nonAndroidEnvironment ? new SyncPoster(this) : new HandlerPoster(this, 10)); + mainThreadSupport = builder.mainThreadSupport != null ? builder.mainThreadSupport : + Logger.AndroidLogger.isAndroidLogAvailable() ? + new MainThreadSupport.AndroidHandlerMainThreadSupport(Looper.getMainLooper()) : null; + mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null; backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0; @@ -126,7 +129,6 @@ public EventBus() { throwSubscriberException = builder.throwSubscriberException; eventInheritance = builder.eventInheritance; executorService = builder.executorService; - mtCalculator = (builder.nonAndroidEnvironment ? new NonAndroidMTCalculator() : new AndroidMTCalculator()); } /** @@ -202,10 +204,20 @@ private void checkPostStickyEventToSubscription(Subscription newSubscription, Ob if (stickyEvent != null) { // If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state) // --> Strange corner case, which we don't take care of here. - postToSubscription(newSubscription, stickyEvent, mtCalculator.isMainThread()); + postToSubscription(newSubscription, stickyEvent, isMainThread()); } } + /** + * Checks if the current thread is running in the main thread. + * If there is no main thread support (e.g. non-Android), "true" is always returned. In that case MAIN thread + * subscribers are always called in posting thread, and BACKGROUND subscribers are always called from a background + * poster. + */ + private boolean isMainThread() { + return mainThreadSupport != null? mainThreadSupport.isMainThread(): true; + } + public synchronized boolean isRegistered(Object subscriber) { return typesBySubscriber.containsKey(subscriber); } @@ -247,7 +259,7 @@ public void post(Object event) { eventQueue.add(event); if (!postingState.isPosting) { - postingState.isMainThread = mtCalculator.isMainThread(); + postingState.isMainThread = isMainThread(); postingState.isPosting = true; if (postingState.canceled) { throw new EventBusException("Internal error. Abort state was not reset"); diff --git a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java index b12a7f38..90e53eb0 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java @@ -41,7 +41,7 @@ public class EventBusBuilder { List> skipMethodVerificationForClasses; List subscriberInfoIndexes; Logger logger; - boolean nonAndroidEnvironment; + MainThreadSupport mainThreadSupport; EventBusBuilder() { } diff --git a/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java b/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java index 3596c47a..95309547 100644 --- a/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java +++ b/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java @@ -20,15 +20,15 @@ import android.os.Message; import android.os.SystemClock; -final class HandlerPoster extends Handler implements Poster { +public class HandlerPoster extends Handler implements Poster { private final PendingPostQueue queue; private final int maxMillisInsideHandleMessage; private final EventBus eventBus; private boolean handlerActive; - HandlerPoster(EventBus eventBus, int maxMillisInsideHandleMessage) { - super(Looper.getMainLooper()); + protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) { + super(looper); this.eventBus = eventBus; this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage; queue = new PendingPostQueue(); diff --git a/EventBus/src/org/greenrobot/eventbus/MainThreadSupport.java b/EventBus/src/org/greenrobot/eventbus/MainThreadSupport.java new file mode 100644 index 00000000..6c77fde8 --- /dev/null +++ b/EventBus/src/org/greenrobot/eventbus/MainThreadSupport.java @@ -0,0 +1,33 @@ +package org.greenrobot.eventbus; + +import android.os.Looper; + +/** + * Interface to the "main" thread, which can be whatever you like. Typically on Android, Android's main thread is used. + */ +public interface MainThreadSupport { + + boolean isMainThread(); + + Poster createPoster(EventBus eventBus); + + class AndroidHandlerMainThreadSupport implements MainThreadSupport { + + private final Looper looper; + + public AndroidHandlerMainThreadSupport(Looper looper) { + this.looper = looper; + } + + @Override + public boolean isMainThread() { + return looper == Looper.myLooper(); + } + + @Override + public Poster createPoster(EventBus eventBus) { + return new HandlerPoster(eventBus, looper, 10); + } + } + +} diff --git a/EventBus/src/org/greenrobot/eventbus/SyncPoster.java b/EventBus/src/org/greenrobot/eventbus/SyncPoster.java deleted file mode 100644 index 29e5c0cf..00000000 --- a/EventBus/src/org/greenrobot/eventbus/SyncPoster.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.greenrobot.eventbus; - - -/** - * Posts events in the current Thread. - * - * @author William Ferguson - */ -class SyncPoster implements Poster { - - private final EventBus eventBus; - - SyncPoster(EventBus eventBus) { - this.eventBus = eventBus; - } - - public void enqueue(Subscription subscription, Object event) { - eventBus.invokeSubscriber(subscription, event); - } -} diff --git a/EventBus/src/org/greenrobot/eventbus/util/AndroidMTCalculator.java b/EventBus/src/org/greenrobot/eventbus/util/AndroidMTCalculator.java deleted file mode 100644 index 23ce5753..00000000 --- a/EventBus/src/org/greenrobot/eventbus/util/AndroidMTCalculator.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.greenrobot.eventbus.util; - -import android.os.Looper; - -/** - * Returns true if the current Thread is the Android Main Looper Thread. - * - * @author William Ferguson - */ -public class AndroidMTCalculator implements MainThreadCalculator { - - @Override - public boolean isMainThread() { - return Looper.getMainLooper() == Looper.myLooper(); - } -} diff --git a/EventBus/src/org/greenrobot/eventbus/util/MainThreadCalculator.java b/EventBus/src/org/greenrobot/eventbus/util/MainThreadCalculator.java deleted file mode 100644 index 6feeb21d..00000000 --- a/EventBus/src/org/greenrobot/eventbus/util/MainThreadCalculator.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.greenrobot.eventbus.util; - -/** - * Determines whether the current Thread is the Android Main Looper Thread. - * - * @author William Ferguson - */ -public interface MainThreadCalculator { - - /** - * @return true if the current Thread is the Android Main Looper Thread. - */ - boolean isMainThread(); -} diff --git a/EventBus/src/org/greenrobot/eventbus/util/NonAndroidMTCalculator.java b/EventBus/src/org/greenrobot/eventbus/util/NonAndroidMTCalculator.java deleted file mode 100644 index 2a7897ee..00000000 --- a/EventBus/src/org/greenrobot/eventbus/util/NonAndroidMTCalculator.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.greenrobot.eventbus.util; - -/** - * Always returns false as the Main Looper Thread only occurs within Android. - */ -public class NonAndroidMTCalculator implements MainThreadCalculator { - - @Override - public boolean isMainThread() { - return false; - } -} From 481357cce44f841a6bc4fa5877bb4636e208b2c7 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 29 Feb 2016 20:11:32 +0100 Subject: [PATCH 180/288] update copyright header --- EventBus/src/org/greenrobot/eventbus/Logger.java | 15 +++++++++++++++ .../greenrobot/eventbus/MainThreadSupport.java | 15 +++++++++++++++ EventBus/src/org/greenrobot/eventbus/Poster.java | 8 ++++---- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/EventBus/src/org/greenrobot/eventbus/Logger.java b/EventBus/src/org/greenrobot/eventbus/Logger.java index 7a1ad232..6609b61b 100644 --- a/EventBus/src/org/greenrobot/eventbus/Logger.java +++ b/EventBus/src/org/greenrobot/eventbus/Logger.java @@ -1,3 +1,18 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.greenrobot.eventbus; import android.util.Log; diff --git a/EventBus/src/org/greenrobot/eventbus/MainThreadSupport.java b/EventBus/src/org/greenrobot/eventbus/MainThreadSupport.java index 6c77fde8..d5655533 100644 --- a/EventBus/src/org/greenrobot/eventbus/MainThreadSupport.java +++ b/EventBus/src/org/greenrobot/eventbus/MainThreadSupport.java @@ -1,3 +1,18 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.greenrobot.eventbus; import android.os.Looper; diff --git a/EventBus/src/org/greenrobot/eventbus/Poster.java b/EventBus/src/org/greenrobot/eventbus/Poster.java index 3ebe24f4..a69a078d 100644 --- a/EventBus/src/org/greenrobot/eventbus/Poster.java +++ b/EventBus/src/org/greenrobot/eventbus/Poster.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ /** * Posts events. - * + * * @author William Ferguson */ interface Poster { @@ -25,8 +25,8 @@ interface Poster { /** * Enqueue an event to be posted for a particular subscription. * - * @param subscription Subscription which will receive the event. - * @param event Event that will be posted to subscribers. + * @param subscription Subscription which will receive the event. + * @param event Event that will be posted to subscribers. */ void enqueue(Subscription subscription, Object event); } From 6d9e15d8b17d71666be3a88eac15530b47245663 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 29 Feb 2016 21:45:18 +0100 Subject: [PATCH 181/288] remove AsyncExecutor.buildForActivityScope --- EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java b/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java index ba5f263d..9c0433e8 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java +++ b/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java @@ -57,10 +57,6 @@ public AsyncExecutor build() { return buildForScope(null); } - public AsyncExecutor buildForActivityScope(Object activity) { - return buildForScope(activity.getClass()); - } - public AsyncExecutor buildForScope(Object executionContext) { if (eventBus == null) { eventBus = EventBus.getDefault(); From 5f62d8bae73fa1f0fb432735f5084914d8690d8e Mon Sep 17 00:00:00 2001 From: Markus Date: Sat, 16 Sep 2017 13:17:15 +0100 Subject: [PATCH 182/288] make AbstractEventBusTest independent from Android --- EventBusTest/build.gradle | 1 + .../eventbus/AbstractAndroidEventBusTest.java | 72 +++++++++++++++++++ .../EventBusBackgroundThreadTest.java | 2 +- .../eventbus/EventBusBuilderTest.java | 2 +- .../EventBusCancelEventDeliveryTest.java | 2 +- .../EventBusFallbackToReflectionTest.java | 2 +- .../eventbus/EventBusGenericsTest.java | 2 +- .../EventBusMainThreadRacingTest.java | 2 +- .../eventbus/EventBusMainThreadTest.java | 2 +- .../eventbus/EventBusMethodModifiersTest.java | 2 +- .../eventbus/EventBusMultithreadedTest.java | 2 +- .../EventBusNoSubscriberEventTest.java | 2 +- .../EventBusOrderedSubscriptionsTest.java | 2 +- .../EventBusRegistrationRacingTest.java | 2 +- .../eventbus/EventBusStickyEventTest.java | 2 +- .../EventBusSubscriberExceptionTest.java | 2 +- .../eventbus/EventBusSubscriberLegalTest.java | 2 +- EventBusTestJava/build.gradle | 21 ++++++ .../eventbus/AbstractEventBusTest.java | 41 ++--------- settings.gradle | 1 + 20 files changed, 115 insertions(+), 51 deletions(-) create mode 100644 EventBusTest/src/org/greenrobot/eventbus/AbstractAndroidEventBusTest.java create mode 100644 EventBusTestJava/build.gradle rename {EventBusTest => EventBusTestJava}/src/org/greenrobot/eventbus/AbstractEventBusTest.java (76%) diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index e92f19aa..ff7208e5 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -21,6 +21,7 @@ repositories { dependencies { androidTestApt project(':EventBusAnnotationProcessor') androidTestCompile project(':EventBus') + androidTestCompile project(':EventBusTestJava') compile fileTree(dir: 'libs', include: '*.jar') androidTestCompile 'com.android.support.test:runner:0.5' androidTestCompile 'com.android.support.test:rules:0.5' diff --git a/EventBusTest/src/org/greenrobot/eventbus/AbstractAndroidEventBusTest.java b/EventBusTest/src/org/greenrobot/eventbus/AbstractAndroidEventBusTest.java new file mode 100644 index 00000000..13178206 --- /dev/null +++ b/EventBusTest/src/org/greenrobot/eventbus/AbstractAndroidEventBusTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.greenrobot.eventbus; + +import android.annotation.SuppressLint; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.runner.RunWith; + + +import static org.junit.Assert.assertFalse; + +/** + * @author Markus Junginger, greenrobot + */ +@RunWith(AndroidJUnit4.class) +public abstract class AbstractAndroidEventBusTest extends AbstractEventBusTest { + private EventPostHandler mainPoster; + + public AbstractAndroidEventBusTest() { + this(false); + } + + public AbstractAndroidEventBusTest(boolean collectEventsReceived) { + super(collectEventsReceived); + } + + @Before + public void setUpAndroid() throws Exception { + mainPoster = new EventPostHandler(Looper.getMainLooper()); + assertFalse(Looper.getMainLooper().getThread().equals(Thread.currentThread())); + } + + protected void postInMainThread(Object event) { + mainPoster.post(event); + } + + @SuppressLint("HandlerLeak") + class EventPostHandler extends Handler { + public EventPostHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + eventBus.post(msg.obj); + } + + void post(Object event) { + sendMessage(obtainMessage(0, event)); + } + + } + +} diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusBackgroundThreadTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusBackgroundThreadTest.java index 5a57f744..6ccb6025 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusBackgroundThreadTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusBackgroundThreadTest.java @@ -25,7 +25,7 @@ /** * @author Markus Junginger, greenrobot */ -public class EventBusBackgroundThreadTest extends AbstractEventBusTest { +public class EventBusBackgroundThreadTest extends AbstractAndroidEventBusTest { @Test public void testPostInCurrentThread() throws InterruptedException { diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java index 42d919de..4c15ca16 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java @@ -23,7 +23,7 @@ /** * @author Markus Junginger, greenrobot */ -public class EventBusBuilderTest extends AbstractEventBusTest { +public class EventBusBuilderTest extends AbstractAndroidEventBusTest { @Test public void testThrowSubscriberException() { diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java index 869da70e..d2aa168f 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java @@ -26,7 +26,7 @@ /** * @author Markus Junginger, greenrobot */ -public class EventBusCancelEventDeliveryTest extends AbstractEventBusTest { +public class EventBusCancelEventDeliveryTest extends AbstractAndroidEventBusTest { private Throwable failed; diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java index 4b884ef4..d9fe5c66 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java @@ -20,7 +20,7 @@ import static org.junit.Assert.assertEquals; -public class EventBusFallbackToReflectionTest extends AbstractEventBusTest { +public class EventBusFallbackToReflectionTest extends AbstractAndroidEventBusTest { private class PrivateEvent { } diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java index 59f8a37b..9e4cc0d8 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java @@ -18,7 +18,7 @@ import org.junit.Test; -public class EventBusGenericsTest extends AbstractEventBusTest { +public class EventBusGenericsTest extends AbstractAndroidEventBusTest { public static class GenericEvent { T value; } diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadRacingTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadRacingTest.java index a598220e..8ed637e8 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadRacingTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadRacingTest.java @@ -26,7 +26,7 @@ /** * @author Markus Junginger, greenrobot */ -public class EventBusMainThreadRacingTest extends AbstractEventBusTest { +public class EventBusMainThreadRacingTest extends AbstractAndroidEventBusTest { private static final int ITERATIONS = LONG_TESTS ? 100000 : 1000; diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java index 2195d10f..d20f2c27 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java @@ -29,7 +29,7 @@ /** * @author Markus Junginger, greenrobot */ -public class EventBusMainThreadTest extends AbstractEventBusTest { +public class EventBusMainThreadTest extends AbstractAndroidEventBusTest { private BackgroundPoster backgroundPoster; diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusMethodModifiersTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMethodModifiersTest.java index e974e73a..2818d85d 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusMethodModifiersTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMethodModifiersTest.java @@ -25,7 +25,7 @@ /** * @author Markus Junginger, greenrobot */ -public class EventBusMethodModifiersTest extends AbstractEventBusTest { +public class EventBusMethodModifiersTest extends AbstractAndroidEventBusTest { @Test public void testRegisterForEventTypeAndPost() throws InterruptedException { diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusMultithreadedTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMultithreadedTest.java index f3e7bd50..f84ee893 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusMultithreadedTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMultithreadedTest.java @@ -30,7 +30,7 @@ /** * @author Markus Junginger, greenrobot */ -public class EventBusMultithreadedTest extends AbstractEventBusTest { +public class EventBusMultithreadedTest extends AbstractAndroidEventBusTest { private static final int COUNT = LONG_TESTS ? 100000 : 1000; diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java index b358f8c3..d666a504 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java @@ -23,7 +23,7 @@ /** * @author Markus Junginger, greenrobot */ -public class EventBusNoSubscriberEventTest extends AbstractEventBusTest { +public class EventBusNoSubscriberEventTest extends AbstractAndroidEventBusTest { @Test public void testNoSubscriberEvent() { diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java index f6f97201..3acb119a 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java @@ -27,7 +27,7 @@ /** * @author Markus Junginger, greenrobot */ -public class EventBusOrderedSubscriptionsTest extends AbstractEventBusTest { +public class EventBusOrderedSubscriptionsTest extends AbstractAndroidEventBusTest { int lastPrio = Integer.MAX_VALUE; final List registered = new ArrayList(); diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java index 7d09d7ad..295066ca 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java @@ -28,7 +28,7 @@ /** * @author Markus Junginger, greenrobot */ -public class EventBusRegistrationRacingTest extends AbstractEventBusTest { +public class EventBusRegistrationRacingTest extends AbstractAndroidEventBusTest { // On a Nexus 5, bad synchronization always failed on the first iteration or went well completely. // So a high number of iterations do not guarantee a better probability of finding bugs. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java index ec426745..e1a5a9f2 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java @@ -22,7 +22,7 @@ /** * @author Markus Junginger, greenrobot */ -public class EventBusStickyEventTest extends AbstractEventBusTest { +public class EventBusStickyEventTest extends AbstractAndroidEventBusTest { @Test public void testPostSticky() throws InterruptedException { diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java index f0dea680..c16f820e 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java @@ -23,7 +23,7 @@ /** * @author Markus Junginger, greenrobot */ -public class EventBusSubscriberExceptionTest extends AbstractEventBusTest { +public class EventBusSubscriberExceptionTest extends AbstractAndroidEventBusTest { @Test public void testSubscriberExceptionEvent() { diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java index c362e900..be02c65c 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java @@ -22,7 +22,7 @@ /** * @author Markus Junginger, greenrobot */ -public class EventBusSubscriberLegalTest extends AbstractEventBusTest { +public class EventBusSubscriberLegalTest extends AbstractAndroidEventBusTest { @Test public void testSubscriberLegal() { diff --git a/EventBusTestJava/build.gradle b/EventBusTestJava/build.gradle new file mode 100644 index 00000000..717037a7 --- /dev/null +++ b/EventBusTestJava/build.gradle @@ -0,0 +1,21 @@ +apply plugin: 'java' + +sourceCompatibility = 1.7 + +repositories { + jcenter() +} + +dependencies { + compile project(':EventBus') + compile 'junit:junit:4.12' +} + +sourceSets { + main { + java { + srcDir 'src' + // exclude 'de/greenrobot/event/util/**' + } + } +} diff --git a/EventBusTest/src/org/greenrobot/eventbus/AbstractEventBusTest.java b/EventBusTestJava/src/org/greenrobot/eventbus/AbstractEventBusTest.java similarity index 76% rename from EventBusTest/src/org/greenrobot/eventbus/AbstractEventBusTest.java rename to EventBusTestJava/src/org/greenrobot/eventbus/AbstractEventBusTest.java index 867cada1..dbd20d68 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/AbstractEventBusTest.java +++ b/EventBusTestJava/src/org/greenrobot/eventbus/AbstractEventBusTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * Copyright (C) 2012-2017 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,15 +15,7 @@ */ package org.greenrobot.eventbus; -import android.annotation.SuppressLint; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.support.test.runner.AndroidJUnit4; - -import org.greenrobot.eventbus.EventBus; import org.junit.Before; -import org.junit.runner.RunWith; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -31,12 +23,14 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import static org.junit.Assert.*; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; /** * @author Markus Junginger, greenrobot */ -@RunWith(AndroidJUnit4.class) public abstract class AbstractEventBusTest { /** Activates long(er) running tests e.g. testing multi-threading more thoroughly. */ protected static final boolean LONG_TESTS = false; @@ -49,8 +43,6 @@ public abstract class AbstractEventBusTest { protected volatile Object lastEvent; protected volatile Thread lastThread; - private EventPostHandler mainPoster; - public AbstractEventBusTest() { this(false); } @@ -67,12 +59,6 @@ public AbstractEventBusTest(boolean collectEventsReceived) { public void setUpBase() throws Exception { EventBus.clearCaches(); eventBus = new EventBus(); - mainPoster = new EventPostHandler(Looper.getMainLooper()); - assertFalse(Looper.getMainLooper().getThread().equals(Thread.currentThread())); - } - - protected void postInMainThread(Object event) { - mainPoster.post(event); } protected void waitForEventCount(int expectedCount, int maxMillis) { @@ -104,23 +90,6 @@ protected void trackEvent(Object event) { eventCount.incrementAndGet(); } - @SuppressLint("HandlerLeak") - class EventPostHandler extends Handler { - public EventPostHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - eventBus.post(msg.obj); - } - - void post(Object event) { - sendMessage(obtainMessage(0, event)); - } - - } - protected void assertEventCount(int expectedEventCount) { assertEquals(expectedEventCount, eventCount.intValue()); } diff --git a/settings.gradle b/settings.gradle index a11c17d8..f78cf550 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,6 @@ include 'EventBus' include 'EventBusAnnotationProcessor' +include 'EventBusTestJava' include 'EventBusTest' include 'EventBusTestSubscriberInJar' include 'EventBusPerformance' From 934786788242c5f54ab87356fdf7cb0b3d8ef345 Mon Sep 17 00:00:00 2001 From: Markus Date: Sat, 16 Sep 2017 14:03:52 +0100 Subject: [PATCH 183/288] check main looper to see if we have "good" Android classes (not Stubs etc.) --- .../src/org/greenrobot/eventbus/EventBus.java | 10 ++----- .../greenrobot/eventbus/EventBusBuilder.java | 30 +++++++++++++++++-- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/EventBus/src/org/greenrobot/eventbus/EventBus.java b/EventBus/src/org/greenrobot/eventbus/EventBus.java index 2518946b..712b3ff9 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBus.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBus.java @@ -15,8 +15,6 @@ */ package org.greenrobot.eventbus; -import android.os.Looper; - import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; @@ -109,13 +107,11 @@ public EventBus() { } EventBus(EventBusBuilder builder) { - logger = builder.initLogger(); + logger = builder.getLogger(); subscriptionsByEventType = new HashMap<>(); typesBySubscriber = new HashMap<>(); stickyEvents = new ConcurrentHashMap<>(); - mainThreadSupport = builder.mainThreadSupport != null ? builder.mainThreadSupport : - Logger.AndroidLogger.isAndroidLogAvailable() ? - new MainThreadSupport.AndroidHandlerMainThreadSupport(Looper.getMainLooper()) : null; + mainThreadSupport = builder.getMainThreadSupport(); mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null; backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); @@ -215,7 +211,7 @@ private void checkPostStickyEventToSubscription(Subscription newSubscription, Ob * poster. */ private boolean isMainThread() { - return mainThreadSupport != null? mainThreadSupport.isMainThread(): true; + return mainThreadSupport != null ? mainThreadSupport.isMainThread() : true; } public synchronized boolean isRegistered(Object subscriber) { diff --git a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java index 90e53eb0..895b57a9 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java @@ -15,6 +15,8 @@ */ package org.greenrobot.eventbus; +import android.os.Looper; + import org.greenrobot.eventbus.meta.SubscriberInfoIndex; import java.util.ArrayList; @@ -150,15 +152,39 @@ public EventBusBuilder logger(Logger logger) { return this; } - Logger initLogger() { + Logger getLogger() { if (logger != null) { return logger; } else { - return Logger.AndroidLogger.isAndroidLogAvailable() ? new Logger.AndroidLogger("EventBus") : + // also check main looper to see if we have "good" Android classes (not Stubs etc.) + return Logger.AndroidLogger.isAndroidLogAvailable() && getAndroidMainLooperOrNull() != null + ? new Logger.AndroidLogger("EventBus") : new Logger.SystemOutLogger(); } } + + MainThreadSupport getMainThreadSupport() { + if (mainThreadSupport != null) { + return mainThreadSupport; + } else if (Logger.AndroidLogger.isAndroidLogAvailable()) { + Object looperOrNull = getAndroidMainLooperOrNull(); + return looperOrNull == null ? null : + new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull); + } else { + return null; + } + } + + Object getAndroidMainLooperOrNull() { + try { + return Looper.getMainLooper(); + } catch (RuntimeException e) { + // Not really a functional Android (e.g. "Stub!" maven dependencies) + return null; + } + } + /** * Installs the default EventBus returned by {@link EventBus#getDefault()} using this builders' values. Must be * done only once before the first usage of the default EventBus. From 2cbf0e0d7cb039c48c71e5b77f97c0a943a74146 Mon Sep 17 00:00:00 2001 From: Markus Date: Sat, 16 Sep 2017 14:05:55 +0100 Subject: [PATCH 184/288] default dir layout for java tests --- EventBusTestJava/build.gradle | 12 +- .../eventbus/AbstractEventBusTest.java | 0 .../eventbus/EventBusBuilderTest.java | 103 ++++++++++++++++++ 3 files changed, 106 insertions(+), 9 deletions(-) rename EventBusTestJava/src/{ => main/java}/org/greenrobot/eventbus/AbstractEventBusTest.java (100%) create mode 100644 EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusBuilderTest.java diff --git a/EventBusTestJava/build.gradle b/EventBusTestJava/build.gradle index 717037a7..4b35cfe6 100644 --- a/EventBusTestJava/build.gradle +++ b/EventBusTestJava/build.gradle @@ -7,15 +7,9 @@ repositories { } dependencies { - compile project(':EventBus') + compile(project(':EventBus')) { + exclude group: "com.google.android" // Does not seem to work... + } compile 'junit:junit:4.12' } -sourceSets { - main { - java { - srcDir 'src' - // exclude 'de/greenrobot/event/util/**' - } - } -} diff --git a/EventBusTestJava/src/org/greenrobot/eventbus/AbstractEventBusTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AbstractEventBusTest.java similarity index 100% rename from EventBusTestJava/src/org/greenrobot/eventbus/AbstractEventBusTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/AbstractEventBusTest.java diff --git a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusBuilderTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusBuilderTest.java new file mode 100644 index 00000000..05a60362 --- /dev/null +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusBuilderTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.greenrobot.eventbus; + +import org.junit.Assert; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * @author Markus Junginger, greenrobot + */ +public class EventBusBuilderTest extends AbstractEventBusTest { + + @Test + public void testThrowSubscriberException() { + eventBus = EventBus.builder().throwSubscriberException(true).build(); + eventBus.register(new SubscriberExceptionEventTracker()); + eventBus.register(new ThrowingSubscriber()); + try { + eventBus.post("Foo"); + fail("Should have thrown"); + } catch (EventBusException e) { + // Expected + } + } + + @Test + public void testDoNotSendSubscriberExceptionEvent() { + eventBus = EventBus.builder().logSubscriberExceptions(false).sendSubscriberExceptionEvent(false).build(); + eventBus.register(new SubscriberExceptionEventTracker()); + eventBus.register(new ThrowingSubscriber()); + eventBus.post("Foo"); + assertEventCount(0); + } + + @Test + public void testDoNotSendNoSubscriberEvent() { + eventBus = EventBus.builder().logNoSubscriberMessages(false).sendNoSubscriberEvent(false).build(); + eventBus.register(new NoSubscriberEventTracker()); + eventBus.post("Foo"); + assertEventCount(0); + } + + @Test + public void testInstallDefaultEventBus() { + EventBusBuilder builder = EventBus.builder(); + try { + // Either this should throw when another unit test got the default event bus... + eventBus = builder.installDefaultEventBus(); + Assert.assertEquals(eventBus, EventBus.getDefault()); + + // ...or this should throw + eventBus = builder.installDefaultEventBus(); + fail("Should have thrown"); + } catch (EventBusException e) { + // Expected + } + } + + @Test + public void testEventInheritance() { + eventBus = EventBus.builder().eventInheritance(false).build(); + eventBus.register(new ThrowingSubscriber()); + eventBus.post("Foo"); + } + + public class SubscriberExceptionEventTracker { + @Subscribe + public void onEvent(SubscriberExceptionEvent event) { + trackEvent(event); + } + } + + public class NoSubscriberEventTracker { + @Subscribe + public void onEvent(NoSubscriberEvent event) { + trackEvent(event); + } + } + + public class ThrowingSubscriber { + @Subscribe + public void onEvent(Object event) { + throw new RuntimeException(); + } + } + +} From 6dbbd767bb1fc754f76ba682709a567d9975ddc0 Mon Sep 17 00:00:00 2001 From: Markus Date: Sat, 16 Sep 2017 14:06:14 +0100 Subject: [PATCH 185/288] Gradle does not pick up tests in src dir, so help Gradle with a suite --- .../src/test/java/EventBusTestSuite.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 EventBusTestJava/src/test/java/EventBusTestSuite.java diff --git a/EventBusTestJava/src/test/java/EventBusTestSuite.java b/EventBusTestJava/src/test/java/EventBusTestSuite.java new file mode 100644 index 00000000..812b8867 --- /dev/null +++ b/EventBusTestJava/src/test/java/EventBusTestSuite.java @@ -0,0 +1,13 @@ +import org.greenrobot.eventbus.EventBusBuilderTest; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +// Gradle does not pick up tests in src dir, so help Gradle with a suite +// (Tests are in main src so we can use them for Android too) +@RunWith(Suite.class) +@SuiteClasses({ + EventBusBuilderTest.class +}) +public class EventBusTestSuite { +} From d72244a73fa282fa9046d0003ac28e01799dd257 Mon Sep 17 00:00:00 2001 From: Markus Date: Sat, 16 Sep 2017 14:40:03 +0100 Subject: [PATCH 186/288] V3.1.0-SNAPSHOT --- EventBus/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index 50637de7..daaa3163 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -5,7 +5,7 @@ apply plugin: 'idea' archivesBaseName = 'eventbus' group = 'org.greenrobot' -version = '3.0.0' +version = '3.1.0-SNAPSHOT' sourceCompatibility = 1.7 def isSnapshot = version.endsWith('-SNAPSHOT') From e9cad5b25083aa97d7951e35bbefb039afba8e6c Mon Sep 17 00:00:00 2001 From: Markus Date: Sat, 16 Sep 2017 14:43:54 +0100 Subject: [PATCH 187/288] compileSdkVersion 25 for perf app --- EventBusPerformance/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 0aab22b0..a76c1899 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -30,7 +30,7 @@ apt { android { buildToolsVersion '25.0.3' // When updating, don't forget to adjust .travis.yml - compileSdkVersion 19 + compileSdkVersion 25 sourceSets { main { From 57e214f5b32e9221701ead0f653e2a6bb1eaf492 Mon Sep 17 00:00:00 2001 From: Markus Date: Sat, 16 Sep 2017 14:47:14 +0100 Subject: [PATCH 188/288] moved EventBusBasicTest to java tests --- .../eventbus/EventBusAndroidActivityTest.java | 71 ++++++++++++ .../eventbus/EventBusBuilderTest.java | 102 ------------------ .../eventbus/AbstractEventBusTest.java | 5 + .../eventbus/EventBusBasicTest.java | 50 ++++----- .../src/test/java/EventBusTestSuite.java | 2 + 5 files changed, 97 insertions(+), 133 deletions(-) create mode 100644 EventBusTest/src/org/greenrobot/eventbus/EventBusAndroidActivityTest.java delete mode 100644 EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java rename {EventBusTest/src => EventBusTestJava/src/main/java}/org/greenrobot/eventbus/EventBusBasicTest.java (87%) diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusAndroidActivityTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusAndroidActivityTest.java new file mode 100644 index 00000000..364a3936 --- /dev/null +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusAndroidActivityTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.greenrobot.eventbus; + +import android.app.Activity; +import android.support.test.annotation.UiThreadTest; +import android.support.test.rule.UiThreadTestRule; +import android.util.Log; + +import org.junit.Rule; +import org.junit.Test; + + +import static org.junit.Assert.assertEquals; + +/** + * @author Markus Junginger, greenrobot + */ +// Do not extend from AbstractAndroidEventBusTest, because it asserts test may not be in main thread +public class EventBusAndroidActivityTest extends AbstractEventBusTest { + + public static class WithIndex extends EventBusBasicTest { + @Test + public void dummy() { + } + + } + + @Rule + public final UiThreadTestRule uiThreadTestRule = new UiThreadTestRule(); + + @Test + @UiThreadTest + public void testRegisterAndPost() { + // Use an activity to test real life performance + TestActivity testActivity = new TestActivity(); + String event = "Hello"; + + long start = System.currentTimeMillis(); + eventBus.register(testActivity); + long time = System.currentTimeMillis() - start; + Log.d(EventBus.TAG, "Registered in " + time + "ms"); + + eventBus.post(event); + + assertEquals(event, testActivity.lastStringEvent); + } + + public static class TestActivity extends Activity { + public String lastStringEvent; + + @Subscribe + public void onEvent(String event) { + lastStringEvent = event; + } + } + +} diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java deleted file mode 100644 index 4c15ca16..00000000 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.greenrobot.eventbus; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -/** - * @author Markus Junginger, greenrobot - */ -public class EventBusBuilderTest extends AbstractAndroidEventBusTest { - - @Test - public void testThrowSubscriberException() { - eventBus = EventBus.builder().throwSubscriberException(true).build(); - eventBus.register(new SubscriberExceptionEventTracker()); - eventBus.register(new ThrowingSubscriber()); - try { - eventBus.post("Foo"); - fail("Should have thrown"); - } catch (EventBusException e) { - // Expected - } - } - - @Test - public void testDoNotSendSubscriberExceptionEvent() { - eventBus = EventBus.builder().logSubscriberExceptions(false).sendSubscriberExceptionEvent(false).build(); - eventBus.register(new SubscriberExceptionEventTracker()); - eventBus.register(new ThrowingSubscriber()); - eventBus.post("Foo"); - assertEventCount(0); - } - - @Test - public void testDoNotSendNoSubscriberEvent() { - eventBus = EventBus.builder().logNoSubscriberMessages(false).sendNoSubscriberEvent(false).build(); - eventBus.register(new NoSubscriberEventTracker()); - eventBus.post("Foo"); - assertEventCount(0); - } - - @Test - public void testInstallDefaultEventBus() { - EventBusBuilder builder = EventBus.builder(); - try { - // Either this should throw when another unit test got the default event bus... - eventBus = builder.installDefaultEventBus(); - assertEquals(eventBus, EventBus.getDefault()); - - // ...or this should throw - eventBus = builder.installDefaultEventBus(); - fail("Should have thrown"); - } catch (EventBusException e) { - // Expected - } - } - - @Test - public void testEventInheritance() { - eventBus = EventBus.builder().eventInheritance(false).build(); - eventBus.register(new ThrowingSubscriber()); - eventBus.post("Foo"); - } - - public class SubscriberExceptionEventTracker { - @Subscribe - public void onEvent(SubscriberExceptionEvent event) { - trackEvent(event); - } - } - - public class NoSubscriberEventTracker { - @Subscribe - public void onEvent(NoSubscriberEvent event) { - trackEvent(event); - } - } - - public class ThrowingSubscriber { - @Subscribe - public void onEvent(Object event) { - throw new RuntimeException(); - } - } - -} diff --git a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AbstractEventBusTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AbstractEventBusTest.java index dbd20d68..dc488dce 100644 --- a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AbstractEventBusTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AbstractEventBusTest.java @@ -22,6 +22,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; import static org.junit.Assert.assertEquals; @@ -107,4 +108,8 @@ protected void awaitLatch(CountDownLatch latch, long seconds) { } } + protected void log(String msg) { + eventBus.getLogger().log(Level.FINE, msg); + } + } diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusBasicTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusBasicTest.java similarity index 87% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusBasicTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusBasicTest.java index d6af1eb4..c00b04bd 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusBasicTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusBasicTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * Copyright (C) 2012-2017 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,35 +15,28 @@ */ package org.greenrobot.eventbus; -import android.app.Activity; -import android.support.test.annotation.UiThreadTest; -import android.support.test.rule.UiThreadTestRule; -import android.support.test.runner.AndroidJUnit4; -import android.util.Log; - -import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.runner.RunWith; -import static org.junit.Assert.*; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; /** * @author Markus Junginger, greenrobot */ -@RunWith(AndroidJUnit4.class) -public class EventBusBasicTest { +@SuppressWarnings({"WeakerAccess", "UnusedParameters", "unused"}) +public class EventBusBasicTest extends AbstractEventBusTest { public static class WithIndex extends EventBusBasicTest { @Test - public void dummy() {} + public void dummy() { + } } - @Rule - public final UiThreadTestRule uiThreadTestRule = new UiThreadTestRule(); - - protected EventBus eventBus; private String lastStringEvent; private int countStringEvent; private int countIntEvent; @@ -52,26 +45,20 @@ public void dummy() {} private int countMyEvent; private int countMyEvent2; - @Before - public void setUp() throws Exception { - eventBus = new EventBus(); - } - @Test - @UiThreadTest public void testRegisterAndPost() { // Use an activity to test real life performance - TestActivity testActivity = new TestActivity(); + StringEventSubscriber stringEventSubscriber = new StringEventSubscriber(); String event = "Hello"; long start = System.currentTimeMillis(); - eventBus.register(testActivity); + eventBus.register(stringEventSubscriber); long time = System.currentTimeMillis() - start; - Log.d(EventBus.TAG, "Registered in " + time + "ms"); + log("Registered in " + time + "ms"); eventBus.post(event); - assertEquals(event, testActivity.lastStringEvent); + assertEquals(event, stringEventSubscriber.lastStringEvent); } @Test @@ -90,12 +77,13 @@ public void testUnregisterWithoutRegister() { public void testUnregisterNotLeaking() { int heapMBytes = (int) (Runtime.getRuntime().maxMemory() / (1024L * 1024L)); for (int i = 0; i < heapMBytes * 2; i++) { + @SuppressWarnings("unused") EventBusBasicTest subscriber = new EventBusBasicTest() { byte[] expensiveObject = new byte[1024 * 1024]; }; eventBus.register(subscriber); eventBus.unregister(subscriber); - Log.d("Test", "Iteration " + i + " / max heap: " + heapMBytes); + log("Iteration " + i + " / max heap: " + heapMBytes); } } @@ -142,7 +130,7 @@ public void testPostMultipleTimes() { } // Debug.stopMethodTracing(); long time = System.currentTimeMillis() - start; - Log.d(EventBus.TAG, "Posted " + count + " events in " + time + "ms"); + log("Posted " + count + " events in " + time + "ms"); assertEquals(count, countMyEvent); } @@ -268,7 +256,7 @@ public void onEvent(MyEventExtended event) { countMyEventExtended++; } - public static class TestActivity extends Activity { + public static class StringEventSubscriber { public String lastStringEvent; @Subscribe diff --git a/EventBusTestJava/src/test/java/EventBusTestSuite.java b/EventBusTestJava/src/test/java/EventBusTestSuite.java index 812b8867..ccd20b0a 100644 --- a/EventBusTestJava/src/test/java/EventBusTestSuite.java +++ b/EventBusTestJava/src/test/java/EventBusTestSuite.java @@ -1,3 +1,4 @@ +import org.greenrobot.eventbus.EventBusBasicTest; import org.greenrobot.eventbus.EventBusBuilderTest; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -7,6 +8,7 @@ // (Tests are in main src so we can use them for Android too) @RunWith(Suite.class) @SuiteClasses({ + EventBusBasicTest.class, EventBusBuilderTest.class }) public class EventBusTestSuite { From a6ab96c329c770cc1f147ac49a6c15f086d74d46 Mon Sep 17 00:00:00 2001 From: Markus Date: Sat, 16 Sep 2017 15:40:01 +0100 Subject: [PATCH 189/288] eventbus 3.1.0-RC --- EventBus/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index daaa3163..e2167121 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -5,7 +5,7 @@ apply plugin: 'idea' archivesBaseName = 'eventbus' group = 'org.greenrobot' -version = '3.1.0-SNAPSHOT' +version = '3.1.0-RC' sourceCompatibility = 1.7 def isSnapshot = version.endsWith('-SNAPSHOT') From 38b127c8d060c9ff6d88af3c49e12287f7028e7e Mon Sep 17 00:00:00 2001 From: Markus Date: Sat, 16 Sep 2017 15:40:56 +0100 Subject: [PATCH 190/288] updated README.md for 3.1.0-RC --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0c154d32..103ac25c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ EventBus ======== -EventBus is a publish/subscribe event bus optimized for Android.
+EventBus is a publish/subscribe event bus for Android and Java.
EventBus... @@ -62,7 +62,7 @@ Add EventBus to your project Via Gradle: ```gradle -compile 'org.greenrobot:eventbus:3.0.0' +compile 'org.greenrobot:eventbus:3.1.0-RC' ``` Via Maven: @@ -70,7 +70,7 @@ Via Maven: org.greenrobot eventbus - 3.0.0 + 3.1.0-RC ``` @@ -94,12 +94,14 @@ How does EventBus compare to other solutions, like Otto from Square? Check this License ------- -Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) +Copyright (C) 2012-2017 Markus Junginger, greenrobot (http://greenrobot.org) EventBus binaries and source code can be used according to the [Apache License, Version 2.0](LICENSE). More Open Source by greenrobot ============================== +[__ObjectBox__](https://github.com/objectbox/objectbox-java) is a new superfast object-oriented database for mobile. + [__greenrobot-common__](https://github.com/greenrobot/greenrobot-common) is a set of utility classes and hash functions for Android & Java projects. [__greenDAO__](https://github.com/greenrobot/greenDAO) is an ORM optimized for Android: it maps database tables to Java objects and uses code generation for optimal speed. From 0ed611d465b6695c6f85cc58e29c6084f4c2bf3d Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 18 Sep 2017 12:13:45 +0200 Subject: [PATCH 191/288] Add main src dir to test source set so tests are picked up. - By default Gradle (Java plugin) only looks in the test source set for tests. But we need to share them with the Android test module, so they have to be in the main source set. --- EventBusTestJava/build.gradle | 10 ++++++++++ .../src/test/java/EventBusTestSuite.java | 15 --------------- 2 files changed, 10 insertions(+), 15 deletions(-) delete mode 100644 EventBusTestJava/src/test/java/EventBusTestSuite.java diff --git a/EventBusTestJava/build.gradle b/EventBusTestJava/build.gradle index 4b35cfe6..6171b530 100644 --- a/EventBusTestJava/build.gradle +++ b/EventBusTestJava/build.gradle @@ -6,6 +6,16 @@ repositories { jcenter() } +// we have tests in the main source set so they can be shared with the Android test module +// to make Gradle pick them up, add the dir to the test source set +sourceSets { + test { + java { + srcDirs += ['src/main/java'] + } + } +} + dependencies { compile(project(':EventBus')) { exclude group: "com.google.android" // Does not seem to work... diff --git a/EventBusTestJava/src/test/java/EventBusTestSuite.java b/EventBusTestJava/src/test/java/EventBusTestSuite.java deleted file mode 100644 index ccd20b0a..00000000 --- a/EventBusTestJava/src/test/java/EventBusTestSuite.java +++ /dev/null @@ -1,15 +0,0 @@ -import org.greenrobot.eventbus.EventBusBasicTest; -import org.greenrobot.eventbus.EventBusBuilderTest; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; -import org.junit.runners.Suite.SuiteClasses; - -// Gradle does not pick up tests in src dir, so help Gradle with a suite -// (Tests are in main src so we can use them for Android too) -@RunWith(Suite.class) -@SuiteClasses({ - EventBusBasicTest.class, - EventBusBuilderTest.class -}) -public class EventBusTestSuite { -} From 85973302e983b48195e9c171872500ebd089d214 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 18 Sep 2017 13:05:24 +0200 Subject: [PATCH 192/288] Move tests not requiring Android API to Java tests. --- EventBusTestJava/build.gradle | 1 + .../libs/EventBusTestSubscriberInJar-3.0.0.jar | Bin 0 -> 2761 bytes .../EventBusFallbackToReflectionTest.java | 2 +- .../eventbus/EventBusGenericsTest.java | 2 +- .../greenrobot/eventbus/EventBusIndexTest.java | 2 +- .../EventBusInheritanceDisabledTest.java | 4 ---- .../eventbus/EventBusInheritanceTest.java | 11 ++++++----- .../eventbus/EventBusNoSubscriberEventTest.java | 2 +- .../EventBusOrderedSubscriptionsTest.java | 8 +++----- .../eventbus/EventBusRegistrationRacingTest.java | 2 +- .../eventbus/EventBusStickyEventTest.java | 2 +- .../EventBusSubscriberExceptionTest.java | 2 +- .../eventbus/EventBusSubscriberInJarTest.java | 9 ++------- .../eventbus/EventBusSubscriberLegalTest.java | 2 +- .../org/greenrobot/eventbus/IntTestEvent.java | 0 15 files changed, 20 insertions(+), 29 deletions(-) create mode 100644 EventBusTestJava/libs/EventBusTestSubscriberInJar-3.0.0.jar rename {EventBusTest/src => EventBusTestJava/src/main/java}/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java (98%) rename {EventBusTest/src => EventBusTestJava/src/main/java}/org/greenrobot/eventbus/EventBusGenericsTest.java (97%) rename {EventBusTest/src => EventBusTestJava/src/main/java}/org/greenrobot/eventbus/EventBusIndexTest.java (100%) rename {EventBusTest/src => EventBusTestJava/src/main/java}/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java (98%) rename {EventBusTest/src => EventBusTestJava/src/main/java}/org/greenrobot/eventbus/EventBusInheritanceTest.java (97%) rename {EventBusTest/src => EventBusTestJava/src/main/java}/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java (96%) rename {EventBusTest/src => EventBusTestJava/src/main/java}/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java (95%) rename {EventBusTest/src => EventBusTestJava/src/main/java}/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java (97%) rename {EventBusTest/src => EventBusTestJava/src/main/java}/org/greenrobot/eventbus/EventBusStickyEventTest.java (98%) rename {EventBusTest/src => EventBusTestJava/src/main/java}/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java (96%) rename {EventBusTest/src => EventBusTestJava/src/main/java}/org/greenrobot/eventbus/EventBusSubscriberInJarTest.java (84%) rename {EventBusTest/src => EventBusTestJava/src/main/java}/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java (96%) rename {EventBusTest/src => EventBusTestJava/src/main/java}/org/greenrobot/eventbus/IntTestEvent.java (100%) diff --git a/EventBusTestJava/build.gradle b/EventBusTestJava/build.gradle index 6171b530..13013aac 100644 --- a/EventBusTestJava/build.gradle +++ b/EventBusTestJava/build.gradle @@ -17,6 +17,7 @@ sourceSets { } dependencies { + compile fileTree(dir: 'libs', include: '*.jar') compile(project(':EventBus')) { exclude group: "com.google.android" // Does not seem to work... } diff --git a/EventBusTestJava/libs/EventBusTestSubscriberInJar-3.0.0.jar b/EventBusTestJava/libs/EventBusTestSubscriberInJar-3.0.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..47b80ef0fe4946e43f2fad4cb34f4c2a94833b76 GIT binary patch literal 2761 zcma)83pkVeAD>%jHO`Q^R&v*nNK0tB)C{?dC6r;D6^6Ow-q0k`(O8&EG90-}TGNe1 zuA`I~6-ukWzjPwxRL;An|LN5F*K@w_^ZwrN`#hh|=l4AC_x*jIj}ux%bS(%ZApxqW zM(zgzCCp!dk_2uC8w?VTar1-GW`A&a#R6 zo50}I6Woj&dHHW?)uS0=rRfDQ?wK5X!mk^~LxUgVX&qGuK5EoT`8zt4tPB#57I5@M z)$-cbEh%%%mk>M)USaRR(<3*9^4k4WkrE-IhLdC&s_OWioNMD#p>(#2szF6&OiFpFOE5o3Ktn<3ZeTxqf@KG1P}FU`kY?^F-# z_udzCtb4eiZagJhrYztAKHE3gZcaO=8nbO{5l(H~?V@{t5n-JvYgd=Fww-NtHf~3J zAElhS8qFlK9xaHPS+sur4(iJTP+jvcx(7UA8U>{7qI zWJos_c_^oU_lJJrOgirR&b0Z%3#Csp5DY|LT;mBF165r5=3yHrHO6Qy+BYU6q{Hw% zQ8cEKvHxyZr{gZtgY1wn-B@;ljZsT;zap#tg3f7-VK_y<+NPjKbIgQ_LUnr4ZZMNK zQznP#H^g3`66tTMc&$G5SoH1C2xQ}ALu^d#NZ@Y3w2U#Z(zOn%G-$EU($L1rSg5VK-a^6_(< zYR_LN@Db_>%~NNaocS$Ha*@m^^0y>+KnDHT(L1qImV+`+{ojB1)x9_O|$Wxjssx?QxQU{h`zd`4NNEoz^p=9bHi3Ahq05XI{oq^s4j8 z8JVE8P-5zBGvyF$YgYpoUVF+bH7{TGRG7yk!?GREHp}^akowj! zG&<#!8ihchtH24@`gbSmC@uu|n*WsxUp8xsCp8qwmqOl_5a zo>lPf+>X&#C2vevh5Zv@{p&HwiXxw!%B&sWM%qd2i==!rs<7*(TrvM~Xr8xirk+^+ znnU_?Rgjp?XJVgutkL9>Eq_@)YD~N#21D1%dxW9HmiJ&yi^d>ZmfUbvl#Ly&>)d%<3Yyezm^QyA%t)IO&!I5G_7!o9m)|^Ga%@+2Y2e}% z*H!M|jV+~I@GcVRl+T3<>v)n1m<3Gc-e6q~5nu=_fOykatWZd=3 z4bp1IO0STk6LkuuyI<}yK2(X9eoAdQ(LQ0^B!k!kDI2j(68d)PK5vKGp8-?P2Rs%2 zlc~E#`jY&@3BGv1Q~_uGY^s^(f{)1{rSGoNyNmS zTf?pJc+83BBg-7>S z+y=MJsp}|EsGe{G(F`!6GM*o-dJwwB)#m8pr&@{xz0pwXO7WsNI~FT-wC&bH({=}vx%>gf zZ2z#`tkkUBMhn)$GBmozB#D@BpRzw!5QQO61%fJoyOpTv-U3jm+xvLhJ;%;_* z6V0kn)gv+gZ0}3?4-P@j6uf!G;}R$@QEKbwPla@0h^$=)6?OKlw@hQHh;F)0qC$x~TtjLc82=L1QB@LQI@}FPg zh#*Zcj_|?!Vvu!!^$YE*a3ZL{NB^CC_!;DL@i&eFT7Dw=8H1llJ{O-+0JMC@SNY^; zWPU#RTzqmj&hq!mFG!L;(X4udQNoVg#V2xb>SRY9lzN7WPfGXFxA@7sc+f=2L< csPmd1i~e6*a6*d#6d { T value; } diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusIndexTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusIndexTest.java similarity index 100% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusIndexTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusIndexTest.java index d5acc814..c3923346 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusIndexTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusIndexTest.java @@ -26,8 +26,8 @@ public class EventBusIndexTest { private String value; - @Test /** Ensures the index is actually used and no reflection fall-back kicks in. */ + @Test public void testManualIndexWithoutAnnotation() { SubscriberInfoIndex index = new SubscriberInfoIndex() { diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java similarity index 98% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java index 80638e8b..44109b04 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java @@ -15,18 +15,14 @@ */ package org.greenrobot.eventbus; -import android.support.test.runner.AndroidJUnit4; - import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import static junit.framework.Assert.assertEquals; /** * @author Markus Junginger, greenrobot */ -@RunWith(AndroidJUnit4.class) public class EventBusInheritanceDisabledTest { protected EventBus eventBus; diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceTest.java similarity index 97% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceTest.java index f9619bed..405037c5 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceTest.java @@ -15,14 +15,15 @@ */ package org.greenrobot.eventbus; -import junit.framework.TestCase; - +import org.junit.Before; import org.junit.Test; +import static org.junit.Assert.assertEquals; + /** * @author Markus Junginger, greenrobot */ -public class EventBusInheritanceTest extends TestCase { +public class EventBusInheritanceTest { protected EventBus eventBus; @@ -32,8 +33,8 @@ public class EventBusInheritanceTest extends TestCase { private int countMyEventInterface; private int countMyEventInterfaceExtended; - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() throws Exception { eventBus = new EventBus(); } diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java similarity index 96% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java index d666a504..b358f8c3 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java @@ -23,7 +23,7 @@ /** * @author Markus Junginger, greenrobot */ -public class EventBusNoSubscriberEventTest extends AbstractAndroidEventBusTest { +public class EventBusNoSubscriberEventTest extends AbstractEventBusTest { @Test public void testNoSubscriberEvent() { diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java similarity index 95% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java index 3acb119a..e8d0d796 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java @@ -15,8 +15,6 @@ */ package org.greenrobot.eventbus; -import android.util.Log; - import org.junit.Test; import java.util.ArrayList; @@ -27,7 +25,7 @@ /** * @author Markus Junginger, greenrobot */ -public class EventBusOrderedSubscriptionsTest extends AbstractAndroidEventBusTest { +public class EventBusOrderedSubscriptionsTest extends AbstractEventBusTest { int lastPrio = Integer.MAX_VALUE; final List registered = new ArrayList(); @@ -137,7 +135,7 @@ protected void handleEvent(int prio, Object event) { } lastPrio = prio; - Log.d(EventBus.TAG, "Subscriber " + prio + " got: " + event); + log("Subscriber " + prio + " got: " + event); trackEvent(event); } @@ -206,7 +204,7 @@ protected void handleEvent(int prio, Object event) { } lastPrio = prio; - Log.d(EventBus.TAG, "Subscriber " + prio + " got: " + event); + log("Subscriber " + prio + " got: " + event); trackEvent(event); } diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java similarity index 97% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java index 295066ca..7d09d7ad 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java @@ -28,7 +28,7 @@ /** * @author Markus Junginger, greenrobot */ -public class EventBusRegistrationRacingTest extends AbstractAndroidEventBusTest { +public class EventBusRegistrationRacingTest extends AbstractEventBusTest { // On a Nexus 5, bad synchronization always failed on the first iteration or went well completely. // So a high number of iterations do not guarantee a better probability of finding bugs. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusStickyEventTest.java similarity index 98% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusStickyEventTest.java index e1a5a9f2..ec426745 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusStickyEventTest.java @@ -22,7 +22,7 @@ /** * @author Markus Junginger, greenrobot */ -public class EventBusStickyEventTest extends AbstractAndroidEventBusTest { +public class EventBusStickyEventTest extends AbstractEventBusTest { @Test public void testPostSticky() throws InterruptedException { diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java similarity index 96% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java index c16f820e..f0dea680 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java @@ -23,7 +23,7 @@ /** * @author Markus Junginger, greenrobot */ -public class EventBusSubscriberExceptionTest extends AbstractAndroidEventBusTest { +public class EventBusSubscriberExceptionTest extends AbstractEventBusTest { @Test public void testSubscriberExceptionEvent() { diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberInJarTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusSubscriberInJarTest.java similarity index 84% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberInJarTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusSubscriberInJarTest.java index 5b013eb9..a553e7bc 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberInJarTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusSubscriberInJarTest.java @@ -16,15 +16,10 @@ package org.greenrobot.eventbus; -import junit.framework.Assert; -import junit.framework.TestCase; - -import org.greenrobot.eventbus.EventBus; +import org.junit.Assert; import org.junit.Test; -import org.greenrobot.eventbus.SubscriberInJar; - -public class EventBusSubscriberInJarTest extends TestCase { +public class EventBusSubscriberInJarTest { protected EventBus eventBus = EventBus.builder().build(); @Test diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java similarity index 96% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java index be02c65c..c362e900 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java @@ -22,7 +22,7 @@ /** * @author Markus Junginger, greenrobot */ -public class EventBusSubscriberLegalTest extends AbstractAndroidEventBusTest { +public class EventBusSubscriberLegalTest extends AbstractEventBusTest { @Test public void testSubscriberLegal() { diff --git a/EventBusTest/src/org/greenrobot/eventbus/IntTestEvent.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/IntTestEvent.java similarity index 100% rename from EventBusTest/src/org/greenrobot/eventbus/IntTestEvent.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/IntTestEvent.java From 8ee4073c789ee58a3b4087ac91ac5ee6acdb678c Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 18 Sep 2017 13:11:45 +0200 Subject: [PATCH 193/288] Experimental: generate index for Java tests for use in Android tests. --- .../org/greenrobot/eventbus/indexed/Indexed.java | 7 ++++++- EventBusTestJava/build.gradle | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java index 1fcda4e3..196038e8 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java @@ -17,10 +17,15 @@ package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.EventBusJavaTestsIndex; import org.greenrobot.eventbus.EventBusTestsIndex; public class Indexed { static EventBus build() { - return EventBus.builder().addIndex(new EventBusTestsIndex()).build(); + // TODO ut: remove index of this module once all tests moved to Java module + return EventBus.builder() + .addIndex(new EventBusTestsIndex()) + .addIndex(new EventBusJavaTestsIndex()) + .build(); } } diff --git a/EventBusTestJava/build.gradle b/EventBusTestJava/build.gradle index 13013aac..fe0140c8 100644 --- a/EventBusTestJava/build.gradle +++ b/EventBusTestJava/build.gradle @@ -1,4 +1,15 @@ +buildscript { + repositories { + maven { url "https://plugins.gradle.org/m2/" } + } + + dependencies { + classpath "net.ltgt.gradle:gradle-apt-plugin:0.12" + } +} + apply plugin: 'java' +apply plugin: 'net.ltgt.apt-idea' sourceCompatibility = 1.7 @@ -21,6 +32,10 @@ dependencies { compile(project(':EventBus')) { exclude group: "com.google.android" // Does not seem to work... } + apt project(':EventBusAnnotationProcessor') compile 'junit:junit:4.12' } +tasks.withType(JavaCompile) { + options.compilerArgs += [ "-AeventBusIndex=org.greenrobot.eventbus.EventBusJavaTestsIndex" ] +} From 74a37523a1035943519c43ee7a34db2e47b2147f Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 18 Sep 2017 13:37:39 +0200 Subject: [PATCH 194/288] Fix JUnit error: (inline) test classes have to be public. --- .../greenrobot/eventbus/EventBusInheritanceDisabledTest.java | 2 +- .../java/org/greenrobot/eventbus/EventBusInheritanceTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java index 44109b04..97b14497 100644 --- a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java @@ -172,7 +172,7 @@ public void onEvent(MyEvent event) { } } - static class SubscriberExtendedWithoutNewSubscriberMethod extends EventBusInheritanceDisabledTest { + public static class SubscriberExtendedWithoutNewSubscriberMethod extends EventBusInheritanceDisabledTest { } public class StickySubscriber { diff --git a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceTest.java index 405037c5..089a3220 100644 --- a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceTest.java @@ -172,7 +172,7 @@ public void onEvent(MyEvent event) { } } - static class SubscriberExtendedWithoutNewSubscriberMethod extends EventBusInheritanceTest { + public static class SubscriberExtendedWithoutNewSubscriberMethod extends EventBusInheritanceTest { } public class StickySubscriber { From 88f2173a854c275d2b4fd14ed07f0626388a03b0 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 18 Sep 2017 14:14:15 +0200 Subject: [PATCH 195/288] Add note about Java apt plugin. --- EventBusTestJava/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/EventBusTestJava/build.gradle b/EventBusTestJava/build.gradle index fe0140c8..19aba56f 100644 --- a/EventBusTestJava/build.gradle +++ b/EventBusTestJava/build.gradle @@ -9,6 +9,7 @@ buildscript { } apply plugin: 'java' +// plugin to make it easier/safer to use EventBus annotation processor apply plugin: 'net.ltgt.apt-idea' sourceCompatibility = 1.7 From e8b7d4e4e647a6894d277c2f4092ccaf7afa2edf Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 18 Sep 2017 14:31:02 +0200 Subject: [PATCH 196/288] Extract Java-only tests from cancel event delivery tests. --- ...ventBusAndroidCancelEventDeliveryTest.java | 41 +++++++++++++++++++ .../EventBusCancelEventDeliveryTest.java | 24 +++-------- 2 files changed, 46 insertions(+), 19 deletions(-) create mode 100644 EventBusTest/src/org/greenrobot/eventbus/EventBusAndroidCancelEventDeliveryTest.java rename {EventBusTest/src => EventBusTestJava/src/main/java}/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java (86%) diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusAndroidCancelEventDeliveryTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusAndroidCancelEventDeliveryTest.java new file mode 100644 index 00000000..781ceda2 --- /dev/null +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusAndroidCancelEventDeliveryTest.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.greenrobot.eventbus; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import android.support.test.runner.AndroidJUnit4; +import android.test.UiThreadTest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +@RunWith(AndroidJUnit4.class) +public class EventBusAndroidCancelEventDeliveryTest extends EventBusCancelEventDeliveryTest { + + @UiThreadTest + @Test + public void testCancelInMainThread() { + SubscriberMainThread subscriber = new SubscriberMainThread(); + eventBus.register(subscriber); + eventBus.post("42"); + awaitLatch(subscriber.done, 10); + assertEquals(0, eventCount.intValue()); + assertNotNull(failed); + } + +} diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java similarity index 86% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java index d2aa168f..aeed8fdd 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java @@ -15,20 +15,17 @@ */ package org.greenrobot.eventbus; -import android.test.UiThreadTest; - import org.junit.Test; import java.util.concurrent.CountDownLatch; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; -/** - * @author Markus Junginger, greenrobot - */ -public class EventBusCancelEventDeliveryTest extends AbstractAndroidEventBusTest { +public class EventBusCancelEventDeliveryTest extends AbstractEventBusTest { - private Throwable failed; + Throwable failed; @Test public void testCancel() { @@ -71,17 +68,6 @@ public void testCancelWrongEvent() { assertNotNull(failed); } - @UiThreadTest - @Test - public void testCancelInMainThread() { - SubscriberMainThread subscriber = new SubscriberMainThread(); - eventBus.register(subscriber); - eventBus.post("42"); - awaitLatch(subscriber.done, 10); - assertEquals(0, eventCount.intValue()); - assertNotNull(failed); - } - public class Subscriber { private final int prio; private final boolean cancel; From a10111767ebd9f6b268c54a8d11551bdeb3d5ef1 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 18 Sep 2017 14:44:35 +0200 Subject: [PATCH 197/288] Support logging exceptions in AbstractEventBusTest. --- .../java/org/greenrobot/eventbus/AbstractEventBusTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AbstractEventBusTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AbstractEventBusTest.java index dc488dce..fbbcf265 100644 --- a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AbstractEventBusTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AbstractEventBusTest.java @@ -112,4 +112,8 @@ protected void log(String msg) { eventBus.getLogger().log(Level.FINE, msg); } + protected void log(String msg, Throwable e) { + eventBus.getLogger().log(Level.FINE, msg, e); + } + } From 794096aa09bb854dae45e662711454f7b1570cc8 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 18 Sep 2017 14:52:45 +0200 Subject: [PATCH 198/288] Extract Java-only tests from multi-threaded tests. --- .../EventBusAndroidMultithreadedTest.java | 100 +++++++++++++++++ .../eventbus/EventBusMultithreadedTest.java | 101 +++--------------- 2 files changed, 114 insertions(+), 87 deletions(-) create mode 100644 EventBusTest/src/org/greenrobot/eventbus/EventBusAndroidMultithreadedTest.java rename {EventBusTest/src => EventBusTestJava/src/main/java}/org/greenrobot/eventbus/EventBusMultithreadedTest.java (65%) diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusAndroidMultithreadedTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusAndroidMultithreadedTest.java new file mode 100644 index 00000000..8be31cc1 --- /dev/null +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusAndroidMultithreadedTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.greenrobot.eventbus; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import android.os.Looper; +import android.support.test.runner.AndroidJUnit4; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; + +@RunWith(AndroidJUnit4.class) +public class EventBusAndroidMultithreadedTest extends EventBusMultithreadedTest { + + @Test + public void testSubscribeUnSubscribeAndPostMixedEventType() throws InterruptedException { + List threads = new ArrayList(); + + // Debug.startMethodTracing("testSubscribeUnSubscribeAndPostMixedEventType"); + for (int i = 0; i < 5; i++) { + SubscribeUnsubscribeThread thread = new SubscribeUnsubscribeThread(); + thread.start(); + threads.add(thread); + } + // This test takes a bit longer, so just use fraction the regular count + runThreadsMixedEventType(COUNT / 4, 5); + for (SubscribeUnsubscribeThread thread : threads) { + thread.shutdown(); + } + for (SubscribeUnsubscribeThread thread : threads) { + thread.join(); + } + // Debug.stopMethodTracing(); + } + + public class SubscribeUnsubscribeThread extends Thread { + boolean running = true; + + public void shutdown() { + running = false; + } + + @Override + public void run() { + try { + while (running) { + eventBus.register(this); + double random = Math.random(); + if (random > 0.6d) { + Thread.sleep(0, (int) (1000000 * Math.random())); + } else if (random > 0.3d) { + Thread.yield(); + } + eventBus.unregister(this); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEventMainThread(String event) { + assertSame(Looper.getMainLooper(), Looper.myLooper()); + } + + @Subscribe(threadMode = ThreadMode.BACKGROUND) + public void onEventBackgroundThread(Integer event) { + assertNotSame(Looper.getMainLooper(), Looper.myLooper()); + } + + @Subscribe + public void onEvent(Object event) { + assertNotSame(Looper.getMainLooper(), Looper.myLooper()); + } + + @Subscribe(threadMode = ThreadMode.ASYNC) + public void onEventAsync(Object event) { + assertNotSame(Looper.getMainLooper(), Looper.myLooper()); + } + } + +} diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusMultithreadedTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusMultithreadedTest.java similarity index 65% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusMultithreadedTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusMultithreadedTest.java index f84ee893..e1c1576c 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusMultithreadedTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusMultithreadedTest.java @@ -15,9 +15,6 @@ */ package org.greenrobot.eventbus; -import android.os.Looper; -import android.util.Log; - import org.junit.Test; import java.util.ArrayList; @@ -25,24 +22,21 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; -/** - * @author Markus Junginger, greenrobot - */ -public class EventBusMultithreadedTest extends AbstractAndroidEventBusTest { +public class EventBusMultithreadedTest extends AbstractEventBusTest { - private static final int COUNT = LONG_TESTS ? 100000 : 1000; + static final int COUNT = LONG_TESTS ? 100000 : 1000; - private final AtomicInteger countStringEvent = new AtomicInteger(); - private final AtomicInteger countIntegerEvent = new AtomicInteger(); - private final AtomicInteger countObjectEvent = new AtomicInteger(); - private final AtomicInteger countIntTestEvent = new AtomicInteger(); + final AtomicInteger countStringEvent = new AtomicInteger(); + final AtomicInteger countIntegerEvent = new AtomicInteger(); + final AtomicInteger countObjectEvent = new AtomicInteger(); + final AtomicInteger countIntTestEvent = new AtomicInteger(); - private String lastStringEvent; - private Integer lastIntegerEvent; + String lastStringEvent; + Integer lastIntegerEvent; - private IntTestEvent lastIntTestEvent; + IntTestEvent lastIntTestEvent; @Test public void testPost01Thread() throws InterruptedException { @@ -74,27 +68,6 @@ public void testPostMixedEventType40Threads() throws InterruptedException { runThreadsMixedEventType(40); } - @Test - public void testSubscribeUnSubscribeAndPostMixedEventType() throws InterruptedException { - List threads = new ArrayList(); - - // Debug.startMethodTracing("testSubscribeUnSubscribeAndPostMixedEventType"); - for (int i = 0; i < 5; i++) { - SubscribeUnsubscribeThread thread = new SubscribeUnsubscribeThread(); - thread.start(); - threads.add(thread); - } - // This test takes a bit longer, so just use fraction the regular count - runThreadsMixedEventType(COUNT / 4, 5); - for (SubscribeUnsubscribeThread thread : threads) { - thread.shutdown(); - } - for (SubscribeUnsubscribeThread thread : threads) { - thread.join(); - } - // Debug.stopMethodTracing(); - } - private void runThreadsSingleEventType(int threadCount) throws InterruptedException { int iterations = COUNT / threadCount; eventBus.register(this); @@ -103,7 +76,7 @@ private void runThreadsSingleEventType(int threadCount) throws InterruptedExcept List threads = startThreads(latch, threadCount, iterations, "Hello"); long time = triggerAndWaitForThreads(threads, latch); - Log.d(EventBus.TAG, threadCount + " threads posted " + iterations + " events each in " + time + "ms"); + log(threadCount + " threads posted " + iterations + " events each in " + time + "ms"); waitForEventCount(COUNT * 2, 5000); @@ -117,7 +90,7 @@ private void runThreadsMixedEventType(int threadCount) throws InterruptedExcepti runThreadsMixedEventType(COUNT, threadCount); } - private void runThreadsMixedEventType(int count, int threadCount) throws InterruptedException { + void runThreadsMixedEventType(int count, int threadCount) throws InterruptedException { eventBus.register(this); int eventTypeCount = 3; int iterations = count / threadCount / eventTypeCount; @@ -133,7 +106,7 @@ private void runThreadsMixedEventType(int count, int threadCount) throws Interru threads.addAll(threadsIntTestEvent); long time = triggerAndWaitForThreads(threads, latch); - Log.d(EventBus.TAG, threadCount * eventTypeCount + " mixed threads posted " + iterations + " events each in " + log(threadCount * eventTypeCount + " mixed threads posted " + iterations + " events each in " + time + "ms"); int expectedCountEach = threadCount * iterations; @@ -219,7 +192,7 @@ public void run() { try { startLatch.await(); } catch (InterruptedException e) { - Log.w(EventBus.TAG, "Unexpeced interrupt", e); + log("Unexpected interrupt", e); } for (int i = 0; i < iterations; i++) { @@ -228,50 +201,4 @@ public void run() { } } - public class SubscribeUnsubscribeThread extends Thread { - boolean running = true; - - public void shutdown() { - running = false; - } - - @Override - public void run() { - try { - while (running) { - eventBus.register(this); - double random = Math.random(); - if (random > 0.6d) { - Thread.sleep(0, (int) (1000000 * Math.random())); - } else if (random > 0.3d) { - Thread.yield(); - } - eventBus.unregister(this); - } - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(String event) { - assertSame(Looper.getMainLooper(), Looper.myLooper()); - } - - @Subscribe(threadMode = ThreadMode.BACKGROUND) - public void onEventBackgroundThread(Integer event) { - assertNotSame(Looper.getMainLooper(), Looper.myLooper()); - } - - @Subscribe - public void onEvent(Object event) { - assertNotSame(Looper.getMainLooper(), Looper.myLooper()); - } - - @Subscribe(threadMode = ThreadMode.ASYNC) - public void onEventAsync(Object event) { - assertNotSame(Looper.getMainLooper(), Looper.myLooper()); - } - } - } From 8a192b4c8d04b6c2d48bf2a03a5dfa81a36cbdc2 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 18 Sep 2017 14:53:41 +0200 Subject: [PATCH 199/288] For now keep both Java and Android module index. --- .../eventbus/indexed/EventBusBackgroundThreadTestWithIndex.java | 2 +- .../greenrobot/eventbus/indexed/EventBusBasicTestWithIndex.java | 2 +- EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBackgroundThreadTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBackgroundThreadTestWithIndex.java index 00e38203..b1f316a1 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBackgroundThreadTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBackgroundThreadTestWithIndex.java @@ -30,6 +30,6 @@ public void overwriteEventBus() throws Exception { @Test public void testIndex() { - assertTrue(eventBus.toString().contains("indexCount=1")); + assertTrue(eventBus.toString().contains("indexCount=2")); } } diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBasicTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBasicTestWithIndex.java index 4237ce8e..662a70b8 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBasicTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBasicTestWithIndex.java @@ -30,6 +30,6 @@ public void overwriteEventBus() throws Exception { @Test public void testIndex() { - assertTrue(eventBus.toString().contains("indexCount=1")); + assertTrue(eventBus.toString().contains("indexCount=2")); } } diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java index 196038e8..4aec1ef6 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java @@ -22,7 +22,6 @@ public class Indexed { static EventBus build() { - // TODO ut: remove index of this module once all tests moved to Java module return EventBus.builder() .addIndex(new EventBusTestsIndex()) .addIndex(new EventBusJavaTestsIndex()) From a90093491d652001d1d8c04cfc7a691d9bc468ca Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 18 Sep 2017 15:16:48 +0200 Subject: [PATCH 200/288] Move inner test classes to upper level so Android runner picks them up. --- ...BusInheritanceDisabledSubclassNoMethod.java | 5 +++++ ...ventBusInheritanceDisabledSubclassTest.java | 13 +++++++++++++ .../EventBusInheritanceDisabledTest.java | 18 ++++-------------- ...ventBusInheritanceSubclassNoMethodTest.java | 5 +++++ .../EventBusInheritanceSubclassTest.java | 12 ++++++++++++ .../eventbus/EventBusInheritanceTest.java | 17 +++-------------- 6 files changed, 42 insertions(+), 28 deletions(-) create mode 100644 EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledSubclassNoMethod.java create mode 100644 EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledSubclassTest.java create mode 100644 EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceSubclassNoMethodTest.java create mode 100644 EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceSubclassTest.java diff --git a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledSubclassNoMethod.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledSubclassNoMethod.java new file mode 100644 index 00000000..0fcc73cf --- /dev/null +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledSubclassNoMethod.java @@ -0,0 +1,5 @@ +package org.greenrobot.eventbus; + +// Need to use upper class or Android test runner does not pick it up +public class EventBusInheritanceDisabledSubclassNoMethod extends EventBusInheritanceDisabledTest { +} diff --git a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledSubclassTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledSubclassTest.java new file mode 100644 index 00000000..b5a51591 --- /dev/null +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledSubclassTest.java @@ -0,0 +1,13 @@ +package org.greenrobot.eventbus; + +// Need to use upper class or Android test runner does not pick it up +public class EventBusInheritanceDisabledSubclassTest extends EventBusInheritanceDisabledTest { + + int countMyEventOverwritten; + + @Subscribe + public void onEvent(MyEvent event) { + countMyEventOverwritten++; + } + +} \ No newline at end of file diff --git a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java index 97b14497..4b026719 100644 --- a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java @@ -90,7 +90,8 @@ public void testEventSuperInterfaceHierarchy() { @Test public void testSubscriberClassHierarchy() { - SubscriberExtended subscriber = new SubscriberExtended(); + EventBusInheritanceDisabledSubclassTest + subscriber = new EventBusInheritanceDisabledSubclassTest(); eventBus.register(subscriber); eventBus.post("Hello"); @@ -110,7 +111,8 @@ public void testSubscriberClassHierarchy() { @Test public void testSubscriberClassHierarchyWithoutNewSubscriberMethod() { - SubscriberExtendedWithoutNewSubscriberMethod subscriber = new SubscriberExtendedWithoutNewSubscriberMethod(); + EventBusInheritanceDisabledSubclassNoMethod + subscriber = new EventBusInheritanceDisabledSubclassNoMethod(); eventBus.register(subscriber); eventBus.post("Hello"); @@ -163,18 +165,6 @@ public static interface MyEventInterfaceExtended extends MyEventInterface { public static class MyEventExtended extends MyEvent implements MyEventInterfaceExtended { } - public static class SubscriberExtended extends EventBusInheritanceDisabledTest { - private int countMyEventOverwritten; - - @Subscribe - public void onEvent(MyEvent event) { - countMyEventOverwritten++; - } - } - - public static class SubscriberExtendedWithoutNewSubscriberMethod extends EventBusInheritanceDisabledTest { - } - public class StickySubscriber { @Subscribe(sticky = true) public void onEvent(Object event) { diff --git a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceSubclassNoMethodTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceSubclassNoMethodTest.java new file mode 100644 index 00000000..a9f6da47 --- /dev/null +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceSubclassNoMethodTest.java @@ -0,0 +1,5 @@ +package org.greenrobot.eventbus; + +// Need to use upper class or Android test runner does not pick it up +public class EventBusInheritanceSubclassNoMethodTest extends EventBusInheritanceTest { +} diff --git a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceSubclassTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceSubclassTest.java new file mode 100644 index 00000000..3edbe890 --- /dev/null +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceSubclassTest.java @@ -0,0 +1,12 @@ +package org.greenrobot.eventbus; + +// Need to use upper class or Android test runner does not pick it up +public class EventBusInheritanceSubclassTest extends EventBusInheritanceTest { + int countMyEventOverwritten; + + @Subscribe + public void onEvent(MyEvent event) { + countMyEventOverwritten++; + } + +} diff --git a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceTest.java index 089a3220..9fd52288 100644 --- a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceTest.java @@ -90,7 +90,7 @@ public void testEventSuperInterfaceHierarchy() { @Test public void testSubscriberClassHierarchy() { - SubscriberExtended subscriber = new SubscriberExtended(); + EventBusInheritanceSubclassTest subscriber = new EventBusInheritanceSubclassTest(); eventBus.register(subscriber); eventBus.post("Hello"); @@ -110,7 +110,8 @@ public void testSubscriberClassHierarchy() { @Test public void testSubscriberClassHierarchyWithoutNewSubscriberMethod() { - SubscriberExtendedWithoutNewSubscriberMethod subscriber = new SubscriberExtendedWithoutNewSubscriberMethod(); + EventBusInheritanceSubclassNoMethodTest + subscriber = new EventBusInheritanceSubclassNoMethodTest(); eventBus.register(subscriber); eventBus.post("Hello"); @@ -163,18 +164,6 @@ public static interface MyEventInterfaceExtended extends MyEventInterface { public static class MyEventExtended extends MyEvent implements MyEventInterfaceExtended { } - public static class SubscriberExtended extends EventBusInheritanceTest { - private int countMyEventOverwritten; - - @Subscribe - public void onEvent(MyEvent event) { - countMyEventOverwritten++; - } - } - - public static class SubscriberExtendedWithoutNewSubscriberMethod extends EventBusInheritanceTest { - } - public class StickySubscriber { @Subscribe(sticky = true) public void onEvent(Object event) { From a5ef8974110ee4ac8a530ef8447ac455c725ad41 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 18 Sep 2017 15:17:35 +0200 Subject: [PATCH 201/288] Temporarily ignore failing subclass inheritance tests. --- .../eventbus/EventBusInheritanceDisabledSubclassTest.java | 7 +++++++ .../eventbus/EventBusInheritanceSubclassTest.java | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledSubclassTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledSubclassTest.java index b5a51591..6ab86d23 100644 --- a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledSubclassTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledSubclassTest.java @@ -1,5 +1,7 @@ package org.greenrobot.eventbus; +import org.junit.Ignore; + // Need to use upper class or Android test runner does not pick it up public class EventBusInheritanceDisabledSubclassTest extends EventBusInheritanceDisabledTest { @@ -10,4 +12,9 @@ public void onEvent(MyEvent event) { countMyEventOverwritten++; } + @Override + @Ignore + public void testEventClassHierarchy() { + // TODO fix test in super, then remove this + } } \ No newline at end of file diff --git a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceSubclassTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceSubclassTest.java index 3edbe890..8b3d4e4d 100644 --- a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceSubclassTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceSubclassTest.java @@ -1,5 +1,7 @@ package org.greenrobot.eventbus; +import org.junit.Ignore; + // Need to use upper class or Android test runner does not pick it up public class EventBusInheritanceSubclassTest extends EventBusInheritanceTest { int countMyEventOverwritten; @@ -9,4 +11,9 @@ public void onEvent(MyEvent event) { countMyEventOverwritten++; } + @Override + @Ignore + public void testEventClassHierarchy() { + // TODO fix test in super, then remove this + } } From 965acb1d01efaac1131ab354cf92e45d5a692afa Mon Sep 17 00:00:00 2001 From: William Ferguson Date: Wed, 11 May 2016 20:36:39 +1000 Subject: [PATCH 202/288] Added ThreadMode.MAIN_ASYNC to allow a subscriber to declare that it wants to be called in the Main UI thread but the events should be queued for delivery in the order in which they are posted. Ie MAIN_ASYNC subscribers never received delivery directly from the poster's thread, even if it is the Main UI thread. --- EventBus/src/org/greenrobot/eventbus/EventBus.java | 3 +++ EventBus/src/org/greenrobot/eventbus/ThreadMode.java | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/EventBus/src/org/greenrobot/eventbus/EventBus.java b/EventBus/src/org/greenrobot/eventbus/EventBus.java index 712b3ff9..fc558b0b 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBus.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBus.java @@ -436,6 +436,9 @@ private void postToSubscription(Subscription subscription, Object event, boolean mainThreadPoster.enqueue(subscription, event); } break; + case MAIN_ASYNC: + mainThreadPoster.enqueue(subscription, event); + break; case BACKGROUND: if (isMainThread) { backgroundPoster.enqueue(subscription, event); diff --git a/EventBus/src/org/greenrobot/eventbus/ThreadMode.java b/EventBus/src/org/greenrobot/eventbus/ThreadMode.java index 79d5dc43..72a8e01f 100644 --- a/EventBus/src/org/greenrobot/eventbus/ThreadMode.java +++ b/EventBus/src/org/greenrobot/eventbus/ThreadMode.java @@ -38,6 +38,12 @@ public enum ThreadMode { */ MAIN, + /** + * Event will be queued for delivery and the subscriber will be called in Android's main thread (sometimes referred to as UI thread). + * This ensures that the poster does not block and that the subscriber is called by Android's main thread so can update UI. + */ + MAIN_ASYNC, + /** * Subscriber will be called in a background thread. If posting thread is not the main thread, event handler methods * will be called directly in the posting thread. If the posting thread is the main thread, EventBus uses a single From b1a0581199238f3162bebeb4869a524c0397cc32 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 19 Sep 2017 08:22:07 +0200 Subject: [PATCH 203/288] Rename new thread mode to MAIN_ORDERED to differentiate from ASYNC. - Update ThreadMode docs: always use subscriber instead of event handler, add differences if not used on Android. --- .../src/org/greenrobot/eventbus/EventBus.java | 2 +- .../org/greenrobot/eventbus/ThreadMode.java | 33 ++++++++++--------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/EventBus/src/org/greenrobot/eventbus/EventBus.java b/EventBus/src/org/greenrobot/eventbus/EventBus.java index fc558b0b..3b0fffeb 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBus.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBus.java @@ -436,7 +436,7 @@ private void postToSubscription(Subscription subscription, Object event, boolean mainThreadPoster.enqueue(subscription, event); } break; - case MAIN_ASYNC: + case MAIN_ORDERED: mainThreadPoster.enqueue(subscription, event); break; case BACKGROUND: diff --git a/EventBus/src/org/greenrobot/eventbus/ThreadMode.java b/EventBus/src/org/greenrobot/eventbus/ThreadMode.java index 72a8e01f..b8ee7d53 100644 --- a/EventBus/src/org/greenrobot/eventbus/ThreadMode.java +++ b/EventBus/src/org/greenrobot/eventbus/ThreadMode.java @@ -16,7 +16,7 @@ package org.greenrobot.eventbus; /** - * Each event handler method has a thread mode, which determines in which thread the method is to be called by EventBus. + * Each subscriber method has a thread mode, which determines in which thread the method is to be called by EventBus. * EventBus takes care of threading independently from the posting thread. * * @see EventBus#register(Object) @@ -24,40 +24,41 @@ */ public enum ThreadMode { /** - * Subscriber will be called in the same thread, which is posting the event. This is the default. Event delivery + * Subscriber will be called directly in the same thread, which is posting the event. This is the default. Event delivery * implies the least overhead because it avoids thread switching completely. Thus this is the recommended mode for - * simple tasks that are known to complete is a very short time without requiring the main thread. Event handlers + * simple tasks that are known to complete in a very short time without requiring the main thread. Event handlers * using this mode must return quickly to avoid blocking the posting thread, which may be the main thread. */ POSTING, /** - * Subscriber will be called in Android's main thread (sometimes referred to as UI thread). If the posting thread is - * the main thread, event handler methods will be called directly. Event handlers using this mode must return - * quickly to avoid blocking the main thread. + * On Android, subscriber will be called in Android's main thread (UI thread). If the posting thread is + * the main thread, subscriber methods will be called directly, blocking the posting thread. Otherwise the event + * is queued for delivery (non-blocking). Subscribers using this mode must return quickly to avoid blocking the main thread. + * If not on Android, behaves the same as {@link #POSTING}. */ MAIN, /** - * Event will be queued for delivery and the subscriber will be called in Android's main thread (sometimes referred to as UI thread). - * This ensures that the poster does not block and that the subscriber is called by Android's main thread so can update UI. + * On Android, subscriber will be called in Android's main thread (UI thread). Different from {@link #MAIN}, + * the event will always be queued for delivery. This ensures that the post call is non-blocking. */ - MAIN_ASYNC, + MAIN_ORDERED, /** - * Subscriber will be called in a background thread. If posting thread is not the main thread, event handler methods + * On Android, subscriber will be called in a background thread. If posting thread is not the main thread, subscriber methods * will be called directly in the posting thread. If the posting thread is the main thread, EventBus uses a single - * background thread, that will deliver all its events sequentially. Event handlers using this mode should try to - * return quickly to avoid blocking the background thread. + * background thread, that will deliver all its events sequentially. Subscribers using this mode should try to + * return quickly to avoid blocking the background thread. If not on Android, always uses a background thread. */ BACKGROUND, /** - * Event handler methods are called in a separate thread. This is always independent from the posting thread and the - * main thread. Posting events never wait for event handler methods using this mode. Event handler methods should + * Subscriber will be called in a separate thread. This is always independent from the posting thread and the + * main thread. Posting events never wait for subscriber methods using this mode. Subscriber methods should * use this mode if their execution might take some time, e.g. for network access. Avoid triggering a large number - * of long running asynchronous handler methods at the same time to limit the number of concurrent threads. EventBus - * uses a thread pool to efficiently reuse threads from completed asynchronous event handler notifications. + * of long running asynchronous subscriber methods at the same time to limit the number of concurrent threads. EventBus + * uses a thread pool to efficiently reuse threads from completed asynchronous subscriber notifications. */ ASYNC } \ No newline at end of file From dfc6198136a5de39e8f59744a45e8353812ef13c Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 19 Sep 2017 09:32:21 +0200 Subject: [PATCH 204/288] Add tests for MAIN vs MAIN_ORDERED behavior. From main thread: create background thread that posts, then post event also. Observe that event posted by main thread is delivered immediately (MAIN) or queued for delivery on main thread (MAIN_ORDERED). --- .../eventbus/EventBusAndroidOrderTest.java | 91 +++++++++++++++++++ .../eventbus/EventBusMainThreadTest.java | 70 +------------- .../eventbus/TestBackgroundPoster.java | 70 ++++++++++++++ 3 files changed, 163 insertions(+), 68 deletions(-) create mode 100644 EventBusTest/src/org/greenrobot/eventbus/EventBusAndroidOrderTest.java create mode 100644 EventBusTest/src/org/greenrobot/eventbus/TestBackgroundPoster.java diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusAndroidOrderTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusAndroidOrderTest.java new file mode 100644 index 00000000..ff348e1d --- /dev/null +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusAndroidOrderTest.java @@ -0,0 +1,91 @@ +package org.greenrobot.eventbus; + +import android.os.Handler; +import android.os.Looper; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + + +import static org.junit.Assert.assertEquals; + +public class EventBusAndroidOrderTest extends AbstractAndroidEventBusTest { + + private TestBackgroundPoster backgroundPoster; + private Handler handler; + + @Before + public void setUp() throws Exception { + handler = new Handler(Looper.getMainLooper()); + backgroundPoster = new TestBackgroundPoster(eventBus); + backgroundPoster.start(); + } + + @After + public void tearDown() throws Exception { + backgroundPoster.shutdown(); + backgroundPoster.join(); + } + + @Test + public void backgroundAndMainUnordered() { + eventBus.register(this); + + handler.post(new Runnable() { + @Override + public void run() { + // post from non-main thread + backgroundPoster.post("non-main"); + // post from main thread + eventBus.post("main"); + } + }); + + waitForEventCount(2, 1000); + + // observe that event from *main* thread is posted FIRST + // NOT in posting order + assertEquals("non-main", lastEvent); + } + + @Test + public void backgroundAndMainOrdered() { + eventBus.register(this); + + handler.post(new Runnable() { + @Override + public void run() { + // post from non-main thread + backgroundPoster.post(new OrderedEvent("non-main")); + // post from main thread + eventBus.post(new OrderedEvent("main")); + } + }); + + waitForEventCount(2, 1000); + + // observe that event from *main* thread is posted LAST + // IN posting order + assertEquals("main", ((OrderedEvent) lastEvent).thread); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEvent(String event) { + trackEvent(event); + } + + @Subscribe(threadMode = ThreadMode.MAIN_ORDERED) + public void onEvent(OrderedEvent event) { + trackEvent(event); + } + + static class OrderedEvent { + String thread; + + OrderedEvent(String thread) { + this.thread = thread; + } + } + +} diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java index d20f2c27..953edb6c 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java @@ -21,8 +21,6 @@ import org.junit.Before; import org.junit.Test; -import java.util.ArrayList; -import java.util.List; import static org.junit.Assert.assertEquals; @@ -31,11 +29,11 @@ */ public class EventBusMainThreadTest extends AbstractAndroidEventBusTest { - private BackgroundPoster backgroundPoster; + private TestBackgroundPoster backgroundPoster; @Before public void setUp() throws Exception { - backgroundPoster = new BackgroundPoster(); + backgroundPoster = new TestBackgroundPoster(eventBus); backgroundPoster.start(); } @@ -69,68 +67,4 @@ public void onEventMainThread(String event) { trackEvent(event); } - class BackgroundPoster extends Thread { - volatile boolean running = true; - private final List eventQ = new ArrayList(); - private final List eventsDone = new ArrayList(); - - public BackgroundPoster() { - super("BackgroundPoster"); - } - - @Override - public void run() { - while (running) { - Object event = pollEvent(); - if (event != null) { - eventBus.post(event); - synchronized (eventsDone) { - eventsDone.add(event); - eventsDone.notifyAll(); - } - } - } - } - - private synchronized Object pollEvent() { - Object event = null; - synchronized (eventQ) { - if (eventQ.isEmpty()) { - try { - eventQ.wait(1000); - } catch (InterruptedException e) { - } - } - if(!eventQ.isEmpty()) { - event = eventQ.remove(0); - } - } - return event; - } - - void shutdown() { - running = false; - synchronized (eventQ) { - eventQ.notifyAll(); - } - } - - void post(Object event) { - synchronized (eventQ) { - eventQ.add(event); - eventQ.notifyAll(); - } - synchronized (eventsDone) { - while (!eventsDone.remove(event)) { - try { - eventsDone.wait(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - } - } - - } - } diff --git a/EventBusTest/src/org/greenrobot/eventbus/TestBackgroundPoster.java b/EventBusTest/src/org/greenrobot/eventbus/TestBackgroundPoster.java new file mode 100644 index 00000000..a40eefd9 --- /dev/null +++ b/EventBusTest/src/org/greenrobot/eventbus/TestBackgroundPoster.java @@ -0,0 +1,70 @@ +package org.greenrobot.eventbus; + +import java.util.ArrayList; +import java.util.List; + +public class TestBackgroundPoster extends Thread { + private final EventBus eventBus; + volatile boolean running = true; + private final List eventQ = new ArrayList<>(); + private final List eventsDone = new ArrayList<>(); + + TestBackgroundPoster(EventBus eventBus) { + super("BackgroundPoster"); + this.eventBus = eventBus; + } + + @Override + public void run() { + while (running) { + Object event = pollEvent(); + if (event != null) { + eventBus.post(event); + synchronized (eventsDone) { + eventsDone.add(event); + eventsDone.notifyAll(); + } + } + } + } + + private synchronized Object pollEvent() { + Object event = null; + synchronized (eventQ) { + if (eventQ.isEmpty()) { + try { + eventQ.wait(1000); + } catch (InterruptedException ignored) { + } + } + if(!eventQ.isEmpty()) { + event = eventQ.remove(0); + } + } + return event; + } + + void shutdown() { + running = false; + synchronized (eventQ) { + eventQ.notifyAll(); + } + } + + void post(Object event) { + synchronized (eventQ) { + eventQ.add(event); + eventQ.notifyAll(); + } + synchronized (eventsDone) { + while (!eventsDone.remove(event)) { + try { + eventsDone.wait(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + } + +} From 618a4f17f13751539c0879ca79d7f534631fdd99 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 19 Sep 2017 10:33:14 +0200 Subject: [PATCH 205/288] Fix regression: test fails if poster set-up out of method. Not sure why, but event is not received if background poster is set up using field. Setting up inside test method works fine. Also works fine in EventBusAndroidOrderTest. --- .../eventbus/EventBusMainThreadTest.java | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java index 953edb6c..34c29ee6 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java @@ -17,8 +17,6 @@ import android.os.Looper; -import org.junit.After; -import org.junit.Before; import org.junit.Test; @@ -29,20 +27,6 @@ */ public class EventBusMainThreadTest extends AbstractAndroidEventBusTest { - private TestBackgroundPoster backgroundPoster; - - @Before - public void setUp() throws Exception { - backgroundPoster = new TestBackgroundPoster(eventBus); - backgroundPoster.start(); - } - - @After - public void tearDown() throws Exception { - backgroundPoster.shutdown(); - backgroundPoster.join(); - } - @Test public void testPost() throws InterruptedException { eventBus.register(this); @@ -55,11 +39,17 @@ public void testPost() throws InterruptedException { @Test public void testPostInBackgroundThread() throws InterruptedException { + TestBackgroundPoster backgroundPoster = new TestBackgroundPoster(eventBus); + backgroundPoster.start(); + eventBus.register(this); backgroundPoster.post("Hello"); waitForEventCount(1, 1000); assertEquals("Hello", lastEvent); assertEquals(Looper.getMainLooper().getThread(), lastThread); + + backgroundPoster.shutdown(); + backgroundPoster.join(); } @Subscribe(threadMode = ThreadMode.MAIN) From 19c6edb2ce5c1e8ed995423ad8ab34af37e1f057 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 19 Sep 2017 11:04:09 +0200 Subject: [PATCH 206/288] Use same targetSdkVersion if running Android tests with Gradle. - Define min and target SDK, version in Gradle config. - Ignore manifest warnings. --- EventBusTest/AndroidManifest.xml | 10 ++++------ EventBusTest/build.gradle | 5 +++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/EventBusTest/AndroidManifest.xml b/EventBusTest/AndroidManifest.xml index 03275fde..657ad878 100644 --- a/EventBusTest/AndroidManifest.xml +++ b/EventBusTest/AndroidManifest.xml @@ -1,16 +1,14 @@ - - + xmlns:tools="http://schemas.android.com/tools" + package="org.greenrobot.eventbus"> + android:label="EventBus Test" + tools:ignore="GoogleAppIndexingWarning,MissingApplicationIcon"> \ No newline at end of file diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index ff7208e5..1a413744 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -47,6 +47,11 @@ android { } defaultConfig { + minSdkVersion 8 + targetSdkVersion 25 + versionCode 1 + versionName "1.0" + testApplicationId "de.greenrobot.event.test" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } From 0be66fb1b12c480a3247992febe0a9ea52a193c8 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 19 Sep 2017 11:11:37 +0200 Subject: [PATCH 207/288] Do not crash if using MAIN_ORDERED on non-Android. Temporarily just directly invoke the subscriber if no main thread poster is available. Technically this breaks the promised decoupling of poster and subscriber. --- EventBus/src/org/greenrobot/eventbus/EventBus.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/EventBus/src/org/greenrobot/eventbus/EventBus.java b/EventBus/src/org/greenrobot/eventbus/EventBus.java index 3b0fffeb..247cbb27 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBus.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBus.java @@ -437,7 +437,12 @@ private void postToSubscription(Subscription subscription, Object event, boolean } break; case MAIN_ORDERED: - mainThreadPoster.enqueue(subscription, event); + if (mainThreadPoster != null) { + mainThreadPoster.enqueue(subscription, event); + } else { + // temporary: technically not correct as poster not decoupled from subscriber + invokeSubscriber(subscription, event); + } break; case BACKGROUND: if (isMainThread) { From 7f5e0cec0a7c021af9a9feb513fba14b1e0855a4 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 17 Oct 2017 10:56:56 +0200 Subject: [PATCH 208/288] Use annotationProcessor instead of android-apt. --- EventBusPerformance/build.gradle | 17 ++++++++--------- EventBusTest/build.gradle | 19 +++++++------------ 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index a76c1899..99b54771 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -5,12 +5,10 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:2.3.3' - classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } apply plugin: 'com.android.application' -apply plugin: 'com.neenbedankt.android-apt' repositories { jcenter() @@ -18,16 +16,10 @@ repositories { dependencies { compile project(':EventBus') - apt project(':EventBusAnnotationProcessor') + annotationProcessor project(':EventBusAnnotationProcessor') compile 'com.squareup:otto:1.3.8' } -apt { - arguments { - eventBusIndex "org.greenrobot.eventbusperf.MyEventBusIndex" - } -} - android { buildToolsVersion '25.0.3' // When updating, don't forget to adjust .travis.yml compileSdkVersion 25 @@ -40,4 +32,11 @@ android { } } + defaultConfig { + javaCompileOptions { + annotationProcessorOptions { + arguments = [eventBusIndex: 'org.greenrobot.eventbusperf.MyEventBusIndex'] + } + } + } } diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 1a413744..e631ce3f 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -5,23 +5,19 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:2.3.3' - classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } apply plugin: 'com.android.application' -apply plugin: 'com.neenbedankt.android-apt' - -sourceCompatibility = 1.7 repositories { jcenter() } dependencies { - androidTestApt project(':EventBusAnnotationProcessor') androidTestCompile project(':EventBus') androidTestCompile project(':EventBusTestJava') + androidTestAnnotationProcessor project(':EventBusAnnotationProcessor') compile fileTree(dir: 'libs', include: '*.jar') androidTestCompile 'com.android.support.test:runner:0.5' androidTestCompile 'com.android.support.test:rules:0.5' @@ -54,6 +50,12 @@ android { testApplicationId "de.greenrobot.event.test" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + + javaCompileOptions { + annotationProcessorOptions { + arguments = [ eventBusIndex : 'org.greenrobot.eventbus.EventBusTestsIndex' ] + } + } } lintOptions { @@ -64,10 +66,3 @@ android { abortOnError false } } - -apt { - arguments { - eventBusIndex "org.greenrobot.eventbus.EventBusTestsIndex" - } -} - From e6d912b0614b453e8cb4474e4498b1ddc25746be Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 17 Oct 2017 11:01:44 +0200 Subject: [PATCH 209/288] Gradle 4.1 - Fixes issues with dependencies not getting recognized by Android Studio. --- build.gradle | 3 ++- gradle/wrapper/gradle-wrapper.jar | Bin 54783 -> 54708 bytes gradle/wrapper/gradle-wrapper.properties | 3 +-- gradlew | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index 2243fd1d..fc18b763 100644 --- a/build.gradle +++ b/build.gradle @@ -7,5 +7,6 @@ if (JavaVersion.current().isJava8Compatible()) { } task wrapper(type: Wrapper) { - gradleVersion = '3.5' + gradleVersion = '4.1' + distributionType = org.gradle.api.tasks.wrapper.Wrapper.DistributionType.ALL } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 79eb0160bc80b1a4d113f3147ed7755989a9ad29..7a3265ee94c0ab25cf079ac8ccdf87f41d455d42 100644 GIT binary patch delta 17061 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 Date: Tue, 17 Oct 2017 11:10:56 +0200 Subject: [PATCH 210/288] EventBusTest: Update testing support library to 1.0.1. - Requires minSdk 9 (was 8), Google repo. --- EventBusTest/build.gradle | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index e631ce3f..068c640a 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -12,6 +12,7 @@ apply plugin: 'com.android.application' repositories { jcenter() + google() } dependencies { @@ -19,8 +20,8 @@ dependencies { androidTestCompile project(':EventBusTestJava') androidTestAnnotationProcessor project(':EventBusAnnotationProcessor') compile fileTree(dir: 'libs', include: '*.jar') - androidTestCompile 'com.android.support.test:runner:0.5' - androidTestCompile 'com.android.support.test:rules:0.5' + androidTestCompile 'com.android.support.test:runner:1.0.1' + androidTestCompile 'com.android.support.test:rules:1.0.1' } android { @@ -43,7 +44,7 @@ android { } defaultConfig { - minSdkVersion 8 + minSdkVersion 9 targetSdkVersion 25 versionCode 1 versionName "1.0" From fb0e64c249dc97a3820daa894a44f84a7d4a8cd4 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 6 Nov 2017 11:27:11 +0100 Subject: [PATCH 211/288] README.md: updated links, added survey link --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 103ac25c..fa176e78 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +Hey, do have a minute for a [quick survey](https://docs.google.com/forms/d/e/1FAIpQLSePA8NqA9Jlbvh28xcFVbmIGUzHW3dnsxuxi23-ZDPPfkWMSQ/viewform) on how we are doing with EventBus? + EventBus ======== EventBus is a publish/subscribe event bus for Android and Java.
@@ -100,10 +102,10 @@ EventBus binaries and source code can be used according to the [Apache License, More Open Source by greenrobot ============================== -[__ObjectBox__](https://github.com/objectbox/objectbox-java) is a new superfast object-oriented database for mobile. +[__ObjectBox__](http://objectbox.io/) ([GitHub](https://github.com/objectbox/objectbox-java)) is a new superfast object-oriented database for mobile. -[__greenrobot-common__](https://github.com/greenrobot/greenrobot-common) is a set of utility classes and hash functions for Android & Java projects. +[__Essentials__](http://greenrobot.org/essentials/) ([GitHub](https://github.com/greenrobot/essentials)) is a set of utility classes and hash functions for Android & Java projects. -[__greenDAO__](https://github.com/greenrobot/greenDAO) is an ORM optimized for Android: it maps database tables to Java objects and uses code generation for optimal speed. +[__greenDAO__](http://greenrobot.org/greendao/) ([GitHub](https://github.com/greenrobot/greenDAO)) is an ORM optimized for Android: it maps database tables to Java objects and uses code generation for optimal speed. [Follow us on Google+](https://plus.google.com/b/114381455741141514652/+GreenrobotDe/posts) or check our [homepage](http://greenrobot.org/) to stay up to date. From 0be1c4d492576266e6586d6c18c0704f10c609a6 Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 7 Nov 2017 14:56:55 +0100 Subject: [PATCH 212/288] 3.1.1 / 3.1.0 --- EventBus/build.gradle | 4 ++-- EventBusAnnotationProcessor/build.gradle | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index e2167121..122e3616 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -5,7 +5,7 @@ apply plugin: 'idea' archivesBaseName = 'eventbus' group = 'org.greenrobot' -version = '3.1.0-RC' +version = '3.1.1' sourceCompatibility = 1.7 def isSnapshot = version.endsWith('-SNAPSHOT') @@ -56,7 +56,7 @@ javadoc { failOnError = false classpath += configurations.provided title = "EventBus ${version} API" - options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2012-2016 greenrobot.org. All Rights Reserved.' + options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2012-2017 greenrobot.org. All Rights Reserved.' } task javadocJar(type: Jar, dependsOn: javadoc) { diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index 4dfa5eca..24d7f34f 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -4,7 +4,7 @@ apply plugin: 'signing' archivesBaseName = 'eventbus-annotation-processor' group = 'org.greenrobot' -version = '3.0.1' +version = '3.1.0' sourceCompatibility = 1.7 From 761731122af864fc4b925e926a6827510a7f07c0 Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 7 Nov 2017 17:06:03 +0100 Subject: [PATCH 213/288] README.md: set gradle dependency to 3.1.1 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fa176e78..3eb738c6 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ Add EventBus to your project Via Gradle: ```gradle -compile 'org.greenrobot:eventbus:3.1.0-RC' +compile 'org.greenrobot:eventbus:3.1.1' ``` Via Maven: @@ -72,7 +72,7 @@ Via Maven: org.greenrobot eventbus - 3.1.0-RC + 3.1.1 ``` From 69417b5af70cd280b90462fe835d649f43bd9cf3 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 13 Nov 2017 13:36:15 +0100 Subject: [PATCH 214/288] Fix uploadArchives task naming issues. - Rename EventBus and EventBusAnnotationProcessor module to fix uploadArchives task. - Drop duplicate settings.gradle file for processor. - Enable uploading to local repository. --- EventBus/build.gradle | 6 +++++- EventBusAnnotationProcessor/build.gradle | 8 ++++++-- EventBusAnnotationProcessor/settings.gradle | 1 - EventBusPerformance/build.gradle | 4 ++-- EventBusTest/build.gradle | 4 ++-- EventBusTestJava/build.gradle | 4 ++-- EventBusTestSubscriberInJar/build.gradle | 4 ++-- settings.gradle | 15 +++++++++------ 8 files changed, 28 insertions(+), 18 deletions(-) delete mode 100644 EventBusAnnotationProcessor/settings.gradle diff --git a/EventBus/build.gradle b/EventBus/build.gradle index 122e3616..16f57190 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -87,7 +87,11 @@ signing { uploadArchives { repositories { mavenDeployer { - if(project.hasProperty('preferedRepo') && project.hasProperty('preferedUsername') + if (project.hasProperty('preferedRepo')) println "preferedRepo = $preferedRepo" + if (project.hasProperty('preferedRepo') && preferedRepo == 'local') { + println "Deploying to local repo (aka install)..." + repository url: repositories.mavenLocal().url + } else if(project.hasProperty('preferedRepo') && project.hasProperty('preferedUsername') && project.hasProperty('preferedPassword')) { configuration = configurations.deployerJars repository(url: preferedRepo) { diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index 24d7f34f..1c454f1b 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -28,7 +28,7 @@ configurations { } dependencies { - compile project(':EventBus') + compile project(':eventbus') compile 'de.greenrobot:java-common:2.3.1' deployerJars 'org.apache.maven.wagon:wagon-webdav:1.0-beta-2' } @@ -79,7 +79,11 @@ signing { uploadArchives { repositories { mavenDeployer { - if (project.hasProperty('preferedRepo') && project.hasProperty('preferedUsername') + if (project.hasProperty('preferedRepo')) println "preferedRepo = $preferedRepo" + if (project.hasProperty('preferedRepo') && preferedRepo == 'local') { + println "Deploying to local repo (aka install)..." + repository url: repositories.mavenLocal().url + } else if (project.hasProperty('preferedRepo') && project.hasProperty('preferedUsername') && project.hasProperty('preferedPassword')) { configuration = configurations.deployerJars repository(url: preferedRepo) { diff --git a/EventBusAnnotationProcessor/settings.gradle b/EventBusAnnotationProcessor/settings.gradle deleted file mode 100644 index 51ebbb79..00000000 --- a/EventBusAnnotationProcessor/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'eventbus-annotation-processor' \ No newline at end of file diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 99b54771..c60bf493 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -15,8 +15,8 @@ repositories { } dependencies { - compile project(':EventBus') - annotationProcessor project(':EventBusAnnotationProcessor') + compile project(':eventbus') + annotationProcessor project(':eventbus-annotation-processor') compile 'com.squareup:otto:1.3.8' } diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 068c640a..d3b951c3 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -16,9 +16,9 @@ repositories { } dependencies { - androidTestCompile project(':EventBus') + androidTestCompile project(':eventbus') androidTestCompile project(':EventBusTestJava') - androidTestAnnotationProcessor project(':EventBusAnnotationProcessor') + androidTestAnnotationProcessor project(':eventbus-annotation-processor') compile fileTree(dir: 'libs', include: '*.jar') androidTestCompile 'com.android.support.test:runner:1.0.1' androidTestCompile 'com.android.support.test:rules:1.0.1' diff --git a/EventBusTestJava/build.gradle b/EventBusTestJava/build.gradle index 19aba56f..0e7f18f2 100644 --- a/EventBusTestJava/build.gradle +++ b/EventBusTestJava/build.gradle @@ -30,10 +30,10 @@ sourceSets { dependencies { compile fileTree(dir: 'libs', include: '*.jar') - compile(project(':EventBus')) { + compile(project(':eventbus')) { exclude group: "com.google.android" // Does not seem to work... } - apt project(':EventBusAnnotationProcessor') + apt project(':eventbus-annotation-processor') compile 'junit:junit:4.12' } diff --git a/EventBusTestSubscriberInJar/build.gradle b/EventBusTestSubscriberInJar/build.gradle index 26adc98b..9211bcfb 100644 --- a/EventBusTestSubscriberInJar/build.gradle +++ b/EventBusTestSubscriberInJar/build.gradle @@ -13,8 +13,8 @@ configurations { } dependencies { - compile project(':EventBus') - provided project(':EventBusAnnotationProcessor') + compile project(':eventbus') + provided project(':eventbus-annotation-processor') } sourceSets { diff --git a/settings.gradle b/settings.gradle index f78cf550..c25cd47e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,9 @@ -include 'EventBus' -include 'EventBusAnnotationProcessor' -include 'EventBusTestJava' -include 'EventBusTest' -include 'EventBusTestSubscriberInJar' -include 'EventBusPerformance' +include ':EventBus' +include ':EventBusAnnotationProcessor' +include ':EventBusTestJava' +include ':EventBusTest' +include ':EventBusTestSubscriberInJar' +include ':EventBusPerformance' + +project(":EventBus").name = "eventbus" +project(":EventBusAnnotationProcessor").name = "eventbus-annotation-processor" \ No newline at end of file From 66fbde49d58670f7b46ff010da22d01e3c4d5b72 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 13 Nov 2017 14:45:55 +0100 Subject: [PATCH 215/288] Add index tests for MAIN vs MAIN_ORDERED behavior. --- .../indexed/EventBusAndroidOrderTestWithIndex.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusAndroidOrderTestWithIndex.java diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusAndroidOrderTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusAndroidOrderTestWithIndex.java new file mode 100644 index 00000000..9e1f2318 --- /dev/null +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusAndroidOrderTestWithIndex.java @@ -0,0 +1,13 @@ +package org.greenrobot.eventbus.indexed; + +import org.greenrobot.eventbus.EventBusAndroidOrderTest; + +public class EventBusAndroidOrderTestWithIndex extends EventBusAndroidOrderTest { + + @Override + public void setUp() throws Exception { + eventBus = Indexed.build(); + super.setUp(); + } + +} From d459d1340d5621829b8821f751d1e00be125f5cf Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 14 Nov 2017 09:37:00 +0100 Subject: [PATCH 216/288] android 26 --- .travis.yml | 4 ++-- EventBusTest/build.gradle | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 94fcd6f9..2210eda2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,9 +7,9 @@ jdk: android: components: - tools - - build-tools-25.0.3 + - build-tools-26.0.3 - android-10 - - android-25 + - android-26 - extra-android-m2repository before_script: diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index d3b951c3..8e2966ce 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -19,14 +19,16 @@ dependencies { androidTestCompile project(':eventbus') androidTestCompile project(':EventBusTestJava') androidTestAnnotationProcessor project(':eventbus-annotation-processor') + // Trying to repro bug: +// androidTestAnnotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.0' compile fileTree(dir: 'libs', include: '*.jar') androidTestCompile 'com.android.support.test:runner:1.0.1' androidTestCompile 'com.android.support.test:rules:1.0.1' } android { - buildToolsVersion '25.0.3' // When updating, don't forget to adjust .travis.yml - compileSdkVersion 25 + buildToolsVersion '26.0.3' // When updating, don't forget to adjust .travis.yml + compileSdkVersion 26 compileOptions { sourceCompatibility = JavaVersion.VERSION_1_7 @@ -45,7 +47,7 @@ android { defaultConfig { minSdkVersion 9 - targetSdkVersion 25 + targetSdkVersion 26 versionCode 1 versionName "1.0" From bbe35ff77d736e4a38072ddc3659b122c46367c1 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 14 Nov 2017 12:47:55 +0100 Subject: [PATCH 217/288] Move AndroidLogger to android package. --- .../greenrobot/eventbus/EventBusBuilder.java | 7 +- .../src/org/greenrobot/eventbus/Logger.java | 57 -------------- .../eventbus/android/AndroidLogger.java | 78 +++++++++++++++++++ 3 files changed, 82 insertions(+), 60 deletions(-) create mode 100644 EventBus/src/org/greenrobot/eventbus/android/AndroidLogger.java diff --git a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java index 895b57a9..3e2b5c9c 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java @@ -17,6 +17,7 @@ import android.os.Looper; +import org.greenrobot.eventbus.android.AndroidLogger; import org.greenrobot.eventbus.meta.SubscriberInfoIndex; import java.util.ArrayList; @@ -157,8 +158,8 @@ Logger getLogger() { return logger; } else { // also check main looper to see if we have "good" Android classes (not Stubs etc.) - return Logger.AndroidLogger.isAndroidLogAvailable() && getAndroidMainLooperOrNull() != null - ? new Logger.AndroidLogger("EventBus") : + return AndroidLogger.isAndroidLogAvailable() && getAndroidMainLooperOrNull() != null + ? new AndroidLogger("EventBus") : new Logger.SystemOutLogger(); } } @@ -167,7 +168,7 @@ Logger getLogger() { MainThreadSupport getMainThreadSupport() { if (mainThreadSupport != null) { return mainThreadSupport; - } else if (Logger.AndroidLogger.isAndroidLogAvailable()) { + } else if (AndroidLogger.isAndroidLogAvailable()) { Object looperOrNull = getAndroidMainLooperOrNull(); return looperOrNull == null ? null : new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull); diff --git a/EventBus/src/org/greenrobot/eventbus/Logger.java b/EventBus/src/org/greenrobot/eventbus/Logger.java index 6609b61b..602e0b51 100644 --- a/EventBus/src/org/greenrobot/eventbus/Logger.java +++ b/EventBus/src/org/greenrobot/eventbus/Logger.java @@ -15,8 +15,6 @@ */ package org.greenrobot.eventbus; -import android.util.Log; - import java.util.logging.Level; public interface Logger { @@ -25,61 +23,6 @@ public interface Logger { void log(Level level, String msg, Throwable th); - public static class AndroidLogger implements Logger { - static final boolean ANDROID_LOG_AVAILABLE; - - static { - boolean android = false; - try { - android = Class.forName("android.util.Log") != null; - } catch (ClassNotFoundException e) { - // OK - } - ANDROID_LOG_AVAILABLE = android; - } - - public static boolean isAndroidLogAvailable() { - return ANDROID_LOG_AVAILABLE; - } - - - private final String tag; - - public AndroidLogger(String tag) { - this.tag = tag; - } - - public void log(Level level, String msg) { - if (level != Level.OFF) { - Log.println(mapLevel(level), tag, msg); - } - } - - public void log(Level level, String msg, Throwable th) { - if (level != Level.OFF) { - // That's how Log does it internally - Log.println(mapLevel(level), tag, msg + "\n" + Log.getStackTraceString(th)); - } - } - - protected int mapLevel(Level level) { - int value = level.intValue(); - if (value < 800) { // below INFO - if (value < 500) { // below FINE - return Log.VERBOSE; - } else { - return Log.DEBUG; - } - } else if (value < 900) { // below WARNING - return Log.INFO; - } else if (value < 1000) { // below ERROR - return Log.WARN; - } else { - return Log.ERROR; - } - } - } - public static class JavaLogger implements Logger { protected final java.util.logging.Logger logger; diff --git a/EventBus/src/org/greenrobot/eventbus/android/AndroidLogger.java b/EventBus/src/org/greenrobot/eventbus/android/AndroidLogger.java new file mode 100644 index 00000000..fc14fe7d --- /dev/null +++ b/EventBus/src/org/greenrobot/eventbus/android/AndroidLogger.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.greenrobot.eventbus.android; + +import android.util.Log; + +import org.greenrobot.eventbus.Logger; + +import java.util.logging.Level; + +public class AndroidLogger implements Logger { + + private static final boolean ANDROID_LOG_AVAILABLE; + + static { + boolean android = false; + try { + android = Class.forName("android.util.Log") != null; + } catch (ClassNotFoundException e) { + // OK + } + ANDROID_LOG_AVAILABLE = android; + } + + public static boolean isAndroidLogAvailable() { + return ANDROID_LOG_AVAILABLE; + } + + + private final String tag; + + public AndroidLogger(String tag) { + this.tag = tag; + } + + public void log(Level level, String msg) { + if (level != Level.OFF) { + Log.println(mapLevel(level), tag, msg); + } + } + + public void log(Level level, String msg, Throwable th) { + if (level != Level.OFF) { + // That's how Log does it internally + Log.println(mapLevel(level), tag, msg + "\n" + Log.getStackTraceString(th)); + } + } + + private int mapLevel(Level level) { + int value = level.intValue(); + if (value < 800) { // below INFO + if (value < 500) { // below FINE + return Log.VERBOSE; + } else { + return Log.DEBUG; + } + } else if (value < 900) { // below WARNING + return Log.INFO; + } else if (value < 1000) { // below ERROR + return Log.WARN; + } else { + return Log.ERROR; + } + } +} From 1ba2f43a298d16b140f0629df35a8f8be3bc69e6 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 14 Nov 2017 12:56:40 +0100 Subject: [PATCH 218/288] Use common build tools version and compileSdk (for Travis). --- EventBusPerformance/build.gradle | 4 ++-- EventBusTest/build.gradle | 4 ++-- build.gradle | 7 +++++++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index c60bf493..a62ff46f 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -21,8 +21,8 @@ dependencies { } android { - buildToolsVersion '25.0.3' // When updating, don't forget to adjust .travis.yml - compileSdkVersion 25 + buildToolsVersion _buildToolsVersion + compileSdkVersion _compileSdkVersion sourceSets { main { diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 8e2966ce..cc426c8b 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -27,8 +27,8 @@ dependencies { } android { - buildToolsVersion '26.0.3' // When updating, don't forget to adjust .travis.yml - compileSdkVersion 26 + buildToolsVersion _buildToolsVersion + compileSdkVersion _compileSdkVersion compileOptions { sourceCompatibility = JavaVersion.VERSION_1_7 diff --git a/build.gradle b/build.gradle index fc18b763..80607751 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,10 @@ +buildscript { + ext { + _buildToolsVersion = '26.0.2' // When updating, don't forget to adjust .travis.yml + _compileSdkVersion = 26 + } +} + if (JavaVersion.current().isJava8Compatible()) { allprojects { tasks.withType(Javadoc) { From 5428a2b095d83012663dfa0629f81f925c156d6d Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 14 Nov 2017 13:02:49 +0100 Subject: [PATCH 219/288] Actually use same build tools version as Travis (26.0.3). --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 80607751..ee1b1ef3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ buildscript { ext { - _buildToolsVersion = '26.0.2' // When updating, don't forget to adjust .travis.yml + _buildToolsVersion = '26.0.3' // When updating, don't forget to adjust .travis.yml _compileSdkVersion = 26 } } From 66fed14fbe3b77330567981657f95cf5b38673dc Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 14 Nov 2017 13:31:24 +0100 Subject: [PATCH 220/288] Define repositories once in root build file. --- EventBus/build.gradle | 4 ---- EventBusAnnotationProcessor/build.gradle | 4 ---- EventBusPerformance/build.gradle | 4 ---- EventBusTest/build.gradle | 5 ----- EventBusTestJava/build.gradle | 4 ---- EventBusTestSubscriberInJar/build.gradle | 4 ---- build.gradle | 8 ++++++++ 7 files changed, 8 insertions(+), 25 deletions(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index 16f57190..4f3c246e 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -16,10 +16,6 @@ if(isSnapshot) { sonatypeRepositoryUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" } -repositories { - mavenCentral() -} - // Still unsupported, see http://issues.gradle.org/browse/GRADLE-784 // Like this, it won't appear at all in the POM configurations { diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index 1c454f1b..644ea215 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -16,10 +16,6 @@ if (isSnapshot) { sonatypeRepositoryUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" } -repositories { - mavenCentral() -} - // Still unsupported, see http://issues.gradle.org/browse/GRADLE-784 // Like this, it won't appear at all in the POM configurations { diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index a62ff46f..fb2cc52f 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -10,10 +10,6 @@ buildscript { apply plugin: 'com.android.application' -repositories { - jcenter() -} - dependencies { compile project(':eventbus') annotationProcessor project(':eventbus-annotation-processor') diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index cc426c8b..ab6b884c 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -10,11 +10,6 @@ buildscript { apply plugin: 'com.android.application' -repositories { - jcenter() - google() -} - dependencies { androidTestCompile project(':eventbus') androidTestCompile project(':EventBusTestJava') diff --git a/EventBusTestJava/build.gradle b/EventBusTestJava/build.gradle index 0e7f18f2..5fec7913 100644 --- a/EventBusTestJava/build.gradle +++ b/EventBusTestJava/build.gradle @@ -14,10 +14,6 @@ apply plugin: 'net.ltgt.apt-idea' sourceCompatibility = 1.7 -repositories { - jcenter() -} - // we have tests in the main source set so they can be shared with the Android test module // to make Gradle pick them up, add the dir to the test source set sourceSets { diff --git a/EventBusTestSubscriberInJar/build.gradle b/EventBusTestSubscriberInJar/build.gradle index 9211bcfb..b75da33b 100644 --- a/EventBusTestSubscriberInJar/build.gradle +++ b/EventBusTestSubscriberInJar/build.gradle @@ -4,10 +4,6 @@ group = 'de.greenrobot' version = '3.0.0' sourceCompatibility = 1.7 -repositories { - jcenter() -} - configurations { provided } diff --git a/build.gradle b/build.gradle index ee1b1ef3..f7b81bdf 100644 --- a/build.gradle +++ b/build.gradle @@ -5,6 +5,14 @@ buildscript { } } +allprojects { + repositories { + jcenter() + mavenCentral() + google() + } +} + if (JavaVersion.current().isJava8Compatible()) { allprojects { tasks.withType(Javadoc) { From b035bf56be70ec039a493abb8e5c0235881250e6 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 14 Nov 2017 13:35:35 +0100 Subject: [PATCH 221/288] Update Android Gradle Plugin to 3.0.0. --- EventBusPerformance/build.gradle | 8 ++++---- EventBusTest/build.gradle | 16 +++++++--------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index fb2cc52f..0dd5d1d3 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -1,19 +1,19 @@ buildscript { repositories { - jcenter() + google() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.3' + classpath 'com.android.tools.build:gradle:3.0.0' } } apply plugin: 'com.android.application' dependencies { - compile project(':eventbus') + implementation project(':eventbus') annotationProcessor project(':eventbus-annotation-processor') - compile 'com.squareup:otto:1.3.8' + implementation 'com.squareup:otto:1.3.8' } android { diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index ab6b884c..5015100f 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -1,24 +1,22 @@ buildscript { repositories { - jcenter() + google() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.3' + classpath 'com.android.tools.build:gradle:3.0.0' } } apply plugin: 'com.android.application' dependencies { - androidTestCompile project(':eventbus') - androidTestCompile project(':EventBusTestJava') + androidTestImplementation project(':eventbus') + androidTestImplementation project(':EventBusTestJava') androidTestAnnotationProcessor project(':eventbus-annotation-processor') - // Trying to repro bug: -// androidTestAnnotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.0' - compile fileTree(dir: 'libs', include: '*.jar') - androidTestCompile 'com.android.support.test:runner:1.0.1' - androidTestCompile 'com.android.support.test:rules:1.0.1' + implementation fileTree(dir: 'libs', include: '*.jar') + androidTestImplementation 'com.android.support.test:runner:1.0.1' + androidTestImplementation 'com.android.support.test:rules:1.0.1' } android { From 0e32fcea992a0a1159033d0c3bbaf160707756c3 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 14 Nov 2017 13:42:44 +0100 Subject: [PATCH 222/288] EventBusPerformance: add MAIN_ORDERED. - Remove redundant findViewById casts. --- EventBusPerformance/res/values/strings.xml | 1 + .../eventbusperf/TestRunnerActivity.java | 2 +- .../eventbusperf/TestSetupActivity.java | 22 ++++++++--------- .../testsubject/PerfTestEventBus.java | 24 +++++++++++++++++++ 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/EventBusPerformance/res/values/strings.xml b/EventBusPerformance/res/values/strings.xml index feed5953..49148076 100644 --- a/EventBusPerformance/res/values/strings.xml +++ b/EventBusPerformance/res/values/strings.xml @@ -21,6 +21,7 @@ POSTING MAIN + MAIN_ORDERED BACKGROUND ASYNC diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunnerActivity.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunnerActivity.java index e22631c1..b21efabf 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunnerActivity.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunnerActivity.java @@ -42,7 +42,7 @@ public class TestRunnerActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_runtests); - textViewResult = (TextView) findViewById(R.id.textViewResult); + textViewResult = findViewById(R.id.textViewResult); controlBus = new EventBus(); controlBus.register(this); } diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestSetupActivity.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestSetupActivity.java index 3488b8da..626f8a0b 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestSetupActivity.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestSetupActivity.java @@ -50,7 +50,7 @@ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_setuptests); - Spinner spinnerRun = (Spinner) findViewById(R.id.spinnerTestToRun); + Spinner spinnerRun = findViewById(R.id.spinnerTestToRun); spinnerRun.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { public void onItemSelected(AdapterView adapter, View v, int pos, long lng) { @@ -65,15 +65,15 @@ public void onNothingSelected(AdapterView arg0) { } public void checkEventBus(View v) { - Spinner spinnerThread = (Spinner) findViewById(R.id.spinnerThread); - CheckBox checkBoxEventBus = (CheckBox) findViewById(R.id.checkBoxEventBus); + Spinner spinnerThread = findViewById(R.id.spinnerThread); + CheckBox checkBoxEventBus = findViewById(R.id.checkBoxEventBus); int visibility = checkBoxEventBus.isChecked() ? View.VISIBLE : View.GONE; spinnerThread.setVisibility(visibility); } public void startClick(View v) { TestParams params = new TestParams(); - Spinner spinnerThread = (Spinner) findViewById(R.id.spinnerThread); + Spinner spinnerThread = findViewById(R.id.spinnerThread); String threadModeStr = spinnerThread.getSelectedItem().toString(); ThreadMode threadMode = ThreadMode.valueOf(threadModeStr); params.setThreadMode(threadMode); @@ -81,13 +81,13 @@ public void startClick(View v) { params.setEventInheritance(((CheckBox) findViewById(R.id.checkBoxEventBusEventHierarchy)).isChecked()); params.setIgnoreGeneratedIndex(((CheckBox) findViewById(R.id.checkBoxEventBusIgnoreGeneratedIndex)).isChecked()); - EditText editTextEvent = (EditText) findViewById(R.id.editTextEvent); + EditText editTextEvent = findViewById(R.id.editTextEvent); params.setEventCount(Integer.parseInt(editTextEvent.getText().toString())); - EditText editTextSubscriber = (EditText) findViewById(R.id.editTextSubscribe); + EditText editTextSubscriber = findViewById(R.id.editTextSubscribe); params.setSubscriberCount(Integer.parseInt(editTextSubscriber.getText().toString())); - Spinner spinnerTestToRun = (Spinner) findViewById(R.id.spinnerTestToRun); + Spinner spinnerTestToRun = findViewById(R.id.spinnerTestToRun); int testPos = spinnerTestToRun.getSelectedItemPosition(); params.setTestNumber(testPos + 1); ArrayList> testClasses = initTestClasses(testPos); @@ -103,10 +103,10 @@ public void startClick(View v) { private ArrayList> initTestClasses(int testPos) { ArrayList> testClasses = new ArrayList>(); // the attributes are putted in the intent (eventbus, otto, broadcast, local broadcast) - final CheckBox checkBoxEventBus = (CheckBox) findViewById(R.id.checkBoxEventBus); - final CheckBox checkBoxOtto = (CheckBox) findViewById(R.id.checkBoxOtto); - final CheckBox checkBoxBroadcast = (CheckBox) findViewById(R.id.checkBoxBroadcast); - final CheckBox checkBoxLocalBroadcast = (CheckBox) findViewById(R.id.checkBoxLocalBroadcast); + final CheckBox checkBoxEventBus = findViewById(R.id.checkBoxEventBus); + final CheckBox checkBoxOtto = findViewById(R.id.checkBoxOtto); + final CheckBox checkBoxBroadcast = findViewById(R.id.checkBoxBroadcast); + final CheckBox checkBoxLocalBroadcast = findViewById(R.id.checkBoxLocalBroadcast); if (checkBoxEventBus.isChecked()) { testClasses.add(TEST_CLASSES_EVENTBUS[testPos]); } diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestEventBus.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestEventBus.java index 7ceb8e6d..f0a5e2f8 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestEventBus.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestEventBus.java @@ -66,6 +66,8 @@ private Class getSubscriberClassForThreadMode() { switch (params.getThreadMode()) { case MAIN: return SubscribeClassEventBusMain.class; + case MAIN_ORDERED: + return SubscribeClassEventBusMainOrdered.class; case BACKGROUND: return SubscribeClassEventBusBackground.class; case ASYNC: @@ -227,6 +229,28 @@ public void dummy5() { } } + public class SubscribeClassEventBusMainOrdered { + @Subscribe(threadMode = ThreadMode.MAIN_ORDERED) + public void onEvent(TestEvent event) { + eventsReceivedCount.incrementAndGet(); + } + + public void dummy() { + } + + public void dummy2() { + } + + public void dummy3() { + } + + public void dummy4() { + } + + public void dummy5() { + } + } + public class SubscribeClassEventBusBackground { @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onEventBackgroundThread(TestEvent event) { From b98135699ab8bcd9622f74172df22e586850feed Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 14 Nov 2017 13:54:13 +0100 Subject: [PATCH 223/288] Revert: Update Android Gradle Plugin to 3.0.0. - IntelliJ 2017.2 does not yet support this version, wait for 2017.3. - https://stackoverflow.com/questions/44796375/is-it-possible-to-use-android-gradle-plugin-3-0-0-with-intellij --- EventBusPerformance/build.gradle | 8 ++++---- EventBusTest/build.gradle | 16 +++++++++------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 0dd5d1d3..fb2cc52f 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -1,19 +1,19 @@ buildscript { repositories { - google() + jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.0' + classpath 'com.android.tools.build:gradle:2.3.3' } } apply plugin: 'com.android.application' dependencies { - implementation project(':eventbus') + compile project(':eventbus') annotationProcessor project(':eventbus-annotation-processor') - implementation 'com.squareup:otto:1.3.8' + compile 'com.squareup:otto:1.3.8' } android { diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 5015100f..ab6b884c 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -1,22 +1,24 @@ buildscript { repositories { - google() + jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.0' + classpath 'com.android.tools.build:gradle:2.3.3' } } apply plugin: 'com.android.application' dependencies { - androidTestImplementation project(':eventbus') - androidTestImplementation project(':EventBusTestJava') + androidTestCompile project(':eventbus') + androidTestCompile project(':EventBusTestJava') androidTestAnnotationProcessor project(':eventbus-annotation-processor') - implementation fileTree(dir: 'libs', include: '*.jar') - androidTestImplementation 'com.android.support.test:runner:1.0.1' - androidTestImplementation 'com.android.support.test:rules:1.0.1' + // Trying to repro bug: +// androidTestAnnotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.0' + compile fileTree(dir: 'libs', include: '*.jar') + androidTestCompile 'com.android.support.test:runner:1.0.1' + androidTestCompile 'com.android.support.test:rules:1.0.1' } android { From 3670d97835f15d0966e29fb8f52785ca3e87c2af Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 11 Dec 2017 21:02:25 +0100 Subject: [PATCH 224/288] over-engineering getDefault() (aka item 71 effective Java, 2nd ed.) --- EventBus/src/org/greenrobot/eventbus/EventBus.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/EventBus/src/org/greenrobot/eventbus/EventBus.java b/EventBus/src/org/greenrobot/eventbus/EventBus.java index 247cbb27..e35ecd38 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBus.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBus.java @@ -78,14 +78,16 @@ protected PostingThreadState initialValue() { /** Convenience singleton for apps using a process-wide EventBus instance. */ public static EventBus getDefault() { - if (defaultInstance == null) { + EventBus instance = defaultInstance; + if (instance == null) { synchronized (EventBus.class) { - if (defaultInstance == null) { - defaultInstance = new EventBus(); + instance = EventBus.defaultInstance; + if (instance == null) { + instance = EventBus.defaultInstance = new EventBus(); } } } - return defaultInstance; + return instance; } public static EventBusBuilder builder() { From d52a0de2acc545a1c6cf94c43fee70cb9b059378 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 27 Aug 2018 14:59:20 +0200 Subject: [PATCH 225/288] README: use new dependency config, update Central search link. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3eb738c6..d66c0d57 100644 --- a/README.md +++ b/README.md @@ -60,11 +60,11 @@ Read the full [getting started guide](http://greenrobot.org/eventbus/documentati Add EventBus to your project ---------------------------- - + Via Gradle: ```gradle -compile 'org.greenrobot:eventbus:3.1.1' +implementation 'org.greenrobot:eventbus:3.1.1' ``` Via Maven: From 2e7c0461106a3c261859579ec6fdcb5353ed31a4 Mon Sep 17 00:00:00 2001 From: greenrobot Team <13865709+greenrobot-team@users.noreply.github.com> Date: Tue, 12 Mar 2019 11:52:00 +0100 Subject: [PATCH 226/288] README: drop Google+ link. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d66c0d57..cf9275f8 100644 --- a/README.md +++ b/README.md @@ -108,4 +108,4 @@ More Open Source by greenrobot [__greenDAO__](http://greenrobot.org/greendao/) ([GitHub](https://github.com/greenrobot/greenDAO)) is an ORM optimized for Android: it maps database tables to Java objects and uses code generation for optimal speed. -[Follow us on Google+](https://plus.google.com/b/114381455741141514652/+GreenrobotDe/posts) or check our [homepage](http://greenrobot.org/) to stay up to date. +Check our [homepage](http://greenrobot.org/) to stay up to date. From be4462eab6b29a25b8bc8f3ccbdcb7e0e4b5ee5f Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 19 Nov 2019 14:42:40 +0100 Subject: [PATCH 227/288] Update Gradle [4.1->5.6.3]. --- build.gradle | 3 +-- gradle/wrapper/gradle-wrapper.jar | Bin 54708 -> 55616 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 22 +++++++++++++++++++--- gradlew.bat | 18 +++++++++++++++++- 5 files changed, 38 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index f7b81bdf..15b35417 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,6 @@ if (JavaVersion.current().isJava8Compatible()) { } } -task wrapper(type: Wrapper) { - gradleVersion = '4.1' +wrapper { distributionType = org.gradle.api.tasks.wrapper.Wrapper.DistributionType.ALL } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7a3265ee94c0ab25cf079ac8ccdf87f41d455d42..5c2d1cf016b3885f6930543d57b744ea8c220a1a 100644 GIT binary patch literal 55616 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

_x$+l{{cH8$W#CT diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index bf1b63c3..3a54a333 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.3-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip diff --git a/gradlew b/gradlew index cccdd3d5..83f2acfd 100755 --- a/gradlew +++ b/gradlew @@ -1,5 +1,21 @@ #!/usr/bin/env sh +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + ############################################################################## ## ## Gradle start up script for UN*X @@ -28,7 +44,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -109,8 +125,8 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` diff --git a/gradlew.bat b/gradlew.bat index e95643d6..24467a14 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome From 7a993aed191d24aac84077f04f9ba2783ca77996 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 19 Nov 2019 14:43:31 +0100 Subject: [PATCH 228/288] Drop apt plugin, use Gradle annotationProcessor instead. --- EventBusTestJava/build.gradle | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/EventBusTestJava/build.gradle b/EventBusTestJava/build.gradle index 5fec7913..f19e3b19 100644 --- a/EventBusTestJava/build.gradle +++ b/EventBusTestJava/build.gradle @@ -1,16 +1,4 @@ -buildscript { - repositories { - maven { url "https://plugins.gradle.org/m2/" } - } - - dependencies { - classpath "net.ltgt.gradle:gradle-apt-plugin:0.12" - } -} - apply plugin: 'java' -// plugin to make it easier/safer to use EventBus annotation processor -apply plugin: 'net.ltgt.apt-idea' sourceCompatibility = 1.7 @@ -29,7 +17,7 @@ dependencies { compile(project(':eventbus')) { exclude group: "com.google.android" // Does not seem to work... } - apt project(':eventbus-annotation-processor') + annotationProcessor project(':eventbus-annotation-processor') compile 'junit:junit:4.12' } From 9c5e2e5a60ecef3cc83e8f6934a187b1832698ee Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 19 Nov 2019 14:46:59 +0100 Subject: [PATCH 229/288] Update Android Gradle Plugin [2.3.3->3.5.2]. --- EventBusPerformance/AndroidManifest.xml | 8 +------- EventBusPerformance/build.gradle | 12 ++++++++---- EventBusTest/build.gradle | 14 +++++++------- build.gradle | 3 +-- 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/EventBusPerformance/AndroidManifest.xml b/EventBusPerformance/AndroidManifest.xml index af353b5d..530cafeb 100644 --- a/EventBusPerformance/AndroidManifest.xml +++ b/EventBusPerformance/AndroidManifest.xml @@ -1,12 +1,6 @@ - - + package="org.greenrobot.eventbusperf"> Date: Tue, 19 Nov 2019 15:06:08 +0100 Subject: [PATCH 230/288] Update Travis config. --- .travis.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2210eda2..e0364a93 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,11 +6,10 @@ jdk: # http://docs.travis-ci.com/user/languages/android/ android: components: - - tools - - build-tools-26.0.3 - - android-10 + - build-tools-28.0.3 - android-26 - - extra-android-m2repository + licenses: + - 'android-sdk-license-.+' before_script: - chmod +x gradlew From 7e363a6bc9ff7a9d242cec24da13db4932ff9042 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 19 Nov 2019 15:41:11 +0100 Subject: [PATCH 231/288] EventBusPerformance: target SDK 26. --- EventBusPerformance/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index e89f9c51..47db03ce 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -30,7 +30,7 @@ android { defaultConfig { minSdkVersion 7 - targetSdkVersion 17 + targetSdkVersion 26 versionCode 1 versionName "2.0.0" javaCompileOptions { From ffeff4d6c92d9d19a13ff51c86ef4c4a42d7b043 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 19 Nov 2019 15:48:43 +0100 Subject: [PATCH 232/288] Travis: add caching. --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.travis.yml b/.travis.yml index e0364a93..b22ae054 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,3 +24,12 @@ before_script: script: - TERM=dumb ./gradlew check + +before_cache: + - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock + - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ +cache: + directories: + - $HOME/.gradle/caches/ + - $HOME/.gradle/wrapper/ + - $HOME/.android/build-cache From 32992a66059b5953eb6c2d45d788e36576f58d17 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 9 Dec 2019 15:23:59 +0100 Subject: [PATCH 233/288] Extract common publishing setup to publish.gradle. --- EventBus/build.gradle | 79 ++------------------ EventBusAnnotationProcessor/build.gradle | 75 +------------------ gradle/publish.gradle | 95 ++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 146 deletions(-) create mode 100644 gradle/publish.gradle diff --git a/EventBus/build.gradle b/EventBus/build.gradle index 4f3c246e..69569215 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -1,6 +1,4 @@ apply plugin: 'java' -apply plugin: 'maven' -apply plugin: 'signing' apply plugin: 'idea' archivesBaseName = 'eventbus' @@ -8,19 +6,10 @@ group = 'org.greenrobot' version = '3.1.1' sourceCompatibility = 1.7 -def isSnapshot = version.endsWith('-SNAPSHOT') -def sonatypeRepositoryUrl -if(isSnapshot) { - sonatypeRepositoryUrl = "https://oss.sonatype.org/content/repositories/snapshots/" -} else { - sonatypeRepositoryUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" -} - // Still unsupported, see http://issues.gradle.org/browse/GRADLE-784 // Like this, it won't appear at all in the POM configurations { provided - deployerJars } dependencies { @@ -28,8 +17,6 @@ dependencies { provided 'com.google.android:android-test:4.1.1.4' provided 'com.google.android:annotations:4.1.1.4' provided 'com.google.android:support-v4:r7' - // deployerJars 'org.apache.maven.wagon:wagon-webdav-jackrabbit:2.4' - deployerJars 'org.apache.maven.wagon:wagon-webdav:1.0-beta-2' } sourceSets { @@ -48,6 +35,8 @@ idea { } } +apply from: rootProject.file("gradle/publish.gradle") + javadoc { failOnError = false classpath += configurations.provided @@ -71,72 +60,14 @@ artifacts { archives sourcesJar } -signing { - if(project.hasProperty('signing.keyId') && project.hasProperty('signing.password') && - project.hasProperty('signing.secretKeyRingFile')) { - sign configurations.archives - } else { - println "Signing information missing/incomplete for ${project.name}" - } -} - uploadArchives { repositories { mavenDeployer { - if (project.hasProperty('preferedRepo')) println "preferedRepo = $preferedRepo" - if (project.hasProperty('preferedRepo') && preferedRepo == 'local') { - println "Deploying to local repo (aka install)..." - repository url: repositories.mavenLocal().url - } else if(project.hasProperty('preferedRepo') && project.hasProperty('preferedUsername') - && project.hasProperty('preferedPassword')) { - configuration = configurations.deployerJars - repository(url: preferedRepo) { - authentication(userName: preferedUsername, password: preferedPassword) - } - } else if(project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePassword')) { - beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } - repository(url: sonatypeRepositoryUrl) { - authentication(userName: sonatypeUsername, password: sonatypePassword) - } - } else { - println "Settings sonatypeUsername/sonatypePassword missing/incomplete for ${project.name}" - } + // Common setup is defined in publish.gradle. + pom.project { name 'EventBus' - packaging 'jar' - description 'EventBus is a publish/subscribe event bus optimized for Android .' - url 'http://greenrobot.org/eventbus/' - - scm { - url 'https://github.com/greenrobot/EventBus' - connection 'scm:git@github.com:greenrobot/EventBus.git' - developerConnection 'scm:git@github.com:greenrobot/EventBus.git' - } - - licenses { - license { - name 'The Apache Software License, Version 2.0' - url 'http://www.apache.org/licenses/LICENSE-2.0.txt' - distribution 'repo' - } - } - - developers { - developer { - id 'greenrobot' - name 'greenrobot' - } - } - - issueManagement { - system 'GitHub Issues' - url 'https://github.com/greenrobot/EventBus/issues' - } - - organization { - name 'greenrobot' - url 'http://greenrobot.org' - } + description 'EventBus is a publish/subscribe event bus optimized for Android.' } } } diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index 644ea215..7c1e53a4 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -1,6 +1,4 @@ apply plugin: 'java' -apply plugin: 'maven' -apply plugin: 'signing' archivesBaseName = 'eventbus-annotation-processor' group = 'org.greenrobot' @@ -8,25 +6,15 @@ version = '3.1.0' sourceCompatibility = 1.7 -def isSnapshot = version.endsWith('-SNAPSHOT') -def sonatypeRepositoryUrl -if (isSnapshot) { - sonatypeRepositoryUrl = "https://oss.sonatype.org/content/repositories/snapshots/" -} else { - sonatypeRepositoryUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" -} - // Still unsupported, see http://issues.gradle.org/browse/GRADLE-784 // Like this, it won't appear at all in the POM configurations { provided - deployerJars } dependencies { compile project(':eventbus') compile 'de.greenrobot:java-common:2.3.1' - deployerJars 'org.apache.maven.wagon:wagon-webdav:1.0-beta-2' } sourceSets { @@ -41,6 +29,8 @@ sourceSets { } } +apply from: rootProject.file("gradle/publish.gradle") + javadoc { classpath += configurations.provided title = "EventBus Annotation Processor ${version} API" @@ -63,73 +53,14 @@ artifacts { archives sourcesJar } -signing { - if (project.hasProperty('signing.keyId') && project.hasProperty('signing.password') && - project.hasProperty('signing.secretKeyRingFile')) { - sign configurations.archives - } else { - println "Signing information missing/incomplete for ${project.name}" - } -} - uploadArchives { repositories { mavenDeployer { - if (project.hasProperty('preferedRepo')) println "preferedRepo = $preferedRepo" - if (project.hasProperty('preferedRepo') && preferedRepo == 'local') { - println "Deploying to local repo (aka install)..." - repository url: repositories.mavenLocal().url - } else if (project.hasProperty('preferedRepo') && project.hasProperty('preferedUsername') - && project.hasProperty('preferedPassword')) { - configuration = configurations.deployerJars - repository(url: preferedRepo) { - authentication(userName: preferedUsername, password: preferedPassword) - } - } else if (project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePassword')) { - beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } - repository(url: sonatypeRepositoryUrl) { - authentication(userName: sonatypeUsername, password: sonatypePassword) - } - } else { - println "Settings sonatypeUsername/sonatypePassword missing/incomplete for ${project.name}" - } + // Common setup is defined in publish.gradle. pom.project { name 'EventBus Annotation Processor' - packaging 'jar' description 'Precompiler for EventBus Annotations.' - url 'http://greenrobot.org/eventbus/' - - scm { - url 'https://github.com/greenrobot/EventBus' - connection 'scm:git@github.com:greenrobot/EventBus.git' - developerConnection 'scm:git@github.com:greenrobot/EventBus.git' - } - - licenses { - license { - name 'The Apache Software License, Version 2.0' - url 'http://www.apache.org/licenses/LICENSE-2.0.txt' - distribution 'repo' - } - } - - developers { - developer { - id 'greenrobot' - name 'greenrobot' - } - } - - issueManagement { - system 'GitHub Issues' - url 'https://github.com/greenrobot/EventBus/issues' - } - - organization { - name 'greenrobot' - url 'http://greenrobot.org' - } } } } diff --git a/gradle/publish.gradle b/gradle/publish.gradle new file mode 100644 index 00000000..236b4afe --- /dev/null +++ b/gradle/publish.gradle @@ -0,0 +1,95 @@ +// Configures common publishing settings. + +apply plugin: "maven" +apply plugin: "signing" + +configurations { + deployerJars +} + +dependencies { + // Using an older version to remain compatible with Wagon API used by Gradle/Maven. + deployerJars 'org.apache.maven.wagon:wagon-webdav-jackrabbit:3.2.0' + deployerJars 'org.apache.maven.wagon:wagon-ftp:3.3.2' +} + +signing { + if (project.hasProperty('signing.keyId') && project.hasProperty('signing.password') && + project.hasProperty('signing.secretKeyRingFile')) { + sign configurations.archives + } else { + println "Signing information missing/incomplete for ${project.name}." + } +} + +// Use afterEvaluate or dependencies might be lost in the generated POM. +afterEvaluate { project -> + uploadArchives { + repositories { + mavenDeployer { + def preferredRepo = project.findProperty('preferredRepo') + println "preferredRepo=$preferredRepo" + + if (preferredRepo == 'local') { + repository url: repositories.mavenLocal().url + } else if (preferredRepo != null + && project.hasProperty('preferredUsername') + && project.hasProperty('preferredPassword')) { + configuration = configurations.deployerJars + repository(url: repositoryUrl) { + authentication(userName: preferredUsername, password: preferredPassword) + } + } else if (project.hasProperty('sonatypeUsername') + && project.hasProperty('sonatypePassword')) { + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + def isSnapshot = version.endsWith('-SNAPSHOT') + def sonatypeRepositoryUrl = isSnapshot + ? "https://oss.sonatype.org/content/repositories/snapshots/" + : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" + repository(url: sonatypeRepositoryUrl) { + authentication(userName: sonatypeUsername, password: sonatypePassword) + } + } else { + println "Deployment settings missing/incomplete for ${project.name}." + } + + // Common properties, projects still need to set name and description. + pom.project { + packaging 'jar' + url 'http://greenrobot.org/eventbus/' + + scm { + url 'https://github.com/greenrobot/EventBus' + connection 'scm:git@github.com:greenrobot/EventBus.git' + developerConnection 'scm:git@github.com:greenrobot/EventBus.git' + } + + licenses { + license { + name 'The Apache Software License, Version 2.0' + url 'http://www.apache.org/licenses/LICENSE-2.0.txt' + distribution 'repo' + } + } + + developers { + developer { + id 'greenrobot' + name 'greenrobot' + } + } + + issueManagement { + system 'GitHub Issues' + url 'https://github.com/greenrobot/EventBus/issues' + } + + organization { + name 'greenrobot' + url 'http://greenrobot.org' + } + } + } + } + } +} From 6c95dbcd4304218a6ff3eb4bcb4e7e27f32ab492 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 9 Dec 2019 15:35:35 +0100 Subject: [PATCH 234/288] Change provided->compileOnly and compile->implementation. --- EventBus/build.gradle | 23 ++++------------------- EventBusAnnotationProcessor/build.gradle | 12 ++---------- 2 files changed, 6 insertions(+), 29 deletions(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index 69569215..621f2409 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -1,27 +1,19 @@ apply plugin: 'java' -apply plugin: 'idea' archivesBaseName = 'eventbus' group = 'org.greenrobot' version = '3.1.1' sourceCompatibility = 1.7 -// Still unsupported, see http://issues.gradle.org/browse/GRADLE-784 -// Like this, it won't appear at all in the POM -configurations { - provided -} - dependencies { - provided 'com.google.android:android:4.1.1.4' - provided 'com.google.android:android-test:4.1.1.4' - provided 'com.google.android:annotations:4.1.1.4' - provided 'com.google.android:support-v4:r7' + compileOnly 'com.google.android:android:4.1.1.4' + compileOnly 'com.google.android:android-test:4.1.1.4' + compileOnly 'com.google.android:annotations:4.1.1.4' + compileOnly 'com.google.android:support-v4:r7' } sourceSets { main { - compileClasspath += configurations.provided java { srcDir 'src' // exclude 'de/greenrobot/event/util/**' @@ -29,17 +21,10 @@ sourceSets { } } -idea { - module { - scopes.PROVIDED.plus += [configurations.provided] - } -} - apply from: rootProject.file("gradle/publish.gradle") javadoc { failOnError = false - classpath += configurations.provided title = "EventBus ${version} API" options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2012-2017 greenrobot.org. All Rights Reserved.' } diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index 7c1e53a4..2a5e4b02 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -6,20 +6,13 @@ version = '3.1.0' sourceCompatibility = 1.7 -// Still unsupported, see http://issues.gradle.org/browse/GRADLE-784 -// Like this, it won't appear at all in the POM -configurations { - provided -} - dependencies { - compile project(':eventbus') - compile 'de.greenrobot:java-common:2.3.1' + implementation project(':eventbus') + implementation 'de.greenrobot:java-common:2.3.1' } sourceSets { main { - compileClasspath += configurations.provided java { srcDir 'src' } @@ -32,7 +25,6 @@ sourceSets { apply from: rootProject.file("gradle/publish.gradle") javadoc { - classpath += configurations.provided title = "EventBus Annotation Processor ${version} API" options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2015-2016 greenrobot.org. All Rights Reserved.' } From 2a9310ef7319238b106302ea70ccc2a208aff2c7 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 21 Jan 2020 08:03:14 +0100 Subject: [PATCH 235/288] README: add R8 rules. --- README.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cf9275f8..0e7fa29b 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,24 @@ Via Maven: Or download [the latest JAR](https://search.maven.org/remote_content?g=org.greenrobot&a=eventbus&v=LATEST) from Maven Central. +R8, ProGuard +------------ + +If your project uses R8 or ProGuard add the following rules: + +```bash +-keepattributes *Annotation* +-keepclassmembers class * { + @org.greenrobot.eventbus.Subscribe ; +} +-keep enum org.greenrobot.eventbus.ThreadMode { *; } + +# And if you use AsyncExecutor: +-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent { + (java.lang.Throwable); +} +``` + Homepage, Documentation, Links ------------------------------ For more details please check the [EventBus website](http://greenrobot.org/eventbus). Here are some direct links you may find useful: @@ -86,8 +104,6 @@ For more details please check the [EventBus website](http://greenrobot.org/event [Documentation](http://greenrobot.org/eventbus/documentation/) -[ProGuard](http://greenrobot.org/eventbus/documentation/proguard) - [Changelog](http://greenrobot.org/eventbus/changelog/) [FAQ](http://greenrobot.org/eventbus/documentation/faq/) From 5778314e0168c6fb2983c03dceadf4064b94278e Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 21 Jan 2020 08:08:23 +0100 Subject: [PATCH 236/288] README: drop broken Central JAR link. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0e7fa29b..ac5baa2a 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,8 @@ Add EventBus to your project ---------------------------- +Available on Maven Central. + Via Gradle: ```gradle implementation 'org.greenrobot:eventbus:3.1.1' @@ -76,8 +78,6 @@ Via Maven: ``` -Or download [the latest JAR](https://search.maven.org/remote_content?g=org.greenrobot&a=eventbus&v=LATEST) from Maven Central. - R8, ProGuard ------------ From 0e0dc21bf3e6c8ba2d96b5cf2fb5c25406981c15 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 21 Jan 2020 08:13:06 +0100 Subject: [PATCH 237/288] README: update links (TLS). --- README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ac5baa2a..56dcd901 100644 --- a/README.md +++ b/README.md @@ -118,10 +118,8 @@ EventBus binaries and source code can be used according to the [Apache License, More Open Source by greenrobot ============================== -[__ObjectBox__](http://objectbox.io/) ([GitHub](https://github.com/objectbox/objectbox-java)) is a new superfast object-oriented database for mobile. +[__ObjectBox__](https://objectbox.io/) ([GitHub](https://github.com/objectbox/objectbox-java)) is a new superfast object-oriented database for mobile. -[__Essentials__](http://greenrobot.org/essentials/) ([GitHub](https://github.com/greenrobot/essentials)) is a set of utility classes and hash functions for Android & Java projects. +[__Essentials__](https://github.com/greenrobot/essentials) is a set of utility classes and hash functions for Android & Java projects. -[__greenDAO__](http://greenrobot.org/greendao/) ([GitHub](https://github.com/greenrobot/greenDAO)) is an ORM optimized for Android: it maps database tables to Java objects and uses code generation for optimal speed. - -Check our [homepage](http://greenrobot.org/) to stay up to date. +[__greenDAO__](https://github.com/greenrobot/greenDAO) is an ORM optimized for Android: it maps database tables to Java objects and uses code generation for optimal speed. From 9fed85f8243067dd66dda3f99038c0fcb82c52e0 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 21 Jan 2020 08:16:04 +0100 Subject: [PATCH 238/288] README: link to examples. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 56dcd901..f32d7afd 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,8 @@ EventBus in 3 steps Read the full [getting started guide](http://greenrobot.org/eventbus/documentation/how-to-get-started/). +There are also some [examples](https://github.com/greenrobot-team/greenrobot-examples). + Add EventBus to your project ---------------------------- From f644d281233d57d4e83d9a57b5030f519027aeeb Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 19 Nov 2019 15:25:27 +0100 Subject: [PATCH 239/288] Mark annotation processor as aggregating. --- EventBusAnnotationProcessor/build.gradle | 5 +++++ .../EventBusAnnotationProcessor.java | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index 2a5e4b02..224b7bda 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -9,6 +9,11 @@ sourceCompatibility = 1.7 dependencies { implementation project(':eventbus') implementation 'de.greenrobot:java-common:2.3.1' + + // Generates the required META-INF descriptor to make the processor incremental. + def incap = '0.2' + compileOnly "net.ltgt.gradle.incap:incap:$incap" + annotationProcessor "net.ltgt.gradle.incap:incap-processor:$incap" } sourceSets { diff --git a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java index c37c18a5..058bc36e 100644 --- a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java @@ -15,6 +15,8 @@ */ package org.greenrobot.eventbus.annotationprocessor; +import net.ltgt.gradle.incap.IncrementalAnnotationProcessor; + import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -46,8 +48,16 @@ import de.greenrobot.common.ListMap; + +import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.AGGREGATING; + +/** + * Is an aggregating processor as it writes a single file, the subscriber index file, + * based on found elements with the @Subscriber annotation. + */ @SupportedAnnotationTypes("org.greenrobot.eventbus.Subscribe") @SupportedOptions(value = {"eventBusIndex", "verbose"}) +@IncrementalAnnotationProcessor(AGGREGATING) public class EventBusAnnotationProcessor extends AbstractProcessor { public static final String OPTION_EVENT_BUS_INDEX = "eventBusIndex"; public static final String OPTION_VERBOSE = "verbose"; From 9b1aeddcd3bab713b094d00e8043a2399bb97000 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 3 Feb 2020 17:49:01 +0100 Subject: [PATCH 240/288] 3.1.2-RC: minor version updates, etc. --- EventBus/build.gradle | 4 ++-- .../src/org/greenrobot/eventbus/EventBus.java | 19 ++++++++++--------- .../greenrobot/eventbus/EventBusBuilder.java | 5 +++-- EventBusAnnotationProcessor/build.gradle | 4 ++-- EventBusPerformance/build.gradle | 2 +- EventBusTest/build.gradle | 6 +++--- README.md | 4 +--- 7 files changed, 22 insertions(+), 22 deletions(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index 621f2409..def4de6b 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'java' archivesBaseName = 'eventbus' group = 'org.greenrobot' -version = '3.1.1' +version = '3.1.2-RC' sourceCompatibility = 1.7 dependencies { @@ -26,7 +26,7 @@ apply from: rootProject.file("gradle/publish.gradle") javadoc { failOnError = false title = "EventBus ${version} API" - options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2012-2017 greenrobot.org. All Rights Reserved.' + options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2012-2020 greenrobot.org. All Rights Reserved.' } task javadocJar(type: Jar, dependsOn: javadoc) { diff --git a/EventBus/src/org/greenrobot/eventbus/EventBus.java b/EventBus/src/org/greenrobot/eventbus/EventBus.java index e35ecd38..aa6c5981 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBus.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBus.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * Copyright (C) 2012-2020 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,12 +27,13 @@ import java.util.logging.Level; /** - * EventBus is a central publish/subscribe event system for Android. Events are posted ({@link #post(Object)}) to the - * bus, which delivers it to subscribers that have a matching handler method for the event type. To receive events, - * subscribers must register themselves to the bus using {@link #register(Object)}. Once registered, subscribers - * receive events until {@link #unregister(Object)} is called. Event handling methods must be annotated by - * {@link Subscribe}, must be public, return nothing (void), and have exactly one parameter - * (the event). + * EventBus is a central publish/subscribe event system for Java and Android. + * Events are posted ({@link #post(Object)}) to the bus, which delivers it to subscribers that have a matching handler + * method for the event type. + * To receive events, subscribers must register themselves to the bus using {@link #register(Object)}. + * Once registered, subscribers receive events until {@link #unregister(Object)} is called. + * Event handling methods must be annotated by {@link Subscribe}, must be public, return nothing (void), + * and have exactly one parameter (the event). * * @author Markus Junginger, greenrobot */ @@ -213,7 +214,7 @@ private void checkPostStickyEventToSubscription(Subscription newSubscription, Ob * poster. */ private boolean isMainThread() { - return mainThreadSupport != null ? mainThreadSupport.isMainThread() : true; + return mainThreadSupport == null || mainThreadSupport.isMainThread(); } public synchronized boolean isRegistered(Object subscriber) { @@ -408,7 +409,7 @@ private boolean postSingleEventForEventType(Object event, PostingThreadState pos for (Subscription subscription : subscriptions) { postingState.event = event; postingState.subscription = subscription; - boolean aborted = false; + boolean aborted; try { postToSubscription(subscription, event, postingState.isMainThread); aborted = postingState.canceled; diff --git a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java index 3e2b5c9c..64e30982 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * Copyright (C) 2012-2020 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +29,7 @@ * Creates EventBus instances with custom parameters and also allows to install a custom default EventBus instance. * Create a new builder using {@link EventBus#builder()}. */ +@SuppressWarnings("unused") public class EventBusBuilder { private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool(); @@ -88,7 +89,7 @@ public EventBusBuilder throwSubscriberException(boolean throwSubscriberException * By default, EventBus considers the event class hierarchy (subscribers to super classes will be notified). * Switching this feature off will improve posting of events. For simple event classes extending Object directly, * we measured a speed up of 20% for event posting. For more complex event hierarchies, the speed up should be - * >20%. + * greater than 20%. *

* However, keep in mind that event posting usually consumes just a small proportion of CPU time inside an app, * unless it is posting at high rates, e.g. hundreds/thousands of events per second. diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index 224b7bda..8a0ba145 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'java' archivesBaseName = 'eventbus-annotation-processor' group = 'org.greenrobot' -version = '3.1.0' +version = '3.1.2-RC' sourceCompatibility = 1.7 @@ -31,7 +31,7 @@ apply from: rootProject.file("gradle/publish.gradle") javadoc { title = "EventBus Annotation Processor ${version} API" - options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2015-2016 greenrobot.org. All Rights Reserved.' + options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2015-2020 greenrobot.org. All Rights Reserved.' } task javadocJar(type: Jar, dependsOn: javadoc) { diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 47db03ce..7123513f 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.5.2' + classpath 'com.android.tools.build:gradle:3.5.3' } } diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 27d44045..22e77647 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.5.2' + classpath 'com.android.tools.build:gradle:3.5.3' } } @@ -18,8 +18,8 @@ dependencies { // Trying to repro bug: // androidTestAnnotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.0' implementation fileTree(dir: 'libs', include: '*.jar') - androidTestImplementation 'com.android.support.test:runner:1.0.1' - androidTestImplementation 'com.android.support.test:rules:1.0.1' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test:rules:1.0.2' } android { diff --git a/README.md b/README.md index f32d7afd..ae3f8cab 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -Hey, do have a minute for a [quick survey](https://docs.google.com/forms/d/e/1FAIpQLSePA8NqA9Jlbvh28xcFVbmIGUzHW3dnsxuxi23-ZDPPfkWMSQ/viewform) on how we are doing with EventBus? - EventBus ======== EventBus is a publish/subscribe event bus for Android and Java.
@@ -114,7 +112,7 @@ How does EventBus compare to other solutions, like Otto from Square? Check this License ------- -Copyright (C) 2012-2017 Markus Junginger, greenrobot (http://greenrobot.org) +Copyright (C) 2012-2020 Markus Junginger, greenrobot (http://greenrobot.org) EventBus binaries and source code can be used according to the [Apache License, Version 2.0](LICENSE). From 0d551f1a493710b92791b82bd915238310c6ed4e Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 4 Feb 2020 14:01:50 +0100 Subject: [PATCH 241/288] add Logger.Default and use it to make ExceptionToResourceMapping independent from Android --- EventBus/build.gradle | 2 +- .../greenrobot/eventbus/EventBusBuilder.java | 8 ++---- .../src/org/greenrobot/eventbus/Logger.java | 27 ++++++++++++++++--- .../util/ExceptionToResourceMapping.java | 8 +++--- 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index def4de6b..ad4f88a4 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'java' archivesBaseName = 'eventbus' group = 'org.greenrobot' -version = '3.1.2-RC' +version = '3.2.0-SNAPSHOT' sourceCompatibility = 1.7 dependencies { diff --git a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java index 64e30982..c091e05e 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java @@ -158,14 +158,10 @@ Logger getLogger() { if (logger != null) { return logger; } else { - // also check main looper to see if we have "good" Android classes (not Stubs etc.) - return AndroidLogger.isAndroidLogAvailable() && getAndroidMainLooperOrNull() != null - ? new AndroidLogger("EventBus") : - new Logger.SystemOutLogger(); + return Logger.Default.get(); } } - MainThreadSupport getMainThreadSupport() { if (mainThreadSupport != null) { return mainThreadSupport; @@ -178,7 +174,7 @@ MainThreadSupport getMainThreadSupport() { } } - Object getAndroidMainLooperOrNull() { + static Object getAndroidMainLooperOrNull() { try { return Looper.getMainLooper(); } catch (RuntimeException e) { diff --git a/EventBus/src/org/greenrobot/eventbus/Logger.java b/EventBus/src/org/greenrobot/eventbus/Logger.java index 602e0b51..69d1063a 100644 --- a/EventBus/src/org/greenrobot/eventbus/Logger.java +++ b/EventBus/src/org/greenrobot/eventbus/Logger.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * Copyright (C) 2012-2020 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,9 @@ */ package org.greenrobot.eventbus; +import android.os.Looper; +import org.greenrobot.eventbus.android.AndroidLogger; + import java.util.logging.Level; public interface Logger { @@ -23,7 +26,7 @@ public interface Logger { void log(Level level, String msg, Throwable th); - public static class JavaLogger implements Logger { + class JavaLogger implements Logger { protected final java.util.logging.Logger logger; public JavaLogger(String tag) { @@ -44,7 +47,7 @@ public void log(Level level, String msg, Throwable th) { } - public static class SystemOutLogger implements Logger { + class SystemOutLogger implements Logger { @Override public void log(Level level, String msg) { @@ -59,4 +62,22 @@ public void log(Level level, String msg, Throwable th) { } + class Default { + public static Logger get() { + // also check main looper to see if we have "good" Android classes (not Stubs etc.) + return AndroidLogger.isAndroidLogAvailable() && getAndroidMainLooperOrNull() != null + ? new AndroidLogger("EventBus") : + new Logger.SystemOutLogger(); + } + + static Object getAndroidMainLooperOrNull() { + try { + return Looper.getMainLooper(); + } catch (RuntimeException e) { + // Not really a functional Android (e.g. "Stub!" maven dependencies) + return null; + } + } + } + } diff --git a/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java b/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java index a3bb67f3..083bd394 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * Copyright (C) 2012-2020 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,13 @@ package org.greenrobot.eventbus.util; -import android.util.Log; +import org.greenrobot.eventbus.Logger; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.logging.Level; /** @@ -50,7 +51,8 @@ public Integer mapThrowable(final Throwable throwable) { throwableToCheck = throwableToCheck.getCause(); depthToGo--; if (depthToGo <= 0 || throwableToCheck == throwable || throwableToCheck == null) { - Log.d("EventBus", "No specific message resource ID found for " + throwable); + Logger logger = Logger.Default.get(); // No EventBus instance here + logger.log(Level.FINE, "No specific message resource ID found for " + throwable); // return config.defaultErrorMsgId; return null; } From 62abc54dec3bf3e1f8d2badc4752f61ff05e8eb3 Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 4 Feb 2020 15:22:36 +0100 Subject: [PATCH 242/288] Skip also androidx.* super classes --- .../src/org/greenrobot/eventbus/SubscriberMethodFinder.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java index db5e0ad3..b688cc46 100644 --- a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java @@ -259,8 +259,10 @@ void moveToSuperclass() { } 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.")) { + // Skip system classes, this degrades performance. + // Also we might avoid some ClassNotFoundException (see FAQ for background). + if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || + clazzName.startsWith("android.") || clazzName.startsWith("androidx.")) { clazz = null; } } From bb5b149b556a6f295c3bad597a66edf83c2e73eb Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 4 Feb 2020 15:23:39 +0100 Subject: [PATCH 243/288] Provide additional info if Class.getMethods() fails --- .../eventbus/SubscriberMethodFinder.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java index b688cc46..37e001ff 100644 --- a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java @@ -15,6 +15,7 @@ */ package org.greenrobot.eventbus; +import android.annotation.TargetApi; import org.greenrobot.eventbus.meta.SubscriberInfo; import org.greenrobot.eventbus.meta.SubscriberInfoIndex; @@ -25,6 +26,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Level; class SubscriberMethodFinder { /* @@ -154,7 +156,14 @@ private void findUsingReflectionInSingleClass(FindState findState) { methods = findState.clazz.getDeclaredMethods(); } catch (Throwable th) { // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149 - methods = findState.clazz.getMethods(); + try { + methods = findState.clazz.getMethods(); + } catch (LinkageError error) { // super class of NoClassDefFoundError to be a bit more broad... + String msg = "Could not inspect methods of " + findState.clazz.getName() + + ". Please consider using EventBus annotation processor to avoid reflection."; + throwLinkageError(error, msg); + return; + } findState.skipSuperClasses = true; } for (Method method : methods) { @@ -184,6 +193,16 @@ private void findUsingReflectionInSingleClass(FindState findState) { } } + @TargetApi(19) + private void throwLinkageError(LinkageError error, String msg) { + try { + error = new LinkageError(msg, error); // Wrapping only works with Java 7 / Android API 19 + } catch (Throwable ex) { + Logger.Default.get().log(Level.SEVERE, msg); // Can not wrap, log additional info + } + throw error; + } + static void clearCaches() { METHOD_CACHE.clear(); } From 34a1537af7364cec9444a24431c566d434d4d0b8 Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 4 Feb 2020 17:04:52 +0100 Subject: [PATCH 244/288] Class.getMethods() failures: provide better info and use EventBusException instead of LinkageError --- .../eventbus/SubscriberMethodFinder.java | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java index 37e001ff..3f2812bc 100644 --- a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java @@ -15,7 +15,6 @@ */ package org.greenrobot.eventbus; -import android.annotation.TargetApi; import org.greenrobot.eventbus.meta.SubscriberInfo; import org.greenrobot.eventbus.meta.SubscriberInfoIndex; @@ -26,7 +25,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import java.util.logging.Level; class SubscriberMethodFinder { /* @@ -159,10 +157,13 @@ private void findUsingReflectionInSingleClass(FindState findState) { try { methods = findState.clazz.getMethods(); } catch (LinkageError error) { // super class of NoClassDefFoundError to be a bit more broad... - String msg = "Could not inspect methods of " + findState.clazz.getName() + - ". Please consider using EventBus annotation processor to avoid reflection."; - throwLinkageError(error, msg); - return; + String msg = "Could not inspect methods of " + findState.clazz.getName(); + if (ignoreGeneratedIndex) { + msg += ". Please consider using EventBus annotation processor to avoid reflection."; + } else { + msg += ". Please make this class visible to EventBus annotation processor to avoid reflection."; + } + throw new EventBusException(msg, error); } findState.skipSuperClasses = true; } @@ -193,16 +194,6 @@ private void findUsingReflectionInSingleClass(FindState findState) { } } - @TargetApi(19) - private void throwLinkageError(LinkageError error, String msg) { - try { - error = new LinkageError(msg, error); // Wrapping only works with Java 7 / Android API 19 - } catch (Throwable ex) { - Logger.Default.get().log(Level.SEVERE, msg); // Can not wrap, log additional info - } - throw error; - } - static void clearCaches() { METHOD_CACHE.clear(); } From ddaace5e2aa70fc2ea0128b2f46f81d8e70d5a56 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 10 Feb 2020 10:05:45 +0100 Subject: [PATCH 245/288] 3.2.0 --- EventBus/build.gradle | 2 +- EventBusAnnotationProcessor/build.gradle | 2 +- README.md | 20 +++++++++++--------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index ad4f88a4..869cfa92 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'java' archivesBaseName = 'eventbus' group = 'org.greenrobot' -version = '3.2.0-SNAPSHOT' +version = '3.2.0' sourceCompatibility = 1.7 dependencies { diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index 8a0ba145..d00f28ea 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'java' archivesBaseName = 'eventbus-annotation-processor' group = 'org.greenrobot' -version = '3.1.2-RC' +version = '3.2.0' sourceCompatibility = 1.7 diff --git a/README.md b/README.md index ae3f8cab..b914c6a5 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ EventBus ======== -EventBus is a publish/subscribe event bus for Android and Java.
+[EventBus](http://greenrobot.org/eventbus/) is a publish/subscribe event bus for Android and Java.
+[![Build Status](https://travis-ci.org/greenrobot/EventBus.svg?branch=master)](https://travis-ci.org/greenrobot/EventBus) +[![Follow greenrobot on Twitter](https://img.shields.io/twitter/follow/greenrobot_de.svg?style=flat-square&logo=twitter)](https://twitter.com/greenrobot_de) + EventBus... * simplifies the communication between components @@ -11,11 +14,10 @@ EventBus... * avoids complex and error-prone dependencies and life cycle issues * makes your code simpler * is fast - * is tiny (~50k jar) - * is proven in practice by apps with 100,000,000+ installs + * is tiny (~60k jar) + * is proven in practice by apps with 1,000,000,000+ installs * has advanced features like delivery threads, subscriber priorities, etc. - [![Build Status](https://travis-ci.org/greenrobot/EventBus.svg?branch=master)](https://travis-ci.org/greenrobot/EventBus) EventBus in 3 steps ------------------- @@ -66,7 +68,7 @@ Available on +[EventBus](https://greenrobot.org/eventbus/) is a publish/subscribe event bus for Android and Java.
[![Build Status](https://travis-ci.org/greenrobot/EventBus.svg?branch=master)](https://travis-ci.org/greenrobot/EventBus) @@ -28,7 +28,7 @@ EventBus in 3 steps ``` 2. Prepare subscribers: - Declare and annotate your subscribing method, optionally specify a [thread mode](http://greenrobot.org/eventbus/documentation/delivery-threads-threadmode/): + Declare and annotate your subscribing method, optionally specify a [thread mode](https://greenrobot.org/eventbus/documentation/delivery-threads-threadmode/): ```java @Subscribe(threadMode = ThreadMode.MAIN) @@ -56,7 +56,7 @@ EventBus in 3 steps EventBus.getDefault().post(new MessageEvent()); ``` -Read the full [getting started guide](http://greenrobot.org/eventbus/documentation/how-to-get-started/). +Read the full [getting started guide](https://greenrobot.org/eventbus/documentation/how-to-get-started/). There are also some [examples](https://github.com/greenrobot-team/greenrobot-examples). @@ -100,21 +100,21 @@ If your project uses R8 or ProGuard add the following rules: Homepage, Documentation, Links ------------------------------ -For more details please check the [EventBus website](http://greenrobot.org/eventbus). Here are some direct links you may find useful: +For more details please check the [EventBus website](https://greenrobot.org/eventbus). Here are some direct links you may find useful: -[Features](http://greenrobot.org/eventbus/features/) +[Features](https://greenrobot.org/eventbus/features/) -[Documentation](http://greenrobot.org/eventbus/documentation/) +[Documentation](https://greenrobot.org/eventbus/documentation/) -[Changelog](http://greenrobot.org/eventbus/changelog/) +[Changelog](https://greenrobot.org/eventbus/changelog/) -[FAQ](http://greenrobot.org/eventbus/documentation/faq/) +[FAQ](https://greenrobot.org/eventbus/documentation/faq/) How does EventBus compare to other solutions, like Otto from Square? Check this [comparison](COMPARISON.md). License ------- -Copyright (C) 2012-2020 Markus Junginger, greenrobot (http://greenrobot.org) +Copyright (C) 2012-2020 Markus Junginger, greenrobot (https://greenrobot.org) EventBus binaries and source code can be used according to the [Apache License, Version 2.0](LICENSE). diff --git a/gradle/publish.gradle b/gradle/publish.gradle index 236b4afe..a887ff3a 100644 --- a/gradle/publish.gradle +++ b/gradle/publish.gradle @@ -56,7 +56,7 @@ afterEvaluate { project -> // Common properties, projects still need to set name and description. pom.project { packaging 'jar' - url 'http://greenrobot.org/eventbus/' + url 'https://greenrobot.org/eventbus/' scm { url 'https://github.com/greenrobot/EventBus' @@ -86,7 +86,7 @@ afterEvaluate { project -> organization { name 'greenrobot' - url 'http://greenrobot.org' + url 'https://greenrobot.org' } } } From 1d995077d0b620a6aae9c60a8b96443113752305 Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 11 Feb 2020 10:52:09 +0100 Subject: [PATCH 247/288] README.md: add recommendation to use subscriber index --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0d911ac0..2a776233 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,6 @@ EventBus... * is proven in practice by apps with 1,000,000,000+ installs * has advanced features like delivery threads, subscriber priorities, etc. - EventBus in 3 steps ------------------- 1. Define events: @@ -60,6 +59,9 @@ Read the full [getting started guide](https://greenrobot.org/eventbus/documentat There are also some [examples](https://github.com/greenrobot-team/greenrobot-examples). +**Note:** we highly recommend the [EventBus annotation processor with its subscriber index](https://greenrobot.org/eventbus/documentation/subscriber-index/). +This will avoid some reflection related problems seen in the wild. + Add EventBus to your project ----------------------------
From bf8e86164001f514ce74514de5d0034f3473ee0f Mon Sep 17 00:00:00 2001 From: Andrei Dobrescu Date: Mon, 10 May 2021 16:04:25 +0300 Subject: [PATCH 248/288] removed error dialog classes --- EventBus/build.gradle | 3 +- .../eventbus/util/ErrorDialogConfig.java | 82 ------ .../util/ErrorDialogFragmentFactory.java | 114 -------- .../eventbus/util/ErrorDialogFragments.java | 91 ------ .../eventbus/util/ErrorDialogManager.java | 262 ------------------ .../eventbus/util/ThrowableFailureEvent.java | 3 +- EventBusAnnotationProcessor/build.gradle | 3 +- EventBusPerformance/build.gradle | 4 +- EventBusTest/build.gradle | 4 +- EventBusTestJava/build.gradle | 3 +- EventBusTestSubscriberInJar/build.gradle | 3 +- build.gradle | 3 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 13 files changed, 15 insertions(+), 562 deletions(-) delete mode 100644 EventBus/src/org/greenrobot/eventbus/util/ErrorDialogConfig.java delete mode 100644 EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragmentFactory.java delete mode 100644 EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragments.java delete mode 100644 EventBus/src/org/greenrobot/eventbus/util/ErrorDialogManager.java diff --git a/EventBus/build.gradle b/EventBus/build.gradle index 45e34b44..af93b5f2 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -3,7 +3,8 @@ apply plugin: 'java' archivesBaseName = 'eventbus' group = 'org.greenrobot' version = '3.2.0' -sourceCompatibility = 1.7 +java.sourceCompatibility = JavaVersion.VERSION_1_8 +java.targetCompatibility = JavaVersion.VERSION_1_8 dependencies { compileOnly 'com.google.android:android:4.1.1.4' diff --git a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogConfig.java b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogConfig.java deleted file mode 100644 index 95e84c72..00000000 --- a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogConfig.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.greenrobot.eventbus.util; - -import android.content.res.Resources; -import android.util.Log; - -import org.greenrobot.eventbus.EventBus; - -public class ErrorDialogConfig { - final Resources resources; - final int defaultTitleId; - final int defaultErrorMsgId; - final ExceptionToResourceMapping mapping; - - EventBus eventBus; - boolean logExceptions = true; - String tagForLoggingExceptions; - int defaultDialogIconId; - Class defaultEventTypeOnDialogClosed; - - public ErrorDialogConfig(Resources resources, int defaultTitleId, int defaultMsgId) { - this.resources = resources; - this.defaultTitleId = defaultTitleId; - this.defaultErrorMsgId = defaultMsgId; - mapping = new ExceptionToResourceMapping(); - } - - public ErrorDialogConfig addMapping(Class clazz, int msgId) { - mapping.addMapping(clazz, msgId); - return this; - } - - public int getMessageIdForThrowable(final Throwable throwable) { - Integer resId = mapping.mapThrowable(throwable); - if (resId != null) { - return resId; - } else { - Log.d(EventBus.TAG, "No specific message ressource ID found for " + throwable); - return defaultErrorMsgId; - } - } - - public void setDefaultDialogIconId(int defaultDialogIconId) { - this.defaultDialogIconId = defaultDialogIconId; - } - - public void setDefaultEventTypeOnDialogClosed(Class defaultEventTypeOnDialogClosed) { - this.defaultEventTypeOnDialogClosed = defaultEventTypeOnDialogClosed; - } - - public void disableExceptionLogging() { - logExceptions = false; - } - - public void setTagForLoggingExceptions(String tagForLoggingExceptions) { - this.tagForLoggingExceptions = tagForLoggingExceptions; - } - - public void setEventBus(EventBus eventBus) { - this.eventBus = eventBus; - } - - /** eventBus!=null ? eventBus: EventBus.getDefault() */ - EventBus getEventBus() { - return eventBus!=null ? eventBus: EventBus.getDefault(); - } -} \ No newline at end of file diff --git a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragmentFactory.java b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragmentFactory.java deleted file mode 100644 index 27ab963d..00000000 --- a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragmentFactory.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.greenrobot.eventbus.util; - -import android.annotation.TargetApi; -import android.os.Build; -import android.os.Bundle; -import android.support.v4.app.Fragment; - -/** - * Factory to allow injecting a more complex exception mapping; typically you would subclass one of {@link Honeycomb} or - * {@link Support}. - */ -public abstract class ErrorDialogFragmentFactory { - protected final ErrorDialogConfig config; - - protected ErrorDialogFragmentFactory(ErrorDialogConfig config) { - this.config = config; - } - - /** - * Prepares the fragment's arguments and creates the fragment. May be overridden to provide custom error fragments. - */ - protected T prepareErrorFragment(ThrowableFailureEvent event, boolean finishAfterDialog, - Bundle argumentsForErrorDialog) { - if (event.isSuppressErrorUi()) { - // Show nothing by default - return null; - } - Bundle bundle; - if (argumentsForErrorDialog != null) { - bundle = (Bundle) argumentsForErrorDialog.clone(); - } else { - bundle = new Bundle(); - } - - if (!bundle.containsKey(ErrorDialogManager.KEY_TITLE)) { - String title = getTitleFor(event, bundle); - bundle.putString(ErrorDialogManager.KEY_TITLE, title); - } - if (!bundle.containsKey(ErrorDialogManager.KEY_MESSAGE)) { - String message = getMessageFor(event, bundle); - bundle.putString(ErrorDialogManager.KEY_MESSAGE, message); - } - if (!bundle.containsKey(ErrorDialogManager.KEY_FINISH_AFTER_DIALOG)) { - bundle.putBoolean(ErrorDialogManager.KEY_FINISH_AFTER_DIALOG, finishAfterDialog); - } - if (!bundle.containsKey(ErrorDialogManager.KEY_EVENT_TYPE_ON_CLOSE) - && config.defaultEventTypeOnDialogClosed != null) { - bundle.putSerializable(ErrorDialogManager.KEY_EVENT_TYPE_ON_CLOSE, config.defaultEventTypeOnDialogClosed); - } - if (!bundle.containsKey(ErrorDialogManager.KEY_ICON_ID) && config.defaultDialogIconId != 0) { - bundle.putInt(ErrorDialogManager.KEY_ICON_ID, config.defaultDialogIconId); - } - return createErrorFragment(event, bundle); - } - - /** Returns either a new Honeycomb+ or a new support library DialogFragment. */ - protected abstract T createErrorFragment(ThrowableFailureEvent event, Bundle arguments); - - /** May be overridden to provide custom error title. */ - protected String getTitleFor(ThrowableFailureEvent event, Bundle arguments) { - return config.resources.getString(config.defaultTitleId); - } - - /** May be overridden to provide custom error messages. */ - protected String getMessageFor(ThrowableFailureEvent event, Bundle arguments) { - int msgResId = config.getMessageIdForThrowable(event.throwable); - return config.resources.getString(msgResId); - } - - public static class Support extends ErrorDialogFragmentFactory { - - public Support(ErrorDialogConfig config) { - super(config); - } - - protected Fragment createErrorFragment(ThrowableFailureEvent event, Bundle arguments) { - ErrorDialogFragments.Support errorFragment = new ErrorDialogFragments.Support(); - errorFragment.setArguments(arguments); - return errorFragment; - } - - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public static class Honeycomb extends ErrorDialogFragmentFactory { - - public Honeycomb(ErrorDialogConfig config) { - super(config); - } - - protected android.app.Fragment createErrorFragment(ThrowableFailureEvent event, Bundle arguments) { - ErrorDialogFragments.Honeycomb errorFragment = new ErrorDialogFragments.Honeycomb(); - errorFragment.setArguments(arguments); - return errorFragment; - } - - } -} \ No newline at end of file diff --git a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragments.java b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragments.java deleted file mode 100644 index 49174766..00000000 --- a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragments.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.greenrobot.eventbus.util; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.os.Build; -import android.os.Bundle; -import android.support.v4.app.DialogFragment; - -import org.greenrobot.eventbus.EventBus; - -public class ErrorDialogFragments { - /** TODO Use config: Icon res ID to use for all error dialogs. May be configured by each app (optional). */ - public static int ERROR_DIALOG_ICON = 0; - - /** TODO Use config: Event class to be fired on dismissing the dialog by the user. May be configured by each app. */ - public static Class EVENT_TYPE_ON_CLICK; - - public static Dialog createDialog(Context context, Bundle arguments, OnClickListener onClickListener) { - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(arguments.getString(ErrorDialogManager.KEY_TITLE)); - builder.setMessage(arguments.getString(ErrorDialogManager.KEY_MESSAGE)); - if (ERROR_DIALOG_ICON != 0) { - builder.setIcon(ERROR_DIALOG_ICON); - } - builder.setPositiveButton(android.R.string.ok, onClickListener); - return builder.create(); - } - - public static void handleOnClick(DialogInterface dialog, int which, Activity activity, Bundle arguments) { - if (EVENT_TYPE_ON_CLICK != null) { - Object event; - try { - event = EVENT_TYPE_ON_CLICK.newInstance(); - } catch (Exception e) { - throw new RuntimeException("Event cannot be constructed", e); - } - EventBus eventBus = ErrorDialogManager.factory.config.getEventBus(); - eventBus.post(event); - } - boolean finish = arguments.getBoolean(ErrorDialogManager.KEY_FINISH_AFTER_DIALOG, false); - if (finish && activity != null) { - activity.finish(); - } - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public static class Honeycomb extends android.app.DialogFragment implements OnClickListener { - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - return createDialog(getActivity(), getArguments(), this); - } - - @Override - public void onClick(DialogInterface dialog, int which) { - handleOnClick(dialog, which, getActivity(), getArguments()); - } - } - - public static class Support extends DialogFragment implements OnClickListener { - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - return createDialog(getActivity(), getArguments(), this); - } - - @Override - public void onClick(DialogInterface dialog, int which) { - handleOnClick(dialog, which, getActivity(), getArguments()); - } - } -} diff --git a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogManager.java b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogManager.java deleted file mode 100644 index 9d5ccf2c..00000000 --- a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogManager.java +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.greenrobot.eventbus.util; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.app.Application; -import android.os.Build; -import android.os.Bundle; -import android.support.v4.app.DialogFragment; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.FragmentManager; -import android.util.Log; - -import org.greenrobot.eventbus.EventBus; - -/** - * Central class for app that want to use event based error dialogs.
- *
- * How to use: - *

    - *
  1. Set the {@link #factory} to configure dialogs for your app, typically in {@link Application#onCreate()}
  2. - *
  3. Use one of {@link #attachTo(Activity)}, {@link #attachTo(Activity, boolean)} or - * {@link #attachTo(Activity, boolean, Bundle)} in your Activity, typically in onCreate.
  4. - *
- * - * For more complex mappings, you can supply your own {@link ErrorDialogFragmentFactory}. - * - * @author Markus - */ -public class ErrorDialogManager { - - public static class SupportManagerFragment extends Fragment { - protected boolean finishAfterDialog; - protected Bundle argumentsForErrorDialog; - private EventBus eventBus; - private boolean skipRegisterOnNextResume; - private Object executionScope; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - eventBus = ErrorDialogManager.factory.config.getEventBus(); - eventBus.register(this); - skipRegisterOnNextResume = true; - } - - @Override - public void onResume() { - super.onResume(); - if (skipRegisterOnNextResume) { - // registered in onCreate, skip registration in this run - skipRegisterOnNextResume = false; - } else { - eventBus = ErrorDialogManager.factory.config.getEventBus(); - eventBus.register(this); - } - } - - @Override - public void onPause() { - eventBus.unregister(this); - super.onPause(); - } - - public void onEventMainThread(ThrowableFailureEvent event) { - if (!isInExecutionScope(executionScope, event)) { - return; - } - checkLogException(event); - // Execute pending commits before finding to avoid multiple error fragments being shown - FragmentManager fm = getFragmentManager(); - fm.executePendingTransactions(); - - DialogFragment existingFragment = (DialogFragment) fm.findFragmentByTag(TAG_ERROR_DIALOG); - if (existingFragment != null) { - // Just show the latest error - existingFragment.dismiss(); - } - - android.support.v4.app.DialogFragment errorFragment = (android.support.v4.app.DialogFragment) factory - .prepareErrorFragment(event, finishAfterDialog, argumentsForErrorDialog); - if (errorFragment != null) { - errorFragment.show(fm, TAG_ERROR_DIALOG); - } - } - - public static void attachTo(Activity activity, Object executionScope, boolean finishAfterDialog, - Bundle argumentsForErrorDialog) { - FragmentManager fm = ((FragmentActivity) activity).getSupportFragmentManager(); - SupportManagerFragment fragment = (SupportManagerFragment) fm.findFragmentByTag(TAG_ERROR_DIALOG_MANAGER); - if (fragment == null) { - fragment = new SupportManagerFragment(); - fm.beginTransaction().add(fragment, TAG_ERROR_DIALOG_MANAGER).commit(); - fm.executePendingTransactions(); - } - fragment.finishAfterDialog = finishAfterDialog; - fragment.argumentsForErrorDialog = argumentsForErrorDialog; - fragment.executionScope = executionScope; - } - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public static class HoneycombManagerFragment extends android.app.Fragment { - protected boolean finishAfterDialog; - protected Bundle argumentsForErrorDialog; - private EventBus eventBus; - private Object executionScope; - - @Override - public void onResume() { - super.onResume(); - eventBus = ErrorDialogManager.factory.config.getEventBus(); - eventBus.register(this); - } - - @Override - public void onPause() { - eventBus.unregister(this); - super.onPause(); - } - - public void onEventMainThread(ThrowableFailureEvent event) { - if (!isInExecutionScope(executionScope, event)) { - return; - } - checkLogException(event); - - // Execute pending commits before finding to avoid multiple error fragments being shown - android.app.FragmentManager fm = getFragmentManager(); - fm.executePendingTransactions(); - - android.app.DialogFragment existingFragment = (android.app.DialogFragment) fm - .findFragmentByTag(TAG_ERROR_DIALOG); - if (existingFragment != null) { - // Just show the latest error - existingFragment.dismiss(); - } - - android.app.DialogFragment errorFragment = (android.app.DialogFragment) factory.prepareErrorFragment(event, - finishAfterDialog, argumentsForErrorDialog); - if (errorFragment != null) { - errorFragment.show(fm, TAG_ERROR_DIALOG); - } - } - - public static void attachTo(Activity activity, Object executionScope, boolean finishAfterDialog, Bundle argumentsForErrorDialog) { - android.app.FragmentManager fm = activity.getFragmentManager(); - HoneycombManagerFragment fragment = (HoneycombManagerFragment) fm - .findFragmentByTag(TAG_ERROR_DIALOG_MANAGER); - if (fragment == null) { - fragment = new HoneycombManagerFragment(); - fm.beginTransaction().add(fragment, TAG_ERROR_DIALOG_MANAGER).commit(); - fm.executePendingTransactions(); - } - fragment.finishAfterDialog = finishAfterDialog; - fragment.argumentsForErrorDialog = argumentsForErrorDialog; - fragment.executionScope = executionScope; - } - } - - /** Must be set by the application. */ - public static ErrorDialogFragmentFactory factory; - - protected static final String TAG_ERROR_DIALOG = "de.greenrobot.eventbus.error_dialog"; - protected static final String TAG_ERROR_DIALOG_MANAGER = "de.greenrobot.eventbus.error_dialog_manager"; - - public static final String KEY_TITLE = "de.greenrobot.eventbus.errordialog.title"; - public static final String KEY_MESSAGE = "de.greenrobot.eventbus.errordialog.message"; - public static final String KEY_FINISH_AFTER_DIALOG = "de.greenrobot.eventbus.errordialog.finish_after_dialog"; - public static final String KEY_ICON_ID = "de.greenrobot.eventbus.errordialog.icon_id"; - public static final String KEY_EVENT_TYPE_ON_CLOSE = "de.greenrobot.eventbus.errordialog.event_type_on_close"; - - /** Scope is limited to the activity's class. */ - public static void attachTo(Activity activity) { - attachTo(activity, false, null); - } - - /** Scope is limited to the activity's class. */ - public static void attachTo(Activity activity, boolean finishAfterDialog) { - attachTo(activity, finishAfterDialog, null); - } - - /** Scope is limited to the activity's class. */ - public static void attachTo(Activity activity, boolean finishAfterDialog, Bundle argumentsForErrorDialog) { - Object executionScope = activity.getClass(); - attachTo(activity, executionScope, finishAfterDialog, argumentsForErrorDialog); - } - - public static void attachTo(Activity activity, Object executionScope, boolean finishAfterDialog, Bundle argumentsForErrorDialog) { - if (factory == null) { - throw new RuntimeException("You must set the static factory field to configure error dialogs for your app."); - } - if (isSupportActivity(activity)) { - SupportManagerFragment.attachTo(activity, executionScope, finishAfterDialog, argumentsForErrorDialog); - } else { - HoneycombManagerFragment.attachTo(activity, executionScope, finishAfterDialog, argumentsForErrorDialog); - } - } - - private static boolean isSupportActivity(Activity activity) { - boolean isSupport = false; - for (Class c = activity.getClass().getSuperclass();; c = c.getSuperclass()) { - if (c == null) { - throw new RuntimeException("Illegal activity type: " + activity.getClass()); - } - String name = c.getName(); - if (name.equals("android.support.v4.app.FragmentActivity")) { - isSupport = true; - break; - } else if (name.startsWith("com.actionbarsherlock.app") - && (name.endsWith(".SherlockActivity") || name.endsWith(".SherlockListActivity") || name - .endsWith(".SherlockPreferenceActivity"))) { - throw new RuntimeException("Please use SherlockFragmentActivity. Illegal activity: " + name); - } else if (name.equals("android.app.Activity")) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { - throw new RuntimeException( - "Illegal activity without fragment support. Either use Android 3.0+ or android.support.v4.app.FragmentActivity."); - } - break; - } - } - return isSupport; - } - - protected static void checkLogException(ThrowableFailureEvent event) { - if (factory.config.logExceptions) { - String tag = factory.config.tagForLoggingExceptions; - if (tag == null) { - tag = EventBus.TAG; - } - Log.i(tag, "Error dialog manager received exception", event.throwable); - } - } - - private static boolean isInExecutionScope(Object executionScope, ThrowableFailureEvent event) { - if (event != null) { - Object eventExecutionScope = event.getExecutionScope(); - if (eventExecutionScope != null && !eventExecutionScope.equals(executionScope)) { - // Event not in our scope, do nothing - return false; - } - } - return true; - } - -} diff --git a/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java b/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java index 9b7b80b6..1b339fba 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java @@ -16,8 +16,7 @@ package org.greenrobot.eventbus.util; /** - * A generic failure event, which can be used by apps to propagate thrown exceptions. Also used in conjunction with - * {@link ErrorDialogManager}. + * A generic failure event, which can be used by apps to propagate thrown exceptions. */ public class ThrowableFailureEvent implements HasExecutionScope { protected final Throwable throwable; diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index ac036ae4..4ccdbb94 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -4,7 +4,8 @@ archivesBaseName = 'eventbus-annotation-processor' group = 'org.greenrobot' version = '3.2.0' -sourceCompatibility = 1.7 +java.sourceCompatibility = JavaVersion.VERSION_1_8 +java.targetCompatibility = JavaVersion.VERSION_1_8 dependencies { implementation project(':eventbus') diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 7123513f..6acf599c 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -1,11 +1,11 @@ buildscript { repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:3.5.3' + classpath 'com.android.tools.build:gradle:4.2.0' } } diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 22e77647..5a3b2a57 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -1,11 +1,11 @@ buildscript { repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:3.5.3' + classpath 'com.android.tools.build:gradle:4.2.0' } } diff --git a/EventBusTestJava/build.gradle b/EventBusTestJava/build.gradle index f19e3b19..ea5c4dd5 100644 --- a/EventBusTestJava/build.gradle +++ b/EventBusTestJava/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'java' -sourceCompatibility = 1.7 +java.sourceCompatibility = JavaVersion.VERSION_1_8 +java.targetCompatibility = JavaVersion.VERSION_1_8 // we have tests in the main source set so they can be shared with the Android test module // to make Gradle pick them up, add the dir to the test source set diff --git a/EventBusTestSubscriberInJar/build.gradle b/EventBusTestSubscriberInJar/build.gradle index b75da33b..b091c149 100644 --- a/EventBusTestSubscriberInJar/build.gradle +++ b/EventBusTestSubscriberInJar/build.gradle @@ -2,7 +2,8 @@ apply plugin: 'java' group = 'de.greenrobot' version = '3.0.0' -sourceCompatibility = 1.7 +java.sourceCompatibility = JavaVersion.VERSION_1_8 +java.targetCompatibility = JavaVersion.VERSION_1_8 configurations { provided diff --git a/build.gradle b/build.gradle index 543d3d9d..b29b352e 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,6 @@ buildscript { allprojects { repositories { - jcenter() mavenCentral() google() } @@ -21,5 +20,5 @@ if (JavaVersion.current().isJava8Compatible()) { } wrapper { - distributionType = org.gradle.api.tasks.wrapper.Wrapper.DistributionType.ALL + distributionType = Wrapper.DistributionType.ALL } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3a54a333..1f3fdbc5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 915357634a435ccf7324284335846c559a624d20 Mon Sep 17 00:00:00 2001 From: Andrei Dobrescu Date: Mon, 10 May 2021 16:46:34 +0300 Subject: [PATCH 249/288] android sdk proxy --- EventBus/build.gradle | 7 -- .../greenrobot/eventbus/EventBusBuilder.java | 21 +--- .../greenrobot/eventbus/HandlerPoster.java | 19 ++-- .../src/org/greenrobot/eventbus/Logger.java | 19 +--- .../eventbus/MainThreadSupport.java | 12 ++- .../eventbus/android/AndroidLogger.java | 39 +++----- .../eventbus/android/AndroidSDK.java | 97 +++++++++++++++++++ .../eventbus/meta/AbstractSubscriberInfo.java | 1 + .../util/ExceptionStackTraceUtils.java | 15 +++ 9 files changed, 150 insertions(+), 80 deletions(-) create mode 100644 EventBus/src/org/greenrobot/eventbus/android/AndroidSDK.java create mode 100644 EventBus/src/org/greenrobot/eventbus/util/ExceptionStackTraceUtils.java diff --git a/EventBus/build.gradle b/EventBus/build.gradle index af93b5f2..47456d58 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -6,13 +6,6 @@ version = '3.2.0' java.sourceCompatibility = JavaVersion.VERSION_1_8 java.targetCompatibility = JavaVersion.VERSION_1_8 -dependencies { - compileOnly 'com.google.android:android:4.1.1.4' - compileOnly 'com.google.android:android-test:4.1.1.4' - compileOnly 'com.google.android:annotations:4.1.1.4' - compileOnly 'com.google.android:support-v4:r7' -} - sourceSets { main { java { diff --git a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java index c091e05e..57a9f40a 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java @@ -15,11 +15,8 @@ */ package org.greenrobot.eventbus; -import android.os.Looper; - -import org.greenrobot.eventbus.android.AndroidLogger; +import org.greenrobot.eventbus.android.AndroidSDK; import org.greenrobot.eventbus.meta.SubscriberInfoIndex; - import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; @@ -165,24 +162,14 @@ Logger getLogger() { MainThreadSupport getMainThreadSupport() { if (mainThreadSupport != null) { return mainThreadSupport; - } else if (AndroidLogger.isAndroidLogAvailable()) { - Object looperOrNull = getAndroidMainLooperOrNull(); - return looperOrNull == null ? null : - new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull); + } else if (AndroidSDK.isAvailable()) { + return new MainThreadSupport.AndroidHandlerMainThreadSupport( + AndroidSDK.get().looper, AndroidSDK.get().systemClock); } else { return null; } } - static Object getAndroidMainLooperOrNull() { - try { - return Looper.getMainLooper(); - } catch (RuntimeException e) { - // Not really a functional Android (e.g. "Stub!" maven dependencies) - return null; - } - } - /** * Installs the default EventBus returned by {@link EventBus#getDefault()} using this builders' values. Must be * done only once before the first usage of the default EventBus. diff --git a/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java b/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java index 95309547..bd285432 100644 --- a/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java +++ b/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java @@ -15,21 +15,22 @@ */ package org.greenrobot.eventbus; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.SystemClock; +import org.greenrobot.eventbus.android.AndroidSDK; -public class HandlerPoster extends Handler implements Poster { +public class HandlerPoster extends AndroidSDK.Handler implements Poster { private final PendingPostQueue queue; private final int maxMillisInsideHandleMessage; + private final AndroidSDK.SystemClock systemClock; private final EventBus eventBus; private boolean handlerActive; - protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) { + protected HandlerPoster(EventBus eventBus, AndroidSDK.Looper looper, + AndroidSDK.SystemClock systemClock, + int maxMillisInsideHandleMessage) { super(looper); this.eventBus = eventBus; + this.systemClock = systemClock; this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage; queue = new PendingPostQueue(); } @@ -48,10 +49,10 @@ public void enqueue(Subscription subscription, Object event) { } @Override - public void handleMessage(Message msg) { + public void handleMessage(AndroidSDK.Message msg) { boolean rescheduled = false; try { - long started = SystemClock.uptimeMillis(); + long started = systemClock.uptimeMillis(); while (true) { PendingPost pendingPost = queue.poll(); if (pendingPost == null) { @@ -65,7 +66,7 @@ public void handleMessage(Message msg) { } } eventBus.invokeSubscriber(pendingPost); - long timeInMethod = SystemClock.uptimeMillis() - started; + long timeInMethod = systemClock.uptimeMillis() - started; if (timeInMethod >= maxMillisInsideHandleMessage) { if (!sendMessage(obtainMessage())) { throw new EventBusException("Could not send handler message"); diff --git a/EventBus/src/org/greenrobot/eventbus/Logger.java b/EventBus/src/org/greenrobot/eventbus/Logger.java index 69d1063a..cc7e5f43 100644 --- a/EventBus/src/org/greenrobot/eventbus/Logger.java +++ b/EventBus/src/org/greenrobot/eventbus/Logger.java @@ -15,9 +15,8 @@ */ package org.greenrobot.eventbus; -import android.os.Looper; import org.greenrobot.eventbus.android.AndroidLogger; - +import org.greenrobot.eventbus.android.AndroidSDK; import java.util.logging.Level; public interface Logger { @@ -64,19 +63,11 @@ public void log(Level level, String msg, Throwable th) { class Default { public static Logger get() { - // also check main looper to see if we have "good" Android classes (not Stubs etc.) - return AndroidLogger.isAndroidLogAvailable() && getAndroidMainLooperOrNull() != null - ? new AndroidLogger("EventBus") : - new Logger.SystemOutLogger(); - } - - static Object getAndroidMainLooperOrNull() { - try { - return Looper.getMainLooper(); - } catch (RuntimeException e) { - // Not really a functional Android (e.g. "Stub!" maven dependencies) - return null; + if (AndroidSDK.isAvailable()) { + return new AndroidLogger(AndroidSDK.get(), "EventBus"); } + + return new SystemOutLogger(); } } diff --git a/EventBus/src/org/greenrobot/eventbus/MainThreadSupport.java b/EventBus/src/org/greenrobot/eventbus/MainThreadSupport.java index d5655533..d45ace2f 100644 --- a/EventBus/src/org/greenrobot/eventbus/MainThreadSupport.java +++ b/EventBus/src/org/greenrobot/eventbus/MainThreadSupport.java @@ -15,7 +15,7 @@ */ package org.greenrobot.eventbus; -import android.os.Looper; +import org.greenrobot.eventbus.android.AndroidSDK; /** * Interface to the "main" thread, which can be whatever you like. Typically on Android, Android's main thread is used. @@ -28,20 +28,22 @@ public interface MainThreadSupport { class AndroidHandlerMainThreadSupport implements MainThreadSupport { - private final Looper looper; + private final AndroidSDK.Looper looper; + private final AndroidSDK.SystemClock systemClock; - public AndroidHandlerMainThreadSupport(Looper looper) { + public AndroidHandlerMainThreadSupport(AndroidSDK.Looper looper, AndroidSDK.SystemClock systemClock) { this.looper = looper; + this.systemClock = systemClock; } @Override public boolean isMainThread() { - return looper == Looper.myLooper(); + return looper == AndroidSDK.Looper.myLooper(); } @Override public Poster createPoster(EventBus eventBus) { - return new HandlerPoster(eventBus, looper, 10); + return new HandlerPoster(eventBus, looper, systemClock, 10); } } diff --git a/EventBus/src/org/greenrobot/eventbus/android/AndroidLogger.java b/EventBus/src/org/greenrobot/eventbus/android/AndroidLogger.java index fc14fe7d..f79a8893 100644 --- a/EventBus/src/org/greenrobot/eventbus/android/AndroidLogger.java +++ b/EventBus/src/org/greenrobot/eventbus/android/AndroidLogger.java @@ -15,47 +15,30 @@ */ package org.greenrobot.eventbus.android; -import android.util.Log; - import org.greenrobot.eventbus.Logger; - +import org.greenrobot.eventbus.util.ExceptionStackTraceUtils; import java.util.logging.Level; public class AndroidLogger implements Logger { - private static final boolean ANDROID_LOG_AVAILABLE; - - static { - boolean android = false; - try { - android = Class.forName("android.util.Log") != null; - } catch (ClassNotFoundException e) { - // OK - } - ANDROID_LOG_AVAILABLE = android; - } - - public static boolean isAndroidLogAvailable() { - return ANDROID_LOG_AVAILABLE; - } - - + private final AndroidSDK androidSDK; private final String tag; - public AndroidLogger(String tag) { + public AndroidLogger(AndroidSDK androidSDK, String tag) { + this.androidSDK = androidSDK; this.tag = tag; } public void log(Level level, String msg) { if (level != Level.OFF) { - Log.println(mapLevel(level), tag, msg); + androidSDK.log.println(mapLevel(level), tag, msg); } } public void log(Level level, String msg, Throwable th) { if (level != Level.OFF) { // That's how Log does it internally - Log.println(mapLevel(level), tag, msg + "\n" + Log.getStackTraceString(th)); + androidSDK.log.println(mapLevel(level), tag, msg + "\n" + ExceptionStackTraceUtils.getStackTraceAsString(th)); } } @@ -63,16 +46,16 @@ private int mapLevel(Level level) { int value = level.intValue(); if (value < 800) { // below INFO if (value < 500) { // below FINE - return Log.VERBOSE; + return androidSDK.log.getLogLevels().verbose; } else { - return Log.DEBUG; + return androidSDK.log.getLogLevels().debug; } } else if (value < 900) { // below WARNING - return Log.INFO; + return androidSDK.log.getLogLevels().info; } else if (value < 1000) { // below ERROR - return Log.WARN; + return androidSDK.log.getLogLevels().warn; } else { - return Log.ERROR; + return androidSDK.log.getLogLevels().error; } } } diff --git a/EventBus/src/org/greenrobot/eventbus/android/AndroidSDK.java b/EventBus/src/org/greenrobot/eventbus/android/AndroidSDK.java new file mode 100644 index 00000000..65e4a801 --- /dev/null +++ b/EventBus/src/org/greenrobot/eventbus/android/AndroidSDK.java @@ -0,0 +1,97 @@ +package org.greenrobot.eventbus.android; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +@SuppressWarnings("TryWithIdenticalCatches") +public final class AndroidSDK +{ + + private static final AndroidSDK implementation; + + static { + boolean isAndroidSDKAvailable = false; + + try { + Class looperClass = Class.forName("android.os.Looper"); + Method getMainLooper = looperClass.getDeclaredMethod("getMainLooper"); + Object mainLooper = getMainLooper.invoke(null); + isAndroidSDKAvailable = mainLooper != null; + } + catch (ClassNotFoundException ignored) {} + catch (NoSuchMethodException ignored) {} + catch (IllegalAccessException ignored) {} + catch (InvocationTargetException ignored) {} + + implementation = isAndroidSDKAvailable ? new AndroidSDK() : null; + } + + public static boolean isAvailable() { + return implementation != null; + } + + public static AndroidSDK get() { + return implementation; + } + + public final Log log = new Log(); + public static final class Log { + + //android.util.Log + //public static int println(int priority, java.lang.String tag, java.lang.String msg) { throw new RuntimeException("Stub!"); } + public void println(int priority, String tag, String msg) { + } + + public LogLevels getLogLevels() { + return new LogLevels(); + } + + public static final class LogLevels { + + public int verbose = 0; + public int debug = 0; + public int info = 0; + public int warn = 0; + public int error = 0; + } + } + + public final Looper looper = new Looper(); + public static final class Looper { + + public static Looper myLooper() { + return null; + } + } + + public static class Handler { + + public Handler(Looper looper) { + + } + + public Message obtainMessage() { + return new Message(); + } + + public boolean sendMessage(Message message) { + return true; + } + + public void handleMessage(Message message) { + + } + } + + public static class Message { + + } + + public final SystemClock systemClock = new SystemClock(); + public static class SystemClock { + + public long uptimeMillis() { + return 0; + } + } +} diff --git a/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java index 9020c24b..c6432d49 100644 --- a/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java @@ -22,6 +22,7 @@ import java.lang.reflect.Method; /** Base class for generated subscriber meta info classes created by annotation processing. */ +@SuppressWarnings({ "rawtypes", "TryWithIdenticalCatches", "unchecked" }) public abstract class AbstractSubscriberInfo implements SubscriberInfo { private final Class subscriberClass; private final Class superSubscriberInfoClass; diff --git a/EventBus/src/org/greenrobot/eventbus/util/ExceptionStackTraceUtils.java b/EventBus/src/org/greenrobot/eventbus/util/ExceptionStackTraceUtils.java new file mode 100644 index 00000000..4d0e1cae --- /dev/null +++ b/EventBus/src/org/greenrobot/eventbus/util/ExceptionStackTraceUtils.java @@ -0,0 +1,15 @@ +package org.greenrobot.eventbus.util; + +import java.io.PrintWriter; +import java.io.StringWriter; + +public class ExceptionStackTraceUtils { + + public static String getStackTraceAsString(Throwable ex) { + + StringWriter stringWriter = new StringWriter(); + PrintWriter printWriter = new PrintWriter(stringWriter); + ex.printStackTrace(printWriter); + return stringWriter.toString(); + } +} From b8a44d8b59b31080971b9ca6a2fb33796bc742d6 Mon Sep 17 00:00:00 2001 From: Andrei Dobrescu Date: Mon, 10 May 2021 18:01:06 +0300 Subject: [PATCH 250/288] android sdk proxy implementation --- .../src/org/greenrobot/eventbus/EventBus.java | 8 ++ .../greenrobot/eventbus/EventBusBuilder.java | 7 +- .../src/org/greenrobot/eventbus/Logger.java | 6 +- .../eventbus/MainThreadSupport.java | 24 ----- .../src/org/greenrobot/eventbus/Poster.java | 2 +- .../android/AndroidDependenciesDetector.java | 46 +++++++++ .../eventbus/android/AndroidLogger.java | 14 +-- .../eventbus/android/AndroidSDK.java | 97 ------------------- .../eventbus/android/AndroidSDKProxy.java | 41 ++++++++ EventBusPerformance/build.gradle | 1 + EventBusTest/build.gradle | 1 + .../eventbus/AndroidSDKProxyTest.java | 16 +++ .../eventbus/AndroidSDKAvailabilityTest.java | 16 +++ .../eventbus/EventBusBuilderTest.java | 1 - eventbus-android/.gitignore | 1 + eventbus-android/build.gradle | 29 ++++++ eventbus-android/consumer-rules.pro | 0 eventbus-android/proguard-rules.pro | 21 ++++ eventbus-android/src/main/AndroidManifest.xml | 4 + .../greenrobot/eventbus/HandlerPoster.java | 19 ++-- .../eventbus/android/AndroidLogProxyImpl.java | 36 +++++++ .../eventbus/android/AndroidSDKProxyImpl.java | 8 ++ .../DefaultAndroidMainThreadSupport.java | 20 ++++ settings.gradle | 3 +- 24 files changed, 273 insertions(+), 148 deletions(-) create mode 100644 EventBus/src/org/greenrobot/eventbus/android/AndroidDependenciesDetector.java delete mode 100644 EventBus/src/org/greenrobot/eventbus/android/AndroidSDK.java create mode 100644 EventBus/src/org/greenrobot/eventbus/android/AndroidSDKProxy.java create mode 100644 EventBusTest/src/org/greenrobot/eventbus/AndroidSDKProxyTest.java create mode 100644 EventBusTestJava/src/main/java/org/greenrobot/eventbus/AndroidSDKAvailabilityTest.java create mode 100644 eventbus-android/.gitignore create mode 100644 eventbus-android/build.gradle create mode 100644 eventbus-android/consumer-rules.pro create mode 100644 eventbus-android/proguard-rules.pro create mode 100644 eventbus-android/src/main/AndroidManifest.xml rename {EventBus/src => eventbus-android/src/main/java}/org/greenrobot/eventbus/HandlerPoster.java (81%) create mode 100644 eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidLogProxyImpl.java create mode 100644 eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidSDKProxyImpl.java create mode 100644 eventbus-android/src/main/java/org/greenrobot/eventbus/android/DefaultAndroidMainThreadSupport.java diff --git a/EventBus/src/org/greenrobot/eventbus/EventBus.java b/EventBus/src/org/greenrobot/eventbus/EventBus.java index aa6c5981..9bf7d0b3 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBus.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBus.java @@ -15,6 +15,7 @@ */ package org.greenrobot.eventbus; +import org.greenrobot.eventbus.android.AndroidDependenciesDetector; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; @@ -139,6 +140,13 @@ public EventBus() { * ThreadMode} and priority. */ public void register(Object subscriber) { + + if (AndroidDependenciesDetector.isAndroidSDKAvailable() && !AndroidDependenciesDetector.isAndroidSDKProxyImplAvailable()) { + //should crash user's app if the user (developer) has not imported the android compatibility library + throw new RuntimeException("Looks like you are using the latest version of EventBus on Android " + + "without importing the EventBus for Android compatibility library. Please import it on app/build.gradle!"); + } + Class subscriberClass = subscriber.getClass(); List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { diff --git a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java index 57a9f40a..a42277d6 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java @@ -15,7 +15,7 @@ */ package org.greenrobot.eventbus; -import org.greenrobot.eventbus.android.AndroidSDK; +import org.greenrobot.eventbus.android.AndroidSDKProxy; import org.greenrobot.eventbus.meta.SubscriberInfoIndex; import java.util.ArrayList; import java.util.List; @@ -162,9 +162,8 @@ Logger getLogger() { MainThreadSupport getMainThreadSupport() { if (mainThreadSupport != null) { return mainThreadSupport; - } else if (AndroidSDK.isAvailable()) { - return new MainThreadSupport.AndroidHandlerMainThreadSupport( - AndroidSDK.get().looper, AndroidSDK.get().systemClock); + } else if (AndroidSDKProxy.isAvailable()) { + return AndroidSDKProxy.get().defaultMainThreadSupport; } else { return null; } diff --git a/EventBus/src/org/greenrobot/eventbus/Logger.java b/EventBus/src/org/greenrobot/eventbus/Logger.java index cc7e5f43..24a6a1cd 100644 --- a/EventBus/src/org/greenrobot/eventbus/Logger.java +++ b/EventBus/src/org/greenrobot/eventbus/Logger.java @@ -16,7 +16,7 @@ package org.greenrobot.eventbus; import org.greenrobot.eventbus.android.AndroidLogger; -import org.greenrobot.eventbus.android.AndroidSDK; +import org.greenrobot.eventbus.android.AndroidSDKProxy; import java.util.logging.Level; public interface Logger { @@ -63,8 +63,8 @@ public void log(Level level, String msg, Throwable th) { class Default { public static Logger get() { - if (AndroidSDK.isAvailable()) { - return new AndroidLogger(AndroidSDK.get(), "EventBus"); + if (AndroidSDKProxy.isAvailable()) { + return new AndroidLogger(AndroidSDKProxy.get(), "EventBus"); } return new SystemOutLogger(); diff --git a/EventBus/src/org/greenrobot/eventbus/MainThreadSupport.java b/EventBus/src/org/greenrobot/eventbus/MainThreadSupport.java index d45ace2f..22605811 100644 --- a/EventBus/src/org/greenrobot/eventbus/MainThreadSupport.java +++ b/EventBus/src/org/greenrobot/eventbus/MainThreadSupport.java @@ -15,8 +15,6 @@ */ package org.greenrobot.eventbus; -import org.greenrobot.eventbus.android.AndroidSDK; - /** * Interface to the "main" thread, which can be whatever you like. Typically on Android, Android's main thread is used. */ @@ -25,26 +23,4 @@ public interface MainThreadSupport { boolean isMainThread(); Poster createPoster(EventBus eventBus); - - class AndroidHandlerMainThreadSupport implements MainThreadSupport { - - private final AndroidSDK.Looper looper; - private final AndroidSDK.SystemClock systemClock; - - public AndroidHandlerMainThreadSupport(AndroidSDK.Looper looper, AndroidSDK.SystemClock systemClock) { - this.looper = looper; - this.systemClock = systemClock; - } - - @Override - public boolean isMainThread() { - return looper == AndroidSDK.Looper.myLooper(); - } - - @Override - public Poster createPoster(EventBus eventBus) { - return new HandlerPoster(eventBus, looper, systemClock, 10); - } - } - } diff --git a/EventBus/src/org/greenrobot/eventbus/Poster.java b/EventBus/src/org/greenrobot/eventbus/Poster.java index a69a078d..67cfd67c 100644 --- a/EventBus/src/org/greenrobot/eventbus/Poster.java +++ b/EventBus/src/org/greenrobot/eventbus/Poster.java @@ -20,7 +20,7 @@ * * @author William Ferguson */ -interface Poster { +public interface Poster { /** * Enqueue an event to be posted for a particular subscription. diff --git a/EventBus/src/org/greenrobot/eventbus/android/AndroidDependenciesDetector.java b/EventBus/src/org/greenrobot/eventbus/android/AndroidDependenciesDetector.java new file mode 100644 index 00000000..fe7f125c --- /dev/null +++ b/EventBus/src/org/greenrobot/eventbus/android/AndroidDependenciesDetector.java @@ -0,0 +1,46 @@ +package org.greenrobot.eventbus.android; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +@SuppressWarnings("TryWithIdenticalCatches") +public class AndroidDependenciesDetector { + + public static boolean isAndroidSDKAvailable() { + + try { + Class looperClass = Class.forName("android.os.Looper"); + Method getMainLooper = looperClass.getDeclaredMethod("getMainLooper"); + Object mainLooper = getMainLooper.invoke(null); + return mainLooper != null; + } + catch (ClassNotFoundException ignored) {} + catch (NoSuchMethodException ignored) {} + catch (IllegalAccessException ignored) {} + catch (InvocationTargetException ignored) {} + + return false; + } + + public static boolean isAndroidSDKProxyImplAvailable() { + + try { + Class.forName("org.greenrobot.eventbus.android.AndroidSDKProxyImpl"); + return true; + } + catch (ClassNotFoundException ex) { + return false; + } + } + + public static AndroidSDKProxy instantiateAndroidSDKProxy() { + + try { + Class impl = Class.forName("org.greenrobot.eventbus.android.AndroidSDKProxyImpl"); + return (AndroidSDKProxy) impl.getConstructor().newInstance(); + } + catch (Throwable ex) { + return null; + } + } +} diff --git a/EventBus/src/org/greenrobot/eventbus/android/AndroidLogger.java b/EventBus/src/org/greenrobot/eventbus/android/AndroidLogger.java index f79a8893..15f5e29d 100644 --- a/EventBus/src/org/greenrobot/eventbus/android/AndroidLogger.java +++ b/EventBus/src/org/greenrobot/eventbus/android/AndroidLogger.java @@ -21,10 +21,10 @@ public class AndroidLogger implements Logger { - private final AndroidSDK androidSDK; + private final AndroidSDKProxy androidSDK; private final String tag; - public AndroidLogger(AndroidSDK androidSDK, String tag) { + public AndroidLogger(AndroidSDKProxy androidSDK, String tag) { this.androidSDK = androidSDK; this.tag = tag; } @@ -46,16 +46,16 @@ private int mapLevel(Level level) { int value = level.intValue(); if (value < 800) { // below INFO if (value < 500) { // below FINE - return androidSDK.log.getLogLevels().verbose; + return androidSDK.log.getVerboseLevelId(); } else { - return androidSDK.log.getLogLevels().debug; + return androidSDK.log.getDebugLevelId(); } } else if (value < 900) { // below WARNING - return androidSDK.log.getLogLevels().info; + return androidSDK.log.getInfoLevelId(); } else if (value < 1000) { // below ERROR - return androidSDK.log.getLogLevels().warn; + return androidSDK.log.getWarnLevelId(); } else { - return androidSDK.log.getLogLevels().error; + return androidSDK.log.getErrorLevelId(); } } } diff --git a/EventBus/src/org/greenrobot/eventbus/android/AndroidSDK.java b/EventBus/src/org/greenrobot/eventbus/android/AndroidSDK.java deleted file mode 100644 index 65e4a801..00000000 --- a/EventBus/src/org/greenrobot/eventbus/android/AndroidSDK.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.greenrobot.eventbus.android; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -@SuppressWarnings("TryWithIdenticalCatches") -public final class AndroidSDK -{ - - private static final AndroidSDK implementation; - - static { - boolean isAndroidSDKAvailable = false; - - try { - Class looperClass = Class.forName("android.os.Looper"); - Method getMainLooper = looperClass.getDeclaredMethod("getMainLooper"); - Object mainLooper = getMainLooper.invoke(null); - isAndroidSDKAvailable = mainLooper != null; - } - catch (ClassNotFoundException ignored) {} - catch (NoSuchMethodException ignored) {} - catch (IllegalAccessException ignored) {} - catch (InvocationTargetException ignored) {} - - implementation = isAndroidSDKAvailable ? new AndroidSDK() : null; - } - - public static boolean isAvailable() { - return implementation != null; - } - - public static AndroidSDK get() { - return implementation; - } - - public final Log log = new Log(); - public static final class Log { - - //android.util.Log - //public static int println(int priority, java.lang.String tag, java.lang.String msg) { throw new RuntimeException("Stub!"); } - public void println(int priority, String tag, String msg) { - } - - public LogLevels getLogLevels() { - return new LogLevels(); - } - - public static final class LogLevels { - - public int verbose = 0; - public int debug = 0; - public int info = 0; - public int warn = 0; - public int error = 0; - } - } - - public final Looper looper = new Looper(); - public static final class Looper { - - public static Looper myLooper() { - return null; - } - } - - public static class Handler { - - public Handler(Looper looper) { - - } - - public Message obtainMessage() { - return new Message(); - } - - public boolean sendMessage(Message message) { - return true; - } - - public void handleMessage(Message message) { - - } - } - - public static class Message { - - } - - public final SystemClock systemClock = new SystemClock(); - public static class SystemClock { - - public long uptimeMillis() { - return 0; - } - } -} diff --git a/EventBus/src/org/greenrobot/eventbus/android/AndroidSDKProxy.java b/EventBus/src/org/greenrobot/eventbus/android/AndroidSDKProxy.java new file mode 100644 index 00000000..ce56f99e --- /dev/null +++ b/EventBus/src/org/greenrobot/eventbus/android/AndroidSDKProxy.java @@ -0,0 +1,41 @@ +package org.greenrobot.eventbus.android; + +import org.greenrobot.eventbus.MainThreadSupport; + +public abstract class AndroidSDKProxy { + + private static final AndroidSDKProxy implementation; + + static { + implementation = AndroidDependenciesDetector.isAndroidSDKAvailable() + ? AndroidDependenciesDetector.instantiateAndroidSDKProxy() + : null; + } + + public static boolean isAvailable() { + return implementation != null; + } + + public static AndroidSDKProxy get() { + return implementation; + } + + public final LogProxy log; + public final MainThreadSupport defaultMainThreadSupport; + + public AndroidSDKProxy(LogProxy log, MainThreadSupport defaultMainThreadSupport) { + this.log = log; + this.defaultMainThreadSupport = defaultMainThreadSupport; + } + + interface LogProxy { + + void println(int priority, String tag, String msg); + + int getVerboseLevelId(); + int getDebugLevelId(); + int getInfoLevelId(); + int getWarnLevelId(); + int getErrorLevelId(); + } +} diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 6acf599c..0a51db7a 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -13,6 +13,7 @@ apply plugin: 'com.android.application' dependencies { implementation project(':eventbus') + implementation project(':eventbus-android') annotationProcessor project(':eventbus-annotation-processor') implementation 'com.squareup:otto:1.3.8' } diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 5a3b2a57..740389ad 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -13,6 +13,7 @@ apply plugin: 'com.android.application' dependencies { androidTestImplementation project(':eventbus') + androidTestImplementation project(':eventbus-android') androidTestImplementation project(':EventBusTestJava') androidTestAnnotationProcessor project(':eventbus-annotation-processor') // Trying to repro bug: diff --git a/EventBusTest/src/org/greenrobot/eventbus/AndroidSDKProxyTest.java b/EventBusTest/src/org/greenrobot/eventbus/AndroidSDKProxyTest.java new file mode 100644 index 00000000..7383d00b --- /dev/null +++ b/EventBusTest/src/org/greenrobot/eventbus/AndroidSDKProxyTest.java @@ -0,0 +1,16 @@ +package org.greenrobot.eventbus; + +import org.greenrobot.eventbus.android.AndroidSDKProxy; +import org.junit.Test; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class AndroidSDKProxyTest { + + @Test + public void shouldBeAvailable() { + assertTrue(AndroidSDKProxy.isAvailable()); + assertNotNull(AndroidSDKProxy.get()); + } +} diff --git a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AndroidSDKAvailabilityTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AndroidSDKAvailabilityTest.java new file mode 100644 index 00000000..f35a7b05 --- /dev/null +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AndroidSDKAvailabilityTest.java @@ -0,0 +1,16 @@ +package org.greenrobot.eventbus; + +import org.greenrobot.eventbus.android.AndroidSDKProxy; +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; + +public class AndroidSDKAvailabilityTest { + + @Test + public void shouldNotBeAvailable() { + assertFalse(AndroidSDKProxy.isAvailable()); + assertNull(AndroidSDKProxy.get()); + } +} diff --git a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusBuilderTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusBuilderTest.java index 05a60362..16f13255 100644 --- a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusBuilderTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusBuilderTest.java @@ -18,7 +18,6 @@ import org.junit.Assert; import org.junit.Test; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; /** diff --git a/eventbus-android/.gitignore b/eventbus-android/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/eventbus-android/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/eventbus-android/build.gradle b/eventbus-android/build.gradle new file mode 100644 index 00000000..e20de7a2 --- /dev/null +++ b/eventbus-android/build.gradle @@ -0,0 +1,29 @@ +buildscript { + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:4.2.0' + } +} + +apply plugin: 'com.android.library' + +android { + compileSdkVersion 30 + + defaultConfig { + minSdkVersion 7 + targetSdkVersion 30 + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + implementation project(":eventbus") +} diff --git a/eventbus-android/consumer-rules.pro b/eventbus-android/consumer-rules.pro new file mode 100644 index 00000000..e69de29b diff --git a/eventbus-android/proguard-rules.pro b/eventbus-android/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/eventbus-android/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/eventbus-android/src/main/AndroidManifest.xml b/eventbus-android/src/main/AndroidManifest.xml new file mode 100644 index 00000000..e4f0b52b --- /dev/null +++ b/eventbus-android/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java b/eventbus-android/src/main/java/org/greenrobot/eventbus/HandlerPoster.java similarity index 81% rename from EventBus/src/org/greenrobot/eventbus/HandlerPoster.java rename to eventbus-android/src/main/java/org/greenrobot/eventbus/HandlerPoster.java index bd285432..71158e2d 100644 --- a/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java +++ b/eventbus-android/src/main/java/org/greenrobot/eventbus/HandlerPoster.java @@ -15,22 +15,21 @@ */ package org.greenrobot.eventbus; -import org.greenrobot.eventbus.android.AndroidSDK; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.SystemClock; -public class HandlerPoster extends AndroidSDK.Handler implements Poster { +public class HandlerPoster extends Handler implements Poster { private final PendingPostQueue queue; private final int maxMillisInsideHandleMessage; - private final AndroidSDK.SystemClock systemClock; private final EventBus eventBus; private boolean handlerActive; - protected HandlerPoster(EventBus eventBus, AndroidSDK.Looper looper, - AndroidSDK.SystemClock systemClock, - int maxMillisInsideHandleMessage) { + public HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) { super(looper); this.eventBus = eventBus; - this.systemClock = systemClock; this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage; queue = new PendingPostQueue(); } @@ -49,10 +48,10 @@ public void enqueue(Subscription subscription, Object event) { } @Override - public void handleMessage(AndroidSDK.Message msg) { + public void handleMessage(Message msg) { boolean rescheduled = false; try { - long started = systemClock.uptimeMillis(); + long started = SystemClock.uptimeMillis(); while (true) { PendingPost pendingPost = queue.poll(); if (pendingPost == null) { @@ -66,7 +65,7 @@ public void handleMessage(AndroidSDK.Message msg) { } } eventBus.invokeSubscriber(pendingPost); - long timeInMethod = systemClock.uptimeMillis() - started; + long timeInMethod = SystemClock.uptimeMillis() - started; if (timeInMethod >= maxMillisInsideHandleMessage) { if (!sendMessage(obtainMessage())) { throw new EventBusException("Could not send handler message"); diff --git a/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidLogProxyImpl.java b/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidLogProxyImpl.java new file mode 100644 index 00000000..65dc06ec --- /dev/null +++ b/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidLogProxyImpl.java @@ -0,0 +1,36 @@ +package org.greenrobot.eventbus.android; + +import android.util.Log; + +public class AndroidLogProxyImpl implements AndroidSDKProxy.LogProxy { + + @Override + public void println(int priority, String tag, String msg) { + Log.println(priority, tag, msg); + } + + @Override + public int getVerboseLevelId() { + return Log.VERBOSE; + } + + @Override + public int getDebugLevelId() { + return Log.DEBUG; + } + + @Override + public int getInfoLevelId() { + return Log.INFO; + } + + @Override + public int getWarnLevelId() { + return Log.WARN; + } + + @Override + public int getErrorLevelId() { + return Log.ERROR; + } +} diff --git a/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidSDKProxyImpl.java b/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidSDKProxyImpl.java new file mode 100644 index 00000000..40a80b25 --- /dev/null +++ b/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidSDKProxyImpl.java @@ -0,0 +1,8 @@ +package org.greenrobot.eventbus.android; + +public class AndroidSDKProxyImpl extends AndroidSDKProxy { + + public AndroidSDKProxyImpl() { + super(new AndroidLogProxyImpl(), new DefaultAndroidMainThreadSupport()); + } +} diff --git a/eventbus-android/src/main/java/org/greenrobot/eventbus/android/DefaultAndroidMainThreadSupport.java b/eventbus-android/src/main/java/org/greenrobot/eventbus/android/DefaultAndroidMainThreadSupport.java new file mode 100644 index 00000000..13339465 --- /dev/null +++ b/eventbus-android/src/main/java/org/greenrobot/eventbus/android/DefaultAndroidMainThreadSupport.java @@ -0,0 +1,20 @@ +package org.greenrobot.eventbus.android; + +import android.os.Looper; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.HandlerPoster; +import org.greenrobot.eventbus.MainThreadSupport; +import org.greenrobot.eventbus.Poster; + +public class DefaultAndroidMainThreadSupport implements MainThreadSupport { + + @Override + public boolean isMainThread() { + return true; + } + + @Override + public Poster createPoster(EventBus eventBus) { + return new HandlerPoster(eventBus, Looper.getMainLooper(), 10); + } +} diff --git a/settings.gradle b/settings.gradle index c25cd47e..44670236 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,6 +4,7 @@ include ':EventBusTestJava' include ':EventBusTest' include ':EventBusTestSubscriberInJar' include ':EventBusPerformance' +include ':eventbus-android' project(":EventBus").name = "eventbus" -project(":EventBusAnnotationProcessor").name = "eventbus-annotation-processor" \ No newline at end of file +project(":EventBusAnnotationProcessor").name = "eventbus-annotation-processor" From 21c6b5602100ef03489502080b6f74edd61e1a53 Mon Sep 17 00:00:00 2001 From: Andrei Dobrescu Date: Mon, 10 May 2021 18:59:12 +0300 Subject: [PATCH 251/288] refactorings --- .../src/org/greenrobot/eventbus/EventBus.java | 2 +- .../greenrobot/eventbus/EventBusBuilder.java | 6 +-- .../src/org/greenrobot/eventbus/Logger.java | 7 ++-- .../eventbus/android/AndroidComponents.java | 31 ++++++++++++++ .../android/AndroidDependenciesDetector.java | 12 +++--- .../eventbus/android/AndroidSDKProxy.java | 41 ------------------- .../AndroidComponentsAvailabilityTest.java | 16 ++++++++ .../eventbus/AndroidSDKProxyTest.java | 16 -------- ...droidComponentsAvailabilityOnJavaTest.java | 17 ++++++++ .../eventbus/AndroidSDKAvailabilityTest.java | 16 -------- .../android/AndroidComponentsImpl.java | 8 ++++ .../eventbus/android/AndroidLogProxyImpl.java | 36 ---------------- .../eventbus/android/AndroidLogger.java | 19 ++++----- .../eventbus/android/AndroidSDKProxyImpl.java | 8 ---- 14 files changed, 95 insertions(+), 140 deletions(-) create mode 100644 EventBus/src/org/greenrobot/eventbus/android/AndroidComponents.java delete mode 100644 EventBus/src/org/greenrobot/eventbus/android/AndroidSDKProxy.java create mode 100644 EventBusTest/src/org/greenrobot/eventbus/AndroidComponentsAvailabilityTest.java delete mode 100644 EventBusTest/src/org/greenrobot/eventbus/AndroidSDKProxyTest.java create mode 100644 EventBusTestJava/src/main/java/org/greenrobot/eventbus/AndroidComponentsAvailabilityOnJavaTest.java delete mode 100644 EventBusTestJava/src/main/java/org/greenrobot/eventbus/AndroidSDKAvailabilityTest.java create mode 100644 eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidComponentsImpl.java delete mode 100644 eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidLogProxyImpl.java rename {EventBus/src => eventbus-android/src/main/java}/org/greenrobot/eventbus/android/AndroidLogger.java (71%) delete mode 100644 eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidSDKProxyImpl.java diff --git a/EventBus/src/org/greenrobot/eventbus/EventBus.java b/EventBus/src/org/greenrobot/eventbus/EventBus.java index 9bf7d0b3..25f93823 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBus.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBus.java @@ -141,7 +141,7 @@ public EventBus() { */ public void register(Object subscriber) { - if (AndroidDependenciesDetector.isAndroidSDKAvailable() && !AndroidDependenciesDetector.isAndroidSDKProxyImplAvailable()) { + if (AndroidDependenciesDetector.isAndroidSDKAvailable() && !AndroidDependenciesDetector.areAndroidComponentsAvailable()) { //should crash user's app if the user (developer) has not imported the android compatibility library throw new RuntimeException("Looks like you are using the latest version of EventBus on Android " + "without importing the EventBus for Android compatibility library. Please import it on app/build.gradle!"); diff --git a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java index a42277d6..ff4a5f80 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java @@ -15,7 +15,7 @@ */ package org.greenrobot.eventbus; -import org.greenrobot.eventbus.android.AndroidSDKProxy; +import org.greenrobot.eventbus.android.AndroidComponents; import org.greenrobot.eventbus.meta.SubscriberInfoIndex; import java.util.ArrayList; import java.util.List; @@ -162,8 +162,8 @@ Logger getLogger() { MainThreadSupport getMainThreadSupport() { if (mainThreadSupport != null) { return mainThreadSupport; - } else if (AndroidSDKProxy.isAvailable()) { - return AndroidSDKProxy.get().defaultMainThreadSupport; + } else if (AndroidComponents.areAvailable()) { + return AndroidComponents.get().defaultMainThreadSupport; } else { return null; } diff --git a/EventBus/src/org/greenrobot/eventbus/Logger.java b/EventBus/src/org/greenrobot/eventbus/Logger.java index 24a6a1cd..e9ec8e88 100644 --- a/EventBus/src/org/greenrobot/eventbus/Logger.java +++ b/EventBus/src/org/greenrobot/eventbus/Logger.java @@ -15,8 +15,7 @@ */ package org.greenrobot.eventbus; -import org.greenrobot.eventbus.android.AndroidLogger; -import org.greenrobot.eventbus.android.AndroidSDKProxy; +import org.greenrobot.eventbus.android.AndroidComponents; import java.util.logging.Level; public interface Logger { @@ -63,8 +62,8 @@ public void log(Level level, String msg, Throwable th) { class Default { public static Logger get() { - if (AndroidSDKProxy.isAvailable()) { - return new AndroidLogger(AndroidSDKProxy.get(), "EventBus"); + if (AndroidComponents.areAvailable()) { + return AndroidComponents.get().logger; } return new SystemOutLogger(); diff --git a/EventBus/src/org/greenrobot/eventbus/android/AndroidComponents.java b/EventBus/src/org/greenrobot/eventbus/android/AndroidComponents.java new file mode 100644 index 00000000..7138b6d9 --- /dev/null +++ b/EventBus/src/org/greenrobot/eventbus/android/AndroidComponents.java @@ -0,0 +1,31 @@ +package org.greenrobot.eventbus.android; + +import org.greenrobot.eventbus.Logger; +import org.greenrobot.eventbus.MainThreadSupport; + +public abstract class AndroidComponents { + + private static final AndroidComponents implementation; + + static { + implementation = AndroidDependenciesDetector.isAndroidSDKAvailable() + ? AndroidDependenciesDetector.instantiateAndroidComponents() + : null; + } + + public static boolean areAvailable() { + return implementation != null; + } + + public static AndroidComponents get() { + return implementation; + } + + public final Logger logger; + public final MainThreadSupport defaultMainThreadSupport; + + public AndroidComponents(Logger logger, MainThreadSupport defaultMainThreadSupport) { + this.logger = logger; + this.defaultMainThreadSupport = defaultMainThreadSupport; + } +} diff --git a/EventBus/src/org/greenrobot/eventbus/android/AndroidDependenciesDetector.java b/EventBus/src/org/greenrobot/eventbus/android/AndroidDependenciesDetector.java index fe7f125c..1783f143 100644 --- a/EventBus/src/org/greenrobot/eventbus/android/AndroidDependenciesDetector.java +++ b/EventBus/src/org/greenrobot/eventbus/android/AndroidDependenciesDetector.java @@ -22,10 +22,12 @@ public static boolean isAndroidSDKAvailable() { return false; } - public static boolean isAndroidSDKProxyImplAvailable() { + private static final String ANDROID_COMPONENTS_IMPLEMENTATION_CLASS_NAME = "org.greenrobot.eventbus.android.AndroidComponentsImpl"; + + public static boolean areAndroidComponentsAvailable() { try { - Class.forName("org.greenrobot.eventbus.android.AndroidSDKProxyImpl"); + Class.forName(ANDROID_COMPONENTS_IMPLEMENTATION_CLASS_NAME); return true; } catch (ClassNotFoundException ex) { @@ -33,11 +35,11 @@ public static boolean isAndroidSDKProxyImplAvailable() { } } - public static AndroidSDKProxy instantiateAndroidSDKProxy() { + public static AndroidComponents instantiateAndroidComponents() { try { - Class impl = Class.forName("org.greenrobot.eventbus.android.AndroidSDKProxyImpl"); - return (AndroidSDKProxy) impl.getConstructor().newInstance(); + Class impl = Class.forName(ANDROID_COMPONENTS_IMPLEMENTATION_CLASS_NAME); + return (AndroidComponents) impl.getConstructor().newInstance(); } catch (Throwable ex) { return null; diff --git a/EventBus/src/org/greenrobot/eventbus/android/AndroidSDKProxy.java b/EventBus/src/org/greenrobot/eventbus/android/AndroidSDKProxy.java deleted file mode 100644 index ce56f99e..00000000 --- a/EventBus/src/org/greenrobot/eventbus/android/AndroidSDKProxy.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.greenrobot.eventbus.android; - -import org.greenrobot.eventbus.MainThreadSupport; - -public abstract class AndroidSDKProxy { - - private static final AndroidSDKProxy implementation; - - static { - implementation = AndroidDependenciesDetector.isAndroidSDKAvailable() - ? AndroidDependenciesDetector.instantiateAndroidSDKProxy() - : null; - } - - public static boolean isAvailable() { - return implementation != null; - } - - public static AndroidSDKProxy get() { - return implementation; - } - - public final LogProxy log; - public final MainThreadSupport defaultMainThreadSupport; - - public AndroidSDKProxy(LogProxy log, MainThreadSupport defaultMainThreadSupport) { - this.log = log; - this.defaultMainThreadSupport = defaultMainThreadSupport; - } - - interface LogProxy { - - void println(int priority, String tag, String msg); - - int getVerboseLevelId(); - int getDebugLevelId(); - int getInfoLevelId(); - int getWarnLevelId(); - int getErrorLevelId(); - } -} diff --git a/EventBusTest/src/org/greenrobot/eventbus/AndroidComponentsAvailabilityTest.java b/EventBusTest/src/org/greenrobot/eventbus/AndroidComponentsAvailabilityTest.java new file mode 100644 index 00000000..15ae3d80 --- /dev/null +++ b/EventBusTest/src/org/greenrobot/eventbus/AndroidComponentsAvailabilityTest.java @@ -0,0 +1,16 @@ +package org.greenrobot.eventbus; + +import org.greenrobot.eventbus.android.AndroidComponents; +import org.junit.Test; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class AndroidComponentsAvailabilityTest { + + @Test + public void shouldBeAvailable() { + assertTrue(AndroidComponents.areAvailable()); + assertNotNull(AndroidComponents.get()); + } +} diff --git a/EventBusTest/src/org/greenrobot/eventbus/AndroidSDKProxyTest.java b/EventBusTest/src/org/greenrobot/eventbus/AndroidSDKProxyTest.java deleted file mode 100644 index 7383d00b..00000000 --- a/EventBusTest/src/org/greenrobot/eventbus/AndroidSDKProxyTest.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.greenrobot.eventbus; - -import org.greenrobot.eventbus.android.AndroidSDKProxy; -import org.junit.Test; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -public class AndroidSDKProxyTest { - - @Test - public void shouldBeAvailable() { - assertTrue(AndroidSDKProxy.isAvailable()); - assertNotNull(AndroidSDKProxy.get()); - } -} diff --git a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AndroidComponentsAvailabilityOnJavaTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AndroidComponentsAvailabilityOnJavaTest.java new file mode 100644 index 00000000..cc2e69ff --- /dev/null +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AndroidComponentsAvailabilityOnJavaTest.java @@ -0,0 +1,17 @@ +package org.greenrobot.eventbus; + +import org.greenrobot.eventbus.android.AndroidComponents; +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; + +public class AndroidComponentsAvailabilityOnJavaTest +{ + + @Test + public void shouldNotBeAvailable() { + assertFalse(AndroidComponents.areAvailable()); + assertNull(AndroidComponents.get()); + } +} diff --git a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AndroidSDKAvailabilityTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AndroidSDKAvailabilityTest.java deleted file mode 100644 index f35a7b05..00000000 --- a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AndroidSDKAvailabilityTest.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.greenrobot.eventbus; - -import org.greenrobot.eventbus.android.AndroidSDKProxy; -import org.junit.Test; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; - -public class AndroidSDKAvailabilityTest { - - @Test - public void shouldNotBeAvailable() { - assertFalse(AndroidSDKProxy.isAvailable()); - assertNull(AndroidSDKProxy.get()); - } -} diff --git a/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidComponentsImpl.java b/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidComponentsImpl.java new file mode 100644 index 00000000..afcb4af0 --- /dev/null +++ b/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidComponentsImpl.java @@ -0,0 +1,8 @@ +package org.greenrobot.eventbus.android; + +public class AndroidComponentsImpl extends AndroidComponents { + + public AndroidComponentsImpl() { + super(new AndroidLogger("EventBus"), new DefaultAndroidMainThreadSupport()); + } +} diff --git a/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidLogProxyImpl.java b/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidLogProxyImpl.java deleted file mode 100644 index 65dc06ec..00000000 --- a/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidLogProxyImpl.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.greenrobot.eventbus.android; - -import android.util.Log; - -public class AndroidLogProxyImpl implements AndroidSDKProxy.LogProxy { - - @Override - public void println(int priority, String tag, String msg) { - Log.println(priority, tag, msg); - } - - @Override - public int getVerboseLevelId() { - return Log.VERBOSE; - } - - @Override - public int getDebugLevelId() { - return Log.DEBUG; - } - - @Override - public int getInfoLevelId() { - return Log.INFO; - } - - @Override - public int getWarnLevelId() { - return Log.WARN; - } - - @Override - public int getErrorLevelId() { - return Log.ERROR; - } -} diff --git a/EventBus/src/org/greenrobot/eventbus/android/AndroidLogger.java b/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidLogger.java similarity index 71% rename from EventBus/src/org/greenrobot/eventbus/android/AndroidLogger.java rename to eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidLogger.java index 15f5e29d..45fd6e4e 100644 --- a/EventBus/src/org/greenrobot/eventbus/android/AndroidLogger.java +++ b/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidLogger.java @@ -15,30 +15,29 @@ */ package org.greenrobot.eventbus.android; +import android.util.Log; import org.greenrobot.eventbus.Logger; import org.greenrobot.eventbus.util.ExceptionStackTraceUtils; import java.util.logging.Level; public class AndroidLogger implements Logger { - private final AndroidSDKProxy androidSDK; private final String tag; - public AndroidLogger(AndroidSDKProxy androidSDK, String tag) { - this.androidSDK = androidSDK; + public AndroidLogger(String tag) { this.tag = tag; } public void log(Level level, String msg) { if (level != Level.OFF) { - androidSDK.log.println(mapLevel(level), tag, msg); + Log.println(mapLevel(level), tag, msg); } } public void log(Level level, String msg, Throwable th) { if (level != Level.OFF) { // That's how Log does it internally - androidSDK.log.println(mapLevel(level), tag, msg + "\n" + ExceptionStackTraceUtils.getStackTraceAsString(th)); + Log.println(mapLevel(level), tag, msg + "\n" + ExceptionStackTraceUtils.getStackTraceAsString(th)); } } @@ -46,16 +45,16 @@ private int mapLevel(Level level) { int value = level.intValue(); if (value < 800) { // below INFO if (value < 500) { // below FINE - return androidSDK.log.getVerboseLevelId(); + return Log.VERBOSE; } else { - return androidSDK.log.getDebugLevelId(); + return Log.DEBUG; } } else if (value < 900) { // below WARNING - return androidSDK.log.getInfoLevelId(); + return Log.INFO; } else if (value < 1000) { // below ERROR - return androidSDK.log.getWarnLevelId(); + return Log.WARN; } else { - return androidSDK.log.getErrorLevelId(); + return Log.ERROR; } } } diff --git a/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidSDKProxyImpl.java b/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidSDKProxyImpl.java deleted file mode 100644 index 40a80b25..00000000 --- a/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidSDKProxyImpl.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.greenrobot.eventbus.android; - -public class AndroidSDKProxyImpl extends AndroidSDKProxy { - - public AndroidSDKProxyImpl() { - super(new AndroidLogProxyImpl(), new DefaultAndroidMainThreadSupport()); - } -} From 53f24c58a36bbe065b5bc26141c1e17016f45a16 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 21 Jun 2021 15:03:18 +0200 Subject: [PATCH 252/288] Update Gradle [6.7.1 -> 6.8.3] --- gradle/wrapper/gradle-wrapper.jar | Bin 55616 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 31 ++++++++++------------- gradlew.bat | 25 +++++------------- 4 files changed, 22 insertions(+), 36 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 5c2d1cf016b3885f6930543d57b744ea8c220a1a..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f 100644 GIT binary patch delta 23334 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 WDWbsF$p{Gi@ZUasP|4|kdH)CXgbPdn delta 19998 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1f3fdbc5..8cf6eb5a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 83f2acfd..4f906e0c 100755 --- a/gradlew +++ b/gradlew @@ -82,6 +82,7 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -129,6 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath @@ -154,19 +156,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -175,14 +177,9 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=$(save "$@") +APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 24467a14..ac1b06f9 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -51,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -61,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell From a396776d0aa29a8ea7f5bc1c0edf5a1952171231 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 21 Jun 2021 15:06:20 +0200 Subject: [PATCH 253/288] Downgrade Android plugin to work with IntelliJ IDEA. --- EventBusPerformance/build.gradle | 3 ++- EventBusTest/build.gradle | 3 ++- eventbus-android/build.gradle | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 0a51db7a..7fc3eea4 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -5,7 +5,8 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:4.2.0' + // Note: IntelliJ IDEA 2021.1 only supports up to version 4.1 + classpath 'com.android.tools.build:gradle:4.1.3' } } diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 740389ad..8fc33ece 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -5,7 +5,8 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:4.2.0' + // Note: IntelliJ IDEA 2021.1 only supports up to version 4.1 + classpath 'com.android.tools.build:gradle:4.1.3' } } diff --git a/eventbus-android/build.gradle b/eventbus-android/build.gradle index e20de7a2..328896af 100644 --- a/eventbus-android/build.gradle +++ b/eventbus-android/build.gradle @@ -5,7 +5,8 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:4.2.0' + // Note: IntelliJ IDEA 2021.1 only supports up to version 4.1 + classpath 'com.android.tools.build:gradle:4.1.3' } } From 1d5e79aa5d7bc1efdf61e85cb14ad6e58bda0ab7 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 21 Jun 2021 15:10:01 +0200 Subject: [PATCH 254/288] CI: use GitHub Actions. --- .github/workflows/gradle.yml | 42 ++++++++++++++++++++++++++++++++++++ .travis.yml | 35 ------------------------------ 2 files changed, 42 insertions(+), 35 deletions(-) create mode 100644 .github/workflows/gradle.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml new file mode 100644 index 00000000..1ac038ec --- /dev/null +++ b/.github/workflows/gradle.yml @@ -0,0 +1,42 @@ +# This workflow will build a Java project with Gradle +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle + +name: Java CI with Gradle + +on: + push: + pull_request: + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: actions/setup-java@v2 + with: + java-version: '11' + distribution: 'adopt' + - name: Cache Gradle packages + uses: actions/cache@v2 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Gradle Info + run: ./gradlew -version + - name: Build with Gradle + run: ./gradlew build + - name: Cleanup Gradle Cache + # Remove some files from the Gradle cache, so they aren't cached by GitHub Actions. + # Restoring these files from a GitHub Actions cache might cause problems for future builds. + run: | + rm -f ~/.gradle/caches/modules-2/modules-2.lock + rm -f ~/.gradle/caches/modules-2/gc.properties diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b22ae054..00000000 --- a/.travis.yml +++ /dev/null @@ -1,35 +0,0 @@ -sudo: false -language: android -jdk: - - oraclejdk8 - -# http://docs.travis-ci.com/user/languages/android/ -android: - components: - - build-tools-28.0.3 - - android-26 - licenses: - - 'android-sdk-license-.+' - -before_script: - - chmod +x gradlew -# - echo no | android create avd --force -n test -t android-10 --abi armeabi -# - emulator -avd test -no-skin -no-audio -no-window & -# - android-wait-for-emulator -# - adb shell input keyevent 82 & - -# Currently connectedCheck fails, so don't run unit test on Emulator for now. Issue: -# com.android.builder.testing.ConnectedDevice > hasTests[test(AVD) - 2.3.3] FAILED -# No tests found. - -script: - - TERM=dumb ./gradlew check - -before_cache: - - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock - - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ -cache: - directories: - - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ - - $HOME/.android/build-cache From b74299b71799cc40bc1c32e51bb4fc46cc295804 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 21 Jun 2021 15:31:04 +0200 Subject: [PATCH 255/288] Embed ProGuard rules for Android. --- eventbus-android/build.gradle | 2 ++ eventbus-android/consumer-rules.pro | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/eventbus-android/build.gradle b/eventbus-android/build.gradle index 328896af..f2818f0e 100644 --- a/eventbus-android/build.gradle +++ b/eventbus-android/build.gradle @@ -18,6 +18,8 @@ android { defaultConfig { minSdkVersion 7 targetSdkVersion 30 + + consumerProguardFiles "consumer-rules.pro" } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 diff --git a/eventbus-android/consumer-rules.pro b/eventbus-android/consumer-rules.pro index e69de29b..06d028c3 100644 --- a/eventbus-android/consumer-rules.pro +++ b/eventbus-android/consumer-rules.pro @@ -0,0 +1,10 @@ +-keepattributes *Annotation* +-keepclassmembers class * { + @org.greenrobot.eventbus.Subscribe ; +} +-keep enum org.greenrobot.eventbus.ThreadMode { *; } + +# And if you use AsyncExecutor: +-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent { + (java.lang.Throwable); +} From 3f4ee0cc6ddc5f6ba99ecea7da0dd431103b5341 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 21 Jun 2021 15:37:24 +0200 Subject: [PATCH 256/288] Use common compile SDK for eventbus-android. --- build.gradle | 2 +- eventbus-android/build.gradle | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index b29b352e..30e30418 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ buildscript { ext { - _compileSdkVersion = 26 // When updating, don't forget to adjust .travis.yml. + _compileSdkVersion = 30 // Android 11 (R) } } diff --git a/eventbus-android/build.gradle b/eventbus-android/build.gradle index f2818f0e..cdb59fb9 100644 --- a/eventbus-android/build.gradle +++ b/eventbus-android/build.gradle @@ -13,11 +13,11 @@ buildscript { apply plugin: 'com.android.library' android { - compileSdkVersion 30 + compileSdkVersion _compileSdkVersion defaultConfig { minSdkVersion 7 - targetSdkVersion 30 + targetSdkVersion 30 // Android 11 (R) consumerProguardFiles "consumer-rules.pro" } From 51a5c05bed252145e7ebe29e8ed7f8d6b8a1b329 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 22 Jun 2021 14:17:00 +0200 Subject: [PATCH 257/288] Switch to maven-publish plugin. --- EventBus/build.gradle | 37 +++++------ EventBusAnnotationProcessor/build.gradle | 37 +++++------ build.gradle | 24 +++++++ eventbus-android/build.gradle | 28 ++++++++ gradle/publish.gradle | 83 ++++++------------------ 5 files changed, 106 insertions(+), 103 deletions(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index 47456d58..ea96d39c 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -1,6 +1,5 @@ apply plugin: 'java' -archivesBaseName = 'eventbus' group = 'org.greenrobot' version = '3.2.0' java.sourceCompatibility = JavaVersion.VERSION_1_8 @@ -15,8 +14,6 @@ sourceSets { } } -apply from: rootProject.file("gradle/publish.gradle") - javadoc { failOnError = false title = "EventBus ${version} API" @@ -24,30 +21,30 @@ javadoc { } task javadocJar(type: Jar, dependsOn: javadoc) { - classifier = 'javadoc' + archiveClassifier.set("javadoc") from 'build/docs/javadoc' } task sourcesJar(type: Jar) { + archiveClassifier.set("sources") from sourceSets.main.allSource - classifier = 'sources' -} - -artifacts { - archives jar - archives javadocJar - archives sourcesJar } -uploadArchives { - repositories { - mavenDeployer { - // Common setup is defined in publish.gradle. - - pom.project { - name 'EventBus' - description 'EventBus is a publish/subscribe event bus optimized for Android.' - } +apply from: rootProject.file("gradle/publish.gradle") +// Set project-specific properties +afterEvaluate { + publishing.publications { + mavenJava(MavenPublication) { + artifactId = "eventbus-java" + + from components.java + artifact javadocJar + artifact sourcesJar + pom { + name = "EventBus" + description = "EventBus is a publish/subscribe event bus optimized for Android." + packaging = "jar" + } } } } diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index 4ccdbb94..d5eb89e6 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -1,6 +1,5 @@ apply plugin: 'java' -archivesBaseName = 'eventbus-annotation-processor' group = 'org.greenrobot' version = '3.2.0' @@ -28,38 +27,36 @@ sourceSets { } } -apply from: rootProject.file("gradle/publish.gradle") - javadoc { title = "EventBus Annotation Processor ${version} API" options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2015-2020 greenrobot.org. All Rights Reserved.' } task javadocJar(type: Jar, dependsOn: javadoc) { - classifier = 'javadoc' + archiveClassifier.set("javadoc") from 'build/docs/javadoc' } task sourcesJar(type: Jar) { + archiveClassifier.set("sources") from sourceSets.main.allSource - classifier = 'sources' -} - -artifacts { - archives jar - archives javadocJar - archives sourcesJar } -uploadArchives { - repositories { - mavenDeployer { - // Common setup is defined in publish.gradle. - - pom.project { - name 'EventBus Annotation Processor' - description 'Precompiler for EventBus Annotations.' +apply from: rootProject.file("gradle/publish.gradle") +// Set project-specific properties +afterEvaluate { + publishing.publications { + mavenJava(MavenPublication) { + artifactId = "eventbus-annotation-processor" + + from components.java + artifact javadocJar + artifact sourcesJar + pom { + name = "EventBus Annotation Processor" + description = "Precompiler for EventBus Annotations." + packaging = "jar" } } } -} \ No newline at end of file +} diff --git a/build.gradle b/build.gradle index 30e30418..d575a7a5 100644 --- a/build.gradle +++ b/build.gradle @@ -2,6 +2,13 @@ buildscript { ext { _compileSdkVersion = 30 // Android 11 (R) } + repositories { + mavenCentral() + maven { url "https://plugins.gradle.org/m2/" } + } + dependencies { + classpath "io.github.gradle-nexus:publish-plugin:1.1.0" + } } allprojects { @@ -22,3 +29,20 @@ if (JavaVersion.current().isJava8Compatible()) { wrapper { distributionType = Wrapper.DistributionType.ALL } + +// Plugin to publish to Central https://github.com/gradle-nexus/publish-plugin/ +// This plugin ensures a separate, named staging repo is created for each build when publishing. +apply plugin: "io.github.gradle-nexus.publish-plugin" +nexusPublishing { + repositories { + sonatype { + if (project.hasProperty("sonatypeUsername") && project.hasProperty("sonatypePassword")) { + println('nexusPublishing credentials supplied.') + username = sonatypeUsername + password = sonatypePassword + } else { + println('nexusPublishing credentials NOT supplied.') + } + } + } +} diff --git a/eventbus-android/build.gradle b/eventbus-android/build.gradle index cdb59fb9..601e0c9a 100644 --- a/eventbus-android/build.gradle +++ b/eventbus-android/build.gradle @@ -12,6 +12,9 @@ buildscript { apply plugin: 'com.android.library' +group = 'org.greenrobot' +version = '3.2.0' + android { compileSdkVersion _compileSdkVersion @@ -30,3 +33,28 @@ android { dependencies { implementation project(":eventbus") } + +task sourcesJar(type: Jar) { + from android.sourceSets.main.java.srcDirs + archiveClassifier.set("sources") +} + +apply from: rootProject.file("gradle/publish.gradle") +// Set project-specific properties +// https://developer.android.com/studio/build/maven-publish-plugin +afterEvaluate { + publishing.publications { + mavenJava(MavenPublication) { + artifactId = "eventbus" + + from components.release + artifact sourcesJar + + pom { + name = "EventBus" + description = "EventBus is a publish/subscribe event bus optimized for Android." + packaging = "aar" + } + } + } +} diff --git a/gradle/publish.gradle b/gradle/publish.gradle index a887ff3a..5420dd44 100644 --- a/gradle/publish.gradle +++ b/gradle/publish.gradle @@ -1,18 +1,8 @@ // Configures common publishing settings. -apply plugin: "maven" +apply plugin: "maven-publish" apply plugin: "signing" -configurations { - deployerJars -} - -dependencies { - // Using an older version to remain compatible with Wagon API used by Gradle/Maven. - deployerJars 'org.apache.maven.wagon:wagon-webdav-jackrabbit:3.2.0' - deployerJars 'org.apache.maven.wagon:wagon-ftp:3.3.2' -} - signing { if (project.hasProperty('signing.keyId') && project.hasProperty('signing.password') && project.hasProperty('signing.secretKeyRingFile')) { @@ -22,71 +12,38 @@ signing { } } -// Use afterEvaluate or dependencies might be lost in the generated POM. -afterEvaluate { project -> - uploadArchives { - repositories { - mavenDeployer { - def preferredRepo = project.findProperty('preferredRepo') - println "preferredRepo=$preferredRepo" - - if (preferredRepo == 'local') { - repository url: repositories.mavenLocal().url - } else if (preferredRepo != null - && project.hasProperty('preferredUsername') - && project.hasProperty('preferredPassword')) { - configuration = configurations.deployerJars - repository(url: repositoryUrl) { - authentication(userName: preferredUsername, password: preferredPassword) - } - } else if (project.hasProperty('sonatypeUsername') - && project.hasProperty('sonatypePassword')) { - beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } - def isSnapshot = version.endsWith('-SNAPSHOT') - def sonatypeRepositoryUrl = isSnapshot - ? "https://oss.sonatype.org/content/repositories/snapshots/" - : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" - repository(url: sonatypeRepositoryUrl) { - authentication(userName: sonatypeUsername, password: sonatypePassword) - } - } else { - println "Deployment settings missing/incomplete for ${project.name}." - } - - // Common properties, projects still need to set name and description. - pom.project { - packaging 'jar' - url 'https://greenrobot.org/eventbus/' +// https://developer.android.com/studio/build/maven-publish-plugin +// Because the Android components are created only during the afterEvaluate phase, you must +// configure your publications using the afterEvaluate() lifecycle method. +afterEvaluate { + publishing { + publications { + // Note: Sonatype repo created by publish-plugin, see root build.gradle. + mavenJava(MavenPublication) { + pom { + url = "https://greenrobot.org/eventbus/" scm { - url 'https://github.com/greenrobot/EventBus' - connection 'scm:git@github.com:greenrobot/EventBus.git' - developerConnection 'scm:git@github.com:greenrobot/EventBus.git' - } - - licenses { - license { - name 'The Apache Software License, Version 2.0' - url 'http://www.apache.org/licenses/LICENSE-2.0.txt' - distribution 'repo' - } + connection = "scm:git@github.com:greenrobot/EventBus.git" + developerConnection = "scm:git@github.com:greenrobot/EventBus.git" + url = "https://github.com/greenrobot/EventBus" } developers { developer { - id 'greenrobot' - name 'greenrobot' + id = "greenrobot" + name = "greenrobot" } } issueManagement { - system 'GitHub Issues' - url 'https://github.com/greenrobot/EventBus/issues' + system = "https://github.com/greenrobot/EventBus/issues" + url = "https://github.com/greenrobot/EventBus/issues" } organization { - name 'greenrobot' - url 'https://greenrobot.org' + name = "greenrobot" + url = "https://greenrobot.org" } } } From 831071ea8ba06a7b956a1930db718b936149b945 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 22 Jun 2021 14:18:39 +0200 Subject: [PATCH 258/288] Start development of next version. --- EventBus/build.gradle | 2 +- EventBusAnnotationProcessor/build.gradle | 2 +- eventbus-android/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index ea96d39c..c3b3092d 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -1,7 +1,7 @@ apply plugin: 'java' group = 'org.greenrobot' -version = '3.2.0' +version = '3.3.0-SNAPSHOT' java.sourceCompatibility = JavaVersion.VERSION_1_8 java.targetCompatibility = JavaVersion.VERSION_1_8 diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index d5eb89e6..52585d50 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -1,7 +1,7 @@ apply plugin: 'java' group = 'org.greenrobot' -version = '3.2.0' +version = '3.3.0-SNAPSHOT' java.sourceCompatibility = JavaVersion.VERSION_1_8 java.targetCompatibility = JavaVersion.VERSION_1_8 diff --git a/eventbus-android/build.gradle b/eventbus-android/build.gradle index 601e0c9a..a08b02cc 100644 --- a/eventbus-android/build.gradle +++ b/eventbus-android/build.gradle @@ -13,7 +13,7 @@ buildscript { apply plugin: 'com.android.library' group = 'org.greenrobot' -version = '3.2.0' +version = '3.3.0-SNAPSHOT' android { compileSdkVersion _compileSdkVersion From a110323585e69993db306f8e1bbbadc02d09e9df Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 22 Jun 2021 14:34:16 +0200 Subject: [PATCH 259/288] Make eventbus-java an exposed dependency of eventbus. --- eventbus-android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eventbus-android/build.gradle b/eventbus-android/build.gradle index a08b02cc..21ff4c34 100644 --- a/eventbus-android/build.gradle +++ b/eventbus-android/build.gradle @@ -31,7 +31,7 @@ android { } dependencies { - implementation project(":eventbus") + api project(":eventbus") } task sourcesJar(type: Jar) { From bc0b3f3fdb4943f07ac6ea54fd5a50d7cba4727f Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 22 Jun 2021 14:38:29 +0200 Subject: [PATCH 260/288] Rename EventBus project so it is added as dependency in POM. --- EventBusAnnotationProcessor/build.gradle | 2 +- EventBusPerformance/build.gradle | 2 +- EventBusTest/build.gradle | 2 +- EventBusTestJava/build.gradle | 2 +- EventBusTestSubscriberInJar/build.gradle | 2 +- eventbus-android/build.gradle | 2 +- settings.gradle | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index 52585d50..8b4b5eea 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -7,7 +7,7 @@ java.sourceCompatibility = JavaVersion.VERSION_1_8 java.targetCompatibility = JavaVersion.VERSION_1_8 dependencies { - implementation project(':eventbus') + implementation project(':eventbus-java') implementation 'de.greenrobot:java-common:2.3.1' // Generates the required META-INF descriptor to make the processor incremental. diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 7fc3eea4..a9bc6e29 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -13,7 +13,7 @@ buildscript { apply plugin: 'com.android.application' dependencies { - implementation project(':eventbus') + implementation project(':eventbus-java') implementation project(':eventbus-android') annotationProcessor project(':eventbus-annotation-processor') implementation 'com.squareup:otto:1.3.8' diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 8fc33ece..e2d1ee27 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -13,7 +13,7 @@ buildscript { apply plugin: 'com.android.application' dependencies { - androidTestImplementation project(':eventbus') + androidTestImplementation project(':eventbus-java') androidTestImplementation project(':eventbus-android') androidTestImplementation project(':EventBusTestJava') androidTestAnnotationProcessor project(':eventbus-annotation-processor') diff --git a/EventBusTestJava/build.gradle b/EventBusTestJava/build.gradle index ea5c4dd5..ef0a331f 100644 --- a/EventBusTestJava/build.gradle +++ b/EventBusTestJava/build.gradle @@ -15,7 +15,7 @@ sourceSets { dependencies { compile fileTree(dir: 'libs', include: '*.jar') - compile(project(':eventbus')) { + compile(project(':eventbus-java')) { exclude group: "com.google.android" // Does not seem to work... } annotationProcessor project(':eventbus-annotation-processor') diff --git a/EventBusTestSubscriberInJar/build.gradle b/EventBusTestSubscriberInJar/build.gradle index b091c149..93960dc9 100644 --- a/EventBusTestSubscriberInJar/build.gradle +++ b/EventBusTestSubscriberInJar/build.gradle @@ -10,7 +10,7 @@ configurations { } dependencies { - compile project(':eventbus') + compile project(':eventbus-java') provided project(':eventbus-annotation-processor') } diff --git a/eventbus-android/build.gradle b/eventbus-android/build.gradle index 21ff4c34..61b28c1d 100644 --- a/eventbus-android/build.gradle +++ b/eventbus-android/build.gradle @@ -31,7 +31,7 @@ android { } dependencies { - api project(":eventbus") + api project(":eventbus-java") } task sourcesJar(type: Jar) { diff --git a/settings.gradle b/settings.gradle index 44670236..9e53b0e9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,5 +6,5 @@ include ':EventBusTestSubscriberInJar' include ':EventBusPerformance' include ':eventbus-android' -project(":EventBus").name = "eventbus" +project(":EventBus").name = "eventbus-java" project(":EventBusAnnotationProcessor").name = "eventbus-annotation-processor" From 740a862356c8a370943d7f565a2049644b67abd7 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 22 Jun 2021 14:52:59 +0200 Subject: [PATCH 261/288] Update Android references and messages. --- EventBus/build.gradle | 2 +- EventBus/src/org/greenrobot/eventbus/EventBus.java | 7 +++---- EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java | 3 +-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index c3b3092d..b591586f 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -42,7 +42,7 @@ afterEvaluate { artifact sourcesJar pom { name = "EventBus" - description = "EventBus is a publish/subscribe event bus optimized for Android." + description = "EventBus is a publish/subscribe event bus." packaging = "jar" } } diff --git a/EventBus/src/org/greenrobot/eventbus/EventBus.java b/EventBus/src/org/greenrobot/eventbus/EventBus.java index 25f93823..147bb5ff 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBus.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBus.java @@ -140,11 +140,10 @@ public EventBus() { * ThreadMode} and priority. */ public void register(Object subscriber) { - if (AndroidDependenciesDetector.isAndroidSDKAvailable() && !AndroidDependenciesDetector.areAndroidComponentsAvailable()) { - //should crash user's app if the user (developer) has not imported the android compatibility library - throw new RuntimeException("Looks like you are using the latest version of EventBus on Android " + - "without importing the EventBus for Android compatibility library. Please import it on app/build.gradle!"); + // Crash if the user (developer) has not imported the Android compatibility library. + throw new RuntimeException("It looks like you are using EventBus on Android, " + + "make sure to add the \"eventbus\" Android library to your dependencies."); } Class subscriberClass = subscriber.getClass(); diff --git a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java index ff4a5f80..6df346d6 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java @@ -143,8 +143,7 @@ public EventBusBuilder addIndex(SubscriberInfoIndex index) { /** * Set a specific log handler for all EventBus logging. *

- * By default all logging is via {@link android.util.Log} but if you want to use EventBus - * outside the Android environment then you will need to provide another log target. + * By default, all logging is via {@code android.util.Log} on Android or System.out on JVM. */ public EventBusBuilder logger(Logger logger) { this.logger = logger; From df94b23dca5683cf881fc8078c4ee1c038f1f663 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 22 Jun 2021 15:35:19 +0200 Subject: [PATCH 262/288] Update Java test projects. --- EventBusTestJava/build.gradle | 14 ++++++-------- EventBusTestSubscriberInJar/build.gradle | 14 +++++++------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/EventBusTestJava/build.gradle b/EventBusTestJava/build.gradle index ef0a331f..9e2bdad1 100644 --- a/EventBusTestJava/build.gradle +++ b/EventBusTestJava/build.gradle @@ -1,4 +1,4 @@ -apply plugin: 'java' +apply plugin: "java-library" java.sourceCompatibility = JavaVersion.VERSION_1_8 java.targetCompatibility = JavaVersion.VERSION_1_8 @@ -8,18 +8,16 @@ java.targetCompatibility = JavaVersion.VERSION_1_8 sourceSets { test { java { - srcDirs += ['src/main/java'] + srcDirs += ["src/main/java"] } } } dependencies { - compile fileTree(dir: 'libs', include: '*.jar') - compile(project(':eventbus-java')) { - exclude group: "com.google.android" // Does not seem to work... - } - annotationProcessor project(':eventbus-annotation-processor') - compile 'junit:junit:4.12' + implementation fileTree(dir: "libs", include: "*.jar") + implementation(project(":eventbus-java")) + annotationProcessor project(":eventbus-annotation-processor") + implementation "junit:junit:4.13.2" } tasks.withType(JavaCompile) { diff --git a/EventBusTestSubscriberInJar/build.gradle b/EventBusTestSubscriberInJar/build.gradle index 93960dc9..21096be3 100644 --- a/EventBusTestSubscriberInJar/build.gradle +++ b/EventBusTestSubscriberInJar/build.gradle @@ -1,7 +1,7 @@ -apply plugin: 'java' +apply plugin: "java-library" -group = 'de.greenrobot' -version = '3.0.0' +group = "de.greenrobot" +version = "3.0.0" java.sourceCompatibility = JavaVersion.VERSION_1_8 java.targetCompatibility = JavaVersion.VERSION_1_8 @@ -10,20 +10,20 @@ configurations { } dependencies { - compile project(':eventbus-java') - provided project(':eventbus-annotation-processor') + implementation project(":eventbus-java") + annotationProcessor project(":eventbus-annotation-processor") } sourceSets { main { compileClasspath += configurations.provided java { - srcDir 'src' + srcDir "src" } } } compileJava { - options.compilerArgs << '-AeventBusIndex=org.greenrobot.eventbus.InJarIndex' + options.compilerArgs << "-AeventBusIndex=org.greenrobot.eventbus.InJarIndex" options.fork = true } From adc7b9f70e327915d048086c87ba80a827c5e8d6 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 22 Jun 2021 15:35:50 +0200 Subject: [PATCH 263/288] Drop explicit eventbus-java dependency from Android test projects. --- EventBusPerformance/build.gradle | 1 - EventBusTest/build.gradle | 1 - 2 files changed, 2 deletions(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index a9bc6e29..247d085e 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -13,7 +13,6 @@ buildscript { apply plugin: 'com.android.application' dependencies { - implementation project(':eventbus-java') implementation project(':eventbus-android') annotationProcessor project(':eventbus-annotation-processor') implementation 'com.squareup:otto:1.3.8' diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index e2d1ee27..f449b739 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -13,7 +13,6 @@ buildscript { apply plugin: 'com.android.application' dependencies { - androidTestImplementation project(':eventbus-java') androidTestImplementation project(':eventbus-android') androidTestImplementation project(':EventBusTestJava') androidTestAnnotationProcessor project(':eventbus-annotation-processor') From 45352be3f13374f545679f1f3d793e0e0a3e16f4 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 22 Jun 2021 15:45:24 +0200 Subject: [PATCH 264/288] Re-add deprecated test classes for Android. --- EventBusTest/build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index f449b739..2ca34312 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -57,6 +57,8 @@ android { } } + useLibrary 'android.test.base' + lintOptions { // To see problems right away, also nice for Travis CI textOutput 'stdout' From e573ffa2b1877398ca95a32f53a1c45363852bc7 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 29 Jun 2021 14:03:55 +0200 Subject: [PATCH 265/288] Regression: correctly check for Android main thread. --- .../eventbus/android/DefaultAndroidMainThreadSupport.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eventbus-android/src/main/java/org/greenrobot/eventbus/android/DefaultAndroidMainThreadSupport.java b/eventbus-android/src/main/java/org/greenrobot/eventbus/android/DefaultAndroidMainThreadSupport.java index 13339465..02b3f3af 100644 --- a/eventbus-android/src/main/java/org/greenrobot/eventbus/android/DefaultAndroidMainThreadSupport.java +++ b/eventbus-android/src/main/java/org/greenrobot/eventbus/android/DefaultAndroidMainThreadSupport.java @@ -10,7 +10,7 @@ public class DefaultAndroidMainThreadSupport implements MainThreadSupport { @Override public boolean isMainThread() { - return true; + return Looper.getMainLooper() == Looper.myLooper(); } @Override From 5efb61f919512df21f5b8e3c1605f70f5281062e Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 29 Jun 2021 14:10:12 +0200 Subject: [PATCH 266/288] Regression: restore AndroidLogger log output. Drop added ExceptionStackTraceUtils class. --- .../eventbus/util/ExceptionStackTraceUtils.java | 15 --------------- .../eventbus/android/AndroidLogger.java | 4 ++-- 2 files changed, 2 insertions(+), 17 deletions(-) delete mode 100644 EventBus/src/org/greenrobot/eventbus/util/ExceptionStackTraceUtils.java diff --git a/EventBus/src/org/greenrobot/eventbus/util/ExceptionStackTraceUtils.java b/EventBus/src/org/greenrobot/eventbus/util/ExceptionStackTraceUtils.java deleted file mode 100644 index 4d0e1cae..00000000 --- a/EventBus/src/org/greenrobot/eventbus/util/ExceptionStackTraceUtils.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.greenrobot.eventbus.util; - -import java.io.PrintWriter; -import java.io.StringWriter; - -public class ExceptionStackTraceUtils { - - public static String getStackTraceAsString(Throwable ex) { - - StringWriter stringWriter = new StringWriter(); - PrintWriter printWriter = new PrintWriter(stringWriter); - ex.printStackTrace(printWriter); - return stringWriter.toString(); - } -} diff --git a/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidLogger.java b/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidLogger.java index 45fd6e4e..04cc1cf3 100644 --- a/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidLogger.java +++ b/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidLogger.java @@ -17,7 +17,7 @@ import android.util.Log; import org.greenrobot.eventbus.Logger; -import org.greenrobot.eventbus.util.ExceptionStackTraceUtils; + import java.util.logging.Level; public class AndroidLogger implements Logger { @@ -37,7 +37,7 @@ public void log(Level level, String msg) { public void log(Level level, String msg, Throwable th) { if (level != Level.OFF) { // That's how Log does it internally - Log.println(mapLevel(level), tag, msg + "\n" + ExceptionStackTraceUtils.getStackTraceAsString(th)); + Log.println(mapLevel(level), tag, msg + "\n" + Log.getStackTraceString(th)); } } From 8980e2d12e7ba6ac68e80ad17800a2b1e87d308e Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 29 Jun 2021 14:13:58 +0200 Subject: [PATCH 267/288] Regression: Remove added suppression. --- .../src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java | 1 - 1 file changed, 1 deletion(-) diff --git a/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java index c6432d49..9020c24b 100644 --- a/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java @@ -22,7 +22,6 @@ import java.lang.reflect.Method; /** Base class for generated subscriber meta info classes created by annotation processing. */ -@SuppressWarnings({ "rawtypes", "TryWithIdenticalCatches", "unchecked" }) public abstract class AbstractSubscriberInfo implements SubscriberInfo { private final Class subscriberClass; private final Class superSubscriberInfoClass; From ece8c276957a99accb2d4000dc8b24e9b392c1e8 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 13 Jul 2021 14:30:43 +0200 Subject: [PATCH 268/288] Publishing: add license back to POM. --- gradle/publish.gradle | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gradle/publish.gradle b/gradle/publish.gradle index 5420dd44..4d0e092d 100644 --- a/gradle/publish.gradle +++ b/gradle/publish.gradle @@ -29,6 +29,14 @@ afterEvaluate { url = "https://github.com/greenrobot/EventBus" } + licenses { + license { + name = "The Apache Software License, Version 2.0" + url = "https://www.apache.org/licenses/LICENSE-2.0.txt" + distribution = "repo" + } + } + developers { developer { id = "greenrobot" From 2d6910e13eb5f0dda3818611098b7bfd0f1b1c61 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 13 Jul 2021 14:33:10 +0200 Subject: [PATCH 269/288] Update README --- README.md | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 2a776233..f5bd9878 100644 --- a/README.md +++ b/README.md @@ -68,16 +68,19 @@ Add EventBus to your project Available on Maven Central. -Via Gradle: -```gradle -implementation 'org.greenrobot:eventbus:3.2.0' +Android projects: +```groovy +implementation("org.greenrobot:eventbus:3.2.0") ``` -Via Maven: +Java projects: +```groovy +implementation("org.greenrobot:eventbus-java:3.2.0") +``` ```xml org.greenrobot - eventbus + eventbus-java 3.2.0 ``` @@ -85,20 +88,7 @@ Via Maven: R8, ProGuard ------------ -If your project uses R8 or ProGuard add the following rules: - -```bash --keepattributes *Annotation* --keepclassmembers class * { - @org.greenrobot.eventbus.Subscribe ; -} --keep enum org.greenrobot.eventbus.ThreadMode { *; } - -# And if you use AsyncExecutor: --keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent { - (java.lang.Throwable); -} -``` +If your project uses R8 or ProGuard this library ships [with embedded rules](/eventbus-android/consumer-rules.pro). Homepage, Documentation, Links ------------------------------ @@ -112,8 +102,6 @@ For more details please check the [EventBus website](https://greenrobot.org/even [FAQ](https://greenrobot.org/eventbus/documentation/faq/) -How does EventBus compare to other solutions, like Otto from Square? Check this [comparison](COMPARISON.md). - License ------- Copyright (C) 2012-2020 Markus Junginger, greenrobot (https://greenrobot.org) @@ -125,5 +113,3 @@ Other projects by greenrobot [__ObjectBox__](https://objectbox.io/) ([GitHub](https://github.com/objectbox/objectbox-java)) is a new superfast object-oriented database. [__Essentials__](https://github.com/greenrobot/essentials) is a set of utility classes and hash functions for Android & Java projects. - -[__greenDAO__](https://github.com/greenrobot/greenDAO) is an ORM optimized for Android: it maps database tables to Java objects and uses code generation for optimal speed. From d74c3bac7ca58a85a9a7cd46cd74bed8a76792fc Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 13 Jul 2021 14:44:39 +0200 Subject: [PATCH 270/288] Prevent removal or renaming of AndroidComponentsImpl. --- eventbus-android/consumer-rules.pro | 3 +++ .../org/greenrobot/eventbus/android/AndroidComponentsImpl.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/eventbus-android/consumer-rules.pro b/eventbus-android/consumer-rules.pro index 06d028c3..d5248bac 100644 --- a/eventbus-android/consumer-rules.pro +++ b/eventbus-android/consumer-rules.pro @@ -8,3 +8,6 @@ -keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent { (java.lang.Throwable); } + +# Accessed via reflection, avoid renaming or removal +-keep class org.greenrobot.eventbus.android.AndroidComponentsImpl diff --git a/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidComponentsImpl.java b/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidComponentsImpl.java index afcb4af0..20f35b18 100644 --- a/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidComponentsImpl.java +++ b/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidComponentsImpl.java @@ -1,5 +1,8 @@ package org.greenrobot.eventbus.android; +/** + * Used via reflection in the Java library by {@link AndroidDependenciesDetector}. + */ public class AndroidComponentsImpl extends AndroidComponents { public AndroidComponentsImpl() { From ee34ff6b3b590a848223bfd9e9e075fd1bfd49b1 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 13 Jul 2021 14:44:51 +0200 Subject: [PATCH 271/288] Add README for Android library. --- eventbus-android/README.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 eventbus-android/README.md diff --git a/eventbus-android/README.md b/eventbus-android/README.md new file mode 100644 index 00000000..126c7ba9 --- /dev/null +++ b/eventbus-android/README.md @@ -0,0 +1,7 @@ +# EventBus for Android + +Despite its name this module is actually published as `org.greenrobot:eventbus` as an Android library (AAR). + +It has a dependency on the Java-only artifact `org.greenrobot:eventbus-java` (JAR) previously available under the `eventbus` name. + +Provides an `AndroidComponents` implementation to the Java library if it detects `AndroidComponentsImpl` on the classpath via reflection. From 846e6656b828fde0c697c5c4df0b05ed1a4ef516 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 13 Jul 2021 14:47:24 +0200 Subject: [PATCH 272/288] Drop AndroidComponentsAvailabilityOnJavaTest, ensured implicitly by other tests. If other tests would use any Android API on JVM, they would crash. --- ...AndroidComponentsAvailabilityOnJavaTest.java | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 EventBusTestJava/src/main/java/org/greenrobot/eventbus/AndroidComponentsAvailabilityOnJavaTest.java diff --git a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AndroidComponentsAvailabilityOnJavaTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AndroidComponentsAvailabilityOnJavaTest.java deleted file mode 100644 index cc2e69ff..00000000 --- a/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AndroidComponentsAvailabilityOnJavaTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.greenrobot.eventbus; - -import org.greenrobot.eventbus.android.AndroidComponents; -import org.junit.Test; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; - -public class AndroidComponentsAvailabilityOnJavaTest -{ - - @Test - public void shouldNotBeAvailable() { - assertFalse(AndroidComponents.areAvailable()); - assertNull(AndroidComponents.get()); - } -} From a49951eae51cfc8024a2c51f4a9fddc945021c66 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 30 Nov 2021 13:36:19 +0100 Subject: [PATCH 273/288] Actually sign new artifacts from mavenJava publication. Add support for file-based signing key (for CI). --- eventbus-android/build.gradle | 2 + gradle/publish.gradle | 107 ++++++++++++++++++++-------------- 2 files changed, 66 insertions(+), 43 deletions(-) diff --git a/eventbus-android/build.gradle b/eventbus-android/build.gradle index 61b28c1d..6edd255e 100644 --- a/eventbus-android/build.gradle +++ b/eventbus-android/build.gradle @@ -42,6 +42,8 @@ task sourcesJar(type: Jar) { apply from: rootProject.file("gradle/publish.gradle") // Set project-specific properties // https://developer.android.com/studio/build/maven-publish-plugin +// Because the Android components are created only during the afterEvaluate phase, you must +// configure your publications using the afterEvaluate() lifecycle method. afterEvaluate { publishing.publications { mavenJava(MavenPublication) { diff --git a/gradle/publish.gradle b/gradle/publish.gradle index 4d0e092d..1206dd62 100644 --- a/gradle/publish.gradle +++ b/gradle/publish.gradle @@ -3,58 +3,79 @@ apply plugin: "maven-publish" apply plugin: "signing" -signing { - if (project.hasProperty('signing.keyId') && project.hasProperty('signing.password') && - project.hasProperty('signing.secretKeyRingFile')) { - sign configurations.archives - } else { - println "Signing information missing/incomplete for ${project.name}." - } -} +publishing { + publications { + // Note: Sonatype repo created by publish-plugin, see root build.gradle. + mavenJava(MavenPublication) { + pom { + url = "https://greenrobot.org/eventbus/" -// https://developer.android.com/studio/build/maven-publish-plugin -// Because the Android components are created only during the afterEvaluate phase, you must -// configure your publications using the afterEvaluate() lifecycle method. -afterEvaluate { - publishing { - publications { - // Note: Sonatype repo created by publish-plugin, see root build.gradle. - mavenJava(MavenPublication) { - pom { - url = "https://greenrobot.org/eventbus/" - - scm { - connection = "scm:git@github.com:greenrobot/EventBus.git" - developerConnection = "scm:git@github.com:greenrobot/EventBus.git" - url = "https://github.com/greenrobot/EventBus" - } + scm { + connection = "scm:git@github.com:greenrobot/EventBus.git" + developerConnection = "scm:git@github.com:greenrobot/EventBus.git" + url = "https://github.com/greenrobot/EventBus" + } - licenses { - license { - name = "The Apache Software License, Version 2.0" - url = "https://www.apache.org/licenses/LICENSE-2.0.txt" - distribution = "repo" - } + licenses { + license { + name = "The Apache Software License, Version 2.0" + url = "https://www.apache.org/licenses/LICENSE-2.0.txt" + distribution = "repo" } + } - developers { - developer { - id = "greenrobot" - name = "greenrobot" - } + developers { + developer { + id = "greenrobot" + name = "greenrobot" } + } - issueManagement { - system = "https://github.com/greenrobot/EventBus/issues" - url = "https://github.com/greenrobot/EventBus/issues" - } + issueManagement { + system = "https://github.com/greenrobot/EventBus/issues" + url = "https://github.com/greenrobot/EventBus/issues" + } - organization { - name = "greenrobot" - url = "https://greenrobot.org" - } + organization { + name = "greenrobot" + url = "https://greenrobot.org" } } } } } + +// Note: ext to export to scripts applying this script. +ext { + // Signing: in-memory ascii-armored key (CI) or keyring file (dev machine), see https://docs.gradle.org/current/userguide/signing_plugin.html + hasSigningPropertiesKeyFile = { + return (project.hasProperty('signingKeyId') + && project.hasProperty('signingKeyFile') + && project.hasProperty('signingPassword')) + } + // Typically via ~/.gradle/gradle.properties; default properties for signing plugin. + hasSigningPropertiesKeyRing = { + return (project.hasProperty('signing.keyId') + && project.hasProperty('signing.secretKeyRingFile') + && project.hasProperty('signing.password')) + } + hasSigningProperties = { + return hasSigningPropertiesKeyFile() || hasSigningPropertiesKeyRing() + } +} + +signing { + if (hasSigningProperties()) { + if (hasSigningPropertiesKeyFile()) { + println "Configured signing to use key file." + String signingKey = new File(signingKeyFile).text + useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword) + } else if (hasSigningPropertiesKeyRing()) { + println "Configured signing to use key ring." + // Note: using expected property names (see above), no need to configure anything. + } + sign publishing.publications.mavenJava + } else { + println "WARNING: signing properties NOT set, will not sign artifacts." + } +} From b95c914c870dcef4df04780ba24464ceedd4f579 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 30 Nov 2021 13:39:09 +0100 Subject: [PATCH 274/288] GitHub Actions: use built-in cache support from setup-java task. --- .github/workflows/gradle.yml | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 1ac038ec..758ea017 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -19,24 +19,10 @@ jobs: with: java-version: '11' distribution: 'adopt' - - name: Cache Gradle packages - uses: actions/cache@v2 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle- + cache: gradle - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Gradle Info run: ./gradlew -version - name: Build with Gradle run: ./gradlew build - - name: Cleanup Gradle Cache - # Remove some files from the Gradle cache, so they aren't cached by GitHub Actions. - # Restoring these files from a GitHub Actions cache might cause problems for future builds. - run: | - rm -f ~/.gradle/caches/modules-2/modules-2.lock - rm -f ~/.gradle/caches/modules-2/gc.properties From 650fc80c395760f352b62fc450e511ae771d6720 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 30 Nov 2021 14:22:44 +0100 Subject: [PATCH 275/288] Make group and version detectable by publish plugin. --- EventBus/build.gradle | 5 +++-- EventBusAnnotationProcessor/build.gradle | 4 ++-- build.gradle | 4 ++++ eventbus-android/build.gradle | 4 ++-- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index b591586f..ffea11b6 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -1,7 +1,8 @@ apply plugin: 'java' -group = 'org.greenrobot' -version = '3.3.0-SNAPSHOT' +group = rootProject.group +version = rootProject.version + java.sourceCompatibility = JavaVersion.VERSION_1_8 java.targetCompatibility = JavaVersion.VERSION_1_8 diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index 8b4b5eea..0ec77d93 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -1,7 +1,7 @@ apply plugin: 'java' -group = 'org.greenrobot' -version = '3.3.0-SNAPSHOT' +group = rootProject.group +version = rootProject.version java.sourceCompatibility = JavaVersion.VERSION_1_8 java.targetCompatibility = JavaVersion.VERSION_1_8 diff --git a/build.gradle b/build.gradle index d575a7a5..57827719 100644 --- a/build.gradle +++ b/build.gradle @@ -11,6 +11,10 @@ buildscript { } } +// Set group and version in root build.gradle so publish-plugin can detect them. +group = "org.greenrobot" +version = "3.3.0-SNAPSHOT" + allprojects { repositories { mavenCentral() diff --git a/eventbus-android/build.gradle b/eventbus-android/build.gradle index 6edd255e..c1992ce4 100644 --- a/eventbus-android/build.gradle +++ b/eventbus-android/build.gradle @@ -12,8 +12,8 @@ buildscript { apply plugin: 'com.android.library' -group = 'org.greenrobot' -version = '3.3.0-SNAPSHOT' +group = rootProject.group +version = rootProject.version android { compileSdkVersion _compileSdkVersion From d4bfdd52a7c8a9ae9ab7f53a04e8471ca3c8c363 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 30 Nov 2021 14:41:19 +0100 Subject: [PATCH 276/288] README: use snapshot version to indicate instructions require next version. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f5bd9878..4e8c8c32 100644 --- a/README.md +++ b/README.md @@ -70,18 +70,18 @@ Available on org.greenrobot eventbus-java - 3.2.0 + 3.3.0-SNAPSHOT ``` From 5fa535537bb121180456b618f91a5de515f775a4 Mon Sep 17 00:00:00 2001 From: Uwe - ObjectBox <13865709+greenrobot-team@users.noreply.github.com> Date: Mon, 6 Dec 2021 08:31:28 +0100 Subject: [PATCH 277/288] Link instructions for stable version. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4e8c8c32..31fb1521 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,8 @@ Add EventBus to your project Available on Maven Central. +**Note: to use the latest stable version [see the previous README](https://github.com/greenrobot/EventBus/tree/V3.2.0#add-eventbus-to-your-project). The following only applies to the 3.3.0 preview release available on the [Maven Central Snapshots](https://oss.sonatype.org/content/repositories/snapshots/) repository.** + Android projects: ```groovy implementation("org.greenrobot:eventbus:3.3.0-SNAPSHOT") From 37c9296f90abdf4feea3454eda8dfa7ab076a797 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 6 Dec 2021 14:50:38 +0100 Subject: [PATCH 278/288] Prepare release 3.3.0 --- README.md | 8 +++----- build.gradle | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 31fb1521..2a1aac69 100644 --- a/README.md +++ b/README.md @@ -68,22 +68,20 @@ Add EventBus to your project Available on Maven Central. -**Note: to use the latest stable version [see the previous README](https://github.com/greenrobot/EventBus/tree/V3.2.0#add-eventbus-to-your-project). The following only applies to the 3.3.0 preview release available on the [Maven Central Snapshots](https://oss.sonatype.org/content/repositories/snapshots/) repository.** - Android projects: ```groovy -implementation("org.greenrobot:eventbus:3.3.0-SNAPSHOT") +implementation("org.greenrobot:eventbus:3.3.0") ``` Java projects: ```groovy -implementation("org.greenrobot:eventbus-java:3.3.0-SNAPSHOT") +implementation("org.greenrobot:eventbus-java:3.3.0") ``` ```xml org.greenrobot eventbus-java - 3.3.0-SNAPSHOT + 3.3.0 ``` diff --git a/build.gradle b/build.gradle index 57827719..0c29d3b2 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ buildscript { // Set group and version in root build.gradle so publish-plugin can detect them. group = "org.greenrobot" -version = "3.3.0-SNAPSHOT" +version = "3.3.0" allprojects { repositories { From f588193f2d4410c90e148fa7fe8f2767c0993023 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Mon, 6 Dec 2021 15:13:58 +0100 Subject: [PATCH 279/288] README: update build badge, license year. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2a1aac69..a8241b11 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ EventBus [EventBus](https://greenrobot.org/eventbus/) is a publish/subscribe event bus for Android and Java.
-[![Build Status](https://travis-ci.org/greenrobot/EventBus.svg?branch=master)](https://travis-ci.org/greenrobot/EventBus) +[![Build Status](https://github.com/greenrobot/EventBus/actions/workflows/gradle.yml/badge.svg)](https://github.com/greenrobot/EventBus/actions) [![Follow greenrobot on Twitter](https://img.shields.io/twitter/follow/greenrobot_de.svg?style=flat-square&logo=twitter)](https://twitter.com/greenrobot_de) EventBus... @@ -98,13 +98,13 @@ For more details please check the [EventBus website](https://greenrobot.org/even [Documentation](https://greenrobot.org/eventbus/documentation/) -[Changelog](https://greenrobot.org/eventbus/changelog/) +[Changelog](https://github.com/greenrobot/EventBus/releases) [FAQ](https://greenrobot.org/eventbus/documentation/faq/) License ------- -Copyright (C) 2012-2020 Markus Junginger, greenrobot (https://greenrobot.org) +Copyright (C) 2012-2021 Markus Junginger, greenrobot (https://greenrobot.org) EventBus binaries and source code can be used according to the [Apache License, Version 2.0](LICENSE). From 9f4d2ec6fa878afd94cc5c1751a439facff0c58a Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Wed, 8 Dec 2021 09:36:41 +0100 Subject: [PATCH 280/288] Fix ProGuard rules to keep default failure event class constructor. --- eventbus-android/consumer-rules.pro | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/eventbus-android/consumer-rules.pro b/eventbus-android/consumer-rules.pro index d5248bac..4646fb1e 100644 --- a/eventbus-android/consumer-rules.pro +++ b/eventbus-android/consumer-rules.pro @@ -4,8 +4,9 @@ } -keep enum org.greenrobot.eventbus.ThreadMode { *; } -# And if you use AsyncExecutor: --keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent { +# If using AsyncExecutord, keep required constructor of default event used. +# Adjust the class name if a custom failure event type is used. +-keepclassmembers class org.greenrobot.eventbus.util.ThrowableFailureEvent { (java.lang.Throwable); } From 757bc9a18ff7c63dc54ef30d208e3931e230292d Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Wed, 8 Dec 2021 09:37:19 +0100 Subject: [PATCH 281/288] AsyncExecutor: update docs with event class requirements, ProGuard rule tip. --- .../greenrobot/eventbus/util/AsyncExecutor.java | 16 ++++++++++++---- .../eventbus/util/ThrowableFailureEvent.java | 1 + 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java b/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java index 9c0433e8..c11e5c6c 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java +++ b/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java @@ -23,10 +23,18 @@ import java.util.logging.Level; /** - * Executes an {@link RunnableEx} using a thread pool. Thrown exceptions are propagated by posting failure events of any - * given type (default is {@link ThrowableFailureEvent}). - * - * @author Markus + * Executes an {@link RunnableEx} using a thread pool. Thrown exceptions are propagated by posting failure events. + * By default, uses {@link ThrowableFailureEvent}. + *

+ * Set a custom event type using {@link Builder#failureEventType(Class)}. + * The failure event class must have a constructor with one parameter of type {@link Throwable}. + * If using ProGuard or R8 make sure the constructor of the failure event class is kept, it is accessed via reflection. + * E.g. add a rule like + *

+ * -keepclassmembers class com.example.CustomThrowableFailureEvent {
+ *     <init>(java.lang.Throwable);
+ * }
+ * 
*/ public class AsyncExecutor { diff --git a/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java b/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java index 1b339fba..7707e289 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java @@ -17,6 +17,7 @@ /** * A generic failure event, which can be used by apps to propagate thrown exceptions. + * Used as default failure event by {@link AsyncExecutor}. */ public class ThrowableFailureEvent implements HasExecutionScope { protected final Throwable throwable; From 60c4b78837b933435f3d22e92690a8812b505ef5 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Wed, 8 Dec 2021 09:37:29 +0100 Subject: [PATCH 282/288] AsyncExecutor: use lambda. --- .../eventbus/util/AsyncExecutor.java | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java b/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java index c11e5c6c..bd9cb365 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java +++ b/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java @@ -111,24 +111,21 @@ private AsyncExecutor(Executor threadPool, EventBus eventBus, Class failureEv /** Posts an failure event if the given {@link RunnableEx} throws an Exception. */ public void execute(final RunnableEx runnable) { - threadPool.execute(new Runnable() { - @Override - public void run() { + threadPool.execute(() -> { + try { + runnable.run(); + } catch (Exception e) { + Object event; try { - runnable.run(); - } catch (Exception e) { - Object event; - try { - event = failureEventConstructor.newInstance(e); - } catch (Exception e1) { - eventBus.getLogger().log(Level.SEVERE, "Original exception:", e); - throw new RuntimeException("Could not create failure event", e1); - } - if (event instanceof HasExecutionScope) { - ((HasExecutionScope) event).setExecutionScope(scope); - } - eventBus.post(event); + event = failureEventConstructor.newInstance(e); + } catch (Exception e1) { + eventBus.getLogger().log(Level.SEVERE, "Original exception:", e); + throw new RuntimeException("Could not create failure event", e1); } + if (event instanceof HasExecutionScope) { + ((HasExecutionScope) event).setExecutionScope(scope); + } + eventBus.post(event); } }); } From eba6809508855cf061437ecae168688eb7259982 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Wed, 8 Dec 2021 10:12:43 +0100 Subject: [PATCH 283/288] Make EventBusPerformance build again (project outdated though) Use Java 8 features. --- EventBusPerformance/build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 247d085e..37a32249 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -40,4 +40,9 @@ android { } } } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } } From c7993322e531653789777360cc4821dd2183c4d7 Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Wed, 8 Dec 2021 11:51:14 +0100 Subject: [PATCH 284/288] Prepare release 3.3.1 --- README.md | 6 +++--- build.gradle | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a8241b11..878807a8 100644 --- a/README.md +++ b/README.md @@ -70,18 +70,18 @@ Available on org.greenrobot eventbus-java - 3.3.0 + 3.3.1 ``` diff --git a/build.gradle b/build.gradle index 0c29d3b2..aaeccfeb 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ buildscript { // Set group and version in root build.gradle so publish-plugin can detect them. group = "org.greenrobot" -version = "3.3.0" +version = "3.3.1" allprojects { repositories { From 6f939ca40a9691f0e12e3facff4bb4f0377aeae1 Mon Sep 17 00:00:00 2001 From: Uwe - ObjectBox <13865709+greenrobot-team@users.noreply.github.com> Date: Mon, 13 Dec 2021 12:53:39 +0100 Subject: [PATCH 285/288] README: fix subscriber method snippet. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 878807a8..75ecf629 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,9 @@ EventBus in 3 steps ```java @Subscribe(threadMode = ThreadMode.MAIN) - public void onMessageEvent(MessageEvent event) {/* Do something */}; + public void onMessageEvent(MessageEvent event) { + // Do something + } ``` Register and unregister your subscriber. For example on Android, activities and fragments should usually register according to their life cycle: From a74cdf0a5c96359b8d10e129740e33d90504f43a Mon Sep 17 00:00:00 2001 From: greenrobot Team Date: Tue, 25 Jan 2022 08:44:41 +0100 Subject: [PATCH 286/288] Document MAIN_ORDERED behavior if not Android. --- .../org/greenrobot/eventbus/ThreadMode.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/EventBus/src/org/greenrobot/eventbus/ThreadMode.java b/EventBus/src/org/greenrobot/eventbus/ThreadMode.java index b8ee7d53..b1ff2427 100644 --- a/EventBus/src/org/greenrobot/eventbus/ThreadMode.java +++ b/EventBus/src/org/greenrobot/eventbus/ThreadMode.java @@ -17,15 +17,14 @@ /** * Each subscriber method has a thread mode, which determines in which thread the method is to be called by EventBus. - * EventBus takes care of threading independently from the posting thread. - * + * EventBus takes care of threading independently of the posting thread. + * * @see EventBus#register(Object) - * @author Markus */ public enum ThreadMode { /** - * Subscriber will be called directly in the same thread, which is posting the event. This is the default. Event delivery - * implies the least overhead because it avoids thread switching completely. Thus this is the recommended mode for + * This is the default. Subscriber will be called directly in the same thread, which is posting the event. Event delivery + * implies the least overhead because it avoids thread switching completely. Thus, this is the recommended mode for * simple tasks that are known to complete in a very short time without requiring the main thread. Event handlers * using this mode must return quickly to avoid blocking the posting thread, which may be the main thread. */ @@ -35,6 +34,7 @@ public enum ThreadMode { * On Android, subscriber will be called in Android's main thread (UI thread). If the posting thread is * the main thread, subscriber methods will be called directly, blocking the posting thread. Otherwise the event * is queued for delivery (non-blocking). Subscribers using this mode must return quickly to avoid blocking the main thread. + *

* If not on Android, behaves the same as {@link #POSTING}. */ MAIN, @@ -42,6 +42,8 @@ public enum ThreadMode { /** * On Android, subscriber will be called in Android's main thread (UI thread). Different from {@link #MAIN}, * the event will always be queued for delivery. This ensures that the post call is non-blocking. + *

+ * If not on Android, behaves the same as {@link #POSTING}. */ MAIN_ORDERED, @@ -49,15 +51,17 @@ public enum ThreadMode { * On Android, subscriber will be called in a background thread. If posting thread is not the main thread, subscriber methods * will be called directly in the posting thread. If the posting thread is the main thread, EventBus uses a single * background thread, that will deliver all its events sequentially. Subscribers using this mode should try to - * return quickly to avoid blocking the background thread. If not on Android, always uses a background thread. + * return quickly to avoid blocking the background thread. + *

+ * If not on Android, always uses a background thread. */ BACKGROUND, /** - * Subscriber will be called in a separate thread. This is always independent from the posting thread and the + * Subscriber will be called in a separate thread. This is always independent of the posting thread and the * main thread. Posting events never wait for subscriber methods using this mode. Subscriber methods should * use this mode if their execution might take some time, e.g. for network access. Avoid triggering a large number - * of long running asynchronous subscriber methods at the same time to limit the number of concurrent threads. EventBus + * of long-running asynchronous subscriber methods at the same time to limit the number of concurrent threads. EventBus * uses a thread pool to efficiently reuse threads from completed asynchronous subscriber notifications. */ ASYNC From 842a4a312c4ea1592bd7067a00495eebe129c078 Mon Sep 17 00:00:00 2001 From: guoci Date: Wed, 22 Dec 2021 14:13:33 -0500 Subject: [PATCH 287/288] fix typo --- EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java b/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java index 624ddf6d..94db640e 100644 --- a/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java +++ b/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java @@ -64,7 +64,7 @@ public void run() { eventBus.invokeSubscriber(pendingPost); } } catch (InterruptedException e) { - eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e); + eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interrupted", e); } } finally { executorRunning = false; From 0194926b3bcf70cc0d7bfd3c5da16708dd5ab876 Mon Sep 17 00:00:00 2001 From: Uwe <13865709+greenrobot-team@users.noreply.github.com> Date: Mon, 11 Jul 2022 09:59:54 +0200 Subject: [PATCH 288/288] CI: use temurin for JDK, update checkout and setup-java to v3. --- .github/workflows/gradle.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 758ea017..365ea1a6 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -13,12 +13,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up JDK 11 - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: java-version: '11' - distribution: 'adopt' + distribution: 'temurin' cache: gradle - name: Grant execute permission for gradlew run: chmod +x gradlew