diff --git a/.gitignore b/.gitignore
index 01696e00..74c05caa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,6 +22,7 @@ buck-out/
.buckd/
# Intellij project files
+.idea/
.idea/libraries
.idea/.name
.idea/compiler.xml
diff --git a/README.md b/README.md
index d616cbc4..0f796a1a 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
Learning RxJava for Android by example
==============
-This is a repository with real-world useful examples of using RxJava with Android. [It usually will be in a constant state of "Work in Progress" (WIP)](http://blog.kaush.co/2014/09/15/learning-rxjava-with-android-by-example/).
+This is a repository with real-world useful examples of using RxJava with Android. [It usually will be in a constant state of "Work in Progress" (WIP)](https://kau.sh/blog/learning-rxjava-with-android-by-example/).
I've also been giving talks about Learning Rx using many of the examples listed in this repo.
@@ -10,22 +10,24 @@ I've also been giving talks about Learning Rx using many of the examples listed
## Examples:
-1. [Background work & concurrency (using Schedulers)](https://github.com/kaushikgopal/RxJava-Android-Samples/blob/master/README.md#1-background-work--concurrency-using-schedulers)
-2. [Accumulate calls (using buffer)](https://github.com/kaushikgopal/RxJava-Android-Samples/blob/master/README.md#2-accumulate-calls-using-buffer)
-3. [Instant/Auto searching text listeners (using Subjects & debounce)](https://github.com/kaushikgopal/RxJava-Android-Samples/blob/master/README.md#3-instantauto-searching-text-listeners-using-subjects--debounce)
-4. [Networking with Retrofit & RxJava (using zip, flatmap)](https://github.com/kaushikgopal/RxJava-Android-Samples/blob/master/README.md#4-networking-with-retrofit--rxjava-using-zip-flatmap)
-5. [Two-way data binding for TextViews (using PublishSubject)](https://github.com/kaushikgopal/RxJava-Android-Samples/blob/master/README.md#5-two-way-data-binding-for-textviews-using-publishsubject)
-6. [Simple and Advanced polling (using interval and repeatWhen)](https://github.com/kaushikgopal/RxJava-Android-Samples/blob/master/README.md#6-simple-and-advanced-polling-using-interval-and-repeatwhen)
-7. [Simple and Advanced exponential backoff (using delay and retryWhen)](https://github.com/kaushikgopal/RxJava-Android-Samples/blob/master/README.md#7-simple-and-advanced-exponential-backoff-using-delay-and-retrywhen)
-8. [Form validation (using combineLatest)](https://github.com/kaushikgopal/RxJava-Android-Samples/blob/master/README.md#8-form-validation-using-combinelatest)
-9. [Pseudo caching : retrieve data first from a cache, then a network call (using concat, concatEager, merge or publish)](https://github.com/kaushikgopal/RxJava-Android-Samples/blob/master/README.md#9-pseudo-caching--retrieve-data-first-from-a-cache-then-a-network-call-using-concat-concateager-merge-or-publish)
-10. [Simple timing demos (using timer, interval or delay)](https://github.com/kaushikgopal/RxJava-Android-Samples/blob/master/README.md#10-simple-timing-demos-using-timer-interval-and-delay)
-11. [RxBus : event bus using RxJava (using RxRelay (never terminating Subjects) and debouncedBuffer)](https://github.com/kaushikgopal/RxJava-Android-Samples/blob/master/README.md#11-rxbus--event-bus-using-rxjava-using-rxrelay-never-terminating-subjects-and-debouncedbuffer)
-12. [Persist data on Activity rotations (using Subjects and retained Fragments)](https://github.com/kaushikgopal/RxJava-Android-Samples/blob/master/README.md#12-persist-data-on-activity-rotations-using-subjects-and-retained-fragments)
-13. [Networking with Volley](https://github.com/kaushikgopal/RxJava-Android-Samples/blob/master/README.md#13-networking-with-volley)
-14. [Pagination with Rx (using Subjects)](https://github.com/kaushikgopal/RxJava-Android-Samples/blob/master/README.md#14-pagination-with-rx-using-subjects)
-15. [Orchestrating Observable: make parallel network calls, then combine the result into a single data point (using flatmap & zip)](https://github.com/kaushikgopal/RxJava-Android-Samples/blob/master/README.md#15-orchestrating-observable-make-parallel-network-calls-then-combine-the-result-into-a-single-data-point-using-flatmap--zip)
-16. [Simple Timeout example (using timeout)]()
+1. [Background work & concurrency (using Schedulers)](#1-background-work--concurrency-using-schedulers)
+2. [Accumulate calls (using buffer)](#2-accumulate-calls-using-buffer)
+3. [Instant/Auto searching text listeners (using Subjects & debounce)](#3-instantauto-searching-text-listeners-using-subjects--debounce)
+4. [Networking with Retrofit & RxJava (using zip, flatmap)](#4-networking-with-retrofit--rxjava-using-zip-flatmap)
+5. [Two-way data binding for TextViews (using PublishSubject)](#5-two-way-data-binding-for-textviews-using-publishsubject)
+6. [Simple and Advanced polling (using interval and repeatWhen)](#6-simple-and-advanced-polling-using-interval-and-repeatwhen)
+7. [Simple and Advanced exponential backoff (using delay and retryWhen)](#7-simple-and-advanced-exponential-backoff-using-delay-and-retrywhen)
+8. [Form validation (using combineLatest)](#8-form-validation-using-combinelatest)
+9. [Pseudo caching : retrieve data first from a cache, then a network call (using concat, concatEager, merge or publish)](#9-pseudo-caching--retrieve-data-first-from-a-cache-then-a-network-call-using-concat-concateager-merge-or-publish)
+10. [Simple timing demos (using timer, interval or delay)](#10-simple-timing-demos-using-timer-interval-and-delay)
+11. [RxBus : event bus using RxJava (using RxRelay (never terminating Subjects) and debouncedBuffer)](#11-rxbus--event-bus-using-rxjava-using-rxrelay-never-terminating-subjects-and-debouncedbuffer)
+12. [Persist data on Activity rotations (using Subjects and retained Fragments)](#12-persist-data-on-activity-rotations-using-subjects-and-retained-fragments)
+13. [Networking with Volley](#13-networking-with-volley)
+14. [Pagination with Rx (using Subjects)](#14-pagination-with-rx-using-subjects)
+15. [Orchestrating Observable: make parallel network calls, then combine the result into a single data point (using flatmap & zip)](#15-orchestrating-observable-make-parallel-network-calls-then-combine-the-result-into-a-single-data-point-using-flatmap--zip)
+16. [Simple Timeout example (using timeout)](#16-simple-timeout-example-using-timeout)
+17. [Setup and teardown resources (using `using`)](#17-setup-and-teardown-resources-using-using)
+18. [Multicast playground](#18-multicast-playground)
## Description
@@ -47,7 +49,7 @@ If you hit the button once, you'll get a message saying the button was hit once.
Note:
-If you're looking for a more foolproof solution that accumulates "continuous" taps vs just the number of taps within a time span, look at the [EventBus Demo](https://github.com/kaushikgopal/Android-RxJava/blob/master/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom3Fragment.java) where a combo of the `publish` and `buffer` operators is used. For a more detailed explanation, you can also have a look at this [blog post](http://blog.kaush.co/2015/01/05/debouncedbuffer-with-rxjava/).
+If you're looking for a more foolproof solution that accumulates "continuous" taps vs just the number of taps within a time span, look at the [EventBus Demo](https://github.com/kaushikgopal/Android-RxJava/blob/master/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom3Fragment.java) where a combo of the `publish` and `buffer` operators is used. For a more detailed explanation, you can also have a look at this [blog post](https://kau.sh/blog/debouncedbuffer-with-rxjava/).
### 3. Instant/Auto searching text listeners (using Subjects & debounce)
@@ -100,6 +102,7 @@ We simulate this behaviour using RxJava with the [`retryWhen` operator](http://r
* http://stackoverflow.com/a/25292833/159825
* Another excellent implementation via @[sddamico](https://github.com/sddamico) : https://gist.github.com/sddamico/c45d7cdabc41e663bea1
+* This one includes support for jittering, by @[leandrofavarin](https://github.com/leandrofavarin) : http://leandrofavarin.com/exponential-backoff-rxjava-operator-with-jitter
Also look at the [Polling example](https://github.com/kaushikgopal/RxJava-Android-Samples#polling-with-schedulers) where we use a very similar Exponential backoff mechanism.
@@ -144,7 +147,7 @@ Sometimes though, you just want to start showing the results immediately. Assumi
Similar to the `concat` operator, if your first Observable is always faster than the second Observable you won't run into any problems. However the problem with `merge` is: if for some strange reason an item is emitted by the cache or slower observable *after* the newer/fresher observable, it will overwrite the newer content. Click the "MERGE (SLOWER DISK)" button in the example to see this problem in action. @JakeWharton and @swankjesse contributions go to 0! In the real world this could be bad, as it would mean the fresh data would get overridden by stale disk data.
-To solve this problem you can use merge in combination with the super nifty `publish` operator which takes in a "selector". I wrote about this usage in a [blog post](http://blog.kaush.co/2015/01/21/rxjava-tip-for-the-day-share-publish-refcount-and-all-that-jazz/) but I have [Jedi JW](https://twitter.com/JakeWharton/status/786363146990649345) to thank for reminding of this technique. We `publish` the network observable and provide it a selector which starts emitting from the disk cache, up until the point that the network observable starts emitting. Once the network observable starts emitting, it ignores all results from the disk observable. This is perfect and handles any problems we might have.
+To solve this problem you can use merge in combination with the super nifty `publish` operator which takes in a "selector". I wrote about this usage in a [blog post](https://kau.sh/blog/rxjava-tip-for-the-day-share-publish-refcount-and-all-that-jazz/) but I have [Jedi JW](https://twitter.com/JakeWharton/status/786363146990649345) to thank for reminding of this technique. We `publish` the network observable and provide it a selector which starts emitting from the disk cache, up until the point that the network observable starts emitting. Once the network observable starts emitting, it ignores all results from the disk observable. This is perfect and handles any problems we might have.
Previously, I was using the `merge` operator but overcoming the problem of results being overwritten by monitoring the "resultAge". See the old `PseudoCacheMergeFragment` example if you're curious to see this old implementation.
@@ -160,13 +163,13 @@ Cases demonstrated here:
4. run a task constantly every 3s, but after running it 5 times, terminate automatically
5. run a task A, pause for sometime, then execute Task B, then terminate
-### 11. RxBus : event bus using RxJava (using RxRelay (never terminating Subjects) and debouncedBuffer)
+### 11. RxBus : event bus using RxJava (using RxRelay (never terminating Subjects) and debouncedBuffer)
There are accompanying blog posts that do a much better job of explaining the details on this demo:
-1. [Implementing an event bus with RxJava](http://blog.kaush.co/2014/12/24/implementing-an-event-bus-with-rxjava-rxbus/)
-2. [DebouncedBuffer used for the fancier variant of the demo](http://blog.kaush.co/2015/01/05/debouncedbuffer-with-rxjava/)
-3. [share/publish/refcount](http://blog.kaush.co/2015/01/21/rxjava-tip-for-the-day-share-publish-refcount-and-all-that-jazz/)
+1. [Implementing an event bus with RxJava](https://kau.sh/blog/implementing-an-event-bus-with-rxjava-rxbus/)
+2. [DebouncedBuffer used for the fancier variant of the demo](https://kau.sh/blog/debouncedbuffer-with-rxjava/)
+3. [share/publish/refcount](https://kau.sh/blog/rxjava-tip-for-the-day-share-publish-refcount-and-all-that-jazz/)
### 12. Persist data on Activity rotations (using Subjects and retained Fragments)
@@ -176,7 +179,7 @@ This example shows you one strategy viz. using retained Fragments. I started usi
Hit the start button and rotate the screen to your heart's content; you'll see the observable continue from where it left off.
-*There are certain quirks about the "hotness" of the source observable used in this example. Check [my blog post](http://blog.kaush.co/2015/07/11/a-note-about-the-warmth-share-operator/) out where I explain the specifics.*
+*There are certain quirks about the "hotness" of the source observable used in this example. Check [my blog post](https://kau.sh/blog/a-note-about-the-warmth-share-operator/) out where I explain the specifics.*
I have since rewritten this example using an alternative approach. While the [`ConnectedObservable` approach worked](https://github.com/kaushikgopal/RxJava-Android-Samples/blob/master/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist1WorkerFragment.java#L20) it enters the lands of "multicasting" which can be tricky (thread-safety, .refcount etc.). Subjects on the other hand are far more simple. You can see it rewritten [using a `Subject` here](https://github.com/kaushikgopal/RxJava-Android-Samples/blob/master/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist2WorkerFragment.java#L22).
@@ -221,6 +224,20 @@ This is a simple example demonstrating the use of the `.timeout` operator. Butto
Notice how we can provide a custom Observable that indicates how to react under a timeout Exception.
+### 17. Setup and teardown resources (using `using`)
+
+The [operator `using`](http://reactivex.io/documentation/operators/using.html) is relatively less known and notoriously hard to Google. It's a beautiful API that helps to setup a (costly) resource, use it and then dispose off in a clean way.
+
+The nice thing about this operator is that it provides a mechansim to use potentially costly resources in a tightly scoped manner. using -> setup, use and dispose. Think DB connections (like Realm instances), socket connections, thread locks etc.
+
+### 18. Multicast Playground
+
+Multicasting in Rx is like a dark art. Not too many folks know how to pull it off without concern. This example condiers two subscribers (in the forms of buttons) and allows you to add/remove subscribers at different points of time and see how the different operators behave under those circumstances.
+
+The source observale is a timer (`interval`) observable and the reason this was chosen was to intentionally pick a non-terminating observable, so you can test/confirm if your multicast experiment will leak.
+
+_I also gave a talk about [Multicasting in detail at 360|Andev](https://speakerdeck.com/kaushikgopal/rx-by-example-volume-3-the-multicast-edition). If you have the inclination and time, I highly suggest watching that talk first (specifically the Multicast operator permutation segment) and then messing around with the example here._
+
## Rx 2.x
All the examples here have been migrated to use RxJava 2.X.
@@ -236,6 +253,18 @@ I try to ensure the examples are not overly contrived but reflect a real-world u
I'm wrapping my head around RxJava too so if you feel there's a better way of doing one of the examples mentioned above, open up an issue explaining how. Even better, send a pull request.
+
+## Sponsorship (Memory Management/Profiling)
+
+Rx threading is messy business. To help, this project uses YourKit tools for analysis.
+
+
+
+
+YourKit supports open source projects with innovative and intelligent tools
+for monitoring and profiling Java applications. YourKit is the creator of YourKit Java Profiler .
+
+
## License
Licensed under the Apache License, Version 2.0 (the "License").
diff --git a/app/build.gradle b/app/build.gradle
index 99e29a4a..edbcd31c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -4,10 +4,8 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'me.tatarka:gradle-retrolambda:3.2.5'
- // can be removed with android-gradle plugin is upgraded to 2.2
- // https://twitter.com/JakeWharton/status/760836175586267136
- classpath 'me.tatarka.retrolambda.projectlombok:lombok.ast:0.2.3.a2'
+ classpath 'me.tatarka:gradle-retrolambda:3.6.0'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}"
}
// Exclude the lombok version that the android plugin depends on.
@@ -16,54 +14,57 @@ buildscript {
apply plugin: 'com.android.application'
apply plugin: 'me.tatarka.retrolambda'
-
-ext {
- okhttpVersion = "3.0.1"
- retrofitVersion = "2.0.0"
- sdkVersion = 24
- supportLibVersion = "24.2.1"
-}
+apply plugin: 'com.f2prateek.javafmt'
+apply plugin: 'kotlin-android'
dependencies {
+ compile 'com.android.support:multidex:1.0.1'
compile "com.android.support:support-v13:${supportLibVersion}"
compile "com.android.support:appcompat-v7:${supportLibVersion}"
compile "com.android.support:recyclerview-v7:${supportLibVersion}"
compile 'com.github.kaushikgopal:CoreTextUtils:c703fa12b6'
- compile 'com.jakewharton:butterknife:7.0.1'
- compile 'com.jakewharton.timber:timber:2.4.2'
+ compile "com.jakewharton:butterknife:${butterKnifeVersion}"
+ kapt "com.jakewharton:butterknife-compiler:${butterKnifeVersion}"
+ compile 'com.jakewharton.timber:timber:4.5.1'
compile "com.squareup.retrofit2:retrofit:${retrofitVersion}"
compile "com.squareup.retrofit2:converter-gson:${retrofitVersion}"
compile "com.squareup.okhttp3:okhttp:${okhttpVersion}"
compile "com.squareup.okhttp3:okhttp-urlconnection:${okhttpVersion}"
compile 'com.mcxiaoke.volley:library:1.0.19'
+ compile "org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}"
+ compile "com.nhaarman:mockito-kotlin:${mockitoKotlinVersion}"
+
+ compile "android.arch.lifecycle:runtime:${archComponentsVersion}"
+ compile "android.arch.lifecycle:extensions:${archComponentsVersion}"
+ kapt "android.arch.lifecycle:compiler:${archComponentsVersion}"
+
// ----------------------------------
// Rx dependencies
- compile 'io.reactivex.rxjava2:rxjava:2.0.1'
+ compile 'io.reactivex.rxjava2:rxjava:2.0.7'
// Because RxAndroid releases are few and far between, it is recommended you also
// explicitly depend on RxJava's latest version for bug fixes and new features.
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
- // libs like rxbinding + rxjava-math haven't been ported to RxJava 2.x yet, so this helps
- compile "com.github.akarnokd:rxjava2-interop:0.6.1"
-
- compile 'io.reactivex:rxjava-math:1.0.0'
+ compile 'com.jakewharton.rx:replaying-share-kotlin:2.0.0'
+ compile "com.github.akarnokd:rxjava2-extensions:0.16.0"
compile 'com.jakewharton.rxrelay2:rxrelay:2.0.0'
- compile 'com.jakewharton.rxbinding:rxbinding:0.2.0'
+
+ compile 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
// ----------------------------------
- debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3'
- releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3'
+ debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1'
+ releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
}
android {
compileSdkVersion sdkVersion
- buildToolsVersion '23.0.3'
+ buildToolsVersion buildToolsVrs
defaultConfig {
applicationId "com.morihacky.android.rxjava"
@@ -71,6 +72,7 @@ android {
targetSdkVersion sdkVersion
versionCode 2
versionName "1.2"
+ multiDexEnabled true
}
buildTypes {
release {
@@ -78,11 +80,13 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
+ sourceSets {
+ main.java.srcDirs += 'src/main/kotlin'
+ }
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
-
packagingOptions {
pickFirst 'META-INF/rxjava.properties'
}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/MainActivity.java b/app/src/main/java/com/morihacky/android/rxjava/MainActivity.java
index 59715261..068a393d 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/MainActivity.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/MainActivity.java
@@ -2,60 +2,58 @@
import android.os.Bundle;
import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentActivity;
+import android.support.v7.app.AppCompatActivity;
import com.morihacky.android.rxjava.fragments.MainFragment;
import com.morihacky.android.rxjava.fragments.RotationPersist1WorkerFragment;
import com.morihacky.android.rxjava.fragments.RotationPersist2WorkerFragment;
import com.morihacky.android.rxjava.rxbus.RxBus;
-public class MainActivity
- extends FragmentActivity {
+public class MainActivity extends AppCompatActivity {
- private RxBus _rxBus = null;
+ private RxBus _rxBus = null;
- @Override
- public void onBackPressed() {
- super.onBackPressed();
- _removeWorkerFragments();
- }
+ @Override
+ public void onBackPressed() {
+ super.onBackPressed();
+ _removeWorkerFragments();
+ }
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
- if (savedInstanceState == null) {
- getSupportFragmentManager().beginTransaction()
- .replace(android.R.id.content, new MainFragment(), this.toString())
- .commit();
- }
+ if (savedInstanceState == null) {
+ getSupportFragmentManager()
+ .beginTransaction()
+ .replace(android.R.id.content, new MainFragment(), this.toString())
+ .commit();
}
+ }
- // This is better done with a DI Library like Dagger
- public RxBus getRxBusSingleton() {
- if (_rxBus == null) {
- _rxBus = new RxBus();
- }
-
- return _rxBus;
+ // This is better done with a DI Library like Dagger
+ public RxBus getRxBusSingleton() {
+ if (_rxBus == null) {
+ _rxBus = new RxBus();
}
- private void _removeWorkerFragments() {
- Fragment frag = getSupportFragmentManager().findFragmentByTag(RotationPersist1WorkerFragment.class.getName());
+ return _rxBus;
+ }
- if (frag != null) {
- getSupportFragmentManager()
- .beginTransaction()
- .remove(frag)
- .commit();
- }
+ private void _removeWorkerFragments() {
+ Fragment frag =
+ getSupportFragmentManager()
+ .findFragmentByTag(RotationPersist1WorkerFragment.class.getName());
+
+ if (frag != null) {
+ getSupportFragmentManager().beginTransaction().remove(frag).commit();
+ }
- frag = getSupportFragmentManager().findFragmentByTag(RotationPersist2WorkerFragment.class.getName());
+ frag =
+ getSupportFragmentManager()
+ .findFragmentByTag(RotationPersist2WorkerFragment.class.getName());
- if (frag != null) {
- getSupportFragmentManager()
- .beginTransaction()
- .remove(frag)
- .commit();
- }
+ if (frag != null) {
+ getSupportFragmentManager().beginTransaction().remove(frag).commit();
}
-}
\ No newline at end of file
+ }
+}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/MyApp.java b/app/src/main/java/com/morihacky/android/rxjava/MyApp.java
index 899b56d6..23a90b23 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/MyApp.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/MyApp.java
@@ -1,38 +1,43 @@
package com.morihacky.android.rxjava;
-import android.app.Application;
+import android.support.multidex.MultiDexApplication;
import com.morihacky.android.rxjava.volley.MyVolley;
import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.RefWatcher;
import timber.log.Timber;
-public class MyApp
- extends Application {
+public class MyApp extends MultiDexApplication {
- private static MyApp _instance;
- private RefWatcher _refWatcher;
+ private static MyApp _instance;
+ private RefWatcher _refWatcher;
- public static MyApp get() {
- return _instance;
- }
+ public static MyApp get() {
+ return _instance;
+ }
- public static RefWatcher getRefWatcher() {
- return MyApp.get()._refWatcher;
- }
+ public static RefWatcher getRefWatcher() {
+ return MyApp.get()._refWatcher;
+ }
- @Override
- public void onCreate() {
- super.onCreate();
+ @Override
+ public void onCreate() {
+ super.onCreate();
- _instance = (MyApp) getApplicationContext();
- _refWatcher = LeakCanary.install(this);
+ if (LeakCanary.isInAnalyzerProcess(this)) {
+ // This process is dedicated to LeakCanary for heap analysis.
+ // You should not init your app in this process.
+ return;
+ }
- // for better RxJava debugging
- //RxJavaHooks.enableAssemblyTracking();
+ _instance = (MyApp) getApplicationContext();
+ _refWatcher = LeakCanary.install(this);
- // Initialize Volley
- MyVolley.init(this);
+ // for better RxJava debugging
+ //RxJavaHooks.enableAssemblyTracking();
- Timber.plant(new Timber.DebugTree());
- }
+ // Initialize Volley
+ MyVolley.init(this);
+
+ Timber.plant(new Timber.DebugTree());
+ }
}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/BaseFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/BaseFragment.java
index 429f8ba0..4ce242f3 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/fragments/BaseFragment.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/BaseFragment.java
@@ -4,13 +4,12 @@
import com.morihacky.android.rxjava.MyApp;
import com.squareup.leakcanary.RefWatcher;
-public class BaseFragment
- extends Fragment {
+public class BaseFragment extends Fragment {
- @Override
- public void onDestroy() {
- super.onDestroy();
- RefWatcher refWatcher = MyApp.getRefWatcher();
- refWatcher.watch(this);
- }
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ RefWatcher refWatcher = MyApp.getRefWatcher();
+ refWatcher.watch(this);
+ }
}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/BufferDemoFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/BufferDemoFragment.java
index 445aa735..bf51b85c 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/fragments/BufferDemoFragment.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/BufferDemoFragment.java
@@ -10,7 +10,7 @@
import android.widget.Button;
import android.widget.ListView;
-import com.jakewharton.rxbinding.view.RxView;
+import com.jakewharton.rxbinding2.view.RxView;
import com.morihacky.android.rxjava.R;
import com.morihacky.android.rxjava.wiring.LogAdapter;
@@ -18,9 +18,9 @@
import java.util.List;
import java.util.concurrent.TimeUnit;
-import butterknife.Bind;
+import butterknife.BindView;
import butterknife.ButterKnife;
-import hu.akarnokd.rxjava.interop.RxJavaInterop;
+import butterknife.Unbinder;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.observers.DisposableObserver;
@@ -29,125 +29,132 @@
/**
* This is a demonstration of the `buffer` Observable.
*
- * The buffer observable allows taps to be collected only within a time span. So taps outside the
+ *
The buffer observable allows taps to be collected only within a time span. So taps outside the
* 2s limit imposed by buffer will get accumulated in the next log statement.
*
- * If you're looking for a more foolproof solution that accumulates "continuous" taps vs
- * a more dumb solution as show below (i.e. number of taps within a timespan)
- * look at {@link com.morihacky.android.rxjava.rxbus.RxBusDemo_Bottom3Fragment} where a combo
- * of `publish` and `buffer` is used.
+ *
If you're looking for a more foolproof solution that accumulates "continuous" taps vs a more
+ * dumb solution as show below (i.e. number of taps within a timespan) look at {@link
+ * com.morihacky.android.rxjava.rxbus.RxBusDemo_Bottom3Fragment} where a combo of `publish` and
+ * `buffer` is used.
*
- * Also http://nerds.weddingpartyapp.com/tech/2015/01/05/debouncedbuffer-used-in-rxbus-example/
+ *
Also http://nerds.weddingpartyapp.com/tech/2015/01/05/debouncedbuffer-used-in-rxbus-example/
* if you're looking for words instead of code
*/
-public class BufferDemoFragment
- extends BaseFragment {
-
- @Bind(R.id.list_threading_log) ListView _logsList;
- @Bind(R.id.btn_start_operation) Button _tapBtn;
-
- private LogAdapter _adapter;
- private List _logs;
-
- private Disposable _disposable;
-
- @Override
- public void onResume() {
- super.onResume();
- _disposable = _getBufferedDisposable();
- }
-
- @Override
- public void onPause() {
- super.onPause();
- _disposable.dispose();
- }
-
- @Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- _setupLogger();
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater,
- @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
- View layout = inflater.inflate(R.layout.fragment_buffer, container, false);
- ButterKnife.bind(this, layout);
- return layout;
- }
-
- @Override public void onDestroyView() {
- super.onDestroyView();
- ButterKnife.unbind(this);
- }
-
- // -----------------------------------------------------------------------------------
- // Main Rx entities
-
- private Disposable _getBufferedDisposable() {
- return RxJavaInterop.toV2Observable(RxView.clickEvents(_tapBtn))
- .map(onClickEvent -> {
- Timber.d("--------- GOT A TAP");
- _log("GOT A TAP");
- return 1;
- })
- .buffer(2, TimeUnit.SECONDS)
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeWith(new DisposableObserver>() {
-
- @Override
- public void onComplete() {
- // fyi: you'll never reach here
- Timber.d("----- onCompleted");
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e(e, "--------- Woops on error!");
- _log("Dang error! check your logs");
- }
-
- @Override
- public void onNext(List integers) {
- Timber.d("--------- onNext");
- if (integers.size() > 0) {
- _log(String.format("%d taps", integers.size()));
- } else {
- Timber.d("--------- No taps received ");
- }
- }
- });
- }
-
- // -----------------------------------------------------------------------------------
- // Methods that help wiring up the example (irrelevant to RxJava)
-
- private void _setupLogger() {
- _logs = new ArrayList<>();
- _adapter = new LogAdapter(getActivity(), new ArrayList<>());
- _logsList.setAdapter(_adapter);
- }
-
- private void _log(String logMsg) {
-
- if (_isCurrentlyOnMainThread()) {
- _logs.add(0, logMsg + " (main thread) ");
- _adapter.clear();
- _adapter.addAll(_logs);
- } else {
- _logs.add(0, logMsg + " (NOT main thread) ");
-
- // You can only do below stuff on main thread.
- new Handler(Looper.getMainLooper()).post(() -> {
+public class BufferDemoFragment extends BaseFragment {
+
+ @BindView(R.id.list_threading_log)
+ ListView _logsList;
+
+ @BindView(R.id.btn_start_operation)
+ Button _tapBtn;
+
+ private LogAdapter _adapter;
+ private List _logs;
+
+ private Disposable _disposable;
+ private Unbinder unbinder;
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ _disposable = _getBufferedDisposable();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ _disposable.dispose();
+ }
+
+ @Override
+ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ _setupLogger();
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View layout = inflater.inflate(R.layout.fragment_buffer, container, false);
+ unbinder = ButterKnife.bind(this, layout);
+ return layout;
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ unbinder.unbind();
+ }
+
+ // -----------------------------------------------------------------------------------
+ // Main Rx entities
+
+ private Disposable _getBufferedDisposable() {
+ return RxView.clicks(_tapBtn)
+ .map(
+ onClickEvent -> {
+ Timber.d("--------- GOT A TAP");
+ _log("GOT A TAP");
+ return 1;
+ })
+ .buffer(2, TimeUnit.SECONDS)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeWith(
+ new DisposableObserver>() {
+
+ @Override
+ public void onComplete() {
+ // fyi: you'll never reach here
+ Timber.d("----- onCompleted");
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ Timber.e(e, "--------- Woops on error!");
+ _log("Dang error! check your logs");
+ }
+
+ @Override
+ public void onNext(List integers) {
+ Timber.d("--------- onNext");
+ if (integers.size() > 0) {
+ _log(String.format("%d taps", integers.size()));
+ } else {
+ Timber.d("--------- No taps received ");
+ }
+ }
+ });
+ }
+
+ // -----------------------------------------------------------------------------------
+ // Methods that help wiring up the example (irrelevant to RxJava)
+
+ private void _setupLogger() {
+ _logs = new ArrayList<>();
+ _adapter = new LogAdapter(getActivity(), new ArrayList<>());
+ _logsList.setAdapter(_adapter);
+ }
+
+ private void _log(String logMsg) {
+
+ if (_isCurrentlyOnMainThread()) {
+ _logs.add(0, logMsg + " (main thread) ");
+ _adapter.clear();
+ _adapter.addAll(_logs);
+ } else {
+ _logs.add(0, logMsg + " (NOT main thread) ");
+
+ // You can only do below stuff on main thread.
+ new Handler(Looper.getMainLooper())
+ .post(
+ () -> {
_adapter.clear();
_adapter.addAll(_logs);
- });
- }
+ });
}
+ }
- private boolean _isCurrentlyOnMainThread() {
- return Looper.myLooper() == Looper.getMainLooper();
- }
+ private boolean _isCurrentlyOnMainThread() {
+ return Looper.myLooper() == Looper.getMainLooper();
+ }
}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/ConcurrencyWithSchedulersDemoFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/ConcurrencyWithSchedulersDemoFragment.java
index f97194d8..9a9a61ea 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/fragments/ConcurrencyWithSchedulersDemoFragment.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/ConcurrencyWithSchedulersDemoFragment.java
@@ -11,10 +11,12 @@
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;
-import butterknife.Bind;
+import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import com.morihacky.android.rxjava.R;
+
+import butterknife.Unbinder;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
@@ -24,137 +26,140 @@
import java.util.List;
import timber.log.Timber;
-public class ConcurrencyWithSchedulersDemoFragment
- extends BaseFragment {
-
- @Bind(R.id.progress_operation_running) ProgressBar _progress;
- @Bind(R.id.list_threading_log) ListView _logsList;
-
- private LogAdapter _adapter;
- private List _logs;
- private CompositeDisposable _disposables = new CompositeDisposable();
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- ButterKnife.unbind(this);
- _disposables.clear();
- }
-
- @Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- _setupLogger();
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater,
- @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
- View layout = inflater.inflate(R.layout.fragment_concurrency_schedulers, container, false);
- ButterKnife.bind(this, layout);
- return layout;
- }
-
- @OnClick(R.id.btn_start_operation)
- public void startLongOperation() {
-
- _progress.setVisibility(View.VISIBLE);
- _log("Button Clicked");
-
- DisposableObserver d = _getDisposableObserver();
-
- _getObservable()
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(d);
-
- _disposables.add(d);
- }
-
- private Observable _getObservable() {
- return Observable.just(true).map(aBoolean -> {
- _log("Within Observable");
- _doSomeLongOperation_thatBlocksCurrentThread();
- return aBoolean;
- });
- }
-
- /**
- * Observer that handles the result through the 3 important actions:
- *
- * 1. onCompleted
- * 2. onError
- * 3. onNext
- */
- private DisposableObserver _getDisposableObserver() {
- return new DisposableObserver() {
-
- @Override
- public void onComplete() {
- _log("On complete");
- _progress.setVisibility(View.INVISIBLE);
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e(e, "Error in RxJava Demo concurrency");
- _log(String.format("Boo! Error %s", e.getMessage()));
- _progress.setVisibility(View.INVISIBLE);
- }
-
- @Override
- public void onNext(Boolean bool) {
- _log(String.format("onNext with return value \"%b\"", bool));
- }
- };
- }
-
- // -----------------------------------------------------------------------------------
- // Method that help wiring up the example (irrelevant to RxJava)
-
- private void _doSomeLongOperation_thatBlocksCurrentThread() {
- _log("performing long operation");
-
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e) {
- Timber.d("Operation was interrupted");
- }
+public class ConcurrencyWithSchedulersDemoFragment extends BaseFragment {
+
+ @BindView(R.id.progress_operation_running)
+ ProgressBar _progress;
+
+ @BindView(R.id.list_threading_log)
+ ListView _logsList;
+
+ private LogAdapter _adapter;
+ private List _logs;
+ private CompositeDisposable _disposables = new CompositeDisposable();
+ private Unbinder unbinder;
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ unbinder.unbind();
+ _disposables.clear();
+ }
+
+ @Override
+ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ _setupLogger();
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View layout = inflater.inflate(R.layout.fragment_concurrency_schedulers, container, false);
+ unbinder = ButterKnife.bind(this, layout);
+ return layout;
+ }
+
+ @OnClick(R.id.btn_start_operation)
+ public void startLongOperation() {
+
+ _progress.setVisibility(View.VISIBLE);
+ _log("Button Clicked");
+
+ DisposableObserver d = _getDisposableObserver();
+
+ _getObservable()
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(d);
+
+ _disposables.add(d);
+ }
+
+ private Observable _getObservable() {
+ return Observable.just(true)
+ .map(
+ aBoolean -> {
+ _log("Within Observable");
+ _doSomeLongOperation_thatBlocksCurrentThread();
+ return aBoolean;
+ });
+ }
+
+ /**
+ * Observer that handles the result through the 3 important actions:
+ *
+ * 1. onCompleted 2. onError 3. onNext
+ */
+ private DisposableObserver _getDisposableObserver() {
+ return new DisposableObserver() {
+
+ @Override
+ public void onComplete() {
+ _log("On complete");
+ _progress.setVisibility(View.INVISIBLE);
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ Timber.e(e, "Error in RxJava Demo concurrency");
+ _log(String.format("Boo! Error %s", e.getMessage()));
+ _progress.setVisibility(View.INVISIBLE);
+ }
+
+ @Override
+ public void onNext(Boolean bool) {
+ _log(String.format("onNext with return value \"%b\"", bool));
+ }
+ };
+ }
+
+ // -----------------------------------------------------------------------------------
+ // Method that help wiring up the example (irrelevant to RxJava)
+
+ private void _doSomeLongOperation_thatBlocksCurrentThread() {
+ _log("performing long operation");
+
+ try {
+ Thread.sleep(3000);
+ } catch (InterruptedException e) {
+ Timber.d("Operation was interrupted");
}
+ }
- private void _log(String logMsg) {
+ private void _log(String logMsg) {
- if (_isCurrentlyOnMainThread()) {
- _logs.add(0, logMsg + " (main thread) ");
- _adapter.clear();
- _adapter.addAll(_logs);
- } else {
- _logs.add(0, logMsg + " (NOT main thread) ");
+ if (_isCurrentlyOnMainThread()) {
+ _logs.add(0, logMsg + " (main thread) ");
+ _adapter.clear();
+ _adapter.addAll(_logs);
+ } else {
+ _logs.add(0, logMsg + " (NOT main thread) ");
- // You can only do below stuff on main thread.
- new Handler(Looper.getMainLooper()).post(() -> {
+ // You can only do below stuff on main thread.
+ new Handler(Looper.getMainLooper())
+ .post(
+ () -> {
_adapter.clear();
_adapter.addAll(_logs);
- });
- }
+ });
}
+ }
- private void _setupLogger() {
- _logs = new ArrayList<>();
- _adapter = new LogAdapter(getActivity(), new ArrayList<>());
- _logsList.setAdapter(_adapter);
- }
+ private void _setupLogger() {
+ _logs = new ArrayList<>();
+ _adapter = new LogAdapter(getActivity(), new ArrayList<>());
+ _logsList.setAdapter(_adapter);
+ }
- private boolean _isCurrentlyOnMainThread() {
- return Looper.myLooper() == Looper.getMainLooper();
- }
+ private boolean _isCurrentlyOnMainThread() {
+ return Looper.myLooper() == Looper.getMainLooper();
+ }
- private class LogAdapter
- extends ArrayAdapter {
+ private class LogAdapter extends ArrayAdapter {
- public LogAdapter(Context context, List logs) {
- super(context, R.layout.item_log, R.id.item_log, logs);
- }
+ public LogAdapter(Context context, List logs) {
+ super(context, R.layout.item_log, R.id.item_log, logs);
}
-}
\ No newline at end of file
+ }
+}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/DebounceSearchEmitterFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/DebounceSearchEmitterFragment.java
index 224bbc94..2d62cff7 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/fragments/DebounceSearchEmitterFragment.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/DebounceSearchEmitterFragment.java
@@ -12,18 +12,18 @@
import android.widget.EditText;
import android.widget.ListView;
-import com.jakewharton.rxbinding.widget.RxTextView;
-import com.jakewharton.rxbinding.widget.TextViewTextChangeEvent;
+import com.jakewharton.rxbinding2.widget.RxTextView;
+import com.jakewharton.rxbinding2.widget.TextViewTextChangeEvent;
import com.morihacky.android.rxjava.R;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
-import butterknife.Bind;
+import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
-import hu.akarnokd.rxjava.interop.RxJavaInterop;
+import butterknife.Unbinder;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.observers.DisposableObserver;
@@ -32,110 +32,114 @@
import static co.kaush.core.util.CoreNullnessUtils.isNotNullOrEmpty;
import static java.lang.String.format;
-public class DebounceSearchEmitterFragment
- extends BaseFragment {
-
- @Bind(R.id.list_threading_log) ListView _logsList;
- @Bind(R.id.input_txt_debounce) EditText _inputSearchText;
-
- private LogAdapter _adapter;
- private List _logs;
-
- private Disposable _disposable;
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- _disposable.dispose();
- ButterKnife.unbind(this);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater,
- @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
- View layout = inflater.inflate(R.layout.fragment_debounce, container, false);
- ButterKnife.bind(this, layout);
- return layout;
- }
-
- @OnClick(R.id.clr_debounce)
- public void onClearLog() {
- _logs = new ArrayList<>();
- _adapter.clear();
- }
-
- @Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
-
- super.onActivityCreated(savedInstanceState);
- _setupLogger();
-
- _disposable = RxJavaInterop.toV2Observable(RxTextView.textChangeEvents(_inputSearchText))
- .debounce(400, TimeUnit.MILLISECONDS)// default Scheduler is Computation
- .filter(changes -> isNotNullOrEmpty(changes.text().toString()))
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeWith(_getSearchObserver());
- }
-
- // -----------------------------------------------------------------------------------
- // Main Rx entities
-
- private DisposableObserver _getSearchObserver() {
- return new DisposableObserver() {
- @Override
- public void onComplete() {
- Timber.d("--------- onComplete");
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e(e, "--------- Woops on error!");
- _log("Dang error. check your logs");
- }
-
- @Override
- public void onNext(TextViewTextChangeEvent onTextChangeEvent) {
- _log(format("Searching for %s", onTextChangeEvent.text().toString()));
- }
- };
- }
-
- // -----------------------------------------------------------------------------------
- // Method that help wiring up the example (irrelevant to RxJava)
-
- private void _setupLogger() {
- _logs = new ArrayList<>();
- _adapter = new LogAdapter(getActivity(), new ArrayList<>());
- _logsList.setAdapter(_adapter);
- }
-
- private void _log(String logMsg) {
-
- if (_isCurrentlyOnMainThread()) {
- _logs.add(0, logMsg + " (main thread) ");
- _adapter.clear();
- _adapter.addAll(_logs);
- } else {
- _logs.add(0, logMsg + " (NOT main thread) ");
-
- // You can only do below stuff on main thread.
- new Handler(Looper.getMainLooper()).post(() -> {
+public class DebounceSearchEmitterFragment extends BaseFragment {
+
+ @BindView(R.id.list_threading_log)
+ ListView _logsList;
+
+ @BindView(R.id.input_txt_debounce)
+ EditText _inputSearchText;
+
+ private LogAdapter _adapter;
+ private List _logs;
+
+ private Disposable _disposable;
+ private Unbinder unbinder;
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ _disposable.dispose();
+ unbinder.unbind();
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View layout = inflater.inflate(R.layout.fragment_debounce, container, false);
+ unbinder = ButterKnife.bind(this, layout);
+ return layout;
+ }
+
+ @OnClick(R.id.clr_debounce)
+ public void onClearLog() {
+ _logs = new ArrayList<>();
+ _adapter.clear();
+ }
+
+ @Override
+ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+
+ super.onActivityCreated(savedInstanceState);
+ _setupLogger();
+
+ _disposable =
+ RxTextView.textChangeEvents(_inputSearchText)
+ .debounce(400, TimeUnit.MILLISECONDS) // default Scheduler is Computation
+ .filter(changes -> isNotNullOrEmpty(changes.text().toString()))
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeWith(_getSearchObserver());
+ }
+
+ // -----------------------------------------------------------------------------------
+ // Main Rx entities
+
+ private DisposableObserver _getSearchObserver() {
+ return new DisposableObserver() {
+ @Override
+ public void onComplete() {
+ Timber.d("--------- onComplete");
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ Timber.e(e, "--------- Woops on error!");
+ _log("Dang error. check your logs");
+ }
+
+ @Override
+ public void onNext(TextViewTextChangeEvent onTextChangeEvent) {
+ _log(format("Searching for %s", onTextChangeEvent.text().toString()));
+ }
+ };
+ }
+
+ // -----------------------------------------------------------------------------------
+ // Method that help wiring up the example (irrelevant to RxJava)
+
+ private void _setupLogger() {
+ _logs = new ArrayList<>();
+ _adapter = new LogAdapter(getActivity(), new ArrayList<>());
+ _logsList.setAdapter(_adapter);
+ }
+
+ private void _log(String logMsg) {
+
+ if (_isCurrentlyOnMainThread()) {
+ _logs.add(0, logMsg + " (main thread) ");
+ _adapter.clear();
+ _adapter.addAll(_logs);
+ } else {
+ _logs.add(0, logMsg + " (NOT main thread) ");
+
+ // You can only do below stuff on main thread.
+ new Handler(Looper.getMainLooper())
+ .post(
+ () -> {
_adapter.clear();
_adapter.addAll(_logs);
- });
- }
+ });
}
+ }
- private boolean _isCurrentlyOnMainThread() {
- return Looper.myLooper() == Looper.getMainLooper();
- }
+ private boolean _isCurrentlyOnMainThread() {
+ return Looper.myLooper() == Looper.getMainLooper();
+ }
- private class LogAdapter
- extends ArrayAdapter {
+ private class LogAdapter extends ArrayAdapter {
- public LogAdapter(Context context, List logs) {
- super(context, R.layout.item_log, R.id.item_log, logs);
- }
+ public LogAdapter(Context context, List logs) {
+ super(context, R.layout.item_log, R.id.item_log, logs);
}
-}
\ No newline at end of file
+ }
+}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/DoubleBindingTextViewFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/DoubleBindingTextViewFragment.java
index d17b1e3c..883f043e 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/fragments/DoubleBindingTextViewFragment.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/DoubleBindingTextViewFragment.java
@@ -7,65 +7,72 @@
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.TextView;
-import butterknife.Bind;
+import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnTextChanged;
import com.morihacky.android.rxjava.R;
+
+import butterknife.Unbinder;
import io.reactivex.disposables.Disposable;
import io.reactivex.processors.PublishProcessor;
-
import static android.text.TextUtils.isEmpty;
-public class DoubleBindingTextViewFragment
- extends BaseFragment {
+public class DoubleBindingTextViewFragment extends BaseFragment {
- @Bind(R.id.double_binding_num1) EditText _number1;
- @Bind(R.id.double_binding_num2) EditText _number2;
- @Bind(R.id.double_binding_result) TextView _result;
+ @BindView(R.id.double_binding_num1)
+ EditText _number1;
- Disposable _disposable;
- PublishProcessor _resultEmitterSubject;
+ @BindView(R.id.double_binding_num2)
+ EditText _number2;
- @Override
- public View onCreateView(LayoutInflater inflater,
- @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
- View layout = inflater.inflate(R.layout.fragment_double_binding_textview, container, false);
- ButterKnife.bind(this, layout);
+ @BindView(R.id.double_binding_result)
+ TextView _result;
- _resultEmitterSubject = PublishProcessor.create();
+ Disposable _disposable;
+ PublishProcessor _resultEmitterSubject;
+ private Unbinder unbinder;
- _disposable = _resultEmitterSubject.subscribe(aFloat -> {
- _result.setText(String.valueOf(aFloat));
- });
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View layout = inflater.inflate(R.layout.fragment_double_binding_textview, container, false);
+ unbinder = ButterKnife.bind(this, layout);
- onNumberChanged();
- _number2.requestFocus();
+ _resultEmitterSubject = PublishProcessor.create();
- return layout;
- }
+ _disposable =
+ _resultEmitterSubject.subscribe(
+ aFloat -> {
+ _result.setText(String.valueOf(aFloat));
+ });
- @OnTextChanged({R.id.double_binding_num1, R.id.double_binding_num2})
- public void onNumberChanged() {
- float num1 = 0;
- float num2 = 0;
+ onNumberChanged();
+ _number2.requestFocus();
- if (!isEmpty(_number1.getText().toString())) {
- num1 = Float.parseFloat(_number1.getText().toString());
- }
+ return layout;
+ }
- if (!isEmpty(_number2.getText().toString())) {
- num2 = Float.parseFloat(_number2.getText().toString());
- }
+ @OnTextChanged({R.id.double_binding_num1, R.id.double_binding_num2})
+ public void onNumberChanged() {
+ float num1 = 0;
+ float num2 = 0;
- _resultEmitterSubject.onNext(num1 + num2);
+ if (!isEmpty(_number1.getText().toString())) {
+ num1 = Float.parseFloat(_number1.getText().toString());
}
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- _disposable.dispose();
- ButterKnife.unbind(this);
+ if (!isEmpty(_number2.getText().toString())) {
+ num2 = Float.parseFloat(_number2.getText().toString());
}
+
+ _resultEmitterSubject.onNext(num1 + num2);
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ _disposable.dispose();
+ unbinder.unbind();
+ }
}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/ExponentialBackoffFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/ExponentialBackoffFragment.java
index 9b6de603..775feaef 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/fragments/ExponentialBackoffFragment.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/ExponentialBackoffFragment.java
@@ -7,12 +7,15 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
-import butterknife.Bind;
+
+import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import com.morihacky.android.rxjava.R;
import com.morihacky.android.rxjava.wiring.LogAdapter;
-import hu.akarnokd.rxjava.interop.RxJavaInterop;
+
+import butterknife.Unbinder;
+import hu.akarnokd.rxjava2.math.MathFlowable;
import io.reactivex.Flowable;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.functions.Function;
@@ -21,205 +24,211 @@
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.reactivestreams.Publisher;
-import rx.observables.MathObservable;
import timber.log.Timber;
-
import static android.os.Looper.getMainLooper;
-public class ExponentialBackoffFragment
- extends BaseFragment {
-
- @Bind(R.id.list_threading_log) ListView _logList;
- private LogAdapter _adapter;
- private CompositeDisposable _disposables = new CompositeDisposable();
- private List _logs;
-
- @Override
- public View onCreateView(LayoutInflater inflater,
- @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
- View layout = inflater.inflate(R.layout.fragment_exponential_backoff, container, false);
- ButterKnife.bind(this, layout);
- return layout;
- }
-
- @Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- _setupLogger();
- }
-
- @Override
- public void onPause() {
- super.onPause();
-
- _disposables.clear();
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- ButterKnife.unbind(this);
- }
-
- // -----------------------------------------------------------------------------------
-
- @OnClick(R.id.btn_eb_retry)
- public void startRetryingWithExponentialBackoffStrategy() {
- _logs = new ArrayList<>();
- _adapter.clear();
-
- DisposableSubscriber disposableSubscriber = new DisposableSubscriber() {
- @Override
- public void onNext(Object aVoid) {
- Timber.d("on Next");
- }
-
- @Override
- public void onComplete() {
- Timber.d("on Completed");
- }
-
- @Override
- public void onError(Throwable e) {
- _log("Error: I give up!");
- }
+public class ExponentialBackoffFragment extends BaseFragment {
+
+ @BindView(R.id.list_threading_log)
+ ListView _logList;
+
+ private LogAdapter _adapter;
+ private CompositeDisposable _disposables = new CompositeDisposable();
+ private List _logs;
+ Unbinder unbinder;
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View layout = inflater.inflate(R.layout.fragment_exponential_backoff, container, false);
+ unbinder = ButterKnife.bind(this, layout);
+ return layout;
+ }
+
+ @Override
+ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ _setupLogger();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+
+ _disposables.clear();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ unbinder.unbind();
+ }
+
+ // -----------------------------------------------------------------------------------
+
+ @OnClick(R.id.btn_eb_retry)
+ public void startRetryingWithExponentialBackoffStrategy() {
+ _logs = new ArrayList<>();
+ _adapter.clear();
+
+ DisposableSubscriber disposableSubscriber =
+ new DisposableSubscriber() {
+ @Override
+ public void onNext(Object aVoid) {
+ Timber.d("on Next");
+ }
+
+ @Override
+ public void onComplete() {
+ Timber.d("on Completed");
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ _log("Error: I give up!");
+ }
};
- Flowable.error(new RuntimeException("testing")) // always fails
- .retryWhen(new RetryWithDelay(5, 1000)) // notice this is called only onError (onNext
- // values sent are ignored)
- .doOnSubscribe(subscription -> _log("Attempting the impossible 5 times in intervals of 1s"))
- .subscribe(disposableSubscriber);
-
- _disposables.add(disposableSubscriber);
- }
-
- @OnClick(R.id.btn_eb_delay)
- public void startExecutingWithExponentialBackoffDelay() {
-
- _logs = new ArrayList<>();
- _adapter.clear();
-
- DisposableSubscriber disposableSubscriber = new DisposableSubscriber() {
- @Override
- public void onNext(Integer integer) {
- Timber.d("executing Task %d [xx:%02d]", integer, _getSecondHand());
- _log(String.format("executing Task %d [xx:%02d]", integer, _getSecondHand()));
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.d(e, "arrrr. Error");
- _log("Error");
- }
-
- @Override
- public void onComplete() {
- Timber.d("onCompleted");
- _log("Completed");
- }
+ Flowable.error(new RuntimeException("testing")) // always fails
+ .retryWhen(new RetryWithDelay(5, 1000)) // notice this is called only onError (onNext
+ // values sent are ignored)
+ .doOnSubscribe(subscription -> _log("Attempting the impossible 5 times in intervals of 1s"))
+ .subscribe(disposableSubscriber);
+
+ _disposables.add(disposableSubscriber);
+ }
+
+ @OnClick(R.id.btn_eb_delay)
+ public void startExecutingWithExponentialBackoffDelay() {
+
+ _logs = new ArrayList<>();
+ _adapter.clear();
+
+ DisposableSubscriber disposableSubscriber =
+ new DisposableSubscriber() {
+ @Override
+ public void onNext(Integer integer) {
+ Timber.d("executing Task %d [xx:%02d]", integer, _getSecondHand());
+ _log(String.format("executing Task %d [xx:%02d]", integer, _getSecondHand()));
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ Timber.d(e, "arrrr. Error");
+ _log("Error");
+ }
+
+ @Override
+ public void onComplete() {
+ Timber.d("onCompleted");
+ _log("Completed");
+ }
};
- Flowable
- .range(1, 4)
- .delay(integer -> {
- // Rx-y way of doing the Fibonnaci :P
- return RxJavaInterop
- .toV2Flowable(MathObservable.sumInteger(rx.Observable.range(1, integer)))
- .flatMap(targetSecondDelay -> Flowable
- .just(integer)
- .delay(targetSecondDelay, TimeUnit.SECONDS));
- })
- .doOnSubscribe(s -> _log(String.format("Execute 4 tasks with delay - time now: [xx:%02d]",
- _getSecondHand())))
- .subscribe(disposableSubscriber);
-
- _disposables.add(disposableSubscriber);
- }
+ Flowable.range(1, 4)
+ .delay(
+ integer -> {
+ // Rx-y way of doing the Fibonnaci :P
+ return MathFlowable.sumInt(Flowable.range(1, integer))
+ .flatMap(
+ targetSecondDelay ->
+ Flowable.just(integer).delay(targetSecondDelay, TimeUnit.SECONDS));
+ })
+ .doOnSubscribe(
+ s ->
+ _log(
+ String.format(
+ "Execute 4 tasks with delay - time now: [xx:%02d]", _getSecondHand())))
+ .subscribe(disposableSubscriber);
+
+ _disposables.add(disposableSubscriber);
+ }
+
+ // -----------------------------------------------------------------------------------
+
+ private int _getSecondHand() {
+ long millis = System.currentTimeMillis();
+ return (int)
+ (TimeUnit.MILLISECONDS.toSeconds(millis)
+ - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
+ }
+
+ // -----------------------------------------------------------------------------------
+
+ private void _setupLogger() {
+ _logs = new ArrayList<>();
+ _adapter = new LogAdapter(getActivity(), new ArrayList<>());
+ _logList.setAdapter(_adapter);
+ }
+
+ private void _log(String logMsg) {
+ _logs.add(logMsg);
+
+ // You can only do below stuff on main thread.
+ new Handler(getMainLooper())
+ .post(
+ () -> {
+ _adapter.clear();
+ _adapter.addAll(_logs);
+ });
+ }
- // -----------------------------------------------------------------------------------
+ // -----------------------------------------------------------------------------------
- private int _getSecondHand() {
- long millis = System.currentTimeMillis();
- return (int) (TimeUnit.MILLISECONDS.toSeconds(millis) -
- TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
- }
+ // CAUTION:
+ // --------------------------------------
+ // THIS notificationHandler class HAS NO BUSINESS BEING non-static
+ // I ONLY did this cause i wanted access to the `_log` method from inside here
+ // for the purpose of demonstration. In the real world, make it static and LET IT BE!!
- // -----------------------------------------------------------------------------------
+ // It's 12am in the morning and i feel lazy dammit !!!
- private void _setupLogger() {
- _logs = new ArrayList<>();
- _adapter = new LogAdapter(getActivity(), new ArrayList<>());
- _logList.setAdapter(_adapter);
- }
+ //public static class RetryWithDelay
+ public class RetryWithDelay implements Function, Publisher>> {
- private void _log(String logMsg) {
- _logs.add(logMsg);
+ private final int _maxRetries;
+ private final int _retryDelayMillis;
+ private int _retryCount;
- // You can only do below stuff on main thread.
- new Handler(getMainLooper()).post(() -> {
- _adapter.clear();
- _adapter.addAll(_logs);
- });
+ public RetryWithDelay(final int maxRetries, final int retryDelayMillis) {
+ _maxRetries = maxRetries;
+ _retryDelayMillis = retryDelayMillis;
+ _retryCount = 0;
}
- // -----------------------------------------------------------------------------------
-
- // CAUTION:
- // --------------------------------------
- // THIS notificationHandler class HAS NO BUSINESS BEING non-static
- // I ONLY did this cause i wanted access to the `_log` method from inside here
- // for the purpose of demonstration. In the real world, make it static and LET IT BE!!
-
- // It's 12am in the morning and i feel lazy dammit !!!
-
- //public static class RetryWithDelay
- public class RetryWithDelay
- implements Function, Publisher>> {
-
- private final int _maxRetries;
- private final int _retryDelayMillis;
- private int _retryCount;
+ // this is a notificationhandler, all that is cared about here
+ // is the emission "type" not emission "content"
+ // only onNext triggers a re-subscription (onError + onComplete kills it)
- public RetryWithDelay(final int maxRetries, final int retryDelayMillis) {
- _maxRetries = maxRetries;
- _retryDelayMillis = retryDelayMillis;
- _retryCount = 0;
- }
-
- // this is a notificationhandler, all that is cared about here
- // is the emission "type" not emission "content"
- // only onNext triggers a re-subscription (onError + onComplete kills it)
-
- @Override
- public Publisher> apply(Flowable extends Throwable> inputObservable) {
+ @Override
+ public Publisher> apply(Flowable extends Throwable> inputObservable) {
- // it is critical to use inputObservable in the chain for the result
- // ignoring it and doing your own thing will break the sequence
+ // it is critical to use inputObservable in the chain for the result
+ // ignoring it and doing your own thing will break the sequence
- return inputObservable.flatMap(new Function>() {
- @Override
- public Publisher> apply(Throwable throwable) {
- if (++_retryCount < _maxRetries) {
+ return inputObservable.flatMap(
+ new Function>() {
+ @Override
+ public Publisher> apply(Throwable throwable) {
+ if (++_retryCount < _maxRetries) {
- // When this Observable calls onNext, the original
- // Observable will be retried (i.e. re-subscribed)
+ // When this Observable calls onNext, the original
+ // Observable will be retried (i.e. re-subscribed)
- Timber.d("Retrying in %d ms", _retryCount * _retryDelayMillis);
- _log(String.format("Retrying in %d ms", _retryCount * _retryDelayMillis));
+ Timber.d("Retrying in %d ms", _retryCount * _retryDelayMillis);
+ _log(String.format("Retrying in %d ms", _retryCount * _retryDelayMillis));
- return Flowable.timer(_retryCount * _retryDelayMillis, TimeUnit.MILLISECONDS);
- }
+ return Flowable.timer(_retryCount * _retryDelayMillis, TimeUnit.MILLISECONDS);
+ }
- Timber.d("Argh! i give up");
+ Timber.d("Argh! i give up");
- // Max retries hit. Pass an error so the chain is forcibly completed
- // only onNext triggers a re-subscription (onError + onComplete kills it)
- return Flowable.error(throwable);
- }
- });
- }
+ // Max retries hit. Pass an error so the chain is forcibly completed
+ // only onNext triggers a re-subscription (onError + onComplete kills it)
+ return Flowable.error(throwable);
+ }
+ });
}
-}
\ No newline at end of file
+ }
+}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/FormValidationCombineLatestFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/FormValidationCombineLatestFragment.java
index 3a985fcc..efc4c2f8 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/fragments/FormValidationCombineLatestFragment.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/FormValidationCombineLatestFragment.java
@@ -1,121 +1,123 @@
package com.morihacky.android.rxjava.fragments;
+import static android.text.TextUtils.isEmpty;
+import static android.util.Patterns.EMAIL_ADDRESS;
+
import android.os.Bundle;
import android.support.annotation.Nullable;
+import android.support.v4.content.ContextCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.TextView;
-import butterknife.Bind;
+import butterknife.BindView;
import butterknife.ButterKnife;
-import com.jakewharton.rxbinding.widget.RxTextView;
+import butterknife.Unbinder;
+import com.jakewharton.rxbinding2.widget.RxTextView;
import com.morihacky.android.rxjava.R;
-import hu.akarnokd.rxjava.interop.RxJavaInterop;
+import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.subscribers.DisposableSubscriber;
import timber.log.Timber;
-
-import static android.text.TextUtils.isEmpty;
-import static android.util.Patterns.EMAIL_ADDRESS;
-
-public class FormValidationCombineLatestFragment
- extends BaseFragment {
-
- @Bind(R.id.btn_demo_form_valid) TextView _btnValidIndicator;
- @Bind(R.id.demo_combl_email) EditText _email;
- @Bind(R.id.demo_combl_password) EditText _password;
- @Bind(R.id.demo_combl_num) EditText _number;
-
- private DisposableSubscriber _disposableObserver = null;
- private Flowable _emailChangeObservable;
- private Flowable _numberChangeObservable;
- private Flowable _passwordChangeObservable;
-
- @Override
- public View onCreateView(LayoutInflater inflater,
- @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
- View layout = inflater.inflate(R.layout.fragment_form_validation_comb_latest, container, false);
- ButterKnife.bind(this, layout);
-
- _emailChangeObservable = RxJavaInterop.toV2Flowable(RxTextView
- .textChanges(_email)
- .skip(1));
- _passwordChangeObservable = RxJavaInterop.toV2Flowable(RxTextView
- .textChanges(_password)
- .skip(1));
- _numberChangeObservable = RxJavaInterop.toV2Flowable(RxTextView
- .textChanges(_number)
- .skip(1));
-
- _combineLatestEvents();
-
- return layout;
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- ButterKnife.unbind(this);
- _disposableObserver.dispose();
- }
-
- private void _combineLatestEvents() {
-
- _disposableObserver = new DisposableSubscriber() {
- @Override
- public void onNext(Boolean formValid) {
- if (formValid) {
- _btnValidIndicator.setBackgroundColor(getResources().getColor(R.color.blue));
- }
- else {
- _btnValidIndicator.setBackgroundColor(getResources().getColor(R.color.gray));
- }
+public class FormValidationCombineLatestFragment extends BaseFragment {
+
+ @BindView(R.id.btn_demo_form_valid)
+ TextView _btnValidIndicator;
+
+ @BindView(R.id.demo_combl_email)
+ EditText _email;
+
+ @BindView(R.id.demo_combl_password)
+ EditText _password;
+
+ @BindView(R.id.demo_combl_num)
+ EditText _number;
+
+ private DisposableSubscriber _disposableObserver = null;
+ private Flowable _emailChangeObservable;
+ private Flowable _numberChangeObservable;
+ private Flowable _passwordChangeObservable;
+ private Unbinder unbinder;
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View layout = inflater.inflate(R.layout.fragment_form_validation_comb_latest, container, false);
+ unbinder = ButterKnife.bind(this, layout);
+
+ _emailChangeObservable =
+ RxTextView.textChanges(_email).skip(1).toFlowable(BackpressureStrategy.LATEST);
+ _passwordChangeObservable =
+ RxTextView.textChanges(_password).skip(1).toFlowable(BackpressureStrategy.LATEST);
+ _numberChangeObservable =
+ RxTextView.textChanges(_number).skip(1).toFlowable(BackpressureStrategy.LATEST);
+
+ _combineLatestEvents();
+
+ return layout;
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ unbinder.unbind();
+ _disposableObserver.dispose();
+ }
+
+ private void _combineLatestEvents() {
+
+ _disposableObserver =
+ new DisposableSubscriber() {
+ @Override
+ public void onNext(Boolean formValid) {
+ if (formValid) {
+ _btnValidIndicator.setBackgroundColor(
+ ContextCompat.getColor(getContext(), R.color.blue));
+ } else {
+ _btnValidIndicator.setBackgroundColor(
+ ContextCompat.getColor(getContext(), R.color.gray));
}
+ }
- @Override
- public void onError(Throwable e) {
- Timber.e(e, "there was an error");
- }
+ @Override
+ public void onError(Throwable e) {
+ Timber.e(e, "there was an error");
+ }
- @Override
- public void onComplete() {
- Timber.d("completed");
- }
+ @Override
+ public void onComplete() {
+ Timber.d("completed");
+ }
};
- Flowable
- .combineLatest(_emailChangeObservable,
- _passwordChangeObservable,
- _numberChangeObservable,
- (newEmail, newPassword, newNumber) -> {
-
- boolean emailValid = !isEmpty(newEmail) &&
- EMAIL_ADDRESS
- .matcher(newEmail)
- .matches();
- if (!emailValid) {
- _email.setError("Invalid Email!");
- }
-
- boolean passValid = !isEmpty(newPassword) && newPassword.length() > 8;
- if (!passValid) {
- _password.setError("Invalid Password!");
- }
-
- boolean numValid = !isEmpty(newNumber);
- if (numValid) {
- int num = Integer.parseInt(newNumber.toString());
- numValid = num > 0 && num <= 100;
- }
- if (!numValid) {
- _number.setError("Invalid Number!");
- }
-
- return emailValid && passValid && numValid;
- })
- .subscribe(_disposableObserver);
- }
+ Flowable.combineLatest(
+ _emailChangeObservable,
+ _passwordChangeObservable,
+ _numberChangeObservable,
+ (newEmail, newPassword, newNumber) -> {
+ boolean emailValid = !isEmpty(newEmail) && EMAIL_ADDRESS.matcher(newEmail).matches();
+ if (!emailValid) {
+ _email.setError("Invalid Email!");
+ }
+
+ boolean passValid = !isEmpty(newPassword) && newPassword.length() > 8;
+ if (!passValid) {
+ _password.setError("Invalid Password!");
+ }
+
+ boolean numValid = !isEmpty(newNumber);
+ if (numValid) {
+ int num = Integer.parseInt(newNumber.toString());
+ numValid = num > 0 && num <= 100;
+ }
+ if (!numValid) {
+ _number.setError("Invalid Number!");
+ }
+
+ return emailValid && passValid && numValid;
+ })
+ .subscribe(_disposableObserver);
+ }
}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/MainFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/MainFragment.java
index 725407f6..75f68fa2 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/fragments/MainFragment.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/MainFragment.java
@@ -9,117 +9,131 @@
import android.view.ViewGroup;
import butterknife.ButterKnife;
import butterknife.OnClick;
+import butterknife.Unbinder;
+
import com.morihacky.android.rxjava.R;
import com.morihacky.android.rxjava.pagination.PaginationAutoFragment;
import com.morihacky.android.rxjava.rxbus.RxBusDemoFragment;
import com.morihacky.android.rxjava.volley.VolleyDemoFragment;
-public class MainFragment
- extends BaseFragment {
-
- @Override
- public View onCreateView(LayoutInflater inflater,
- @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
- View layout = inflater.inflate(R.layout.fragment_main, container, false);
- ButterKnife.bind(this, layout);
- return layout;
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- ButterKnife.unbind(this);
- }
-
- @OnClick(R.id.btn_demo_schedulers)
- void demoConcurrencyWithSchedulers() {
- clickedOn(new ConcurrencyWithSchedulersDemoFragment());
- }
-
- @OnClick(R.id.btn_demo_buffer)
- void demoBuffer() {
- clickedOn(new BufferDemoFragment());
- }
-
- @OnClick(R.id.btn_demo_debounce)
- void demoThrottling() {
- clickedOn(new DebounceSearchEmitterFragment());
- }
-
- @OnClick(R.id.btn_demo_retrofit)
- void demoRetrofitCalls() {
- clickedOn(new RetrofitFragment());
- }
-
- @OnClick(R.id.btn_demo_polling)
- void demoPolling() {
- clickedOn(new PollingFragment());
- }
-
- @OnClick(R.id.btn_demo_double_binding_textview)
- void demoDoubleBindingWithPublishSubject() {
- clickedOn(new DoubleBindingTextViewFragment());
- }
-
- @OnClick(R.id.btn_demo_rxbus)
- void demoRxBus() {
- clickedOn(new RxBusDemoFragment());
- }
-
- @OnClick(R.id.btn_demo_form_validation_combinel)
- void formValidation() {
- clickedOn(new FormValidationCombineLatestFragment());
- }
-
- @OnClick(R.id.btn_demo_pseudo_cache)
- void pseudoCacheDemo() {
- clickedOn(new PseudoCacheFragment());
- }
-
- @OnClick(R.id.btn_demo_timing)
- void demoTimerIntervalDelays() {
- clickedOn(new TimingDemoFragment());
- }
-
- @OnClick(R.id.btn_demo_timeout)
- void demoTimeout() {
- clickedOn(new TimeoutDemoFragment());
- }
-
- @OnClick(R.id.btn_demo_exponential_backoff)
- void demoExponentialBackoff() {
- clickedOn(new ExponentialBackoffFragment());
- }
-
- @OnClick(R.id.btn_demo_rotation_persist)
- void demoRotationPersist() {
- clickedOn(new RotationPersist2Fragment());
- //clickedOn(new RotationPersist1Fragment());
- }
-
- @OnClick(R.id.btn_demo_pagination)
- void demoPaging() {
- clickedOn(new PaginationAutoFragment());
- //clickedOn(new PaginationFragment());
- }
-
- @OnClick(R.id.btn_demo_volley)
- void demoVolleyRequest() {
- clickedOn(new VolleyDemoFragment());
- }
-
- @OnClick(R.id.btn_demo_networkDetector)
- void demoNetworkDetector() {
- clickedOn(new NetworkDetectorFragment());
- }
-
- private void clickedOn(@NonNull Fragment fragment) {
- final String tag = fragment.getClass().toString();
- getActivity().getSupportFragmentManager()
- .beginTransaction()
- .addToBackStack(tag)
- .replace(android.R.id.content, fragment, tag)
- .commit();
- }
+public class MainFragment extends BaseFragment {
+
+ private Unbinder unbinder;
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View layout = inflater.inflate(R.layout.fragment_main, container, false);
+ unbinder = ButterKnife.bind(this, layout);
+ return layout;
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ unbinder.unbind();
+ }
+
+ @OnClick(R.id.btn_demo_schedulers)
+ void demoConcurrencyWithSchedulers() {
+ clickedOn(new ConcurrencyWithSchedulersDemoFragment());
+ }
+
+ @OnClick(R.id.btn_demo_buffer)
+ void demoBuffer() {
+ clickedOn(new BufferDemoFragment());
+ }
+
+ @OnClick(R.id.btn_demo_debounce)
+ void demoThrottling() {
+ clickedOn(new DebounceSearchEmitterFragment());
+ }
+
+ @OnClick(R.id.btn_demo_retrofit)
+ void demoRetrofitCalls() {
+ clickedOn(new RetrofitFragment());
+ }
+
+ @OnClick(R.id.btn_demo_polling)
+ void demoPolling() {
+ clickedOn(new PollingFragment());
+ }
+
+ @OnClick(R.id.btn_demo_double_binding_textview)
+ void demoDoubleBindingWithPublishSubject() {
+ clickedOn(new DoubleBindingTextViewFragment());
+ }
+
+ @OnClick(R.id.btn_demo_rxbus)
+ void demoRxBus() {
+ clickedOn(new RxBusDemoFragment());
+ }
+
+ @OnClick(R.id.btn_demo_form_validation_combinel)
+ void formValidation() {
+ clickedOn(new FormValidationCombineLatestFragment());
+ }
+
+ @OnClick(R.id.btn_demo_pseudo_cache)
+ void pseudoCacheDemo() {
+ clickedOn(new PseudoCacheFragment());
+ }
+
+ @OnClick(R.id.btn_demo_timing)
+ void demoTimerIntervalDelays() {
+ clickedOn(new TimingDemoFragment());
+ }
+
+ @OnClick(R.id.btn_demo_timeout)
+ void demoTimeout() {
+ clickedOn(new TimeoutDemoFragment());
+ }
+
+ @OnClick(R.id.btn_demo_exponential_backoff)
+ void demoExponentialBackoff() {
+ clickedOn(new ExponentialBackoffFragment());
+ }
+
+ @OnClick(R.id.btn_demo_rotation_persist)
+ void demoRotationPersist() {
+ clickedOn(new RotationPersist3Fragment());
+ // clickedOn(new RotationPersist2Fragment());
+ // clickedOn(new RotationPersist1Fragment());
+ }
+
+ @OnClick(R.id.btn_demo_pagination)
+ void demoPaging() {
+ clickedOn(new PaginationAutoFragment());
+ //clickedOn(new PaginationFragment());
+ }
+
+ @OnClick(R.id.btn_demo_volley)
+ void demoVolleyRequest() {
+ clickedOn(new VolleyDemoFragment());
+ }
+
+ @OnClick(R.id.btn_demo_networkDetector)
+ void demoNetworkDetector() {
+ clickedOn(new NetworkDetectorFragment());
+ }
+
+ @OnClick(R.id.btn_demo_using)
+ void demoUsing() {
+ clickedOn(new UsingFragment());
+ }
+
+ @OnClick(R.id.btn_demo_multicastPlayground)
+ void demoMulticastPlayground() {
+ clickedOn(new MulticastPlaygroundFragment());
+ }
+
+ private void clickedOn(@NonNull Fragment fragment) {
+ final String tag = fragment.getClass().toString();
+ getActivity()
+ .getSupportFragmentManager()
+ .beginTransaction()
+ .addToBackStack(tag)
+ .replace(android.R.id.content, fragment, tag)
+ .commit();
+ }
}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/NetworkDetectorFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/NetworkDetectorFragment.java
index 9ee6f81b..af1392d4 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/fragments/NetworkDetectorFragment.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/NetworkDetectorFragment.java
@@ -15,132 +15,137 @@
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
-import butterknife.Bind;
+import butterknife.BindView;
import butterknife.ButterKnife;
import com.morihacky.android.rxjava.R;
+
+import butterknife.Unbinder;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.processors.PublishProcessor;
import java.util.ArrayList;
import java.util.List;
-public class NetworkDetectorFragment
- extends BaseFragment {
-
- @Bind(R.id.list_threading_log) ListView logsList;
-
- private LogAdapter adapter;
- private BroadcastReceiver broadcastReceiver;
- private List logs;
- private Disposable disposable;
- private PublishProcessor publishProcessor;
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- ButterKnife.unbind(this);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater,
- @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
- View layout = inflater.inflate(R.layout.fragment_network_detector, container, false);
- ButterKnife.bind(this, layout);
- return layout;
- }
-
- @Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- setupLogger();
- }
-
- @Override
- public void onStart() {
- super.onStart();
-
- publishProcessor = PublishProcessor.create();
-
- disposable = publishProcessor
- .startWith(getConnectivityStatus(getActivity()))
- .distinctUntilChanged()
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(online -> {
+public class NetworkDetectorFragment extends BaseFragment {
+
+ @BindView(R.id.list_threading_log)
+ ListView logsList;
+
+ private LogAdapter adapter;
+ private BroadcastReceiver broadcastReceiver;
+ private List logs;
+ private Disposable disposable;
+ private PublishProcessor publishProcessor;
+ private Unbinder unbinder;
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ unbinder.unbind();
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View layout = inflater.inflate(R.layout.fragment_network_detector, container, false);
+ unbinder = ButterKnife.bind(this, layout);
+ return layout;
+ }
+
+ @Override
+ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ setupLogger();
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ publishProcessor = PublishProcessor.create();
+
+ disposable =
+ publishProcessor
+ .startWith(getConnectivityStatus(getActivity()))
+ .distinctUntilChanged()
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ online -> {
if (online) {
- log("You are online");
- }
- else {
- log("You are offline");
+ log("You are online");
+ } else {
+ log("You are offline");
}
- });
+ });
- listenToNetworkConnectivity();
- }
+ listenToNetworkConnectivity();
+ }
- @Override
- public void onStop() {
- super.onStop();
+ @Override
+ public void onStop() {
+ super.onStop();
- disposable.dispose();
- getActivity().unregisterReceiver(broadcastReceiver);
- }
+ disposable.dispose();
+ getActivity().unregisterReceiver(broadcastReceiver);
+ }
- private void listenToNetworkConnectivity() {
+ private void listenToNetworkConnectivity() {
- broadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- publishProcessor.onNext(getConnectivityStatus(context));
- }
+ broadcastReceiver =
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ publishProcessor.onNext(getConnectivityStatus(context));
+ }
};
- final IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
- getActivity().registerReceiver(broadcastReceiver, intentFilter);
- }
-
- private boolean getConnectivityStatus(Context context) {
- ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo networkInfo = cm.getActiveNetworkInfo();
- return networkInfo != null && networkInfo.isConnected();
- }
-
- // -----------------------------------------------------------------------------------
- // Method that help wiring up the example (irrelevant to RxJava)
-
- private void log(String logMsg) {
-
- if (isCurrentlyOnMainThread()) {
- logs.add(0, logMsg + " (main thread) ");
- adapter.clear();
- adapter.addAll(logs);
- }
- else {
- logs.add(0, logMsg + " (NOT main thread) ");
-
- // You can only do below stuff on main thread.
- new Handler(Looper.getMainLooper()).post(() -> {
+ final IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
+ getActivity().registerReceiver(broadcastReceiver, intentFilter);
+ }
+
+ private boolean getConnectivityStatus(Context context) {
+ ConnectivityManager cm =
+ (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo networkInfo = cm.getActiveNetworkInfo();
+ return networkInfo != null && networkInfo.isConnected();
+ }
+
+ // -----------------------------------------------------------------------------------
+ // Method that help wiring up the example (irrelevant to RxJava)
+
+ private void log(String logMsg) {
+
+ if (isCurrentlyOnMainThread()) {
+ logs.add(0, logMsg + " (main thread) ");
+ adapter.clear();
+ adapter.addAll(logs);
+ } else {
+ logs.add(0, logMsg + " (NOT main thread) ");
+
+ // You can only do below stuff on main thread.
+ new Handler(Looper.getMainLooper())
+ .post(
+ () -> {
adapter.clear();
adapter.addAll(logs);
- });
- }
+ });
}
+ }
- private void setupLogger() {
- logs = new ArrayList<>();
- adapter = new LogAdapter(getActivity(), new ArrayList<>());
- logsList.setAdapter(adapter);
- }
+ private void setupLogger() {
+ logs = new ArrayList<>();
+ adapter = new LogAdapter(getActivity(), new ArrayList<>());
+ logsList.setAdapter(adapter);
+ }
- private boolean isCurrentlyOnMainThread() {
- return Looper.myLooper() == Looper.getMainLooper();
- }
+ private boolean isCurrentlyOnMainThread() {
+ return Looper.myLooper() == Looper.getMainLooper();
+ }
- private class LogAdapter
- extends ArrayAdapter {
+ private class LogAdapter extends ArrayAdapter {
- public LogAdapter(Context context, List logs) {
- super(context, R.layout.item_log, R.id.item_log, logs);
- }
+ public LogAdapter(Context context, List logs) {
+ super(context, R.layout.item_log, R.id.item_log, logs);
}
-}
\ No newline at end of file
+ }
+}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/PlaygroundFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/PlaygroundFragment.java
deleted file mode 100644
index 21f61fe5..00000000
--- a/app/src/main/java/com/morihacky/android/rxjava/fragments/PlaygroundFragment.java
+++ /dev/null
@@ -1,138 +0,0 @@
-package com.morihacky.android.rxjava.fragments;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.support.annotation.Nullable;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-import android.widget.ProgressBar;
-import butterknife.Bind;
-import butterknife.ButterKnife;
-import butterknife.OnClick;
-import com.morihacky.android.rxjava.R;
-import io.reactivex.Observable;
-import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.schedulers.Schedulers;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import timber.log.Timber;
-
-public class PlaygroundFragment
- extends BaseFragment {
-
- @Bind(R.id.progress_operation_running) ProgressBar _progress;
- @Bind(R.id.list_threading_log) ListView _logsList;
-
- private LogAdapter _adapter;
- private int _attempt = 0;
- private List _logs;
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- ButterKnife.unbind(this);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater,
- @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
- View layout = inflater.inflate(R.layout.fragment_concurrency_schedulers, container, false);
- ButterKnife.bind(this, layout);
- return layout;
- }
-
- @Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- _setupLogger();
- }
-
- @OnClick(R.id.btn_start_operation)
- public void startOperation() {
-
- _logs.clear();
- _log("Button Clicked");
-
- Observable.fromIterable(Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"))//
- .flatMap(s1 -> {
-
- _log(s1 + "start");
-
- if (s1.equalsIgnoreCase("b") && _attempt < 5) {
- _attempt++;
- return Observable.error(new Throwable("b can't be processed (" + (_attempt - 1) + ")"));
- }
-
- if (s1.equalsIgnoreCase("c") || s1.equalsIgnoreCase("f")) {
- return Observable.just(s1);
- }
- else {
- return Observable
- .timer(2, TimeUnit.SECONDS)
- .map(l -> s1);
- }
- })
- .retryWhen(source -> source.delay(8, TimeUnit.SECONDS))
- .doOnNext(s -> _log(s + "stop"))
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe();
- }
-
- // -----------------------------------------------------------------------------------
- // Method that help wiring up the example (irrelevant to RxJava)
-
- private void _doSomeLongOperation_thatBlocksCurrentThread() {
- _log("performing long operation");
-
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e) {
- Timber.d("Operation was interrupted");
- }
- }
-
- private void _log(String logMsg) {
-
- if (_isCurrentlyOnMainThread()) {
- _logs.add(0, logMsg + " (main thread) ");
- _adapter.clear();
- _adapter.addAll(_logs);
- }
- else {
- _logs.add(0, logMsg + " (NOT main thread) ");
-
- // You can only do below stuff on main thread.
- new Handler(Looper.getMainLooper()).post(() -> {
- _adapter.clear();
- _adapter.addAll(_logs);
- });
- }
- }
-
- private void _setupLogger() {
- _logs = new ArrayList<>();
- _adapter = new LogAdapter(getActivity(), new ArrayList<>());
- _logsList.setAdapter(_adapter);
- }
-
- private boolean _isCurrentlyOnMainThread() {
- return Looper.myLooper() == Looper.getMainLooper();
- }
-
- private class LogAdapter
- extends ArrayAdapter {
-
- public LogAdapter(Context context, List logs) {
- super(context, R.layout.item_log, R.id.item_log, logs);
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/PollingFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/PollingFragment.java
index 9f4398a9..5eb8b187 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/fragments/PollingFragment.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/PollingFragment.java
@@ -10,10 +10,12 @@
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
-import butterknife.Bind;
+import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import com.morihacky.android.rxjava.R;
+
+import butterknife.Unbinder;
import io.reactivex.Flowable;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
@@ -25,201 +27,211 @@
import org.reactivestreams.Publisher;
import timber.log.Timber;
-public class PollingFragment
- extends BaseFragment {
-
- private static final int INITIAL_DELAY = 0;
- private static final int POLLING_INTERVAL = 1000;
- private static final int POLL_COUNT = 8;
-
- @Bind(R.id.list_threading_log) ListView _logsList;
-
- private LogAdapter _adapter;
- private int _counter = 0;
- private CompositeDisposable _disposables;
- private List _logs;
-
- @Override
- public void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- _disposables = new CompositeDisposable();
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater,
- @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
- View layout = inflater.inflate(R.layout.fragment_polling, container, false);
- ButterKnife.bind(this, layout);
- return layout;
- }
-
- @Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- _setupLogger();
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- _disposables.clear();
- ButterKnife.unbind(this);
- }
-
- @OnClick(R.id.btn_start_simple_polling)
- public void onStartSimplePollingClicked() {
-
- final int pollCount = POLL_COUNT;
-
- Disposable d = Flowable
- .interval(INITIAL_DELAY, POLLING_INTERVAL, TimeUnit.MILLISECONDS)
- .map(this::_doNetworkCallAndGetStringResult)
- .take(pollCount)
- .doOnSubscribe(subscription -> {
+public class PollingFragment extends BaseFragment {
+
+ private static final int INITIAL_DELAY = 0;
+ private static final int POLLING_INTERVAL = 1000;
+ private static final int POLL_COUNT = 8;
+
+ @BindView(R.id.list_threading_log)
+ ListView _logsList;
+
+ private LogAdapter _adapter;
+ private int _counter = 0;
+ private CompositeDisposable _disposables;
+ private List _logs;
+ private Unbinder unbinder;
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ _disposables = new CompositeDisposable();
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View layout = inflater.inflate(R.layout.fragment_polling, container, false);
+ unbinder = ButterKnife.bind(this, layout);
+ return layout;
+ }
+
+ @Override
+ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ _setupLogger();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ _disposables.clear();
+ unbinder.unbind();
+ }
+
+ @OnClick(R.id.btn_start_simple_polling)
+ public void onStartSimplePollingClicked() {
+
+ final int pollCount = POLL_COUNT;
+
+ Disposable d =
+ Flowable.interval(INITIAL_DELAY, POLLING_INTERVAL, TimeUnit.MILLISECONDS)
+ .map(this::_doNetworkCallAndGetStringResult)
+ .take(pollCount)
+ .doOnSubscribe(
+ subscription -> {
_log(String.format("Start simple polling - %s", _counter));
- })
- .subscribe(taskName -> {
- _log(String.format(Locale.US,
- "Executing polled task [%s] now time : [xx:%02d]",
- taskName,
- _getSecondHand()));
- });
-
- _disposables.add(d);
+ })
+ .subscribe(
+ taskName -> {
+ _log(
+ String.format(
+ Locale.US,
+ "Executing polled task [%s] now time : [xx:%02d]",
+ taskName,
+ _getSecondHand()));
+ });
+
+ _disposables.add(d);
+ }
+
+ @OnClick(R.id.btn_start_increasingly_delayed_polling)
+ public void onStartIncreasinglyDelayedPolling() {
+ _setupLogger();
+
+ final int pollingInterval = POLLING_INTERVAL;
+ final int pollCount = POLL_COUNT;
+
+ _log(
+ String.format(
+ Locale.US, "Start increasingly delayed polling now time: [xx:%02d]", _getSecondHand()));
+
+ _disposables.add(
+ Flowable.just(1L)
+ .repeatWhen(new RepeatWithDelay(pollCount, pollingInterval))
+ .subscribe(
+ o ->
+ _log(
+ String.format(
+ Locale.US,
+ "Executing polled task now time : [xx:%02d]",
+ _getSecondHand())),
+ e -> Timber.d(e, "arrrr. Error")));
+ }
+
+ // -----------------------------------------------------------------------------------
+
+ // CAUTION:
+ // --------------------------------------
+ // THIS notificationHandler class HAS NO BUSINESS BEING non-static
+ // I ONLY did this cause i wanted access to the `_log` method from inside here
+ // for the purpose of demonstration. In the real world, make it static and LET IT BE!!
+
+ // It's 12am in the morning and i feel lazy dammit !!!
+
+ private String _doNetworkCallAndGetStringResult(long attempt) {
+ try {
+ if (attempt == 4) {
+ // randomly make one event super long so we test that the repeat logic waits
+ // and accounts for this.
+ Thread.sleep(9000);
+ } else {
+ Thread.sleep(3000);
+ }
+
+ } catch (InterruptedException e) {
+ Timber.d("Operation was interrupted");
}
-
- @OnClick(R.id.btn_start_increasingly_delayed_polling)
- public void onStartIncreasinglyDelayedPolling() {
- _setupLogger();
-
- final int pollingInterval = POLLING_INTERVAL;
- final int pollCount = POLL_COUNT;
-
- _log(String.format(Locale.US, "Start increasingly delayed polling now time: [xx:%02d]", _getSecondHand()));
-
- _disposables.add(Flowable
- .just(1L)
- .repeatWhen(new RepeatWithDelay(pollCount, pollingInterval))
- .subscribe(o -> _log(String.format(Locale.US,
- "Executing polled task now time : [xx:%02d]",
- _getSecondHand())),
- e -> Timber.d(e, "arrrr. Error")));
+ _counter++;
+
+ return String.valueOf(_counter);
+ }
+
+ // -----------------------------------------------------------------------------------
+ // Method that help wiring up the example (irrelevant to RxJava)
+
+ private int _getSecondHand() {
+ long millis = System.currentTimeMillis();
+ return (int)
+ (TimeUnit.MILLISECONDS.toSeconds(millis)
+ - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
+ }
+
+ private void _log(String logMsg) {
+ if (_isCurrentlyOnMainThread()) {
+ _logs.add(0, logMsg + " (main thread) ");
+ _adapter.clear();
+ _adapter.addAll(_logs);
+ } else {
+ _logs.add(0, logMsg + " (NOT main thread) ");
+
+ // You can only do below stuff on main thread.
+ new Handler(Looper.getMainLooper())
+ .post(
+ () -> {
+ _adapter.clear();
+ _adapter.addAll(_logs);
+ });
}
+ }
- // -----------------------------------------------------------------------------------
-
- // CAUTION:
- // --------------------------------------
- // THIS notificationHandler class HAS NO BUSINESS BEING non-static
- // I ONLY did this cause i wanted access to the `_log` method from inside here
- // for the purpose of demonstration. In the real world, make it static and LET IT BE!!
-
- // It's 12am in the morning and i feel lazy dammit !!!
-
- private String _doNetworkCallAndGetStringResult(long attempt) {
- try {
- if (attempt == 4) {
- // randomly make one event super long so we test that the repeat logic waits
- // and accounts for this.
- Thread.sleep(9000);
- }
- else {
- Thread.sleep(3000);
- }
-
- } catch (InterruptedException e) {
- Timber.d("Operation was interrupted");
- }
- _counter++;
+ private void _setupLogger() {
+ _logs = new ArrayList<>();
+ _adapter = new LogAdapter(getActivity(), new ArrayList<>());
+ _logsList.setAdapter(_adapter);
+ _counter = 0;
+ }
- return String.valueOf(_counter);
- }
+ private boolean _isCurrentlyOnMainThread() {
+ return Looper.myLooper() == Looper.getMainLooper();
+ }
- // -----------------------------------------------------------------------------------
- // Method that help wiring up the example (irrelevant to RxJava)
+ //public static class RepeatWithDelay
+ public class RepeatWithDelay implements Function, Publisher> {
- private int _getSecondHand() {
- long millis = System.currentTimeMillis();
- return (int) (TimeUnit.MILLISECONDS.toSeconds(millis) -
- TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
- }
+ private final int _repeatLimit;
+ private final int _pollingInterval;
+ private int _repeatCount = 1;
- private void _log(String logMsg) {
- if (_isCurrentlyOnMainThread()) {
- _logs.add(0, logMsg + " (main thread) ");
- _adapter.clear();
- _adapter.addAll(_logs);
- }
- else {
- _logs.add(0, logMsg + " (NOT main thread) ");
-
- // You can only do below stuff on main thread.
- new Handler(Looper.getMainLooper()).post(() -> {
- _adapter.clear();
- _adapter.addAll(_logs);
- });
- }
+ RepeatWithDelay(int repeatLimit, int pollingInterval) {
+ _pollingInterval = pollingInterval;
+ _repeatLimit = repeatLimit;
}
- private void _setupLogger() {
- _logs = new ArrayList<>();
- _adapter = new LogAdapter(getActivity(), new ArrayList<>());
- _logsList.setAdapter(_adapter);
- _counter = 0;
- }
-
- private boolean _isCurrentlyOnMainThread() {
- return Looper.myLooper() == Looper.getMainLooper();
- }
+ // this is a notificationhandler, all we care about is
+ // the emission "type" not emission "content"
+ // only onNext triggers a re-subscription
- //public static class RepeatWithDelay
- public class RepeatWithDelay
- implements Function, Publisher> {
-
- private final int _repeatLimit;
- private final int _pollingInterval;
- private int _repeatCount = 1;
-
- RepeatWithDelay(int repeatLimit, int pollingInterval) {
- _pollingInterval = pollingInterval;
- _repeatLimit = repeatLimit;
- }
-
- // this is a notificationhandler, all we care about is
- // the emission "type" not emission "content"
- // only onNext triggers a re-subscription
-
- @Override
- public Publisher apply(Flowable inputFlowable) throws Exception {
- // it is critical to use inputObservable in the chain for the result
- // ignoring it and doing your own thing will break the sequence
-
- return inputFlowable.flatMap(new Function>() {
- @Override
- public Publisher apply(Object o) throws Exception {
- if (_repeatCount >= _repeatLimit) {
- // terminate the sequence cause we reached the limit
- _log("Completing sequence");
- return Flowable.empty();
- }
-
- // since we don't get an input
- // we store state in this handler to tell us the point of time we're firing
- _repeatCount++;
-
- return Flowable.timer(_repeatCount * _pollingInterval, TimeUnit.MILLISECONDS);
- }
- });
- }
+ @Override
+ public Publisher apply(Flowable inputFlowable) throws Exception {
+ // it is critical to use inputObservable in the chain for the result
+ // ignoring it and doing your own thing will break the sequence
+
+ return inputFlowable.flatMap(
+ new Function>() {
+ @Override
+ public Publisher apply(Object o) throws Exception {
+ if (_repeatCount >= _repeatLimit) {
+ // terminate the sequence cause we reached the limit
+ _log("Completing sequence");
+ return Flowable.empty();
+ }
+
+ // since we don't get an input
+ // we store state in this handler to tell us the point of time we're firing
+ _repeatCount++;
+
+ return Flowable.timer(_repeatCount * _pollingInterval, TimeUnit.MILLISECONDS);
+ }
+ });
}
+ }
- private class LogAdapter
- extends ArrayAdapter {
+ private class LogAdapter extends ArrayAdapter {
- public LogAdapter(Context context, List logs) {
- super(context, R.layout.item_log, R.id.item_log, logs);
- }
+ public LogAdapter(Context context, List logs) {
+ super(context, R.layout.item_log, R.id.item_log, logs);
}
-}
\ No newline at end of file
+ }
+}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheFragment.java
index e4d3de1a..a214ce41 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheFragment.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheFragment.java
@@ -22,287 +22,311 @@
import java.util.Map;
import java.util.concurrent.TimeUnit;
-import butterknife.Bind;
+import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
+import butterknife.Unbinder;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.observers.DisposableObserver;
import io.reactivex.schedulers.Schedulers;
import timber.log.Timber;
-public class PseudoCacheFragment
- extends BaseFragment {
-
- @Bind(R.id.info_pseudoCache_demo) TextView infoText;
- @Bind(R.id.info_pseudoCache_listSubscription) ListView listSubscriptionInfo;
- @Bind(R.id.info_pseudoCache_listDtl) ListView listDetail;
-
- private ArrayAdapter adapterDetail, adapterSubscriptionInfo;
- private HashMap contributionMap = null;
-
- @Override
- public View onCreateView(LayoutInflater inflater,
- @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
- View layout = inflater.inflate(R.layout.fragment_pseudo_cache, container, false);
- ButterKnife.bind(this, layout);
- return layout;
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- ButterKnife.unbind(this);
- }
-
- @OnClick(R.id.btn_pseudoCache_concat)
- public void onConcatBtnClicked() {
- infoText.setText(R.string.msg_pseudoCache_demoInfo_concat);
- wireupDemo();
-
- Observable.concat(getSlowCachedDiskData(), getFreshNetworkData())
- .subscribeOn(Schedulers.io()) // we want to add a list item at time of subscription
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(new DisposableObserver() {
- @Override
- public void onComplete() {
- Timber.d("done loading all data");
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e(e, "arr something went wrong");
- }
-
- @Override
- public void onNext(Contributor contributor) {
- contributionMap.put(contributor.login, contributor.contributions);
- adapterDetail.clear();
- adapterDetail.addAll(mapAsList(contributionMap));
- }
- });
- }
-
- @OnClick(R.id.btn_pseudoCache_concatEager)
- public void onConcatEagerBtnClicked() {
- infoText.setText(R.string.msg_pseudoCache_demoInfo_concatEager);
- wireupDemo();
-
- List> observables = new ArrayList<>(2);
- observables.add(getSlowCachedDiskData());
- observables.add(getFreshNetworkData());
-
- Observable.concatEager(observables)
- .subscribeOn(Schedulers.io()) // we want to add a list item at time of subscription
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(new DisposableObserver() {
- @Override
- public void onComplete() {
- Timber.d("done loading all data");
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e(e, "arr something went wrong");
- }
-
- @Override
- public void onNext(Contributor contributor) {
- contributionMap.put(contributor.login, contributor.contributions);
- adapterDetail.clear();
- adapterDetail.addAll(mapAsList(contributionMap));
- }
- });
-
- }
-
- @OnClick(R.id.btn_pseudoCache_merge)
- public void onMergeBtnClicked() {
- infoText.setText(R.string.msg_pseudoCache_demoInfo_merge);
- wireupDemo();
-
- Observable.merge(getCachedDiskData(), getFreshNetworkData())
- .subscribeOn(Schedulers.io()) // we want to add a list item at time of subscription
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(new DisposableObserver() {
- @Override
- public void onComplete() {
- Timber.d("done loading all data");
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e(e, "arr something went wrong");
- }
-
- @Override
- public void onNext(Contributor contributor) {
- contributionMap.put(contributor.login, contributor.contributions);
- adapterDetail.clear();
- adapterDetail.addAll(mapAsList(contributionMap));
- }
- });
- }
-
- @OnClick(R.id.btn_pseudoCache_mergeSlowDisk)
- public void onMergeSlowBtnClicked() {
- infoText.setText(R.string.msg_pseudoCache_demoInfo_mergeSlowDisk);
- wireupDemo();
-
- Observable.merge(getSlowCachedDiskData(), getFreshNetworkData())
- .subscribeOn(Schedulers.io()) // we want to add a list item at time of subscription
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(new DisposableObserver() {
- @Override
- public void onComplete() {
- Timber.d("done loading all data");
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e(e, "arr something went wrong");
- }
-
- @Override
- public void onNext(Contributor contributor) {
- contributionMap.put(contributor.login, contributor.contributions);
- adapterDetail.clear();
- adapterDetail.addAll(mapAsList(contributionMap));
- }
- });
- }
-
- @OnClick(R.id.btn_pseudoCache_mergeOptimized)
- public void onMergeOptimizedBtnClicked() {
- infoText.setText(R.string.msg_pseudoCache_demoInfo_mergeOptimized);
- wireupDemo();
-
- getFreshNetworkData()//
- .publish(network ->//
- Observable.merge(network,//
- getCachedDiskData().takeUntil(network)))
- .subscribeOn(Schedulers.io()) // we want to add a list item at time of subscription
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(new DisposableObserver() {
- @Override
- public void onComplete() {
- Timber.d("done loading all data");
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e(e, "arr something went wrong");
- }
-
- @Override
- public void onNext(Contributor contributor) {
- contributionMap.put(contributor.login, contributor.contributions);
- adapterDetail.clear();
- adapterDetail.addAll(mapAsList(contributionMap));
- }
- });
+public class PseudoCacheFragment extends BaseFragment {
+
+ @BindView(R.id.info_pseudoCache_demo)
+ TextView infoText;
+
+ @BindView(R.id.info_pseudoCache_listSubscription)
+ ListView listSubscriptionInfo;
+
+ @BindView(R.id.info_pseudoCache_listDtl)
+ ListView listDetail;
+
+ private ArrayAdapter adapterDetail, adapterSubscriptionInfo;
+ private HashMap contributionMap = null;
+ private Unbinder unbinder;
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View layout = inflater.inflate(R.layout.fragment_pseudo_cache, container, false);
+ unbinder = ButterKnife.bind(this, layout);
+ return layout;
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ unbinder.unbind();
+ }
+
+ @OnClick(R.id.btn_pseudoCache_concat)
+ public void onConcatBtnClicked() {
+ infoText.setText(R.string.msg_pseudoCache_demoInfo_concat);
+ wireupDemo();
+
+ Observable.concat(getSlowCachedDiskData(), getFreshNetworkData())
+ .subscribeOn(Schedulers.io()) // we want to add a list item at time of subscription
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ new DisposableObserver() {
+ @Override
+ public void onComplete() {
+ Timber.d("done loading all data");
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ Timber.e(e, "arr something went wrong");
+ }
+
+ @Override
+ public void onNext(Contributor contributor) {
+ contributionMap.put(contributor.login, contributor.contributions);
+ adapterDetail.clear();
+ adapterDetail.addAll(mapAsList(contributionMap));
+ }
+ });
+ }
+
+ @OnClick(R.id.btn_pseudoCache_concatEager)
+ public void onConcatEagerBtnClicked() {
+ infoText.setText(R.string.msg_pseudoCache_demoInfo_concatEager);
+ wireupDemo();
+
+ List> observables = new ArrayList<>(2);
+ observables.add(getSlowCachedDiskData());
+ observables.add(getFreshNetworkData());
+
+ Observable.concatEager(observables)
+ .subscribeOn(Schedulers.io()) // we want to add a list item at time of subscription
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ new DisposableObserver() {
+ @Override
+ public void onComplete() {
+ Timber.d("done loading all data");
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ Timber.e(e, "arr something went wrong");
+ }
+
+ @Override
+ public void onNext(Contributor contributor) {
+ contributionMap.put(contributor.login, contributor.contributions);
+ adapterDetail.clear();
+ adapterDetail.addAll(mapAsList(contributionMap));
+ }
+ });
+ }
+
+ @OnClick(R.id.btn_pseudoCache_merge)
+ public void onMergeBtnClicked() {
+ infoText.setText(R.string.msg_pseudoCache_demoInfo_merge);
+ wireupDemo();
+
+ Observable.merge(getCachedDiskData(), getFreshNetworkData())
+ .subscribeOn(Schedulers.io()) // we want to add a list item at time of subscription
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ new DisposableObserver() {
+ @Override
+ public void onComplete() {
+ Timber.d("done loading all data");
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ Timber.e(e, "arr something went wrong");
+ }
+
+ @Override
+ public void onNext(Contributor contributor) {
+ contributionMap.put(contributor.login, contributor.contributions);
+ adapterDetail.clear();
+ adapterDetail.addAll(mapAsList(contributionMap));
+ }
+ });
+ }
+
+ @OnClick(R.id.btn_pseudoCache_mergeSlowDisk)
+ public void onMergeSlowBtnClicked() {
+ infoText.setText(R.string.msg_pseudoCache_demoInfo_mergeSlowDisk);
+ wireupDemo();
+
+ Observable.merge(getSlowCachedDiskData(), getFreshNetworkData())
+ .subscribeOn(Schedulers.io()) // we want to add a list item at time of subscription
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ new DisposableObserver() {
+ @Override
+ public void onComplete() {
+ Timber.d("done loading all data");
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ Timber.e(e, "arr something went wrong");
+ }
+
+ @Override
+ public void onNext(Contributor contributor) {
+ contributionMap.put(contributor.login, contributor.contributions);
+ adapterDetail.clear();
+ adapterDetail.addAll(mapAsList(contributionMap));
+ }
+ });
+ }
+
+ @OnClick(R.id.btn_pseudoCache_mergeOptimized)
+ public void onMergeOptimizedBtnClicked() {
+ infoText.setText(R.string.msg_pseudoCache_demoInfo_mergeOptimized);
+ wireupDemo();
+
+ getFreshNetworkData() //
+ .publish(
+ network -> //
+ Observable.merge(
+ network, //
+ getCachedDiskData().takeUntil(network)))
+ .subscribeOn(Schedulers.io()) // we want to add a list item at time of subscription
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ new DisposableObserver() {
+ @Override
+ public void onComplete() {
+ Timber.d("done loading all data");
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ Timber.e(e, "arr something went wrong");
+ }
+
+ @Override
+ public void onNext(Contributor contributor) {
+ contributionMap.put(contributor.login, contributor.contributions);
+ adapterDetail.clear();
+ adapterDetail.addAll(mapAsList(contributionMap));
+ }
+ });
+ }
+
+ @OnClick(R.id.btn_pseudoCache_mergeOptimizedSlowDisk)
+ public void onMergeOptimizedWithSlowDiskBtnClicked() {
+ infoText.setText(R.string.msg_pseudoCache_demoInfo_mergeOptimizedSlowDisk);
+ wireupDemo();
+
+ getFreshNetworkData() //
+ .publish(
+ network -> //
+ Observable.merge(
+ network, //
+ getSlowCachedDiskData().takeUntil(network)))
+ .subscribeOn(Schedulers.io()) // we want to add a list item at time of subscription
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ new DisposableObserver() {
+ @Override
+ public void onComplete() {
+ Timber.d("done loading all data");
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ Timber.e(e, "arr something went wrong");
+ }
+
+ @Override
+ public void onNext(Contributor contributor) {
+ contributionMap.put(contributor.login, contributor.contributions);
+ adapterDetail.clear();
+ adapterDetail.addAll(mapAsList(contributionMap));
+ }
+ });
+ }
+
+ // -----------------------------------------------------------------------------------
+ // WIRING for example
+
+ private void wireupDemo() {
+ contributionMap = new HashMap<>();
+
+ adapterDetail =
+ new ArrayAdapter<>(
+ getActivity(), R.layout.item_log_white, R.id.item_log, new ArrayList<>());
+ listDetail.setAdapter(adapterDetail);
+
+ adapterSubscriptionInfo =
+ new ArrayAdapter<>(
+ getActivity(), R.layout.item_log_white, R.id.item_log, new ArrayList<>());
+ listSubscriptionInfo.setAdapter(adapterSubscriptionInfo);
+ }
+
+ private Observable getSlowCachedDiskData() {
+ return Observable.timer(1, TimeUnit.SECONDS).flatMap(dummy -> getCachedDiskData());
+ }
+
+ private Observable getCachedDiskData() {
+ List list = new ArrayList<>();
+ Map map = dummyDiskData();
+
+ for (String username : map.keySet()) {
+ Contributor c = new Contributor();
+ c.login = username;
+ c.contributions = map.get(username);
+ list.add(c);
}
- @OnClick(R.id.btn_pseudoCache_mergeOptimizedSlowDisk)
- public void onMergeOptimizedWithSlowDiskBtnClicked() {
- infoText.setText(R.string.msg_pseudoCache_demoInfo_mergeOptimizedSlowDisk);
- wireupDemo();
-
- getFreshNetworkData()//
- .publish(network ->//
- Observable.merge(network,//
- getSlowCachedDiskData().takeUntil(network)))
- .subscribeOn(Schedulers.io()) // we want to add a list item at time of subscription
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(new DisposableObserver() {
- @Override
- public void onComplete() {
- Timber.d("done loading all data");
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e(e, "arr something went wrong");
- }
-
- @Override
- public void onNext(Contributor contributor) {
- contributionMap.put(contributor.login, contributor.contributions);
- adapterDetail.clear();
- adapterDetail.addAll(mapAsList(contributionMap));
- }
- });
- }
-
- // -----------------------------------------------------------------------------------
- // WIRING for example
-
- private void wireupDemo() {
- contributionMap = new HashMap<>();
-
- adapterDetail = new ArrayAdapter<>(getActivity(), R.layout.item_log_white, R.id.item_log, new ArrayList<>());
- listDetail.setAdapter(adapterDetail);
-
- adapterSubscriptionInfo = new ArrayAdapter<>(getActivity(),
- R.layout.item_log_white,
- R.id.item_log,
- new ArrayList<>());
- listSubscriptionInfo.setAdapter(adapterSubscriptionInfo);
- }
-
- private Observable getSlowCachedDiskData() {
- return Observable.timer(1, TimeUnit.SECONDS).flatMap(dummy -> getCachedDiskData());
- }
-
- private Observable getCachedDiskData() {
- List list = new ArrayList<>();
- Map map = dummyDiskData();
-
- for (String username : map.keySet()) {
- Contributor c = new Contributor();
- c.login = username;
- c.contributions = map.get(username);
- list.add(c);
- }
-
- return Observable.fromIterable(list)//
- .doOnSubscribe((data) -> new Handler(Looper.getMainLooper())//
- .post(() -> adapterSubscriptionInfo.add("(disk) cache subscribed")))//
- .doOnComplete(() -> new Handler(Looper.getMainLooper())//
+ return Observable.fromIterable(list) //
+ .doOnSubscribe(
+ (data) ->
+ new Handler(Looper.getMainLooper()) //
+ .post(() -> adapterSubscriptionInfo.add("(disk) cache subscribed"))) //
+ .doOnComplete(
+ () ->
+ new Handler(Looper.getMainLooper()) //
.post(() -> adapterSubscriptionInfo.add("(disk) cache completed")));
- }
-
- private Observable getFreshNetworkData() {
- String githubToken = getResources().getString(R.string.github_oauth_token);
- GithubApi githubService = GithubService.createGithubService(githubToken);
-
- return githubService.contributors("square", "retrofit")
- .flatMap(Observable::fromIterable)
- .doOnSubscribe((data) -> new Handler(Looper.getMainLooper())//
- .post(() -> adapterSubscriptionInfo.add("(network) subscribed")))//
- .doOnComplete(() -> new Handler(Looper.getMainLooper())//
+ }
+
+ private Observable getFreshNetworkData() {
+ String githubToken = getResources().getString(R.string.github_oauth_token);
+ GithubApi githubService = GithubService.createGithubService(githubToken);
+
+ return githubService
+ .contributors("square", "retrofit")
+ .flatMap(Observable::fromIterable)
+ .doOnSubscribe(
+ (data) ->
+ new Handler(Looper.getMainLooper()) //
+ .post(() -> adapterSubscriptionInfo.add("(network) subscribed"))) //
+ .doOnComplete(
+ () ->
+ new Handler(Looper.getMainLooper()) //
.post(() -> adapterSubscriptionInfo.add("(network) completed")));
- }
-
- private List mapAsList(HashMap map) {
- List list = new ArrayList<>();
+ }
- for (String username : map.keySet()) {
- String rowLog = String.format("%s [%d]", username, contributionMap.get(username));
- list.add(rowLog);
- }
+ private List mapAsList(HashMap map) {
+ List list = new ArrayList<>();
- return list;
+ for (String username : map.keySet()) {
+ String rowLog = String.format("%s [%d]", username, contributionMap.get(username));
+ list.add(rowLog);
}
- private Map dummyDiskData() {
- Map map = new HashMap<>();
- map.put("JakeWharton", 0L);
- map.put("pforhan", 0L);
- map.put("edenman", 0L);
- map.put("swankjesse", 0L);
- map.put("bruceLee", 0L);
- return map;
- }
+ return list;
+ }
+
+ private Map dummyDiskData() {
+ Map map = new HashMap<>();
+ map.put("JakeWharton", 0L);
+ map.put("pforhan", 0L);
+ map.put("edenman", 0L);
+ map.put("swankjesse", 0L);
+ map.put("bruceLee", 0L);
+ return map;
+ }
}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheMergeFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheMergeFragment.java
index ec2d49e5..3871437d 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheMergeFragment.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheMergeFragment.java
@@ -18,123 +18,127 @@
import java.util.HashMap;
import java.util.List;
-import butterknife.Bind;
+import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
+import butterknife.Unbinder;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.observers.DisposableObserver;
import io.reactivex.schedulers.Schedulers;
import timber.log.Timber;
-public class PseudoCacheMergeFragment
- extends BaseFragment {
-
- @Bind(R.id.log_list) ListView _resultList;
-
- private ArrayAdapter _adapter;
- private HashMap _contributionMap = null;
- private HashMap _resultAgeMap = new HashMap<>();
-
- @Override
- public View onCreateView(LayoutInflater inflater,
- @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
- View layout = inflater.inflate(R.layout.fragment_pseudo_cache_concat, container, false);
- ButterKnife.bind(this, layout);
- _initializeCache();
- return layout;
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- ButterKnife.unbind(this);
- }
-
- @OnClick(R.id.btn_start_pseudo_cache)
- public void onDemoPseudoCacheClicked() {
- _adapter = new ArrayAdapter<>(getActivity(), R.layout.item_log, R.id.item_log, new ArrayList<>());
-
- _resultList.setAdapter(_adapter);
- _initializeCache();
-
- Observable.merge(_getCachedData(), _getFreshData())
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(new DisposableObserver>() {
- @Override
- public void onComplete() {
- Timber.d("done loading all data");
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e(e, "arr something went wrong");
- }
-
- @Override
- public void onNext(Pair contributorAgePair) {
- Contributor contributor = contributorAgePair.first;
-
- if (_resultAgeMap.containsKey(contributor) &&
- _resultAgeMap.get(contributor) > contributorAgePair.second) {
- return;
- }
-
- _contributionMap.put(contributor.login, contributor.contributions);
- _resultAgeMap.put(contributor, contributorAgePair.second);
-
- _adapter.clear();
- _adapter.addAll(getListStringFromMap());
- }
- });
+public class PseudoCacheMergeFragment extends BaseFragment {
+
+ @BindView(R.id.log_list)
+ ListView _resultList;
+
+ private ArrayAdapter _adapter;
+ private HashMap _contributionMap = null;
+ private HashMap _resultAgeMap = new HashMap<>();
+ private Unbinder unbinder;
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View layout = inflater.inflate(R.layout.fragment_pseudo_cache_concat, container, false);
+ unbinder = ButterKnife.bind(this, layout);
+ _initializeCache();
+ return layout;
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ unbinder.unbind();
+ }
+
+ @OnClick(R.id.btn_start_pseudo_cache)
+ public void onDemoPseudoCacheClicked() {
+ _adapter =
+ new ArrayAdapter<>(getActivity(), R.layout.item_log, R.id.item_log, new ArrayList<>());
+
+ _resultList.setAdapter(_adapter);
+ _initializeCache();
+
+ Observable.merge(_getCachedData(), _getFreshData())
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ new DisposableObserver>() {
+ @Override
+ public void onComplete() {
+ Timber.d("done loading all data");
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ Timber.e(e, "arr something went wrong");
+ }
+
+ @Override
+ public void onNext(Pair contributorAgePair) {
+ Contributor contributor = contributorAgePair.first;
+
+ if (_resultAgeMap.containsKey(contributor)
+ && _resultAgeMap.get(contributor) > contributorAgePair.second) {
+ return;
+ }
+
+ _contributionMap.put(contributor.login, contributor.contributions);
+ _resultAgeMap.put(contributor, contributorAgePair.second);
+
+ _adapter.clear();
+ _adapter.addAll(getListStringFromMap());
+ }
+ });
+ }
+
+ private List getListStringFromMap() {
+ List list = new ArrayList<>();
+
+ for (String username : _contributionMap.keySet()) {
+ String rowLog = String.format("%s [%d]", username, _contributionMap.get(username));
+ list.add(rowLog);
}
- private List getListStringFromMap() {
- List list = new ArrayList<>();
+ return list;
+ }
- for (String username : _contributionMap.keySet()) {
- String rowLog = String.format("%s [%d]", username, _contributionMap.get(username));
- list.add(rowLog);
- }
+ private Observable> _getCachedData() {
- return list;
- }
+ List> list = new ArrayList<>();
- private Observable> _getCachedData() {
+ Pair dataWithAgePair;
- List> list = new ArrayList<>();
+ for (String username : _contributionMap.keySet()) {
+ Contributor c = new Contributor();
+ c.login = username;
+ c.contributions = _contributionMap.get(username);
- Pair dataWithAgePair;
-
- for (String username : _contributionMap.keySet()) {
- Contributor c = new Contributor();
- c.login = username;
- c.contributions = _contributionMap.get(username);
-
- dataWithAgePair = new Pair<>(c, System.currentTimeMillis());
- list.add(dataWithAgePair);
- }
-
- return Observable.fromIterable(list);
+ dataWithAgePair = new Pair<>(c, System.currentTimeMillis());
+ list.add(dataWithAgePair);
}
- private Observable> _getFreshData() {
- String githubToken = getResources().getString(R.string.github_oauth_token);
- GithubApi githubService = GithubService.createGithubService(githubToken);
-
- return githubService.contributors("square", "retrofit")
- .flatMap(Observable::fromIterable)
- .map(contributor -> new Pair<>(contributor, System.currentTimeMillis()));
- }
-
- private void _initializeCache() {
- _contributionMap = new HashMap<>();
- _contributionMap.put("JakeWharton", 0l);
- _contributionMap.put("pforhan", 0l);
- _contributionMap.put("edenman", 0l);
- _contributionMap.put("swankjesse", 0l);
- _contributionMap.put("bruceLee", 0l);
- }
+ return Observable.fromIterable(list);
+ }
+
+ private Observable> _getFreshData() {
+ String githubToken = getResources().getString(R.string.github_oauth_token);
+ GithubApi githubService = GithubService.createGithubService(githubToken);
+
+ return githubService
+ .contributors("square", "retrofit")
+ .flatMap(Observable::fromIterable)
+ .map(contributor -> new Pair<>(contributor, System.currentTimeMillis()));
+ }
+
+ private void _initializeCache() {
+ _contributionMap = new HashMap<>();
+ _contributionMap.put("JakeWharton", 0l);
+ _contributionMap.put("pforhan", 0l);
+ _contributionMap.put("edenman", 0l);
+ _contributionMap.put("swankjesse", 0l);
+ _contributionMap.put("bruceLee", 0l);
+ }
}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/RetrofitAsyncTaskDeathFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/RetrofitAsyncTaskDeathFragment.java
index 180462c9..baa391ed 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/fragments/RetrofitAsyncTaskDeathFragment.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/RetrofitAsyncTaskDeathFragment.java
@@ -18,101 +18,62 @@
import java.util.ArrayList;
-import butterknife.Bind;
+import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
+import butterknife.Unbinder;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.observers.DisposableObserver;
import io.reactivex.schedulers.Schedulers;
import static java.lang.String.format;
-public class RetrofitAsyncTaskDeathFragment
- extends Fragment {
+public class RetrofitAsyncTaskDeathFragment extends Fragment {
- @Bind(R.id.btn_demo_retrofit_async_death_username) EditText _username;
- @Bind(R.id.log_list) ListView _resultList;
+ @BindView(R.id.btn_demo_retrofit_async_death_username)
+ EditText _username;
- private GithubApi _githubService;
- private ArrayAdapter _adapter;
+ @BindView(R.id.log_list)
+ ListView _resultList;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ private GithubApi _githubService;
+ private ArrayAdapter _adapter;
+ private Unbinder unbinder;
- String githubToken = getResources().getString(R.string.github_oauth_token);
- _githubService = GithubService.createGithubService(githubToken);
- }
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
- @Override
- public View onCreateView(LayoutInflater inflater,
- @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
-
- View layout = inflater.inflate(R.layout.fragment_retrofit_async_task_death,
- container,
- false);
- ButterKnife.bind(this, layout);
-
- _adapter = new ArrayAdapter<>(getActivity(),
- R.layout.item_log,
- R.id.item_log,
- new ArrayList<>());
- //_adapter.setNotifyOnChange(true);
- _resultList.setAdapter(_adapter);
-
- return layout;
- }
+ String githubToken = getResources().getString(R.string.github_oauth_token);
+ _githubService = GithubService.createGithubService(githubToken);
+ }
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- ButterKnife.unbind(this);
- }
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
- @OnClick(R.id.btn_demo_retrofit_async_death)
- public void onGetGithubUserClicked() {
- _adapter.clear();
+ View layout = inflater.inflate(R.layout.fragment_retrofit_async_task_death, container, false);
+ unbinder = ButterKnife.bind(this, layout);
- /*new AsyncTask() {
- @Override
- protected User doInBackground(String... params) {
- return _githubService.getUser(params[0]);
- }
+ _adapter =
+ new ArrayAdapter<>(getActivity(), R.layout.item_log, R.id.item_log, new ArrayList<>());
+ //_adapter.setNotifyOnChange(true);
+ _resultList.setAdapter(_adapter);
- @Override
- protected void onPostExecute(User user) {
- _adapter.add(format("%s = [%s: %s]", _username.getText(), user.name, user.email));
- }
- }.execute(_username.getText().toString());*/
-
- _githubService.user(_username.getText().toString())
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(new DisposableObserver() {
- @Override
- public void onComplete() {
- }
-
- @Override
- public void onError(Throwable e) {
- }
-
- @Override
- public void onNext(User user) {
- _adapter.add(format("%s = [%s: %s]",
- _username.getText(),
- user.name,
- user.email));
- }
- });
- }
+ return layout;
+ }
- // -----------------------------------------------------------------------------------
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ unbinder.unbind();
+ }
- private class GetGithubUser
- extends AsyncTask {
+ @OnClick(R.id.btn_demo_retrofit_async_death)
+ public void onGetGithubUserClicked() {
+ _adapter.clear();
+ /*new AsyncTask() {
@Override
protected User doInBackground(String... params) {
return _githubService.getUser(params[0]);
@@ -122,5 +83,39 @@ protected User doInBackground(String... params) {
protected void onPostExecute(User user) {
_adapter.add(format("%s = [%s: %s]", _username.getText(), user.name, user.email));
}
+ }.execute(_username.getText().toString());*/
+
+ _githubService
+ .user(_username.getText().toString())
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ new DisposableObserver() {
+ @Override
+ public void onComplete() {}
+
+ @Override
+ public void onError(Throwable e) {}
+
+ @Override
+ public void onNext(User user) {
+ _adapter.add(format("%s = [%s: %s]", _username.getText(), user.name, user.email));
+ }
+ });
+ }
+
+ // -----------------------------------------------------------------------------------
+
+ private class GetGithubUser extends AsyncTask {
+
+ @Override
+ protected User doInBackground(String... params) {
+ return _githubService.getUser(params[0]);
+ }
+
+ @Override
+ protected void onPostExecute(User user) {
+ _adapter.add(format("%s = [%s: %s]", _username.getText(), user.name, user.email));
}
+ }
}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/RetrofitFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/RetrofitFragment.java
index 96875d60..0626e5b0 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/fragments/RetrofitFragment.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/RetrofitFragment.java
@@ -20,9 +20,10 @@
import java.util.ArrayList;
import java.util.List;
-import butterknife.Bind;
+import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
+import butterknife.Unbinder;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
@@ -33,136 +34,151 @@
import static android.text.TextUtils.isEmpty;
import static java.lang.String.format;
-public class RetrofitFragment
- extends Fragment {
-
- @Bind(R.id.demo_retrofit_contributors_username) EditText _username;
- @Bind(R.id.demo_retrofit_contributors_repository) EditText _repo;
- @Bind(R.id.log_list) ListView _resultList;
-
- private ArrayAdapter _adapter;
- private GithubApi _githubService;
- private CompositeDisposable _disposables;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- String githubToken = getResources().getString(R.string.github_oauth_token);
- _githubService = GithubService.createGithubService(githubToken);
-
- _disposables = new CompositeDisposable();
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater,
- @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
-
- View layout = inflater.inflate(R.layout.fragment_retrofit, container, false);
- ButterKnife.bind(this, layout);
-
- _adapter = new ArrayAdapter<>(getActivity(), R.layout.item_log, R.id.item_log, new ArrayList<>());
- //_adapter.setNotifyOnChange(true);
- _resultList.setAdapter(_adapter);
-
- return layout;
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- ButterKnife.unbind(this);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- _disposables.dispose();
- }
-
- @OnClick(R.id.btn_demo_retrofit_contributors)
- public void onListContributorsClicked() {
- _adapter.clear();
-
- _disposables.add(//
- _githubService.contributors(_username.getText().toString(), _repo.getText().toString())
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeWith(new DisposableObserver>() {
-
- @Override
- public void onComplete() {
- Timber.d("Retrofit call 1 completed");
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e(e, "woops we got an error while getting the list of contributors");
- }
-
- @Override
- public void onNext(List contributors) {
- for (Contributor c : contributors) {
- _adapter.add(format("%s has made %d contributions to %s",
- c.login,
- c.contributions,
- _repo.getText().toString()));
-
- Timber.d("%s has made %d contributions to %s",
- c.login,
- c.contributions,
- _repo.getText().toString());
- }
- }
- }));
- }
-
- @OnClick(R.id.btn_demo_retrofit_contributors_with_user_info)
- public void onListContributorsWithFullUserInfoClicked() {
- _adapter.clear();
-
- _disposables.add(_githubService.contributors(_username.getText().toString(), _repo.getText().toString())
- .flatMap(Observable::fromIterable)
- .flatMap(contributor -> {
- Observable _userObservable = _githubService.user(contributor.login)
- .filter(user -> !isEmpty(user.name) && !isEmpty(user.email));
-
- return Observable.zip(_userObservable,
- Observable.just(contributor),
- Pair::new);
- })
- .subscribeOn(Schedulers.newThread())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeWith(new DisposableObserver>() {
+public class RetrofitFragment extends Fragment {
+
+ @BindView(R.id.demo_retrofit_contributors_username)
+ EditText _username;
+
+ @BindView(R.id.demo_retrofit_contributors_repository)
+ EditText _repo;
+
+ @BindView(R.id.log_list)
+ ListView _resultList;
+
+ private ArrayAdapter _adapter;
+ private GithubApi _githubService;
+ private CompositeDisposable _disposables;
+ private Unbinder unbinder;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ String githubToken = getResources().getString(R.string.github_oauth_token);
+ _githubService = GithubService.createGithubService(githubToken);
+
+ _disposables = new CompositeDisposable();
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+
+ View layout = inflater.inflate(R.layout.fragment_retrofit, container, false);
+ unbinder = ButterKnife.bind(this, layout);
+
+ _adapter =
+ new ArrayAdapter<>(getActivity(), R.layout.item_log, R.id.item_log, new ArrayList<>());
+ //_adapter.setNotifyOnChange(true);
+ _resultList.setAdapter(_adapter);
+
+ return layout;
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ unbinder.unbind();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ _disposables.dispose();
+ }
+
+ @OnClick(R.id.btn_demo_retrofit_contributors)
+ public void onListContributorsClicked() {
+ _adapter.clear();
+
+ _disposables.add( //
+ _githubService
+ .contributors(_username.getText().toString(), _repo.getText().toString())
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeWith(
+ new DisposableObserver>() {
+
+ @Override
+ public void onComplete() {
+ Timber.d("Retrofit call 1 completed");
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ Timber.e(e, "woops we got an error while getting the list of contributors");
+ }
+
+ @Override
+ public void onNext(List contributors) {
+ for (Contributor c : contributors) {
+ _adapter.add(
+ format(
+ "%s has made %d contributions to %s",
+ c.login, c.contributions, _repo.getText().toString()));
+
+ Timber.d(
+ "%s has made %d contributions to %s",
+ c.login, c.contributions, _repo.getText().toString());
+ }
+ }
+ }));
+ }
+
+ @OnClick(R.id.btn_demo_retrofit_contributors_with_user_info)
+ public void onListContributorsWithFullUserInfoClicked() {
+ _adapter.clear();
+
+ _disposables.add(
+ _githubService
+ .contributors(_username.getText().toString(), _repo.getText().toString())
+ .flatMap(Observable::fromIterable)
+ .flatMap(
+ contributor -> {
+ Observable _userObservable =
+ _githubService
+ .user(contributor.login)
+ .filter(user -> !isEmpty(user.name) && !isEmpty(user.email));
+
+ return Observable.zip(_userObservable, Observable.just(contributor), Pair::new);
+ })
+ .subscribeOn(Schedulers.newThread())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeWith(
+ new DisposableObserver>() {
@Override
public void onComplete() {
- Timber.d("Retrofit call 2 completed ");
+ Timber.d("Retrofit call 2 completed ");
}
@Override
public void onError(Throwable e) {
- Timber.e(e, "error while getting the list of contributors along with full " + "names");
+ Timber.e(
+ e,
+ "error while getting the list of contributors along with full " + "names");
}
@Override
- public void onNext(Pair pair) {
- User user = ((Pair)pair).first;
- Contributor contributor = ((Pair)pair).second;
+ public void onNext(Pair pair) {
+ User user = pair.first;
+ Contributor contributor = pair.second;
- _adapter.add(format("%s(%s) has made %d contributions to %s",
+ _adapter.add(
+ format(
+ "%s(%s) has made %d contributions to %s",
user.name,
user.email,
contributor.contributions,
_repo.getText().toString()));
- _adapter.notifyDataSetChanged();
+ _adapter.notifyDataSetChanged();
- Timber.d("%s(%s) has made %d contributions to %s",
- user.name,
- user.email,
- contributor.contributions,
- _repo.getText().toString());
+ Timber.d(
+ "%s(%s) has made %d contributions to %s",
+ user.name,
+ user.email,
+ contributor.contributions,
+ _repo.getText().toString());
}
- }));
- }
+ }));
+ }
}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist1Fragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist1Fragment.java
index ec990a13..00882958 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist1Fragment.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist1Fragment.java
@@ -1,5 +1,7 @@
package com.morihacky.android.rxjava.fragments;
+import static android.os.Looper.getMainLooper;
+
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.Nullable;
@@ -8,9 +10,10 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
-import butterknife.Bind;
+import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
+import butterknife.Unbinder;
import com.morihacky.android.rxjava.R;
import com.morihacky.android.rxjava.wiring.LogAdapter;
import io.reactivex.Flowable;
@@ -20,116 +23,116 @@
import java.util.List;
import timber.log.Timber;
+public class RotationPersist1Fragment extends BaseFragment
+ implements RotationPersist1WorkerFragment.IAmYourMaster {
-import static android.os.Looper.getMainLooper;
-
-public class RotationPersist1Fragment
- extends BaseFragment
- implements RotationPersist1WorkerFragment.IAmYourMaster {
-
- public static final String FRAG_TAG = RotationPersist1WorkerFragment.class.getName();
+ public static final String TAG = RotationPersist1Fragment.class.toString();
- @Bind(R.id.list_threading_log) ListView _logList;
+ @BindView(R.id.list_threading_log)
+ ListView _logList;
- private LogAdapter _adapter;
- private List _logs;
+ private LogAdapter _adapter;
+ private List _logs;
+ private Unbinder unbinder;
- private CompositeDisposable _disposables = new CompositeDisposable();
+ private CompositeDisposable _disposables = new CompositeDisposable();
- // -----------------------------------------------------------------------------------
+ // -----------------------------------------------------------------------------------
- @OnClick(R.id.btn_rotate_persist)
- public void startOperationFromWorkerFrag() {
- _logs = new ArrayList<>();
- _adapter.clear();
+ @OnClick(R.id.btn_rotate_persist)
+ public void startOperationFromWorkerFrag() {
+ _logs = new ArrayList<>();
+ _adapter.clear();
- FragmentManager fm = getActivity().getSupportFragmentManager();
- RotationPersist1WorkerFragment frag =
- (RotationPersist1WorkerFragment) fm.findFragmentByTag(FRAG_TAG);
+ FragmentManager fm = getActivity().getSupportFragmentManager();
+ RotationPersist1WorkerFragment frag =
+ (RotationPersist1WorkerFragment) fm.findFragmentByTag(RotationPersist1WorkerFragment.TAG);
- if (frag == null) {
- frag = new RotationPersist1WorkerFragment();
- fm.beginTransaction().add(frag, FRAG_TAG).commit();
- } else {
- Timber.d("Worker frag already spawned");
- }
+ if (frag == null) {
+ frag = new RotationPersist1WorkerFragment();
+ fm.beginTransaction().add(frag, RotationPersist1WorkerFragment.TAG).commit();
+ } else {
+ Timber.d("Worker frag already spawned");
}
-
- @Override
- public void observeResults(Flowable intsFlowable) {
-
- DisposableSubscriber d = new DisposableSubscriber() {
- @Override
- public void onNext(Integer integer) {
- _log(String.format("Worker frag spits out - %d", integer));
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e(e, "Error in worker demo frag observable");
- _log("Dang! something went wrong.");
- }
-
- @Override
- public void onComplete() {
- _log("Observable is complete");
- }
+ }
+
+ @Override
+ public void observeResults(Flowable intsFlowable) {
+
+ DisposableSubscriber d =
+ new DisposableSubscriber() {
+ @Override
+ public void onNext(Integer integer) {
+ _log(String.format("Worker frag spits out - %d", integer));
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ Timber.e(e, "Error in worker demo frag observable");
+ _log("Dang! something went wrong.");
+ }
+
+ @Override
+ public void onComplete() {
+ _log("Observable is complete");
+ }
};
- intsFlowable
- .doOnSubscribe(subscription -> {
- _log("Subscribing to intsObservable");
- })
- .subscribe(d);
-
- _disposables.add(d);
- }
-
- // -----------------------------------------------------------------------------------
- // Boilerplate
- // -----------------------------------------------------------------------------------
-
- @Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- _setupLogger();
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater,
- @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
- View layout = inflater.inflate(R.layout.fragment_rotation_persist, container, false);
- ButterKnife.bind(this, layout);
- return layout;
- }
-
- @Override
- public void onPause() {
- super.onPause();
- _disposables.clear();
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- ButterKnife.unbind(this);
- }
-
- private void _setupLogger() {
- _logs = new ArrayList<>();
- _adapter = new LogAdapter(getActivity(), new ArrayList<>());
- _logList.setAdapter(_adapter);
- }
-
- private void _log(String logMsg) {
- _logs.add(0, logMsg);
-
- // You can only do below stuff on main thread.
- new Handler(getMainLooper()).post(() -> {
- _adapter.clear();
- _adapter.addAll(_logs);
- });
- }
-
-}
\ No newline at end of file
+ intsFlowable
+ .doOnSubscribe(
+ subscription -> {
+ _log("Subscribing to intsObservable");
+ })
+ .subscribe(d);
+
+ _disposables.add(d);
+ }
+
+ // -----------------------------------------------------------------------------------
+ // Boilerplate
+ // -----------------------------------------------------------------------------------
+
+ @Override
+ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ _setupLogger();
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View layout = inflater.inflate(R.layout.fragment_rotation_persist, container, false);
+ unbinder = ButterKnife.bind(this, layout);
+ return layout;
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ _disposables.clear();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ unbinder.unbind();
+ }
+
+ private void _setupLogger() {
+ _logs = new ArrayList<>();
+ _adapter = new LogAdapter(getActivity(), new ArrayList<>());
+ _logList.setAdapter(_adapter);
+ }
+
+ private void _log(String logMsg) {
+ _logs.add(0, logMsg);
+
+ // You can only do below stuff on main thread.
+ new Handler(getMainLooper())
+ .post(
+ () -> {
+ _adapter.clear();
+ _adapter.addAll(_logs);
+ });
+ }
+}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist1WorkerFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist1WorkerFragment.java
index 34b479fa..d16adc14 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist1WorkerFragment.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist1WorkerFragment.java
@@ -7,88 +7,75 @@
import io.reactivex.Flowable;
import io.reactivex.disposables.Disposable;
import io.reactivex.flowables.ConnectableFlowable;
-import java.util.List;
import java.util.concurrent.TimeUnit;
-public class RotationPersist1WorkerFragment
- extends Fragment {
-
- private IAmYourMaster _masterFrag;
- private ConnectableFlowable _storedIntsFlowable;
- private Disposable _storedIntsDisposable;
-
- /**
- * Hold a reference to the activity -> caller fragment
- * this way when the worker frag kicks off
- * we can talk back to the master and send results
- */
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
-
- List frags = ((MainActivity) context)
- .getSupportFragmentManager()
- .getFragments();
- for (Fragment f : frags) {
- if (f instanceof IAmYourMaster) {
- _masterFrag = (IAmYourMaster) f;
- }
- }
-
- if (_masterFrag == null) {
- throw new ClassCastException("We did not find a master who can understand us :(");
- }
- }
+public class RotationPersist1WorkerFragment extends Fragment {
- /**
- * This method will only be called once when the retained Fragment is first created.
- */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ public static final String TAG = RotationPersist1WorkerFragment.class.toString();
- // Retain this fragment across configuration changes.
- setRetainInstance(true);
+ private IAmYourMaster _masterFrag;
+ private ConnectableFlowable _storedIntsFlowable;
+ private Disposable _storedIntsDisposable;
- if (_storedIntsFlowable != null) {
- return;
- }
+ /**
+ * Hold a reference to the activity -> caller fragment this way when the worker frag kicks off we
+ * can talk back to the master and send results
+ */
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
- Flowable intsObservable = Flowable
- .interval(1, TimeUnit.SECONDS)
- .map(Long::intValue)
- .take(20);
+ _masterFrag =
+ (RotationPersist1Fragment)
+ ((MainActivity) context)
+ .getSupportFragmentManager()
+ .findFragmentByTag(RotationPersist1Fragment.TAG);
- _storedIntsFlowable = intsObservable.publish();
- _storedIntsDisposable = _storedIntsFlowable.connect();
+ if (_masterFrag == null) {
+ throw new ClassCastException("We did not find a master who can understand us :(");
}
+ }
- /**
- * The Worker fragment has started doing it's thing
- */
- @Override
- public void onResume() {
- super.onResume();
- _masterFrag.observeResults(_storedIntsFlowable);
- }
+ /** This method will only be called once when the retained Fragment is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
- @Override
- public void onDestroy() {
- super.onDestroy();
- _storedIntsDisposable.dispose();
- }
+ // Retain this fragment across configuration changes.
+ setRetainInstance(true);
- /**
- * Set the callback to null so we don't accidentally leak the
- * Activity instance.
- */
- @Override
- public void onDetach() {
- super.onDetach();
- _masterFrag = null;
+ if (_storedIntsFlowable != null) {
+ return;
}
- public interface IAmYourMaster {
- void observeResults(Flowable intsObservable);
- }
+ Flowable intsObservable =
+ Flowable.interval(1, TimeUnit.SECONDS).map(Long::intValue).take(20);
+
+ _storedIntsFlowable = intsObservable.publish();
+ _storedIntsDisposable = _storedIntsFlowable.connect();
+ }
+
+ /** The Worker fragment has started doing it's thing */
+ @Override
+ public void onResume() {
+ super.onResume();
+ _masterFrag.observeResults(_storedIntsFlowable);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ _storedIntsDisposable.dispose();
+ }
+
+ /** Set the callback to null so we don't accidentally leak the Activity instance. */
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ _masterFrag = null;
+ }
+
+ public interface IAmYourMaster {
+ void observeResults(Flowable intsObservable);
+ }
}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist2Fragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist2Fragment.java
index cdf5d244..6e523013 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist2Fragment.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist2Fragment.java
@@ -1,5 +1,7 @@
package com.morihacky.android.rxjava.fragments;
+import static android.os.Looper.getMainLooper;
+
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.Nullable;
@@ -8,7 +10,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
-import butterknife.Bind;
+import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import com.morihacky.android.rxjava.R;
@@ -20,110 +22,103 @@
import java.util.List;
import timber.log.Timber;
+public class RotationPersist2Fragment extends BaseFragment
+ implements RotationPersist2WorkerFragment.IAmYourMaster {
-import static android.os.Looper.getMainLooper;
-
-public class RotationPersist2Fragment
- extends BaseFragment
- implements RotationPersist2WorkerFragment.IAmYourMaster {
-
- public static final String FRAG_TAG = RotationPersist2WorkerFragment.class.getName();
+ public static final String TAG = RotationPersist2Fragment.class.toString();
- @Bind(R.id.list_threading_log) ListView _logList;
+ @BindView(R.id.list_threading_log)
+ ListView _logList;
- private LogAdapter _adapter;
- private List _logs;
+ private LogAdapter _adapter;
+ private List _logs;
- private CompositeDisposable _disposables = new CompositeDisposable();
+ private CompositeDisposable _disposables = new CompositeDisposable();
- // -----------------------------------------------------------------------------------
+ // -----------------------------------------------------------------------------------
- @OnClick(R.id.btn_rotate_persist)
- public void startOperationFromWorkerFrag() {
- _logs = new ArrayList<>();
- _adapter.clear();
+ @OnClick(R.id.btn_rotate_persist)
+ public void startOperationFromWorkerFrag() {
+ _logs = new ArrayList<>();
+ _adapter.clear();
- FragmentManager fm = getActivity().getSupportFragmentManager();
- RotationPersist2WorkerFragment frag = (RotationPersist2WorkerFragment) fm.findFragmentByTag(FRAG_TAG);
+ FragmentManager fm = getActivity().getSupportFragmentManager();
+ RotationPersist2WorkerFragment frag =
+ (RotationPersist2WorkerFragment) fm.findFragmentByTag(RotationPersist2WorkerFragment.TAG);
- if (frag == null) {
- frag = new RotationPersist2WorkerFragment();
- fm
- .beginTransaction()
- .add(frag, FRAG_TAG)
- .commit();
- }
- else {
- Timber.d("Worker frag already spawned");
- }
+ if (frag == null) {
+ frag = new RotationPersist2WorkerFragment();
+ fm.beginTransaction().add(frag, RotationPersist2WorkerFragment.TAG).commit();
+ } else {
+ Timber.d("Worker frag already spawned");
}
-
- @Override
- public void setStream(Flowable intStream) {
- DisposableSubscriber d = new DisposableSubscriber() {
- @Override
- public void onNext(Integer integer) {
- _log(String.format("Worker frag spits out - %d", integer));
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e(e, "Error in worker demo frag observable");
- _log("Dang! something went wrong.");
- }
-
- @Override
- public void onComplete() {
- _log("Observable is complete");
- }
+ }
+
+ @Override
+ public void setStream(Flowable intStream) {
+ DisposableSubscriber d =
+ new DisposableSubscriber() {
+ @Override
+ public void onNext(Integer integer) {
+ _log(String.format("Worker frag spits out - %d", integer));
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ Timber.e(e, "Error in worker demo frag observable");
+ _log("Dang! something went wrong.");
+ }
+
+ @Override
+ public void onComplete() {
+ _log("Observable is complete");
+ }
};
- intStream
- .doOnSubscribe(subscription -> _log("Subscribing to intsObservable"))
- .subscribe(d);
-
- _disposables.add(d);
-
- }
-
-// -----------------------------------------------------------------------------------
- // Boilerplate
- // -----------------------------------------------------------------------------------
-
- @Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- _setupLogger();
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater,
- @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
- View layout = inflater.inflate(R.layout.fragment_rotation_persist, container, false);
- ButterKnife.bind(this, layout);
- return layout;
- }
-
- @Override
- public void onPause() {
- super.onPause();
- _disposables.clear();
- }
-
- private void _setupLogger() {
- _logs = new ArrayList<>();
- _adapter = new LogAdapter(getActivity(), new ArrayList<>());
- _logList.setAdapter(_adapter);
- }
-
- private void _log(String logMsg) {
- _logs.add(0, logMsg);
-
- // You can only do below stuff on main thread.
- new Handler(getMainLooper()).post(() -> {
- _adapter.clear();
- _adapter.addAll(_logs);
- });
- }
-}
\ No newline at end of file
+ intStream.doOnSubscribe(subscription -> _log("Subscribing to intsObservable")).subscribe(d);
+
+ _disposables.add(d);
+ }
+
+ // -----------------------------------------------------------------------------------
+ // Boilerplate
+ // -----------------------------------------------------------------------------------
+
+ @Override
+ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ _setupLogger();
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View layout = inflater.inflate(R.layout.fragment_rotation_persist, container, false);
+ ButterKnife.bind(this, layout);
+ return layout;
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ _disposables.clear();
+ }
+
+ private void _setupLogger() {
+ _logs = new ArrayList<>();
+ _adapter = new LogAdapter(getActivity(), new ArrayList<>());
+ _logList.setAdapter(_adapter);
+ }
+
+ private void _log(String logMsg) {
+ _logs.add(0, logMsg);
+
+ // You can only do below stuff on main thread.
+ new Handler(getMainLooper())
+ .post(
+ () -> {
+ _adapter.clear();
+ _adapter.addAll(_logs);
+ });
+ }
+}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist2WorkerFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist2WorkerFragment.java
index 353a8faa..cdbe6cd3 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist2WorkerFragment.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist2WorkerFragment.java
@@ -6,90 +6,75 @@
import com.morihacky.android.rxjava.MainActivity;
import io.reactivex.Flowable;
import io.reactivex.processors.PublishProcessor;
-import java.util.List;
import java.util.concurrent.TimeUnit;
-public class RotationPersist2WorkerFragment
- extends Fragment {
-
- private PublishProcessor _intStream;
- private PublishProcessor _lifeCycleStream;
-
- private IAmYourMaster _masterFrag;
-
- /**
- * Since we're holding a reference to the Master a.k.a Activity/Master Frag
- * remember to explicitly remove the worker fragment or you'll have a mem leak in your hands.
- *
- * See {@link MainActivity#onBackPressed()}
- */
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
-
- List frags = ((MainActivity) context)
- .getSupportFragmentManager()
- .getFragments();
- for (Fragment f : frags) {
- if (f instanceof IAmYourMaster) {
- _masterFrag = (IAmYourMaster) f;
- }
- }
-
- if (_masterFrag == null) {
- throw new ClassCastException("We did not find a master who can understand us :(");
- }
- }
-
- /**
- * This method will only be called once when the retained Fragment is first created.
- */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+public class RotationPersist2WorkerFragment extends Fragment {
- _intStream = PublishProcessor.create();
- _lifeCycleStream = PublishProcessor.create();
+ public static final String TAG = RotationPersist2WorkerFragment.class.toString();
- // Retain this fragment across configuration changes.
- setRetainInstance(true);
+ private PublishProcessor _intStream;
+ private PublishProcessor _lifeCycleStream;
- _intStream.takeUntil(_lifeCycleStream);
+ private IAmYourMaster _masterFrag;
- Flowable
- .interval(1, TimeUnit.SECONDS)
- .map(Long::intValue)
- .take(20)
- .subscribe(_intStream);
+ /**
+ * Since we're holding a reference to the Master a.k.a Activity/Master Frag remember to explicitly
+ * remove the worker fragment or you'll have a mem leak in your hands.
+ *
+ * See {@link MainActivity#onBackPressed()}
+ */
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
- }
-
- /**
- * The Worker fragment has started doing it's thing
- */
- @Override
- public void onResume() {
- super.onResume();
- _masterFrag.setStream(_intStream);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- _lifeCycleStream.onComplete();
- }
-
- /**
- * Set the callback to null so we don't accidentally leak the
- * Activity instance.
- */
- @Override
- public void onDetach() {
- super.onDetach();
- _masterFrag = null;
- }
+ _masterFrag =
+ (RotationPersist2Fragment)
+ ((MainActivity) context)
+ .getSupportFragmentManager()
+ .findFragmentByTag(RotationPersist2Fragment.TAG);
- public interface IAmYourMaster {
- void setStream(Flowable intStream);
+ if (_masterFrag == null) {
+ throw new ClassCastException("We did not find a master who can understand us :(");
}
+ }
+
+ /** This method will only be called once when the retained Fragment is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ _intStream = PublishProcessor.create();
+ _lifeCycleStream = PublishProcessor.create();
+
+ // Retain this fragment across configuration changes.
+ setRetainInstance(true);
+
+ _intStream.takeUntil(_lifeCycleStream);
+
+ Flowable.interval(1, TimeUnit.SECONDS).map(Long::intValue).take(20).subscribe(_intStream);
+ }
+
+ /** The Worker fragment has started doing it's thing */
+ @Override
+ public void onResume() {
+ super.onResume();
+ _masterFrag.setStream(_intStream);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ _lifeCycleStream.onComplete();
+ }
+
+ /** Set the callback to null so we don't accidentally leak the Activity instance. */
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ _masterFrag = null;
+ }
+
+ public interface IAmYourMaster {
+ void setStream(Flowable intStream);
+ }
}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist3Fragment.kt b/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist3Fragment.kt
new file mode 100644
index 00000000..a69e0426
--- /dev/null
+++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist3Fragment.kt
@@ -0,0 +1,116 @@
+package com.morihacky.android.rxjava.fragments
+
+import android.arch.lifecycle.ViewModel
+import android.arch.lifecycle.ViewModelProviders
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper.getMainLooper
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ListView
+import butterknife.BindView
+import butterknife.ButterKnife
+import butterknife.OnClick
+import com.morihacky.android.rxjava.MyApp
+import com.morihacky.android.rxjava.R
+import com.morihacky.android.rxjava.ext.plus
+import com.morihacky.android.rxjava.wiring.LogAdapter
+import io.reactivex.Flowable
+import io.reactivex.disposables.CompositeDisposable
+import io.reactivex.disposables.Disposable
+import timber.log.Timber
+import java.util.concurrent.TimeUnit
+
+class RotationPersist3Fragment : BaseFragment() {
+
+ @BindView(R.id.list_threading_log)
+ lateinit var logList: ListView
+ lateinit var adapter: LogAdapter
+ lateinit var sharedViewModel: SharedViewModel
+
+ private var logs: MutableList = ArrayList()
+ private var disposables = CompositeDisposable()
+
+ // -----------------------------------------------------------------------------------
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ sharedViewModel = ViewModelProviders.of(activity).get(SharedViewModel::class.java)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ val layout = inflater!!.inflate(R.layout.fragment_rotation_persist, container, false)
+ ButterKnife.bind(this, layout)
+ return layout
+ }
+
+ @OnClick(R.id.btn_rotate_persist)
+ fun startOperationFromWorkerFrag() {
+ logs = ArrayList()
+ adapter.clear()
+
+ disposables +=
+ sharedViewModel
+ .sourceStream()
+ .subscribe({ l ->
+ _log("Received element $l")
+ })
+ }
+
+ // -----------------------------------------------------------------------------------
+ // Boilerplate
+ // -----------------------------------------------------------------------------------
+
+ override fun onActivityCreated(savedInstanceState: Bundle?) {
+ super.onActivityCreated(savedInstanceState)
+ _setupLogger()
+ }
+
+ override fun onPause() {
+ super.onPause()
+ disposables.clear()
+ }
+
+ private fun _setupLogger() {
+ logs = ArrayList()
+ adapter = LogAdapter(activity, ArrayList())
+ logList.adapter = adapter
+ }
+
+ private fun _log(logMsg: String) {
+ logs.add(0, logMsg)
+
+ // You can only do below stuff on main thread.
+ Handler(getMainLooper())
+ .post {
+ adapter.clear()
+ adapter.addAll(logs)
+ }
+ }
+}
+
+class SharedViewModel : ViewModel() {
+ var disposable: Disposable? = null
+
+ var sharedObservable: Flowable =
+ Flowable.interval(1, TimeUnit.SECONDS)
+ .take(20)
+ .doOnNext { l -> Timber.tag("KG").d("onNext $l") }
+ // .replayingShare()
+ .replay(1)
+ .autoConnect(1) { t -> disposable = t }
+
+ fun sourceStream(): Flowable {
+ return sharedObservable
+ }
+
+ override fun onCleared() {
+ super.onCleared()
+ Timber.tag("KG").d("Clearing ViewModel")
+ disposable?.dispose()
+ MyApp.getRefWatcher().watch(this)
+ }
+}
+
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/TimeoutDemoFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/TimeoutDemoFragment.java
index d70dd669..abeace6b 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/fragments/TimeoutDemoFragment.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/TimeoutDemoFragment.java
@@ -8,7 +8,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
-import butterknife.Bind;
+import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import com.morihacky.android.rxjava.R;
@@ -24,158 +24,160 @@
import java.util.concurrent.TimeUnit;
import timber.log.Timber;
-public class TimeoutDemoFragment
- extends BaseFragment {
+public class TimeoutDemoFragment extends BaseFragment {
- @Bind(R.id.list_threading_log) ListView _logsList;
+ @BindView(R.id.list_threading_log)
+ ListView _logsList;
- private LogAdapter _adapter;
- private DisposableObserver _disposable;
- private List _logs;
+ private LogAdapter _adapter;
+ private DisposableObserver _disposable;
+ private List _logs;
- @Override
- public void onDestroy() {
- super.onDestroy();
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
- if (_disposable == null) {
- return;
- }
-
- _disposable.dispose();
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater,
- @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
- View layout = inflater.inflate(R.layout.fragment_subject_timeout, container, false);
- ButterKnife.bind(this, layout);
- return layout;
- }
-
- @Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- _setupLogger();
- }
-
- @OnClick(R.id.btn_demo_timeout_1_2s)
- public void onStart2sTask() {
- _disposable = _getEventCompletionObserver();
-
- _getObservableTask_2sToComplete()
- .timeout(3, TimeUnit.SECONDS)
- .subscribeOn(Schedulers.computation())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(_disposable);
+ if (_disposable == null) {
+ return;
}
- @OnClick(R.id.btn_demo_timeout_1_5s)
- public void onStart5sTask() {
- _disposable = _getEventCompletionObserver();
-
- _getObservableTask_5sToComplete()
- .timeout(3, TimeUnit.SECONDS, _onTimeoutObservable())
- .subscribeOn(Schedulers.computation())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(_disposable);
- }
-
- // -----------------------------------------------------------------------------------
- // Main Rx entities
-
- private Observable _getObservableTask_5sToComplete() {
- return Observable.create(new ObservableOnSubscribe() {
- @Override
- public void subscribe(ObservableEmitter subscriber) throws Exception {
- _log(String.format("Starting a 5s task"));
- subscriber.onNext("5 s");
- try {
- Thread.sleep(5_000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- subscriber.onComplete();
+ _disposable.dispose();
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View layout = inflater.inflate(R.layout.fragment_subject_timeout, container, false);
+ ButterKnife.bind(this, layout);
+ return layout;
+ }
+
+ @Override
+ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ _setupLogger();
+ }
+
+ @OnClick(R.id.btn_demo_timeout_1_2s)
+ public void onStart2sTask() {
+ _disposable = _getEventCompletionObserver();
+
+ _getObservableTask_2sToComplete()
+ .timeout(3, TimeUnit.SECONDS)
+ .subscribeOn(Schedulers.computation())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(_disposable);
+ }
+
+ @OnClick(R.id.btn_demo_timeout_1_5s)
+ public void onStart5sTask() {
+ _disposable = _getEventCompletionObserver();
+
+ _getObservableTask_5sToComplete()
+ .timeout(3, TimeUnit.SECONDS, _onTimeoutObservable())
+ .subscribeOn(Schedulers.computation())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(_disposable);
+ }
+
+ // -----------------------------------------------------------------------------------
+ // Main Rx entities
+
+ private Observable _getObservableTask_5sToComplete() {
+ return Observable.create(
+ new ObservableOnSubscribe() {
+ @Override
+ public void subscribe(ObservableEmitter subscriber) throws Exception {
+ _log(String.format("Starting a 5s task"));
+ subscriber.onNext("5 s");
+ try {
+ Thread.sleep(5_000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
}
+ subscriber.onComplete();
+ }
});
- }
-
- private Observable _getObservableTask_2sToComplete() {
- return Observable
- .create(new ObservableOnSubscribe() {
- @Override
- public void subscribe(ObservableEmitter subscriber) throws Exception {
- _log(String.format("Starting a 2s task"));
- subscriber.onNext("2 s");
- try {
- Thread.sleep(2_000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- subscriber.onComplete();
- }
- });
- }
-
- private Observable extends String> _onTimeoutObservable() {
- return Observable.create(new ObservableOnSubscribe() {
-
- @Override
- public void subscribe(ObservableEmitter subscriber) throws Exception {
- _log("Timing out this task ...");
- subscriber.onError(new Throwable("Timeout Error"));
+ }
+
+ private Observable _getObservableTask_2sToComplete() {
+ return Observable.create(
+ new ObservableOnSubscribe() {
+ @Override
+ public void subscribe(ObservableEmitter subscriber) throws Exception {
+ _log(String.format("Starting a 2s task"));
+ subscriber.onNext("2 s");
+ try {
+ Thread.sleep(2_000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
}
+ subscriber.onComplete();
+ }
});
- }
-
- private DisposableObserver _getEventCompletionObserver() {
- return new DisposableObserver() {
- @Override
- public void onNext(String taskType) {
- _log(String.format("onNext %s task", taskType));
- }
-
- @Override
- public void onError(Throwable e) {
- _log(String.format("Dang a task timeout"));
- Timber.e(e, "Timeout Demo exception");
- }
-
- @Override
- public void onComplete() {
- _log(String.format("task was completed"));
- }
- };
- }
-
- // -----------------------------------------------------------------------------------
- // Method that help wiring up the example (irrelevant to RxJava)
-
- private void _setupLogger() {
- _logs = new ArrayList<>();
- _adapter = new LogAdapter(getActivity(), new ArrayList<>());
- _logsList.setAdapter(_adapter);
- }
+ }
- private void _log(String logMsg) {
+ private Observable extends String> _onTimeoutObservable() {
+ return Observable.create(
+ new ObservableOnSubscribe() {
- if (_isCurrentlyOnMainThread()) {
- _logs.add(0, logMsg + " (main thread) ");
- _adapter.clear();
- _adapter.addAll(_logs);
- }
- else {
- _logs.add(0, logMsg + " (NOT main thread) ");
-
- // You can only do below stuff on main thread.
- new Handler(Looper.getMainLooper()).post(() -> {
+ @Override
+ public void subscribe(ObservableEmitter subscriber) throws Exception {
+ _log("Timing out this task ...");
+ subscriber.onError(new Throwable("Timeout Error"));
+ }
+ });
+ }
+
+ private DisposableObserver _getEventCompletionObserver() {
+ return new DisposableObserver() {
+ @Override
+ public void onNext(String taskType) {
+ _log(String.format("onNext %s task", taskType));
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ _log(String.format("Dang a task timeout"));
+ Timber.e(e, "Timeout Demo exception");
+ }
+
+ @Override
+ public void onComplete() {
+ _log(String.format("task was completed"));
+ }
+ };
+ }
+
+ // -----------------------------------------------------------------------------------
+ // Method that help wiring up the example (irrelevant to RxJava)
+
+ private void _setupLogger() {
+ _logs = new ArrayList<>();
+ _adapter = new LogAdapter(getActivity(), new ArrayList<>());
+ _logsList.setAdapter(_adapter);
+ }
+
+ private void _log(String logMsg) {
+
+ if (_isCurrentlyOnMainThread()) {
+ _logs.add(0, logMsg + " (main thread) ");
+ _adapter.clear();
+ _adapter.addAll(_logs);
+ } else {
+ _logs.add(0, logMsg + " (NOT main thread) ");
+
+ // You can only do below stuff on main thread.
+ new Handler(Looper.getMainLooper())
+ .post(
+ () -> {
_adapter.clear();
_adapter.addAll(_logs);
- });
- }
+ });
}
+ }
- private boolean _isCurrentlyOnMainThread() {
- return Looper.myLooper() == Looper.getMainLooper();
- }
-}
\ No newline at end of file
+ private boolean _isCurrentlyOnMainThread() {
+ return Looper.myLooper() == Looper.getMainLooper();
+ }
+}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/TimingDemoFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/TimingDemoFragment.java
index 8e8458b7..55fb027c 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/fragments/TimingDemoFragment.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/TimingDemoFragment.java
@@ -7,11 +7,13 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
-import butterknife.Bind;
+import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import com.morihacky.android.rxjava.R;
import com.morihacky.android.rxjava.wiring.LogAdapter;
+
+import butterknife.Unbinder;
import io.reactivex.Flowable;
import io.reactivex.subscribers.DefaultSubscriber;
import io.reactivex.subscribers.DisposableSubscriber;
@@ -23,213 +25,212 @@
import java.util.concurrent.TimeUnit;
import timber.log.Timber;
-
import static android.os.Looper.getMainLooper;
import static android.os.Looper.myLooper;
-public class TimingDemoFragment
- extends BaseFragment {
-
- @Bind(R.id.list_threading_log) ListView _logsList;
-
- private LogAdapter _adapter;
- private List _logs;
-
- private DisposableSubscriber _subscriber1;
- private DisposableSubscriber _subscriber2;
-
- @Override
- public View onCreateView(LayoutInflater inflater,
- @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
- View layout = inflater.inflate(R.layout.fragment_demo_timing, container, false);
- ButterKnife.bind(this, layout);
- return layout;
- }
-
- @Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- _setupLogger();
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- ButterKnife.unbind(this);
-
- }
-// -----------------------------------------------------------------------------------
-
- @OnClick(R.id.btn_demo_timing_1)
- public void btn1_RunSingleTaskAfter2s() {
- _log(String.format("A1 [%s] --- BTN click", _getCurrentTimestamp()));
-
- Flowable.timer(2, TimeUnit.SECONDS)//
- .subscribe(new DefaultSubscriber() {
- @Override
- public void onNext(Long number) {
- _log(String.format("A1 [%s] NEXT", _getCurrentTimestamp()));
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e(e, "something went wrong in TimingDemoFragment example");
- }
-
- @Override
- public void onComplete() {
- _log(String.format("A1 [%s] XXX COMPLETE", _getCurrentTimestamp()));
- }
- });
+public class TimingDemoFragment extends BaseFragment {
+
+ @BindView(R.id.list_threading_log)
+ ListView _logsList;
+
+ private LogAdapter _adapter;
+ private List _logs;
+
+ private DisposableSubscriber _subscriber1;
+ private DisposableSubscriber _subscriber2;
+ private Unbinder unbinder;
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View layout = inflater.inflate(R.layout.fragment_demo_timing, container, false);
+ unbinder = ButterKnife.bind(this, layout);
+ return layout;
+ }
+
+ @Override
+ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ _setupLogger();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ unbinder.unbind();
+ }
+ // -----------------------------------------------------------------------------------
+
+ @OnClick(R.id.btn_demo_timing_1)
+ public void btn1_RunSingleTaskAfter2s() {
+ _log(String.format("A1 [%s] --- BTN click", _getCurrentTimestamp()));
+
+ Flowable.timer(2, TimeUnit.SECONDS) //
+ .subscribe(
+ new DefaultSubscriber() {
+ @Override
+ public void onNext(Long number) {
+ _log(String.format("A1 [%s] NEXT", _getCurrentTimestamp()));
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ Timber.e(e, "something went wrong in TimingDemoFragment example");
+ }
+
+ @Override
+ public void onComplete() {
+ _log(String.format("A1 [%s] XXX COMPLETE", _getCurrentTimestamp()));
+ }
+ });
+ }
+
+ @OnClick(R.id.btn_demo_timing_2)
+ public void btn2_RunTask_IntervalOf1s() {
+ if (_subscriber1 != null && !_subscriber1.isDisposed()) {
+ _subscriber1.dispose();
+ _log(String.format("B2 [%s] XXX BTN KILLED", _getCurrentTimestamp()));
+ return;
}
- @OnClick(R.id.btn_demo_timing_2)
- public void btn2_RunTask_IntervalOf1s() {
- if (_subscriber1 != null && !_subscriber1.isDisposed()) {
- _subscriber1.dispose();
- _log(String.format("B2 [%s] XXX BTN KILLED", _getCurrentTimestamp()));
- return;
- }
-
- _log(String.format("B2 [%s] --- BTN click", _getCurrentTimestamp()));
+ _log(String.format("B2 [%s] --- BTN click", _getCurrentTimestamp()));
- _subscriber1 = new DisposableSubscriber() {
- @Override
- public void onComplete() {
- _log(String.format("B2 [%s] XXXX COMPLETE", _getCurrentTimestamp()));
- }
+ _subscriber1 =
+ new DisposableSubscriber() {
+ @Override
+ public void onComplete() {
+ _log(String.format("B2 [%s] XXXX COMPLETE", _getCurrentTimestamp()));
+ }
- @Override
- public void onError(Throwable e) {
- Timber.e(e, "something went wrong in TimingDemoFragment example");
- }
+ @Override
+ public void onError(Throwable e) {
+ Timber.e(e, "something went wrong in TimingDemoFragment example");
+ }
- @Override
- public void onNext(Long number) {
- _log(String.format("B2 [%s] NEXT", _getCurrentTimestamp()));
- }
+ @Override
+ public void onNext(Long number) {
+ _log(String.format("B2 [%s] NEXT", _getCurrentTimestamp()));
+ }
};
- Flowable
- .interval(1, TimeUnit.SECONDS)
- .subscribe(_subscriber1);
- }
-
- @OnClick(R.id.btn_demo_timing_3)
- public void btn3_RunTask_IntervalOf1s_StartImmediately() {
- if (_subscriber2 != null && !_subscriber2.isDisposed()) {
- _subscriber2.dispose();
- _log(String.format("C3 [%s] XXX BTN KILLED", _getCurrentTimestamp()));
- return;
- }
-
- _log(String.format("C3 [%s] --- BTN click", _getCurrentTimestamp()));
-
- _subscriber2 = new DisposableSubscriber() {
- @Override
- public void onNext(Long number) {
- _log(String.format("C3 [%s] NEXT", _getCurrentTimestamp()));
- }
-
- @Override
- public void onComplete() {
- _log(String.format("C3 [%s] XXXX COMPLETE", _getCurrentTimestamp()));
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e(e, "something went wrong in TimingDemoFragment example");
- }
+ Flowable.interval(1, TimeUnit.SECONDS).subscribe(_subscriber1);
+ }
- };
-
- Flowable
- .interval(0, 1, TimeUnit.SECONDS)
- .subscribe(_subscriber2);
+ @OnClick(R.id.btn_demo_timing_3)
+ public void btn3_RunTask_IntervalOf1s_StartImmediately() {
+ if (_subscriber2 != null && !_subscriber2.isDisposed()) {
+ _subscriber2.dispose();
+ _log(String.format("C3 [%s] XXX BTN KILLED", _getCurrentTimestamp()));
+ return;
}
- @OnClick(R.id.btn_demo_timing_4)
- public void btn4_RunTask5Times_IntervalOf3s() {
- _log(String.format("D4 [%s] --- BTN click", _getCurrentTimestamp()));
-
- Flowable
- .interval(3, TimeUnit.SECONDS)
- .take(5)
- .subscribe(new DefaultSubscriber() {
- @Override
- public void onNext(Long number) {
- _log(String.format("D4 [%s] NEXT", _getCurrentTimestamp()));
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e(e, "something went wrong in TimingDemoFragment example");
- }
-
- @Override
- public void onComplete() {
- _log(String.format("D4 [%s] XXX COMPLETE", _getCurrentTimestamp()));
- }
-
- });
- }
+ _log(String.format("C3 [%s] --- BTN click", _getCurrentTimestamp()));
- @OnClick(R.id.btn_demo_timing_5)
- public void btn5_RunTask5Times_IntervalOf3s() {
- _log(String.format("D5 [%s] --- BTN click", _getCurrentTimestamp()));
-
- Flowable
- .just("Do task A right away")
- .doOnNext(input -> _log(String.format("D5 %s [%s]", input, _getCurrentTimestamp())))
- .delay(1, TimeUnit.SECONDS)
- .doOnNext(oldInput -> _log(String.format("D5 %s [%s]",
- "Doing Task B after a delay",
- _getCurrentTimestamp())))
- .subscribe(new DefaultSubscriber() {
- @Override
- public void onComplete() {
- _log(String.format("D5 [%s] XXX COMPLETE", _getCurrentTimestamp()));
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e(e, "something went wrong in TimingDemoFragment example");
- }
-
- @Override
- public void onNext(String number) {
- _log(String.format("D5 [%s] NEXT", _getCurrentTimestamp()));
- }
- });
- }
+ _subscriber2 =
+ new DisposableSubscriber() {
+ @Override
+ public void onNext(Long number) {
+ _log(String.format("C3 [%s] NEXT", _getCurrentTimestamp()));
+ }
- // -----------------------------------------------------------------------------------
- // Method that help wiring up the example (irrelevant to RxJava)
+ @Override
+ public void onComplete() {
+ _log(String.format("C3 [%s] XXXX COMPLETE", _getCurrentTimestamp()));
+ }
- @OnClick(R.id.btn_clr)
- public void OnClearLog() {
- _logs = new ArrayList<>();
- _adapter.clear();
- }
+ @Override
+ public void onError(Throwable e) {
+ Timber.e(e, "something went wrong in TimingDemoFragment example");
+ }
+ };
- private void _setupLogger() {
- _logs = new ArrayList<>();
- _adapter = new LogAdapter(getActivity(), new ArrayList<>());
- _logsList.setAdapter(_adapter);
- }
+ Flowable.interval(0, 1, TimeUnit.SECONDS).subscribe(_subscriber2);
+ }
- private void _log(String logMsg) {
- _logs.add(0, String.format(logMsg + " [MainThread: %b]", getMainLooper() == myLooper()));
+ @OnClick(R.id.btn_demo_timing_4)
+ public void btn4_RunTask5Times_IntervalOf3s() {
+ _log(String.format("D4 [%s] --- BTN click", _getCurrentTimestamp()));
- // You can only do below stuff on main thread.
- new Handler(getMainLooper()).post(() -> {
- _adapter.clear();
- _adapter.addAll(_logs);
- });
- }
+ Flowable.interval(3, TimeUnit.SECONDS)
+ .take(5)
+ .subscribe(
+ new DefaultSubscriber() {
+ @Override
+ public void onNext(Long number) {
+ _log(String.format("D4 [%s] NEXT", _getCurrentTimestamp()));
+ }
- private String _getCurrentTimestamp() {
- return new SimpleDateFormat("k:m:s:S a", Locale.getDefault()).format(new Date());
- }
+ @Override
+ public void onError(Throwable e) {
+ Timber.e(e, "something went wrong in TimingDemoFragment example");
+ }
+
+ @Override
+ public void onComplete() {
+ _log(String.format("D4 [%s] XXX COMPLETE", _getCurrentTimestamp()));
+ }
+ });
+ }
+
+ @OnClick(R.id.btn_demo_timing_5)
+ public void btn5_RunTask5Times_IntervalOf3s() {
+ _log(String.format("D5 [%s] --- BTN click", _getCurrentTimestamp()));
+
+ Flowable.just("Do task A right away")
+ .doOnNext(input -> _log(String.format("D5 %s [%s]", input, _getCurrentTimestamp())))
+ .delay(1, TimeUnit.SECONDS)
+ .doOnNext(
+ oldInput ->
+ _log(
+ String.format(
+ "D5 %s [%s]", "Doing Task B after a delay", _getCurrentTimestamp())))
+ .subscribe(
+ new DefaultSubscriber() {
+ @Override
+ public void onComplete() {
+ _log(String.format("D5 [%s] XXX COMPLETE", _getCurrentTimestamp()));
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ Timber.e(e, "something went wrong in TimingDemoFragment example");
+ }
+
+ @Override
+ public void onNext(String number) {
+ _log(String.format("D5 [%s] NEXT", _getCurrentTimestamp()));
+ }
+ });
+ }
+
+ // -----------------------------------------------------------------------------------
+ // Method that help wiring up the example (irrelevant to RxJava)
+
+ @OnClick(R.id.btn_clr)
+ public void OnClearLog() {
+ _logs = new ArrayList<>();
+ _adapter.clear();
+ }
+
+ private void _setupLogger() {
+ _logs = new ArrayList<>();
+ _adapter = new LogAdapter(getActivity(), new ArrayList<>());
+ _logsList.setAdapter(_adapter);
+ }
+
+ private void _log(String logMsg) {
+ _logs.add(0, String.format(logMsg + " [MainThread: %b]", getMainLooper() == myLooper()));
+
+ // You can only do below stuff on main thread.
+ new Handler(getMainLooper())
+ .post(
+ () -> {
+ _adapter.clear();
+ _adapter.addAll(_logs);
+ });
+ }
+
+ private String _getCurrentTimestamp() {
+ return new SimpleDateFormat("k:m:s:S a", Locale.getDefault()).format(new Date());
+ }
}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationAdapter.java b/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationAdapter.java
index 5de559f9..48cc49fd 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationAdapter.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationAdapter.java
@@ -13,92 +13,88 @@
import java.util.ArrayList;
import java.util.List;
-/**
- * There isn't anything specific to Pagination here.
- * Just wiring for the example
- */
+/** There isn't anything specific to Pagination here. Just wiring for the example */
class PaginationAdapter extends RecyclerView.Adapter {
- private static final int ITEM_LOG = 0;
- private static final int ITEM_BTN = 1;
+ private static final int ITEM_LOG = 0;
+ private static final int ITEM_BTN = 1;
- private final List _items = new ArrayList<>();
- private final RxBus _bus;
+ private final List _items = new ArrayList<>();
+ private final RxBus _bus;
- PaginationAdapter(RxBus bus) {
- _bus = bus;
- }
-
- void addItems(List items) {
- _items.addAll(items);
- }
+ PaginationAdapter(RxBus bus) {
+ _bus = bus;
+ }
- @Override
- public int getItemViewType(int position) {
- if (position == _items.size()) {
- return ITEM_BTN;
- }
+ void addItems(List items) {
+ _items.addAll(items);
+ }
- return ITEM_LOG;
+ @Override
+ public int getItemViewType(int position) {
+ if (position == _items.size()) {
+ return ITEM_BTN;
}
- @Override
- public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- switch (viewType) {
- case ITEM_BTN:
- return ItemBtnViewHolder.create(parent);
- default:
- return ItemLogViewHolder.create(parent);
- }
- }
+ return ITEM_LOG;
+ }
- @Override
- public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
- switch (getItemViewType(position)) {
- case ITEM_LOG:
- ((ItemLogViewHolder) holder).bindContent(_items.get(position));
- return;
- case ITEM_BTN:
- ((ItemBtnViewHolder) holder).bindContent(_bus);
- }
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ switch (viewType) {
+ case ITEM_BTN:
+ return ItemBtnViewHolder.create(parent);
+ default:
+ return ItemLogViewHolder.create(parent);
}
-
- @Override
- public int getItemCount() {
- return _items.size() + 1; // add 1 for paging button
+ }
+
+ @Override
+ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+ switch (getItemViewType(position)) {
+ case ITEM_LOG:
+ ((ItemLogViewHolder) holder).bindContent(_items.get(position));
+ return;
+ case ITEM_BTN:
+ ((ItemBtnViewHolder) holder).bindContent(_bus);
}
+ }
- private static class ItemLogViewHolder extends RecyclerView.ViewHolder {
- ItemLogViewHolder(View itemView) {
- super(itemView);
- }
+ @Override
+ public int getItemCount() {
+ return _items.size() + 1; // add 1 for paging button
+ }
- static ItemLogViewHolder create(ViewGroup parent) {
- return new ItemLogViewHolder(LayoutInflater.from(parent.getContext())
- .inflate(R.layout.item_log, parent, false));
- }
+ private static class ItemLogViewHolder extends RecyclerView.ViewHolder {
+ ItemLogViewHolder(View itemView) {
+ super(itemView);
+ }
- void bindContent(String content) {
- ((TextView) itemView).setText(content);
- }
+ static ItemLogViewHolder create(ViewGroup parent) {
+ return new ItemLogViewHolder(
+ LayoutInflater.from(parent.getContext()).inflate(R.layout.item_log, parent, false));
}
- static class ItemBtnViewHolder extends RecyclerView.ViewHolder {
- ItemBtnViewHolder(View itemView) {
- super(itemView);
- }
+ void bindContent(String content) {
+ ((TextView) itemView).setText(content);
+ }
+ }
- static ItemBtnViewHolder create(ViewGroup parent) {
- return new ItemBtnViewHolder(LayoutInflater.from(parent.getContext())
- .inflate(R.layout.item_btn, parent, false));
- }
+ static class ItemBtnViewHolder extends RecyclerView.ViewHolder {
+ ItemBtnViewHolder(View itemView) {
+ super(itemView);
+ }
- void bindContent(RxBus bus) {
- ((Button) itemView).setText(R.string.btn_demo_pagination_more);
- itemView.setOnClickListener(v -> bus.send(new ItemBtnViewHolder.PageEvent()));
- }
+ static ItemBtnViewHolder create(ViewGroup parent) {
+ return new ItemBtnViewHolder(
+ LayoutInflater.from(parent.getContext()).inflate(R.layout.item_btn, parent, false));
+ }
- static class PageEvent {
- }
+ void bindContent(RxBus bus) {
+ ((Button) itemView).setText(R.string.btn_demo_pagination_more);
+ itemView.setOnClickListener(v -> bus.send(new ItemBtnViewHolder.PageEvent()));
}
+
+ static class PageEvent {}
+ }
}
diff --git a/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationAutoAdapter.java b/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationAutoAdapter.java
index ece28f76..75d8adeb 100644
--- a/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationAutoAdapter.java
+++ b/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationAutoAdapter.java
@@ -10,62 +10,60 @@
import java.util.ArrayList;
import java.util.List;
-class PaginationAutoAdapter
- extends RecyclerView.Adapter {
+class PaginationAutoAdapter extends RecyclerView.Adapter {
- private static final int ITEM_LOG = 0;
+ private static final int ITEM_LOG = 0;
- private final List