Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 7.6k
Initial support for scheduling on Android Handler threads#318
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
8df8e9af5e3b5b3919547d34372a0959aa535cf4577d397a7b80de9360fa7546f18d8bFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| apply plugin: 'java' | ||
| apply plugin: 'eclipse' | ||
| apply plugin: 'idea' | ||
| apply plugin: 'osgi' | ||
| sourceCompatibility = JavaVersion.VERSION_1_6 | ||
| targetCompatibility = JavaVersion.VERSION_1_6 | ||
| dependencies { | ||
| compile project(':rxjava-core') | ||
| provided 'junit:junit-dep:4.10' | ||
| provided 'org.mockito:mockito-core:1.8.5' | ||
| provided 'org.robolectric:robolectric:2.1.1' | ||
| provided 'com.google.android:android:4.0.1.2' | ||
| } | ||
| eclipse { | ||
| classpath { | ||
| // include 'provided' dependencies on the classpath | ||
| plusConfigurations += configurations.provided | ||
| downloadSources = true | ||
| downloadJavadoc = true | ||
| } | ||
| } | ||
| idea { | ||
| module { | ||
| // include 'provided' dependencies on the classpath | ||
| scopes.PROVIDED.plus += configurations.provided | ||
| } | ||
| } | ||
| javadoc { | ||
| options { | ||
| doclet = "org.benjchristensen.doclet.DocletExclude" | ||
| docletpath = [rootProject.file('./gradle/doclet-exclude.jar')] | ||
| stylesheetFile = rootProject.file('./gradle/javadocStyleSheet.css') | ||
| windowTitle = "RxJava Android Javadoc ${project.version}" | ||
| } | ||
| options.addStringOption('top').value = '<h2 class="title" style="padding-top:40px">RxJava Android</h2>' | ||
| } | ||
| jar { | ||
| manifest { | ||
| name = 'rxjava-android' | ||
| instruction 'Bundle-Vendor', 'Netflix' | ||
ContributorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In case SoundCloud wants to take ownership of the Android module, should probably update this Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know enough about OSGI requirements to comment on how this behaves. This artifact as part of RxJava however will be on maven central under "com.netflix.rxjava" as that's the namespace on Maven, despite keeping all of the code namespaced to just "rx". | ||
| instruction 'Bundle-DocURL', 'https://github.com/Netflix/RxJava' | ||
| instruction 'Import-Package', '!org.junit,!junit.framework,!org.mockito.*,*' | ||
| } | ||
| } | ||
| test { | ||
| testLogging { | ||
| exceptionFormat "full" | ||
| events "started" | ||
| displayGranularity 2 | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| package rx.android.concurrency; | ||
| import android.os.Handler; | ||
| import android.os.Looper; | ||
| import rx.Scheduler; | ||
| /** | ||
| * Schedulers that have Android specific functionality | ||
| */ | ||
| public class AndroidSchedulers { | ||
| private static final Scheduler MAIN_THREAD_SCHEDULER = | ||
| new HandlerThreadScheduler(new Handler(Looper.getMainLooper())); | ||
| private AndroidSchedulers(){ | ||
| } | ||
| /** | ||
| * {@link Scheduler} which uses the provided {@link Handler} to execute an action | ||
| * @param handler The handler that will be used when executing the action | ||
| * @return A handler based scheduler | ||
| */ | ||
| public static Scheduler handlerThread(final Handler handler) { | ||
| return new HandlerThreadScheduler(handler); | ||
| } | ||
| /** | ||
| * {@link Scheduler} which will execute an action on the main Android UI thread. | ||
| * | ||
| * @return A Main {@link Looper} based scheduler | ||
| */ | ||
| public static Scheduler mainThread() { | ||
| return MAIN_THREAD_SCHEDULER; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| package rx.android.concurrency; | ||
| import android.os.Handler; | ||
| import org.junit.Test; | ||
| import org.junit.runner.RunWith; | ||
| import org.mockito.ArgumentCaptor; | ||
| import org.robolectric.RobolectricTestRunner; | ||
| import org.robolectric.annotation.Config; | ||
| import rx.Scheduler; | ||
| import rx.Subscription; | ||
| import rx.operators.AtomicObservableSubscription; | ||
| import rx.util.functions.Func2; | ||
| import java.util.concurrent.TimeUnit; | ||
| import static org.mockito.Matchers.eq; | ||
| import static org.mockito.Mockito.mock; | ||
| import static org.mockito.Mockito.verify; | ||
| /** | ||
| * Schedules actions to run on an Android Handler thread. | ||
| */ | ||
| public class HandlerThreadScheduler extends Scheduler { | ||
| private final Handler handler; | ||
| /** | ||
| * Constructs a {@link HandlerThreadScheduler} using the given {@link Handler} | ||
| * @param handler {@link Handler} to use when scheduling actions | ||
| */ | ||
| public HandlerThreadScheduler(Handler handler) { | ||
| this.handler = handler; | ||
| } | ||
| /** | ||
| * Calls {@link HandlerThreadScheduler#schedule(Object, rx.util.functions.Func2, long, java.util.concurrent.TimeUnit)} | ||
| * with a delay of zero milliseconds. | ||
| * | ||
| * See {@link #schedule(Object, rx.util.functions.Func2, long, java.util.concurrent.TimeUnit)} | ||
| */ | ||
| @Override | ||
| public <T> Subscription schedule(final T state, final Func2<Scheduler, T, Subscription> action) { | ||
| return schedule(state, action, 0L, TimeUnit.MILLISECONDS); | ||
| } | ||
| /** | ||
| * Calls {@link Handler#postDelayed(Runnable, long)} with a runnable that executes the given action. | ||
| * @param state | ||
| * State to pass into the action. | ||
| * @param action | ||
| * Action to schedule. | ||
| * @param delayTime | ||
| * Time the action is to be delayed before executing. | ||
| * @param unit | ||
| * Time unit of the delay time. | ||
| * @return A Subscription from which one can unsubscribe from. | ||
| */ | ||
| @Override | ||
| public <T> Subscription schedule(final T state, final Func2<Scheduler, T, Subscription> action, long delayTime, TimeUnit unit) { | ||
| final AtomicObservableSubscription subscription = new AtomicObservableSubscription(); | ||
| final Scheduler _scheduler = this; | ||
| handler.postDelayed(new Runnable() { | ||
| @Override | ||
| public void run() { | ||
| subscription.wrap(action.call(_scheduler, state)); | ||
| } | ||
| }, unit.toMillis(delayTime)); | ||
| return subscription; | ||
| } | ||
| @RunWith(RobolectricTestRunner.class) | ||
| @Config(manifest=Config.NONE) | ||
| public static final class UnitTest { | ||
| @Test | ||
| public void shouldScheduleImmediateActionOnHandlerThread() { | ||
| final Handler handler = mock(Handler.class); | ||
| final Object state = new Object(); | ||
| final Func2<Scheduler, Object, Subscription> action = mock(Func2.class); | ||
| Scheduler scheduler = new HandlerThreadScheduler(handler); | ||
| scheduler.schedule(state, action); | ||
| // verify that we post to the given Handler | ||
| ArgumentCaptor<Runnable> runnable = ArgumentCaptor.forClass(Runnable.class); | ||
| verify(handler).postDelayed(runnable.capture(), eq(0L)); | ||
| // verify that the given handler delegates to our action | ||
| runnable.getValue().run(); | ||
| verify(action).call(scheduler, state); | ||
| } | ||
| @Test | ||
| public void shouldScheduleDelayedActionOnHandlerThread() { | ||
| final Handler handler = mock(Handler.class); | ||
| final Object state = new Object(); | ||
| final Func2<Scheduler, Object, Subscription> action = mock(Func2.class); | ||
| Scheduler scheduler = new HandlerThreadScheduler(handler); | ||
| scheduler.schedule(state, action, 1L, TimeUnit.SECONDS); | ||
| // verify that we post to the given Handler | ||
| ArgumentCaptor<Runnable> runnable = ArgumentCaptor.forClass(Runnable.class); | ||
| verify(handler).postDelayed(runnable.capture(), eq(1000L)); | ||
| // verify that the given handler delegates to our action | ||
| runnable.getValue().run(); | ||
| verify(action).call(scheduler, state); | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I basically copied this file over from the Swing contrib module. There's a lot of cruft in here which I think can be remove or at least shared with the parent modules? I'm thinking about IDE project file generation and JavaDoc setup.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes that's probably the case, I have not yet attempted doing that as I'm not the most comfortable with Gradle.