diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml new file mode 100644 index 00000000..365ea1a6 --- /dev/null +++ b/.github/workflows/gradle.yml @@ -0,0 +1,28 @@ +# 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@v3 + - name: Set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + 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 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5f3aa2fd..00000000 --- a/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -sudo: false -language: android -jdk: - - oraclejdk7 - -# http://docs.travis-ci.com/user/languages/android/ -android: - components: - - tools - - build-tools-23.0.2 - - android-10 - - extra-android-m2repository - -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 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b656e1a5..1402e6bb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,7 @@ Before you create an Issue... There are better Places for Support ----------------------------------- 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. +Instead, please use [stackoverflow.com](https://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, check http://greenrobot.org/contact-support/. diff --git a/EventBus/build.gradle b/EventBus/build.gradle index 50637de7..ffea11b6 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -1,44 +1,13 @@ apply plugin: 'java' -apply plugin: 'maven' -apply plugin: 'signing' -apply plugin: 'idea' -archivesBaseName = 'eventbus' -group = 'org.greenrobot' -version = '3.0.0' -sourceCompatibility = 1.7 +group = rootProject.group +version = rootProject.version -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 { - 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' - // deployerJars 'org.apache.maven.wagon:wagon-webdav-jackrabbit:2.4' - deployerJars 'org.apache.maven.wagon:wagon-webdav:1.0-beta-2' -} +java.sourceCompatibility = JavaVersion.VERSION_1_8 +java.targetCompatibility = JavaVersion.VERSION_1_8 sourceSets { main { - compileClasspath += configurations.provided java { srcDir 'src' // exclude 'de/greenrobot/event/util/**' @@ -46,98 +15,37 @@ sourceSets { } } -idea { - module { - scopes.PROVIDED.plus += [configurations.provided] - } -} - 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-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 -} - -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}" +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." + packaging = "jar" } - 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' - } - } } } } 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..94db640e 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 java.util.logging.Level; /** * 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); + eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interrupted", e); } } finally { executorRunning = false; diff --git a/EventBus/src/org/greenrobot/eventbus/EventBus.java b/EventBus/src/org/greenrobot/eventbus/EventBus.java index 1cd57e32..147bb5ff 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. @@ -15,9 +15,7 @@ */ package org.greenrobot.eventbus; -import android.os.Looper; -import android.util.Log; - +import org.greenrobot.eventbus.android.AndroidDependenciesDetector; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; @@ -27,14 +25,16 @@ 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 - * 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 */ @@ -59,7 +59,10 @@ protected PostingThreadState initialValue() { } }; - private final HandlerPoster mainThreadPoster; + // @Nullable + private final MainThreadSupport mainThreadSupport; + // @Nullable + private final Poster mainThreadPoster; private final BackgroundPoster backgroundPoster; private final AsyncPoster asyncPoster; private final SubscriberMethodFinder subscriberMethodFinder; @@ -73,17 +76,20 @@ 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() { - 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() { @@ -105,10 +111,12 @@ public EventBus() { } EventBus(EventBusBuilder builder) { + logger = builder.getLogger(); subscriptionsByEventType = new HashMap<>(); typesBySubscriber = new HashMap<>(); stickyEvents = new ConcurrentHashMap<>(); - mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); + mainThreadSupport = builder.getMainThreadSupport(); + mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null; backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0; @@ -132,6 +140,12 @@ public EventBus() { * ThreadMode} and priority. */ public void register(Object subscriber) { + if (AndroidDependenciesDetector.isAndroidSDKAvailable() && !AndroidDependenciesDetector.areAndroidComponentsAvailable()) { + // 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(); List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { @@ -196,10 +210,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, Looper.getMainLooper() == Looper.myLooper()); + 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(); + } + public synchronized boolean isRegistered(Object subscriber) { return typesBySubscriber.containsKey(subscriber); } @@ -230,7 +254,7 @@ public synchronized void unregister(Object subscriber) { } typesBySubscriber.remove(subscriber); } else { - Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass()); + logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass()); } } @@ -241,7 +265,7 @@ public void post(Object event) { eventQueue.add(event); if (!postingState.isPosting) { - postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper(); + postingState.isMainThread = isMainThread(); postingState.isPosting = true; if (postingState.canceled) { throw new EventBusException("Internal error. Abort state was not reset"); @@ -374,7 +398,7 @@ private void postSingleEvent(Object event, PostingThreadState postingState) thro } if (!subscriptionFound) { if (logNoSubscriberMessages) { - Log.d(TAG, "No subscribers registered for event " + eventClass); + logger.log(Level.FINE, "No subscribers registered for event " + eventClass); } if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) { @@ -392,7 +416,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; @@ -422,6 +446,14 @@ private void postToSubscription(Subscription subscription, Object event, boolean mainThreadPoster.enqueue(subscription, event); } break; + case MAIN_ORDERED: + 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) { backgroundPoster.enqueue(subscription, event); @@ -494,10 +526,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() + logger.log(Level.SEVERE, "SubscriberExceptionEvent subscriber " + subscription.subscriber.getClass() + " threw an exception", cause); SubscriberExceptionEvent exEvent = (SubscriberExceptionEvent) event; - Log.e(TAG, "Initial event " + exEvent.causingEvent + " caused exception in " + logger.log(Level.SEVERE, "Initial event " + exEvent.causingEvent + " caused exception in " + exEvent.causingSubscriber, exEvent.throwable); } } else { @@ -505,7 +537,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 " + logger.log(Level.SEVERE, "Could not dispatch event: " + event.getClass() + " to subscribing class " + subscription.subscriber.getClass(), cause); } if (sendSubscriberExceptionEvent) { @@ -518,7 +550,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; @@ -530,6 +562,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 e212750e..6df346d6 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. @@ -15,8 +15,8 @@ */ package org.greenrobot.eventbus; +import org.greenrobot.eventbus.android.AndroidComponents; import org.greenrobot.eventbus.meta.SubscriberInfoIndex; - import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; @@ -26,6 +26,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(); @@ -40,6 +41,8 @@ public class EventBusBuilder { ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE; List> skipMethodVerificationForClasses; List subscriberInfoIndexes; + Logger logger; + MainThreadSupport mainThreadSupport; EventBusBuilder() { } @@ -83,7 +86,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. @@ -130,13 +133,41 @@ 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); return this; } + /** + * Set a specific log handler for all EventBus logging. + *

+ * 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; + return this; + } + + Logger getLogger() { + if (logger != null) { + return logger; + } else { + return Logger.Default.get(); + } + } + + MainThreadSupport getMainThreadSupport() { + if (mainThreadSupport != null) { + return mainThreadSupport; + } else if (AndroidComponents.areAvailable()) { + return AndroidComponents.get().defaultMainThreadSupport; + } else { + 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/Logger.java b/EventBus/src/org/greenrobot/eventbus/Logger.java new file mode 100644 index 00000000..e9ec8e88 --- /dev/null +++ b/EventBus/src/org/greenrobot/eventbus/Logger.java @@ -0,0 +1,73 @@ +/* + * 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. + * 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.android.AndroidComponents; +import java.util.logging.Level; + +public interface Logger { + + void log(Level level, String msg); + + void log(Level level, String msg, Throwable th); + + class JavaLogger implements Logger { + protected final java.util.logging.Logger logger; + + public JavaLogger(String tag) { + logger = java.util.logging.Logger.getLogger(tag); + } + + @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); + } + + } + + class SystemOutLogger implements Logger { + + @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); + } + + } + + class Default { + public static Logger get() { + if (AndroidComponents.areAvailable()) { + return AndroidComponents.get().logger; + } + + return new SystemOutLogger(); + } + } + +} diff --git a/EventBus/src/org/greenrobot/eventbus/MainThreadSupport.java b/EventBus/src/org/greenrobot/eventbus/MainThreadSupport.java new file mode 100644 index 00000000..22605811 --- /dev/null +++ b/EventBus/src/org/greenrobot/eventbus/MainThreadSupport.java @@ -0,0 +1,26 @@ +/* + * 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; + +/** + * 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); +} diff --git a/EventBus/src/org/greenrobot/eventbus/Poster.java b/EventBus/src/org/greenrobot/eventbus/Poster.java new file mode 100644 index 00000000..67cfd67c --- /dev/null +++ b/EventBus/src/org/greenrobot/eventbus/Poster.java @@ -0,0 +1,32 @@ +/* + * 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; + +/** + * Posts events. + * + * @author William Ferguson + */ +public 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/SubscriberMethodFinder.java b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java index db5e0ad3..3f2812bc 100644 --- a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java @@ -154,7 +154,17 @@ 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(); + 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; } for (Method method : methods) { @@ -259,8 +269,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; } } diff --git a/EventBus/src/org/greenrobot/eventbus/ThreadMode.java b/EventBus/src/org/greenrobot/eventbus/ThreadMode.java index 79d5dc43..b1ff2427 100644 --- a/EventBus/src/org/greenrobot/eventbus/ThreadMode.java +++ b/EventBus/src/org/greenrobot/eventbus/ThreadMode.java @@ -16,42 +16,53 @@ 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. - * EventBus takes care of threading independently from the posting thread. - * + * 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 of the posting thread. + * * @see EventBus#register(Object) - * @author Markus */ public enum ThreadMode { /** - * 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 + * 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. */ 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, /** - * 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 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, + + /** + * 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 + * 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 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 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 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 new file mode 100644 index 00000000..1783f143 --- /dev/null +++ b/EventBus/src/org/greenrobot/eventbus/android/AndroidDependenciesDetector.java @@ -0,0 +1,48 @@ +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; + } + + private static final String ANDROID_COMPONENTS_IMPLEMENTATION_CLASS_NAME = "org.greenrobot.eventbus.android.AndroidComponentsImpl"; + + public static boolean areAndroidComponentsAvailable() { + + try { + Class.forName(ANDROID_COMPONENTS_IMPLEMENTATION_CLASS_NAME); + return true; + } + catch (ClassNotFoundException ex) { + return false; + } + } + + public static AndroidComponents instantiateAndroidComponents() { + + try { + 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/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); } } diff --git a/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java b/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java index c44c1366..bd9cb365 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java +++ b/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java @@ -15,20 +15,26 @@ */ 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 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 { @@ -59,10 +65,6 @@ public AsyncExecutor build() { return buildForScope(null); } - public AsyncExecutor buildForActivityScope(Activity activity) { - return buildForScope(activity.getClass()); - } - public AsyncExecutor buildForScope(Object executionContext) { if (eventBus == null) { eventBus = EventBus.getDefault(); @@ -109,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) { - Log.e(EventBus.TAG, "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); } }); } 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/ExceptionToResourceMapping.java b/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java index 9ab0d006..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,14 +16,13 @@ package org.greenrobot.eventbus.util; -import android.util.Log; - -import org.greenrobot.eventbus.EventBus; +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; /** @@ -36,7 +35,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 +51,8 @@ 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); + 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; } diff --git a/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java b/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java index 9b7b80b6..7707e289 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java @@ -16,8 +16,8 @@ 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. + * Used as default failure event by {@link AsyncExecutor}. */ public class ThrowableFailureEvent implements HasExecutionScope { protected final Throwable throwable; diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index 4dfa5eca..0ec77d93 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -1,41 +1,23 @@ apply plugin: 'java' -apply plugin: 'maven' -apply plugin: 'signing' -archivesBaseName = 'eventbus-annotation-processor' -group = 'org.greenrobot' -version = '3.0.1' +group = rootProject.group +version = rootProject.version -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 -} +java.sourceCompatibility = JavaVersion.VERSION_1_8 +java.targetCompatibility = JavaVersion.VERSION_1_8 dependencies { - compile project(':EventBus') - compile 'de.greenrobot:java-common:2.3.1' - deployerJars 'org.apache.maven.wagon:wagon-webdav:1.0-beta-2' + implementation project(':eventbus-java') + 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 { main { - compileClasspath += configurations.provided java { srcDir 'src' } @@ -46,91 +28,35 @@ sourceSets { } 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.' + 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 -} - -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.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' - } +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/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/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"; 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"> 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) { diff --git a/EventBusTest/AndroidManifest.xml b/EventBusTest/AndroidManifest.xml index 22aedee0..657ad878 100644 --- a/EventBusTest/AndroidManifest.xml +++ b/EventBusTest/AndroidManifest.xml @@ -1,20 +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 a1d04468..2ca34312 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -1,34 +1,30 @@ buildscript { repositories { - jcenter() + google() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.1' - classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' + // Note: IntelliJ IDEA 2021.1 only supports up to version 4.1 + classpath 'com.android.tools.build:gradle:4.1.3' } } apply plugin: 'com.android.application' -apply plugin: 'com.neenbedankt.android-apt' - -sourceCompatibility = 1.7 - -repositories { - jcenter() -} 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' + androidTestImplementation project(':eventbus-android') + androidTestImplementation project(':EventBusTestJava') + androidTestAnnotationProcessor project(':eventbus-annotation-processor') + // 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.2' + androidTestImplementation 'com.android.support.test:rules:1.0.2' } android { - buildToolsVersion '23.0.2' // When updating, don't forget to adjust .travis.yml - compileSdkVersion 19 + compileSdkVersion _compileSdkVersion compileOptions { sourceCompatibility = JavaVersion.VERSION_1_7 @@ -46,14 +42,28 @@ android { } defaultConfig { + minSdkVersion 9 + targetSdkVersion 26 + versionCode 1 + versionName "1.0" + testApplicationId "de.greenrobot.event.test" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + + javaCompileOptions { + annotationProcessorOptions { + arguments = [ eventBusIndex : 'org.greenrobot.eventbus.EventBusTestsIndex' ] + } + } } -} -apt { - arguments { - eventBusIndex "org.greenrobot.eventbus.EventBusTestsIndex" + useLibrary 'android.test.base' + + lintOptions { + // To see problems right away, also nice for Travis CI + textOutput 'stdout' + + // TODO FIXME: Travis only error + abortOnError false } } - 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/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/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/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/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/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/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/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..34c29ee6 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java @@ -17,33 +17,15 @@ import android.os.Looper; -import org.junit.After; -import org.junit.Before; import org.junit.Test; -import java.util.ArrayList; -import java.util.List; import static org.junit.Assert.assertEquals; /** * @author Markus Junginger, greenrobot */ -public class EventBusMainThreadTest extends AbstractEventBusTest { - - private BackgroundPoster backgroundPoster; - - @Before - public void setUp() throws Exception { - backgroundPoster = new BackgroundPoster(); - backgroundPoster.start(); - } - - @After - public void tearDown() throws Exception { - backgroundPoster.shutdown(); - backgroundPoster.join(); - } +public class EventBusMainThreadTest extends AbstractAndroidEventBusTest { @Test public void testPost() throws InterruptedException { @@ -57,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) @@ -69,68 +57,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/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/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); + } + } + } + } + +} 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(); + } + +} 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 1fcda4e3..4aec1ef6 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java @@ -17,10 +17,14 @@ 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(); + return EventBus.builder() + .addIndex(new EventBusTestsIndex()) + .addIndex(new EventBusJavaTestsIndex()) + .build(); } } diff --git a/EventBusTestJava/build.gradle b/EventBusTestJava/build.gradle new file mode 100644 index 00000000..9e2bdad1 --- /dev/null +++ b/EventBusTestJava/build.gradle @@ -0,0 +1,25 @@ +apply plugin: "java-library" + +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 +sourceSets { + test { + java { + srcDirs += ["src/main/java"] + } + } +} + +dependencies { + implementation fileTree(dir: "libs", include: "*.jar") + implementation(project(":eventbus-java")) + annotationProcessor project(":eventbus-annotation-processor") + implementation "junit:junit:4.13.2" +} + +tasks.withType(JavaCompile) { + options.compilerArgs += [ "-AeventBusIndex=org.greenrobot.eventbus.EventBusJavaTestsIndex" ] +} diff --git a/EventBusTestJava/libs/EventBusTestSubscriberInJar-3.0.0.jar b/EventBusTestJava/libs/EventBusTestSubscriberInJar-3.0.0.jar new file mode 100644 index 00000000..47b80ef0 Binary files /dev/null and b/EventBusTestJava/libs/EventBusTestSubscriberInJar-3.0.0.jar differ diff --git a/EventBusTest/src/org/greenrobot/eventbus/AbstractEventBusTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/AbstractEventBusTest.java similarity index 76% rename from EventBusTest/src/org/greenrobot/eventbus/AbstractEventBusTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/AbstractEventBusTest.java index 867cada1..fbbcf265 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/AbstractEventBusTest.java +++ b/EventBusTestJava/src/main/java/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,28 +15,23 @@ */ 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; 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.*; +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 +44,6 @@ public abstract class AbstractEventBusTest { protected volatile Object lastEvent; protected volatile Thread lastThread; - private EventPostHandler mainPoster; - public AbstractEventBusTest() { this(false); } @@ -67,12 +60,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 +91,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()); } @@ -138,4 +108,12 @@ protected void awaitLatch(CountDownLatch latch, long seconds) { } } + 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); + } + } 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/EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusBuilderTest.java similarity index 96% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusBuilderTest.java index 42d919de..16f13255 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusBuilderTest.java @@ -15,9 +15,9 @@ */ package org.greenrobot.eventbus; +import org.junit.Assert; import org.junit.Test; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; /** @@ -61,7 +61,7 @@ public void testInstallDefaultEventBus() { try { // Either this should throw when another unit test got the default event bus... eventBus = builder.installDefaultEventBus(); - assertEquals(eventBus, EventBus.getDefault()); + Assert.assertEquals(eventBus, EventBus.getDefault()); // ...or this should throw eventBus = builder.installDefaultEventBus(); diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java similarity index 88% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java index 869da70e..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 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; diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java similarity index 100% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusGenericsTest.java similarity index 100% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusGenericsTest.java 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/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..6ab86d23 --- /dev/null +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledSubclassTest.java @@ -0,0 +1,20 @@ +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 { + + int countMyEventOverwritten; + + @Subscribe + 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/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java similarity index 89% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java index 80638e8b..4b026719 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; @@ -94,7 +90,8 @@ public void testEventSuperInterfaceHierarchy() { @Test public void testSubscriberClassHierarchy() { - SubscriberExtended subscriber = new SubscriberExtended(); + EventBusInheritanceDisabledSubclassTest + subscriber = new EventBusInheritanceDisabledSubclassTest(); eventBus.register(subscriber); eventBus.post("Hello"); @@ -114,7 +111,8 @@ public void testSubscriberClassHierarchy() { @Test public void testSubscriberClassHierarchyWithoutNewSubscriberMethod() { - SubscriberExtendedWithoutNewSubscriberMethod subscriber = new SubscriberExtendedWithoutNewSubscriberMethod(); + EventBusInheritanceDisabledSubclassNoMethod + subscriber = new EventBusInheritanceDisabledSubclassNoMethod(); eventBus.register(subscriber); eventBus.post("Hello"); @@ -167,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++; - } - } - - 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..8b3d4e4d --- /dev/null +++ b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceSubclassTest.java @@ -0,0 +1,19 @@ +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; + + @Subscribe + public void onEvent(MyEvent event) { + countMyEventOverwritten++; + } + + @Override + @Ignore + public void testEventClassHierarchy() { + // TODO fix test in super, then remove this + } +} diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceTest.java similarity index 88% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusInheritanceTest.java index f9619bed..9fd52288 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(); } @@ -89,7 +90,7 @@ public void testEventSuperInterfaceHierarchy() { @Test public void testSubscriberClassHierarchy() { - SubscriberExtended subscriber = new SubscriberExtended(); + EventBusInheritanceSubclassTest subscriber = new EventBusInheritanceSubclassTest(); eventBus.register(subscriber); eventBus.post("Hello"); @@ -109,7 +110,8 @@ public void testSubscriberClassHierarchy() { @Test public void testSubscriberClassHierarchyWithoutNewSubscriberMethod() { - SubscriberExtendedWithoutNewSubscriberMethod subscriber = new SubscriberExtendedWithoutNewSubscriberMethod(); + EventBusInheritanceSubclassNoMethodTest + subscriber = new EventBusInheritanceSubclassNoMethodTest(); eventBus.register(subscriber); eventBus.post("Hello"); @@ -162,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++; - } - } - - static class SubscriberExtendedWithoutNewSubscriberMethod extends EventBusInheritanceTest { - } - public class StickySubscriber { @Subscribe(sticky = true) public void onEvent(Object event) { 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 f3e7bd50..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 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()); - } - } - } diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java similarity index 100% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java similarity index 97% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java index f6f97201..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; @@ -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 100% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusStickyEventTest.java similarity index 100% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusStickyEventTest.java diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java b/EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java similarity index 100% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java 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 100% rename from EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java rename to EventBusTestJava/src/main/java/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java 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 diff --git a/EventBusTestSubscriberInJar/build.gradle b/EventBusTestSubscriberInJar/build.gradle index 26adc98b..21096be3 100644 --- a/EventBusTestSubscriberInJar/build.gradle +++ b/EventBusTestSubscriberInJar/build.gradle @@ -1,32 +1,29 @@ -apply plugin: 'java' +apply plugin: "java-library" -group = 'de.greenrobot' -version = '3.0.0' -sourceCompatibility = 1.7 - -repositories { - jcenter() -} +group = "de.greenrobot" +version = "3.0.0" +java.sourceCompatibility = JavaVersion.VERSION_1_8 +java.targetCompatibility = JavaVersion.VERSION_1_8 configurations { provided } dependencies { - compile project(':EventBus') - provided project(':EventBusAnnotationProcessor') + 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 } diff --git a/README.md b/README.md index 1f193bd9..75ecf629 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ EventBus ======== -EventBus is a publish/subscribe event bus optimized for Android.
+[EventBus](https://greenrobot.org/eventbus/) is a publish/subscribe event bus for Android and Java.
+[![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... * simplifies the communication between components @@ -11,12 +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 ------------------- 1. Define events: @@ -26,11 +27,13 @@ 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) - 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: @@ -54,52 +57,61 @@ 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). + +**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 ---------------------------- -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: -```gradle -compile 'org.greenrobot:eventbus:3.0.0' +Available on Maven Central. + +Android projects: +```groovy +implementation("org.greenrobot:eventbus:3.3.1") ``` -Maven: +Java projects: +```groovy +implementation("org.greenrobot:eventbus-java:3.3.1") +``` ```xml org.greenrobot - eventbus - 3.0.0 + eventbus-java + 3.3.1 ``` -[Or download EventBus from Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.greenrobot%22%20AND%20a%3A%22eventbus%22) +R8, ProGuard +------------ + +If your project uses R8 or ProGuard this library ships [with embedded rules](/eventbus-android/consumer-rules.pro). 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](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://github.com/greenrobot/EventBus/releases) -[FAQ](http://greenrobot.org/eventbus/documentation/faq/) - -How does EventBus compare to other solutions, like Otto from Square? Check this [comparison](COMPARISON.md). +[FAQ](https://greenrobot.org/eventbus/documentation/faq/) License ------- -Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://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). -More Open Source by greenrobot -============================== -[__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. +Other projects by greenrobot +============================ +[__ObjectBox__](https://objectbox.io/) ([GitHub](https://github.com/objectbox/objectbox-java)) is a new superfast object-oriented database. -[Follow us on Google+](https://plus.google.com/b/114381455741141514652/+GreenrobotDe/posts) or check our [homepage](http://greenrobot.org/) to stay up to date. +[__Essentials__](https://github.com/greenrobot/essentials) is a set of utility classes and hash functions for Android & Java projects. diff --git a/build.gradle b/build.gradle index 9c519b5c..aaeccfeb 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,27 @@ +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" + } +} + +// Set group and version in root build.gradle so publish-plugin can detect them. +group = "org.greenrobot" +version = "3.3.1" + +allprojects { + repositories { + mavenCentral() + google() + } +} + if (JavaVersion.current().isJava8Compatible()) { allprojects { tasks.withType(Javadoc) { @@ -6,6 +30,23 @@ if (JavaVersion.current().isJava8Compatible()) { } } -task wrapper(type: Wrapper) { - gradleVersion = '2.14.1' +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/.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/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. diff --git a/eventbus-android/build.gradle b/eventbus-android/build.gradle new file mode 100644 index 00000000..c1992ce4 --- /dev/null +++ b/eventbus-android/build.gradle @@ -0,0 +1,62 @@ +buildscript { + repositories { + google() + mavenCentral() + } + + dependencies { + // Note: IntelliJ IDEA 2021.1 only supports up to version 4.1 + classpath 'com.android.tools.build:gradle:4.1.3' + } +} + +apply plugin: 'com.android.library' + +group = rootProject.group +version = rootProject.version + +android { + compileSdkVersion _compileSdkVersion + + defaultConfig { + minSdkVersion 7 + targetSdkVersion 30 // Android 11 (R) + + consumerProguardFiles "consumer-rules.pro" + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + api project(":eventbus-java") +} + +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 +// 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) { + 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/eventbus-android/consumer-rules.pro b/eventbus-android/consumer-rules.pro new file mode 100644 index 00000000..4646fb1e --- /dev/null +++ b/eventbus-android/consumer-rules.pro @@ -0,0 +1,14 @@ +-keepattributes *Annotation* +-keepclassmembers class * { + @org.greenrobot.eventbus.Subscribe ; +} +-keep enum org.greenrobot.eventbus.ThreadMode { *; } + +# 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); +} + +# Accessed via reflection, avoid renaming or removal +-keep class org.greenrobot.eventbus.android.AndroidComponentsImpl 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 92% rename from EventBus/src/org/greenrobot/eventbus/HandlerPoster.java rename to eventbus-android/src/main/java/org/greenrobot/eventbus/HandlerPoster.java index 3247be53..71158e2d 100644 --- a/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java +++ b/eventbus-android/src/main/java/org/greenrobot/eventbus/HandlerPoster.java @@ -20,21 +20,21 @@ import android.os.Message; import android.os.SystemClock; -final class HandlerPoster extends Handler { +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, Looper looper, int maxMillisInsideHandleMessage) { + public HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) { super(looper); 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-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..20f35b18 --- /dev/null +++ b/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidComponentsImpl.java @@ -0,0 +1,11 @@ +package org.greenrobot.eventbus.android; + +/** + * Used via reflection in the Java library by {@link AndroidDependenciesDetector}. + */ +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/AndroidLogger.java b/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidLogger.java new file mode 100644 index 00000000..04cc1cf3 --- /dev/null +++ b/eventbus-android/src/main/java/org/greenrobot/eventbus/android/AndroidLogger.java @@ -0,0 +1,60 @@ +/* + * 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 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; + } + } +} 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..02b3f3af --- /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 Looper.getMainLooper() == Looper.myLooper(); + } + + @Override + public Poster createPoster(EventBus eventBus) { + return new HandlerPoster(eventBus, Looper.getMainLooper(), 10); + } +} diff --git a/gradle/publish.gradle b/gradle/publish.gradle new file mode 100644 index 00000000..1206dd62 --- /dev/null +++ b/gradle/publish.gradle @@ -0,0 +1,81 @@ +// Configures common publishing settings. + +apply plugin: "maven-publish" +apply plugin: "signing" + +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" + } + + 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" + } + } + + issueManagement { + system = "https://github.com/greenrobot/EventBus/issues" + url = "https://github.com/greenrobot/EventBus/issues" + } + + 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." + } +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d3b83982..e708b1c0 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4fde35c7..8cf6eb5a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Tue Jul 12 16:09:12 SGT 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip diff --git a/gradlew b/gradlew index 27309d92..4f906e0c 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,20 @@ -#!/usr/bin/env bash +#!/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. +# ############################################################################## ## @@ -28,16 +44,16 @@ 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" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -66,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 @@ -109,10 +126,11 @@ 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"` # We build the pattern for arguments to be converted via cygpath @@ -138,27 +156,30 @@ if $cygwin ; 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 -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +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" -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index f6d5974e..ac1b06f9 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 @@ -13,15 +29,18 @@ 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= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @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 +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,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% @@ -45,34 +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 -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% +"%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 diff --git a/settings.gradle b/settings.gradle index a11c17d8..9e53b0e9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,10 @@ -include 'EventBus' -include 'EventBusAnnotationProcessor' -include 'EventBusTest' -include 'EventBusTestSubscriberInJar' -include 'EventBusPerformance' +include ':EventBus' +include ':EventBusAnnotationProcessor' +include ':EventBusTestJava' +include ':EventBusTest' +include ':EventBusTestSubscriberInJar' +include ':EventBusPerformance' +include ':eventbus-android' + +project(":EventBus").name = "eventbus-java" +project(":EventBusAnnotationProcessor").name = "eventbus-annotation-processor"