From cd9e16a26b75b731c07080f28bec0114b02a24e3 Mon Sep 17 00:00:00 2001 From: Jonathan Caryl Date: Wed, 15 Mar 2017 09:09:58 +0000 Subject: [PATCH 01/22] Update build tools --- app/build.gradle | 2 +- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 49896 -> 54208 bytes gradle/wrapper/gradle-wrapper.properties | 4 +- gradlew | 74 +++++++++++++---------- gradlew.bat | 14 ++--- 6 files changed, 49 insertions(+), 47 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 99e29a4a..70474071 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -63,7 +63,7 @@ dependencies { android { compileSdkVersion sdkVersion - buildToolsVersion '23.0.3' + buildToolsVersion '25.0.2' defaultConfig { applicationId "com.morihacky.android.rxjava" diff --git a/build.gradle b/build.gradle index 85ab3d95..2735236d 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.2' + classpath 'com.android.tools.build:gradle:2.3.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 8c0fb64a8698b08ecc4158d828ca593c4928e9dd..2f220caedff2788de4bf62f2c784391386e6b72b 100644 GIT binary patch delta 48186 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 delta 43978 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a0a2dce4..7ff88c47 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sat Oct 01 19:11:24 PDT 2016 +#Wed Mar 15 09:09:23 GMT 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip diff --git a/gradlew b/gradlew index 91a7e269..4453ccea 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -6,12 +6,30 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,31 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -90,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -114,6 +113,7 @@ fi if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` @@ -154,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save ( ) { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index aec99730..e95643d6 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,10 +46,9 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +59,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line From c42b46dad87e9e1216fe76d581ff0d177f2feae3 Mon Sep 17 00:00:00 2001 From: Jonathan Caryl Date: Wed, 15 Mar 2017 09:10:05 +0000 Subject: [PATCH 02/22] Update butterknife --- app/build.gradle | 4 ++- .../rxjava/fragments/BufferDemoFragment.java | 12 ++++---- ...ConcurrencyWithSchedulersDemoFragment.java | 13 +++++---- .../DebounceSearchEmitterFragment.java | 12 ++++---- .../DoubleBindingTextViewFragment.java | 15 ++++++---- .../fragments/ExponentialBackoffFragment.java | 12 +++++--- .../FormValidationCombineLatestFragment.java | 29 ++++++++++--------- .../rxjava/fragments/MainFragment.java | 7 +++-- .../fragments/NetworkDetectorFragment.java | 11 ++++--- .../rxjava/fragments/PlaygroundFragment.java | 13 +++++---- .../rxjava/fragments/PollingFragment.java | 11 ++++--- .../rxjava/fragments/PseudoCacheFragment.java | 14 +++++---- .../fragments/PseudoCacheMergeFragment.java | 10 ++++--- .../RetrofitAsyncTaskDeathFragment.java | 12 ++++---- .../rxjava/fragments/RetrofitFragment.java | 14 +++++---- .../fragments/RotationPersist1Fragment.java | 11 ++++--- .../fragments/RotationPersist2Fragment.java | 4 +-- .../rxjava/fragments/TimeoutDemoFragment.java | 4 +-- .../rxjava/fragments/TimingDemoFragment.java | 11 ++++--- .../pagination/PaginationAutoFragment.java | 6 ++-- .../rxjava/pagination/PaginationFragment.java | 6 ++-- .../rxbus/RxBusDemo_Bottom1Fragment.java | 4 +-- .../rxbus/RxBusDemo_Bottom2Fragment.java | 6 ++-- .../rxbus/RxBusDemo_Bottom3Fragment.java | 6 ++-- .../rxjava/volley/VolleyDemoFragment.java | 11 ++++--- 25 files changed, 153 insertions(+), 105 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 70474071..8d5dcaad 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -22,6 +22,7 @@ ext { retrofitVersion = "2.0.0" sdkVersion = 24 supportLibVersion = "24.2.1" + butterKnifeVersion = '8.5.1' } dependencies { @@ -30,7 +31,8 @@ dependencies { compile "com.android.support:recyclerview-v7:${supportLibVersion}" compile 'com.github.kaushikgopal:CoreTextUtils:c703fa12b6' - compile 'com.jakewharton:butterknife:7.0.1' + compile "com.jakewharton:butterknife:$butterKnifeVersion" + annotationProcessor "com.jakewharton:butterknife-compiler:$butterKnifeVersion" compile 'com.jakewharton.timber:timber:2.4.2' compile "com.squareup.retrofit2:retrofit:${retrofitVersion}" compile "com.squareup.retrofit2:converter-gson:${retrofitVersion}" 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..60fa6131 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 @@ -18,9 +18,10 @@ 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; @@ -43,13 +44,14 @@ public class BufferDemoFragment extends BaseFragment { - @Bind(R.id.list_threading_log) ListView _logsList; - @Bind(R.id.btn_start_operation) Button _tapBtn; + @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() { @@ -74,13 +76,13 @@ 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); + unbinder = ButterKnife.bind(this, layout); return layout; } @Override public void onDestroyView() { super.onDestroyView(); - ButterKnife.unbind(this); + unbinder.unbind(); } // ----------------------------------------------------------------------------------- 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..f374ed3b 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; @@ -27,17 +29,18 @@ public class ConcurrencyWithSchedulersDemoFragment extends BaseFragment { - @Bind(R.id.progress_operation_running) ProgressBar _progress; - @Bind(R.id.list_threading_log) ListView _logsList; + @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(); - ButterKnife.unbind(this); + unbinder.unbind(); _disposables.clear(); } @@ -52,7 +55,7 @@ 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); + unbinder = ButterKnife.bind(this, layout); return layout; } 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..b7a36987 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 @@ -20,10 +20,11 @@ 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; @@ -35,19 +36,20 @@ public class DebounceSearchEmitterFragment extends BaseFragment { - @Bind(R.id.list_threading_log) ListView _logsList; - @Bind(R.id.input_txt_debounce) EditText _inputSearchText; + @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(); - ButterKnife.unbind(this); + unbinder.unbind(); } @Override @@ -55,7 +57,7 @@ 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); + unbinder = ButterKnife.bind(this, layout); return layout; } 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..63f8dab7 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,10 +7,12 @@ 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; @@ -20,19 +22,20 @@ 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; + @BindView(R.id.double_binding_num2) EditText _number2; + @BindView(R.id.double_binding_result) TextView _result; Disposable _disposable; PublishProcessor _resultEmitterSubject; + private Unbinder unbinder; @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); + unbinder = ButterKnife.bind(this, layout); _resultEmitterSubject = PublishProcessor.create(); @@ -66,6 +69,6 @@ public void onNumberChanged() { public void onDestroyView() { super.onDestroyView(); _disposable.dispose(); - ButterKnife.unbind(this); + 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..89d7a0f8 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 io.reactivex.Flowable; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.functions.Function; @@ -30,17 +33,18 @@ public class ExponentialBackoffFragment extends BaseFragment { - @Bind(R.id.list_threading_log) ListView _logList; + @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); - ButterKnife.bind(this, layout); + unbinder = ButterKnife.bind(this, layout); return layout; } @@ -60,7 +64,7 @@ public void onPause() { @Override public void onDestroyView() { super.onDestroyView(); - ButterKnife.unbind(this); + unbinder.unbind(); } // ----------------------------------------------------------------------------------- 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..61c1d17e 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 @@ -7,10 +7,12 @@ 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 com.morihacky.android.rxjava.R; + +import butterknife.Unbinder; import hu.akarnokd.rxjava.interop.RxJavaInterop; import io.reactivex.Flowable; import io.reactivex.subscribers.DisposableSubscriber; @@ -23,32 +25,33 @@ 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; + @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); - ButterKnife.bind(this, layout); + unbinder = ButterKnife.bind(this, layout); _emailChangeObservable = RxJavaInterop.toV2Flowable(RxTextView - .textChanges(_email) - .skip(1)); + .textChanges(_email) + .skip(1)); _passwordChangeObservable = RxJavaInterop.toV2Flowable(RxTextView - .textChanges(_password) - .skip(1)); + .textChanges(_password) + .skip(1)); _numberChangeObservable = RxJavaInterop.toV2Flowable(RxTextView - .textChanges(_number) - .skip(1)); + .textChanges(_number) + .skip(1)); _combineLatestEvents(); @@ -58,7 +61,7 @@ public View onCreateView(LayoutInflater inflater, @Override public void onDestroyView() { super.onDestroyView(); - ButterKnife.unbind(this); + unbinder.unbind(); _disposableObserver.dispose(); } 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..99cb52af 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,6 +9,8 @@ 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; @@ -17,19 +19,20 @@ 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); - ButterKnife.bind(this, layout); + unbinder = ButterKnife.bind(this, layout); return layout; } @Override public void onDestroyView() { super.onDestroyView(); - ButterKnife.unbind(this); + unbinder.unbind(); } @OnClick(R.id.btn_demo_schedulers) 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..6ed8ee77 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,9 +15,11 @@ 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; @@ -27,18 +29,19 @@ public class NetworkDetectorFragment extends BaseFragment { - @Bind(R.id.list_threading_log) ListView logsList; + @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(); - ButterKnife.unbind(this); + unbinder.unbind(); } @Override @@ -46,7 +49,7 @@ 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); + unbinder = ButterKnife.bind(this, layout); return layout; } 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 index 21f61fe5..2cac3942 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/PlaygroundFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/PlaygroundFragment.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.schedulers.Schedulers; @@ -27,17 +29,18 @@ public class PlaygroundFragment extends BaseFragment { - @Bind(R.id.progress_operation_running) ProgressBar _progress; - @Bind(R.id.list_threading_log) ListView _logsList; + @BindView(R.id.progress_operation_running) ProgressBar _progress; + @BindView(R.id.list_threading_log) ListView _logsList; private LogAdapter _adapter; private int _attempt = 0; private List _logs; + private Unbinder unbinder; @Override public void onDestroy() { super.onDestroy(); - ButterKnife.unbind(this); + unbinder.unbind(); } @Override @@ -45,7 +48,7 @@ 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); + unbinder = ButterKnife.bind(this, layout); return layout; } 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..1d320fa9 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; @@ -32,12 +34,13 @@ public class PollingFragment private static final int POLLING_INTERVAL = 1000; private static final int POLL_COUNT = 8; - @Bind(R.id.list_threading_log) ListView _logsList; + @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) { @@ -51,7 +54,7 @@ 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); + unbinder = ButterKnife.bind(this, layout); return layout; } @@ -65,7 +68,7 @@ public void onActivityCreated(@Nullable Bundle savedInstanceState) { public void onDestroy() { super.onDestroy(); _disposables.clear(); - ButterKnife.unbind(this); + unbinder.unbind(); } @OnClick(R.id.btn_start_simple_polling) 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..873794d1 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,9 +22,10 @@ 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; @@ -34,26 +35,27 @@ 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; + @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); - ButterKnife.bind(this, layout); + unbinder = ButterKnife.bind(this, layout); return layout; } @Override public void onDestroyView() { super.onDestroyView(); - ButterKnife.unbind(this); + unbinder.unbind(); } @OnClick(R.id.btn_pseudoCache_concat) 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..9c8d79bf 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,9 +18,10 @@ 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; @@ -30,18 +31,19 @@ public class PseudoCacheMergeFragment extends BaseFragment { - @Bind(R.id.log_list) ListView _resultList; + @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); - ButterKnife.bind(this, layout); + unbinder = ButterKnife.bind(this, layout); _initializeCache(); return layout; } @@ -49,7 +51,7 @@ public View onCreateView(LayoutInflater inflater, @Override public void onDestroyView() { super.onDestroyView(); - ButterKnife.unbind(this); + unbinder.unbind(); } @OnClick(R.id.btn_start_pseudo_cache) 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..9da8535e 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,9 +18,10 @@ 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; @@ -30,11 +31,12 @@ 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; + @BindView(R.id.log_list) ListView _resultList; private GithubApi _githubService; private ArrayAdapter _adapter; + private Unbinder unbinder; @Override public void onCreate(Bundle savedInstanceState) { @@ -52,7 +54,7 @@ public View onCreateView(LayoutInflater inflater, View layout = inflater.inflate(R.layout.fragment_retrofit_async_task_death, container, false); - ButterKnife.bind(this, layout); + unbinder = ButterKnife.bind(this, layout); _adapter = new ArrayAdapter<>(getActivity(), R.layout.item_log, @@ -67,7 +69,7 @@ public View onCreateView(LayoutInflater inflater, @Override public void onDestroyView() { super.onDestroyView(); - ButterKnife.unbind(this); + unbinder.unbind(); } @OnClick(R.id.btn_demo_retrofit_async_death) 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..540f3bf5 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; @@ -36,13 +37,14 @@ 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; + @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) { @@ -59,7 +61,7 @@ public View onCreateView(LayoutInflater inflater, @Nullable Bundle savedInstanceState) { View layout = inflater.inflate(R.layout.fragment_retrofit, container, false); - ButterKnife.bind(this, layout); + unbinder = ButterKnife.bind(this, layout); _adapter = new ArrayAdapter<>(getActivity(), R.layout.item_log, R.id.item_log, new ArrayList<>()); //_adapter.setNotifyOnChange(true); @@ -71,7 +73,7 @@ public View onCreateView(LayoutInflater inflater, @Override public void onDestroyView() { super.onDestroyView(); - ButterKnife.unbind(this); + unbinder.unbind(); } @Override 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..9ee37153 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 @@ -8,11 +8,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.disposables.CompositeDisposable; import io.reactivex.subscribers.DisposableSubscriber; @@ -29,10 +31,11 @@ public class RotationPersist1Fragment public static final String FRAG_TAG = RotationPersist1WorkerFragment.class.getName(); - @Bind(R.id.list_threading_log) ListView _logList; + @BindView(R.id.list_threading_log) ListView _logList; private LogAdapter _adapter; private List _logs; + private Unbinder unbinder; private CompositeDisposable _disposables = new CompositeDisposable(); @@ -100,7 +103,7 @@ 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); + unbinder = ButterKnife.bind(this, layout); return layout; } @@ -113,7 +116,7 @@ public void onPause() { @Override public void onDestroyView() { super.onDestroyView(); - ButterKnife.unbind(this); + unbinder.unbind(); } private void _setupLogger() { 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..d9597478 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 @@ -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; @@ -29,7 +29,7 @@ public class RotationPersist2Fragment public static final String FRAG_TAG = RotationPersist2WorkerFragment.class.getName(); - @Bind(R.id.list_threading_log) ListView _logList; + @BindView(R.id.list_threading_log) ListView _logList; private LogAdapter _adapter; private List _logs; 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..2cda5f2a 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; @@ -27,7 +27,7 @@ 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; 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..7bcc9147 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; @@ -30,20 +32,21 @@ public class TimingDemoFragment extends BaseFragment { - @Bind(R.id.list_threading_log) ListView _logsList; + @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); - ButterKnife.bind(this, layout); + unbinder = ButterKnife.bind(this, layout); return layout; } @@ -56,7 +59,7 @@ public void onActivityCreated(@Nullable Bundle savedInstanceState) { @Override public void onDestroyView() { super.onDestroyView(); - ButterKnife.unbind(this); + unbinder.unbind(); } // ----------------------------------------------------------------------------------- diff --git a/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationAutoFragment.java b/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationAutoFragment.java index a506c629..607a38d0 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationAutoFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationAutoFragment.java @@ -8,7 +8,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; -import butterknife.Bind; +import butterknife.BindView; import butterknife.ButterKnife; import com.morihacky.android.rxjava.MainActivity; import com.morihacky.android.rxjava.R; @@ -26,8 +26,8 @@ public class PaginationAutoFragment extends BaseFragment { - @Bind(R.id.list_paging) RecyclerView _pagingList; - @Bind(R.id.progress_paging) ProgressBar _progressBar; + @BindView(R.id.list_paging) RecyclerView _pagingList; + @BindView(R.id.progress_paging) ProgressBar _progressBar; private PaginationAutoAdapter _adapter; private RxBus _bus; diff --git a/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationFragment.java b/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationFragment.java index 7569b3c9..c7042d99 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationFragment.java @@ -8,7 +8,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; -import butterknife.Bind; +import butterknife.BindView; import butterknife.ButterKnife; import com.morihacky.android.rxjava.MainActivity; import com.morihacky.android.rxjava.R; @@ -26,8 +26,8 @@ public class PaginationFragment extends BaseFragment { - @Bind(R.id.list_paging) RecyclerView _pagingList; - @Bind(R.id.progress_paging) ProgressBar _progressBar; + @BindView(R.id.list_paging) RecyclerView _pagingList; + @BindView(R.id.progress_paging) ProgressBar _progressBar; private PaginationAdapter _adapter; private RxBus _bus; private CompositeDisposable _disposables; diff --git a/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom1Fragment.java b/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom1Fragment.java index 4ebb3200..91bc5cdb 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom1Fragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom1Fragment.java @@ -7,7 +7,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import butterknife.Bind; +import butterknife.BindView; import butterknife.ButterKnife; import com.morihacky.android.rxjava.MainActivity; import com.morihacky.android.rxjava.R; @@ -17,7 +17,7 @@ public class RxBusDemo_Bottom1Fragment extends BaseFragment { - @Bind(R.id.demo_rxbus_tap_txt) TextView _tapEventTxtShow; + @BindView(R.id.demo_rxbus_tap_txt) TextView _tapEventTxtShow; private CompositeDisposable _disposables; private RxBus _rxBus; diff --git a/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom2Fragment.java b/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom2Fragment.java index a2a99587..51e2e3c1 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom2Fragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom2Fragment.java @@ -7,7 +7,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import butterknife.Bind; +import butterknife.BindView; import butterknife.ButterKnife; import com.morihacky.android.rxjava.MainActivity; import com.morihacky.android.rxjava.R; @@ -21,8 +21,8 @@ public class RxBusDemo_Bottom2Fragment extends BaseFragment { - @Bind(R.id.demo_rxbus_tap_txt) TextView _tapEventTxtShow; - @Bind(R.id.demo_rxbus_tap_count) TextView _tapEventCountShow; + @BindView(R.id.demo_rxbus_tap_txt) TextView _tapEventTxtShow; + @BindView(R.id.demo_rxbus_tap_count) TextView _tapEventCountShow; private RxBus _rxBus; private CompositeDisposable _disposables; diff --git a/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom3Fragment.java b/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom3Fragment.java index d4125f0a..ec5ea58a 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom3Fragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom3Fragment.java @@ -7,7 +7,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import butterknife.Bind; +import butterknife.BindView; import butterknife.ButterKnife; import com.morihacky.android.rxjava.MainActivity; import com.morihacky.android.rxjava.R; @@ -20,8 +20,8 @@ public class RxBusDemo_Bottom3Fragment extends BaseFragment { - @Bind(R.id.demo_rxbus_tap_txt) TextView _tapEventTxtShow; - @Bind(R.id.demo_rxbus_tap_count) TextView _tapEventCountShow; + @BindView(R.id.demo_rxbus_tap_txt) TextView _tapEventTxtShow; + @BindView(R.id.demo_rxbus_tap_count) TextView _tapEventCountShow; private RxBus _rxBus; private CompositeDisposable _disposables; diff --git a/app/src/main/java/com/morihacky/android/rxjava/volley/VolleyDemoFragment.java b/app/src/main/java/com/morihacky/android/rxjava/volley/VolleyDemoFragment.java index c357e536..9a8e9d2f 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/volley/VolleyDemoFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/volley/VolleyDemoFragment.java @@ -9,7 +9,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.android.volley.Request; @@ -19,6 +19,8 @@ import com.morihacky.android.rxjava.R; import com.morihacky.android.rxjava.fragments.BaseFragment; import com.morihacky.android.rxjava.wiring.LogAdapter; + +import butterknife.Unbinder; import io.reactivex.Flowable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; @@ -36,10 +38,11 @@ public class VolleyDemoFragment public static final String TAG = "VolleyDemoFragment"; - @Bind(R.id.list_threading_log) ListView _logsList; + @BindView(R.id.list_threading_log) ListView _logsList; private List _logs; private LogAdapter _adapter; + private Unbinder unbinder; private CompositeDisposable _disposables = new CompositeDisposable(); @@ -48,7 +51,7 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View layout = inflater.inflate(R.layout.fragment_volley, container, false); - ButterKnife.bind(this, layout); + unbinder = ButterKnife.bind(this, layout); return layout; } @@ -67,7 +70,7 @@ public void onPause() { @Override public void onDestroyView() { super.onDestroyView(); - ButterKnife.unbind(this); + unbinder.unbind(); } /** From cbd585b30844e4e96c9333026cc221b69cb45012 Mon Sep 17 00:00:00 2001 From: Kaushik Gopal Date: Wed, 15 Mar 2017 06:09:01 -0700 Subject: [PATCH 03/22] chore: ignore idea files --- .gitignore | 1 + 1 file changed, 1 insertion(+) 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 From 06f8bd3350900c078b2b51a61cc2cae7d259c920 Mon Sep 17 00:00:00 2001 From: Kaushik Gopal Date: Wed, 15 Mar 2017 06:23:13 -0700 Subject: [PATCH 04/22] fix: avoid use of private api getFragments Closes #97 --- app/build.gradle | 2 +- .../fragments/RotationPersist1Fragment.java | 15 +++++++-------- .../fragments/RotationPersist1WorkerFragment.java | 14 +++++--------- .../fragments/RotationPersist2Fragment.java | 12 ++++++------ .../fragments/RotationPersist2WorkerFragment.java | 14 +++++--------- 5 files changed, 24 insertions(+), 33 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 8d5dcaad..7ec46136 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -21,7 +21,7 @@ ext { okhttpVersion = "3.0.1" retrofitVersion = "2.0.0" sdkVersion = 24 - supportLibVersion = "24.2.1" + supportLibVersion = "25.2.0" butterKnifeVersion = '8.5.1' } 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 9ee37153..e1b4ac53 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; @@ -11,10 +13,9 @@ 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 butterknife.Unbinder; import io.reactivex.Flowable; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.subscribers.DisposableSubscriber; @@ -22,14 +23,11 @@ import java.util.List; import timber.log.Timber; - -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(); @BindView(R.id.list_threading_log) ListView _logList; @@ -48,11 +46,12 @@ public void startOperationFromWorkerFrag() { FragmentManager fm = getActivity().getSupportFragmentManager(); RotationPersist1WorkerFragment frag = - (RotationPersist1WorkerFragment) fm.findFragmentByTag(FRAG_TAG); + (RotationPersist1WorkerFragment) fm.findFragmentByTag( + RotationPersist1WorkerFragment.TAG); if (frag == null) { frag = new RotationPersist1WorkerFragment(); - fm.beginTransaction().add(frag, FRAG_TAG).commit(); + fm.beginTransaction().add(frag, RotationPersist1WorkerFragment.TAG).commit(); } else { Timber.d("Worker frag already spawned"); } 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..69b18027 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,13 +7,14 @@ 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; + public static final String TAG = RotationPersist1WorkerFragment.class.toString(); + + private IAmYourMaster _masterFrag; private ConnectableFlowable _storedIntsFlowable; private Disposable _storedIntsDisposable; @@ -26,14 +27,9 @@ public class RotationPersist1WorkerFragment public void onAttach(Context context) { super.onAttach(context); - List frags = ((MainActivity) context) + _masterFrag = (RotationPersist1Fragment) ((MainActivity) context) .getSupportFragmentManager() - .getFragments(); - for (Fragment f : frags) { - if (f instanceof IAmYourMaster) { - _masterFrag = (IAmYourMaster) f; - } - } + .findFragmentByTag(RotationPersist1Fragment.TAG); if (_masterFrag == null) { throw new ClassCastException("We did not find a master who can understand us :("); 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 d9597478..3308bf7c 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; @@ -20,14 +22,11 @@ import java.util.List; import timber.log.Timber; - -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(); @BindView(R.id.list_threading_log) ListView _logList; @@ -44,13 +43,14 @@ public void startOperationFromWorkerFrag() { _adapter.clear(); FragmentManager fm = getActivity().getSupportFragmentManager(); - RotationPersist2WorkerFragment frag = (RotationPersist2WorkerFragment) fm.findFragmentByTag(FRAG_TAG); + RotationPersist2WorkerFragment frag = (RotationPersist2WorkerFragment) fm.findFragmentByTag( + RotationPersist2WorkerFragment.TAG); if (frag == null) { frag = new RotationPersist2WorkerFragment(); fm .beginTransaction() - .add(frag, FRAG_TAG) + .add(frag, RotationPersist2WorkerFragment.TAG) .commit(); } else { 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..bc6ca287 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,12 +6,13 @@ 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 { + public static final String TAG = RotationPersist2WorkerFragment.class.toString(); + private PublishProcessor _intStream; private PublishProcessor _lifeCycleStream; @@ -27,14 +28,9 @@ public class RotationPersist2WorkerFragment 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; - } - } + _masterFrag = (RotationPersist2Fragment) ((MainActivity) context) + .getSupportFragmentManager().findFragmentByTag(RotationPersist2Fragment.TAG); + if (_masterFrag == null) { throw new ClassCastException("We did not find a master who can understand us :("); From 21eac522aa4931e93cfe4c91fab3d0884c4f714d Mon Sep 17 00:00:00 2001 From: Kaushik Gopal Date: Wed, 15 Mar 2017 06:28:55 -0700 Subject: [PATCH 05/22] chore: add javafmt plugin dep --- app/build.gradle | 1 + build.gradle | 2 ++ 2 files changed, 3 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index 7ec46136..3472af89 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,6 +16,7 @@ buildscript { apply plugin: 'com.android.application' apply plugin: 'me.tatarka.retrolambda' +apply plugin: 'com.f2prateek.javafmt' ext { okhttpVersion = "3.0.1" diff --git a/build.gradle b/build.gradle index 2735236d..09bf45bb 100644 --- a/build.gradle +++ b/build.gradle @@ -7,9 +7,11 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:2.3.0' + classpath 'com.f2prateek.javafmt:javafmt:0.1.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files + } } From 59e31d1732eb94e597d5c04724685126f0712d21 Mon Sep 17 00:00:00 2001 From: Kaushik Gopal Date: Wed, 15 Mar 2017 06:29:14 -0700 Subject: [PATCH 06/22] fix: cleaup formatting to google-java-fmt --- .../android/rxjava/MainActivity.java | 76 ++- .../com/morihacky/android/rxjava/MyApp.java | 41 +- .../rxjava/fragments/BaseFragment.java | 15 +- .../rxjava/fragments/BufferDemoFragment.java | 232 ++++---- ...ConcurrencyWithSchedulersDemoFragment.java | 248 ++++---- .../DebounceSearchEmitterFragment.java | 205 +++---- .../DoubleBindingTextViewFragment.java | 82 +-- .../fragments/ExponentialBackoffFragment.java | 361 ++++++------ .../FormValidationCombineLatestFragment.java | 185 +++--- .../rxjava/fragments/MainFragment.java | 218 +++---- .../fragments/NetworkDetectorFragment.java | 210 +++---- .../rxjava/fragments/PlaygroundFragment.java | 202 +++---- .../rxjava/fragments/PollingFragment.java | 377 ++++++------ .../rxjava/fragments/PseudoCacheFragment.java | 556 +++++++++--------- .../fragments/PseudoCacheMergeFragment.java | 206 +++---- .../RetrofitAsyncTaskDeathFragment.java | 143 +++-- .../rxjava/fragments/RetrofitFragment.java | 244 ++++---- .../fragments/RotationPersist1Fragment.java | 203 +++---- .../RotationPersist1WorkerFragment.java | 127 ++-- .../fragments/RotationPersist2Fragment.java | 183 +++--- .../RotationPersist2WorkerFragment.java | 135 ++--- .../rxjava/fragments/TimeoutDemoFragment.java | 280 ++++----- .../rxjava/fragments/TimingDemoFragment.java | 378 ++++++------ .../rxjava/pagination/PaginationAdapter.java | 132 ++--- .../pagination/PaginationAutoAdapter.java | 84 ++- .../pagination/PaginationAutoFragment.java | 188 +++--- .../rxjava/pagination/PaginationFragment.java | 180 +++--- .../android/rxjava/retrofit/Contributor.java | 4 +- .../android/rxjava/retrofit/GithubApi.java | 32 +- .../rxjava/retrofit/GithubService.java | 49 +- .../android/rxjava/retrofit/User.java | 4 +- .../morihacky/android/rxjava/rxbus/RxBus.java | 26 +- .../rxjava/rxbus/RxBusDemoFragment.java | 46 +- .../rxbus/RxBusDemo_Bottom1Fragment.java | 85 ++- .../rxbus/RxBusDemo_Bottom2Fragment.java | 151 ++--- .../rxbus/RxBusDemo_Bottom3Fragment.java | 153 ++--- .../rxjava/rxbus/RxBusDemo_TopFragment.java | 40 +- .../android/rxjava/volley/MyVolley.java | 26 +- .../rxjava/volley/VolleyDemoFragment.java | 271 ++++----- .../android/rxjava/wiring/LogAdapter.java | 9 +- 40 files changed, 3211 insertions(+), 3176 deletions(-) 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..8c5df2f4 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/MainActivity.java +++ b/app/src/main/java/com/morihacky/android/rxjava/MainActivity.java @@ -8,54 +8,52 @@ import com.morihacky.android.rxjava.fragments.RotationPersist2WorkerFragment; import com.morihacky.android.rxjava.rxbus.RxBus; -public class MainActivity - extends FragmentActivity { +public class MainActivity extends FragmentActivity { - 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..99adc071 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/MyApp.java +++ b/app/src/main/java/com/morihacky/android/rxjava/MyApp.java @@ -6,33 +6,32 @@ import com.squareup.leakcanary.RefWatcher; import timber.log.Timber; -public class MyApp - extends Application { +public class MyApp extends Application { - 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); + _instance = (MyApp) getApplicationContext(); + _refWatcher = LeakCanary.install(this); - // for better RxJava debugging - //RxJavaHooks.enableAssemblyTracking(); + // for better RxJava debugging + //RxJavaHooks.enableAssemblyTracking(); - // Initialize Volley - MyVolley.init(this); + // Initialize Volley + MyVolley.init(this); - Timber.plant(new Timber.DebugTree()); - } + 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 60fa6131..85f618ef 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 @@ -30,126 +30,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 { - - @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 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 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( + () -> { _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 f374ed3b..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 @@ -26,138 +26,140 @@ import java.util.List; import timber.log.Timber; -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"); - } +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 b7a36987..129f7b11 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 @@ -33,111 +33,114 @@ import static co.kaush.core.util.CoreNullnessUtils.isNotNullOrEmpty; import static java.lang.String.format; -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 = 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 = + 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( + () -> { _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 63f8dab7..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 @@ -16,59 +16,63 @@ 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 { - @BindView(R.id.double_binding_num1) EditText _number1; - @BindView(R.id.double_binding_num2) EditText _number2; - @BindView(R.id.double_binding_result) TextView _result; + @BindView(R.id.double_binding_num1) + EditText _number1; - Disposable _disposable; - PublishProcessor _resultEmitterSubject; - private Unbinder unbinder; + @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); - unbinder = 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(); - unbinder.unbind(); + 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 89d7a0f8..0516b934 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 @@ -27,203 +27,210 @@ import rx.observables.MathObservable; import timber.log.Timber; - import static android.os.Looper.getMainLooper; -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!"); - } +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 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); + } + + // ----------------------------------------------------------------------------------- + + 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 inputObservable) { + @Override + public Publisher apply(Flowable 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 61c1d17e..07f8972d 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 @@ -18,107 +18,102 @@ 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 { - - @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 = 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(); - unbinder.unbind(); - _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 { - @Override - public void onError(Throwable e) { - Timber.e(e, "there was an error"); - } + @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); - @Override - public void onComplete() { - Timber.d("completed"); + _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(); + unbinder.unbind(); + _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)); } + } + + @Override + public void onError(Throwable e) { + Timber.e(e, "there was an error"); + } + + @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 99cb52af..c09925be 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 @@ -16,113 +16,113 @@ import com.morihacky.android.rxjava.rxbus.RxBusDemoFragment; import com.morihacky.android.rxjava.volley.VolleyDemoFragment; -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 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 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(); + } } 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 6ed8ee77..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 @@ -26,124 +26,126 @@ import java.util.ArrayList; import java.util.List; -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 -> { +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 index 2cac3942..6af2f8a0 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/PlaygroundFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/PlaygroundFragment.java @@ -26,116 +26,116 @@ import java.util.concurrent.TimeUnit; import timber.log.Timber; -public class PlaygroundFragment - extends BaseFragment { - - @BindView(R.id.progress_operation_running) ProgressBar _progress; - @BindView(R.id.list_threading_log) ListView _logsList; - - private LogAdapter _adapter; - private int _attempt = 0; - private List _logs; - 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_concurrency_schedulers, container, false); - unbinder = ButterKnife.bind(this, layout); - return layout; - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - _setupLogger(); +public class PlaygroundFragment extends BaseFragment { + + @BindView(R.id.progress_operation_running) + ProgressBar _progress; + + @BindView(R.id.list_threading_log) + ListView _logsList; + + private LogAdapter _adapter; + private int _attempt = 0; + private List _logs; + 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_concurrency_schedulers, container, false); + unbinder = 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"); } + } - @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(); - } + private void _log(String logMsg) { - // ----------------------------------------------------------------------------------- - // Method that help wiring up the example (irrelevant to RxJava) + if (_isCurrentlyOnMainThread()) { + _logs.add(0, logMsg + " (main thread) "); + _adapter.clear(); + _adapter.addAll(_logs); + } else { + _logs.add(0, logMsg + " (NOT main thread) "); - 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(() -> { + // 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/PollingFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/PollingFragment.java index 1d320fa9..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 @@ -27,202 +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; - - @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 -> { +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); + }); } + } - // ----------------------------------------------------------------------------------- + private void _setupLogger() { + _logs = new ArrayList<>(); + _adapter = new LogAdapter(getActivity(), new ArrayList<>()); + _logsList.setAdapter(_adapter); + _counter = 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!! + private boolean _isCurrentlyOnMainThread() { + return Looper.myLooper() == Looper.getMainLooper(); + } - // It's 12am in the morning and i feel lazy dammit !!! + //public static class RepeatWithDelay + public class RepeatWithDelay implements Function, Publisher> { - 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 final int _repeatLimit; + private final int _pollingInterval; + private int _repeatCount = 1; - return String.valueOf(_counter); + RepeatWithDelay(int repeatLimit, int pollingInterval) { + _pollingInterval = pollingInterval; + _repeatLimit = repeatLimit; } - // ----------------------------------------------------------------------------------- - // 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))); - } + // this is a notificationhandler, all we care about is + // the emission "type" not emission "content" + // only onNext triggers a re-subscription - 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); - _counter = 0; - } - - private boolean _isCurrentlyOnMainThread() { - return Looper.myLooper() == Looper.getMainLooper(); - } - - //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 873794d1..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 @@ -32,279 +32,301 @@ import io.reactivex.schedulers.Schedulers; import timber.log.Timber; -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; +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); } - @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); - } - - 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 9c8d79bf..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 @@ -28,115 +28,117 @@ import io.reactivex.schedulers.Schedulers; import timber.log.Timber; -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; +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); } - @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); - } - - return list; - } - - private Observable> _getCachedData() { - - List> list = new ArrayList<>(); + return list; + } - Pair dataWithAgePair; + private Observable> _getCachedData() { - for (String username : _contributionMap.keySet()) { - Contributor c = new Contributor(); - c.login = username; - c.contributions = _contributionMap.get(username); + List> list = new ArrayList<>(); - dataWithAgePair = new Pair<>(c, System.currentTimeMillis()); - list.add(dataWithAgePair); - } + Pair dataWithAgePair; - return Observable.fromIterable(list); - } - - private Observable> _getFreshData() { - String githubToken = getResources().getString(R.string.github_oauth_token); - GithubApi githubService = GithubService.createGithubService(githubToken); + for (String username : _contributionMap.keySet()) { + Contributor c = new Contributor(); + c.login = username; + c.contributions = _contributionMap.get(username); - return githubService.contributors("square", "retrofit") - .flatMap(Observable::fromIterable) - .map(contributor -> new Pair<>(contributor, System.currentTimeMillis())); + dataWithAgePair = new Pair<>(c, System.currentTimeMillis()); + list.add(dataWithAgePair); } - 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 9da8535e..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 @@ -28,93 +28,52 @@ import static java.lang.String.format; -public class RetrofitAsyncTaskDeathFragment - extends Fragment { +public class RetrofitAsyncTaskDeathFragment extends Fragment { - @BindView(R.id.btn_demo_retrofit_async_death_username) EditText _username; - @BindView(R.id.log_list) ListView _resultList; + @BindView(R.id.btn_demo_retrofit_async_death_username) + EditText _username; - private GithubApi _githubService; - private ArrayAdapter _adapter; - private Unbinder unbinder; + @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); - 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; - } + String githubToken = getResources().getString(R.string.github_oauth_token); + _githubService = GithubService.createGithubService(githubToken); + } - @Override - public void onDestroyView() { - super.onDestroyView(); - unbinder.unbind(); - } + @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]); @@ -124,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 540f3bf5..cb9eeb38 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 @@ -34,137 +34,151 @@ import static android.text.TextUtils.isEmpty; import static java.lang.String.format; -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>() { +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; + User user = ((Pair) pair).first; + Contributor contributor = ((Pair) 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 e1b4ac53..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 @@ -23,115 +23,116 @@ import java.util.List; import timber.log.Timber; -public class RotationPersist1Fragment - extends BaseFragment - implements RotationPersist1WorkerFragment.IAmYourMaster { +public class RotationPersist1Fragment extends BaseFragment + implements RotationPersist1WorkerFragment.IAmYourMaster { - public static final String TAG = RotationPersist1Fragment.class.toString(); + public static final String TAG = RotationPersist1Fragment.class.toString(); - @BindView(R.id.list_threading_log) ListView _logList; + @BindView(R.id.list_threading_log) + ListView _logList; - private LogAdapter _adapter; - private List _logs; - private Unbinder unbinder; + 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( - RotationPersist1WorkerFragment.TAG); + FragmentManager fm = getActivity().getSupportFragmentManager(); + RotationPersist1WorkerFragment frag = + (RotationPersist1WorkerFragment) fm.findFragmentByTag(RotationPersist1WorkerFragment.TAG); - if (frag == null) { - frag = new RotationPersist1WorkerFragment(); - fm.beginTransaction().add(frag, RotationPersist1WorkerFragment.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); - 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); - }); - } - -} \ 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 69b18027..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 @@ -9,82 +9,73 @@ import io.reactivex.flowables.ConnectableFlowable; import java.util.concurrent.TimeUnit; -public class RotationPersist1WorkerFragment - extends Fragment { +public class RotationPersist1WorkerFragment extends Fragment { public static final String TAG = RotationPersist1WorkerFragment.class.toString(); 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); - - _masterFrag = (RotationPersist1Fragment) ((MainActivity) context) - .getSupportFragmentManager() - .findFragmentByTag(RotationPersist1Fragment.TAG); - - if (_masterFrag == null) { - throw new ClassCastException("We did not find a master who can understand us :("); - } + 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); + + _masterFrag = + (RotationPersist1Fragment) + ((MainActivity) context) + .getSupportFragmentManager() + .findFragmentByTag(RotationPersist1Fragment.TAG); + + 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); + /** This method will only be called once when the retained Fragment is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); - // Retain this fragment across configuration changes. - setRetainInstance(true); + // Retain this fragment across configuration changes. + setRetainInstance(true); - if (_storedIntsFlowable != null) { - return; - } - - Flowable intsObservable = Flowable - .interval(1, TimeUnit.SECONDS) - .map(Long::intValue) - .take(20); - - _storedIntsFlowable = intsObservable.publish(); - _storedIntsDisposable = _storedIntsFlowable.connect(); + if (_storedIntsFlowable != null) { + return; } - /** - * 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); - } + 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 3308bf7c..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 @@ -22,108 +22,103 @@ import java.util.List; import timber.log.Timber; -public class RotationPersist2Fragment - extends BaseFragment - implements RotationPersist2WorkerFragment.IAmYourMaster { +public class RotationPersist2Fragment extends BaseFragment + implements RotationPersist2WorkerFragment.IAmYourMaster { - public static final String TAG = RotationPersist2Fragment.class.toString(); + public static final String TAG = RotationPersist2Fragment.class.toString(); - @BindView(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( - RotationPersist2WorkerFragment.TAG); + FragmentManager fm = getActivity().getSupportFragmentManager(); + RotationPersist2WorkerFragment frag = + (RotationPersist2WorkerFragment) fm.findFragmentByTag(RotationPersist2WorkerFragment.TAG); - if (frag == null) { - frag = new RotationPersist2WorkerFragment(); - fm - .beginTransaction() - .add(frag, RotationPersist2WorkerFragment.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 bc6ca287..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 @@ -8,84 +8,73 @@ import io.reactivex.processors.PublishProcessor; import java.util.concurrent.TimeUnit; -public class RotationPersist2WorkerFragment - extends Fragment { +public class RotationPersist2WorkerFragment extends Fragment { - public static final String TAG = RotationPersist2WorkerFragment.class.toString(); + public static final String TAG = RotationPersist2WorkerFragment.class.toString(); - private PublishProcessor _intStream; - private PublishProcessor _lifeCycleStream; + private PublishProcessor _intStream; + private PublishProcessor _lifeCycleStream; - private IAmYourMaster _masterFrag; + 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); + /** + * 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); - _masterFrag = (RotationPersist2Fragment) ((MainActivity) context) - .getSupportFragmentManager().findFragmentByTag(RotationPersist2Fragment.TAG); + _masterFrag = + (RotationPersist2Fragment) + ((MainActivity) context) + .getSupportFragmentManager() + .findFragmentByTag(RotationPersist2Fragment.TAG); - - 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); + 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/TimeoutDemoFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/TimeoutDemoFragment.java index 2cda5f2a..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 @@ -24,158 +24,160 @@ import java.util.concurrent.TimeUnit; import timber.log.Timber; -public class TimeoutDemoFragment - extends BaseFragment { +public class TimeoutDemoFragment extends BaseFragment { - @BindView(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 _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 _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 7bcc9147..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 @@ -25,214 +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 { - - @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())); - } - }); +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 _items = new ArrayList<>(); - private final RxBus _bus; + private final List _items = new ArrayList<>(); + private final RxBus _bus; - PaginationAutoAdapter(RxBus bus) { - _bus = bus; - } + PaginationAutoAdapter(RxBus bus) { + _bus = bus; + } - @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - return ItemLogViewHolder.create(parent); - } + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return ItemLogViewHolder.create(parent); + } - @Override - public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - ((ItemLogViewHolder) holder).bindContent(_items.get(position)); + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + ((ItemLogViewHolder) holder).bindContent(_items.get(position)); - boolean lastPositionReached = position == _items.size() - 1; - if (lastPositionReached) { - _bus.send(new PageEvent()); - } + boolean lastPositionReached = position == _items.size() - 1; + if (lastPositionReached) { + _bus.send(new PageEvent()); } + } - @Override - public int getItemViewType(int position) { - return ITEM_LOG; - } + @Override + public int getItemViewType(int position) { + return ITEM_LOG; + } - @Override - public int getItemCount() { - return _items.size(); - } + @Override + public int getItemCount() { + return _items.size(); + } - void addItems(List items) { - _items.addAll(items); - } + void addItems(List items) { + _items.addAll(items); + } - private static class ItemLogViewHolder - extends RecyclerView.ViewHolder { - ItemLogViewHolder(View itemView) { - super(itemView); - } + private static class ItemLogViewHolder extends RecyclerView.ViewHolder { + ItemLogViewHolder(View itemView) { + super(itemView); + } - static ItemLogViewHolder create(ViewGroup parent) { - return new ItemLogViewHolder(LayoutInflater.from(parent.getContext()) - .inflate(R.layout.item_log, parent, false)); - } + static ItemLogViewHolder create(ViewGroup parent) { + return new ItemLogViewHolder( + LayoutInflater.from(parent.getContext()).inflate(R.layout.item_log, parent, false)); + } - void bindContent(String content) { - ((TextView) itemView).setText(content); - } + void bindContent(String content) { + ((TextView) itemView).setText(content); } + } - static class PageEvent { } + static class PageEvent {} } diff --git a/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationAutoFragment.java b/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationAutoFragment.java index 607a38d0..e90d923b 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationAutoFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationAutoFragment.java @@ -23,109 +23,113 @@ import java.util.List; import java.util.concurrent.TimeUnit; -public class PaginationAutoFragment - extends BaseFragment { - - @BindView(R.id.list_paging) RecyclerView _pagingList; - @BindView(R.id.progress_paging) ProgressBar _progressBar; - - private PaginationAutoAdapter _adapter; - private RxBus _bus; - private CompositeDisposable _disposables; - private PublishProcessor _paginator; - private boolean _requestUnderWay = false; - - @Override - public View onCreateView(LayoutInflater inflater, - @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View layout = inflater.inflate(R.layout.fragment_pagination, container, false); - ButterKnife.bind(this, layout); - return layout; - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - _bus = ((MainActivity) getActivity()).getRxBusSingleton(); - - LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); - layoutManager.setOrientation(LinearLayoutManager.VERTICAL); - _pagingList.setLayoutManager(layoutManager); - - _adapter = new PaginationAutoAdapter(_bus); - _pagingList.setAdapter(_adapter); - - _paginator = PublishProcessor.create(); - } - - @Override - public void onStart() { - super.onStart(); - _disposables = new CompositeDisposable(); - - Disposable d2 = _paginator - .onBackpressureDrop() - .doOnNext(i -> { +public class PaginationAutoFragment extends BaseFragment { + + @BindView(R.id.list_paging) + RecyclerView _pagingList; + + @BindView(R.id.progress_paging) + ProgressBar _progressBar; + + private PaginationAutoAdapter _adapter; + private RxBus _bus; + private CompositeDisposable _disposables; + private PublishProcessor _paginator; + private boolean _requestUnderWay = false; + + @Override + public View onCreateView( + LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.fragment_pagination, container, false); + ButterKnife.bind(this, layout); + return layout; + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + _bus = ((MainActivity) getActivity()).getRxBusSingleton(); + + LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + _pagingList.setLayoutManager(layoutManager); + + _adapter = new PaginationAutoAdapter(_bus); + _pagingList.setAdapter(_adapter); + + _paginator = PublishProcessor.create(); + } + + @Override + public void onStart() { + super.onStart(); + _disposables = new CompositeDisposable(); + + Disposable d2 = + _paginator + .onBackpressureDrop() + .doOnNext( + i -> { _requestUnderWay = true; _progressBar.setVisibility(View.VISIBLE); - }) - .concatMap(this::_itemsFromNetworkCall) - .observeOn(AndroidSchedulers.mainThread()) - .map(items -> { + }) + .concatMap(this::_itemsFromNetworkCall) + .observeOn(AndroidSchedulers.mainThread()) + .map( + items -> { _adapter.addItems(items); _adapter.notifyDataSetChanged(); return items; - }) - .doOnNext(i -> { + }) + .doOnNext( + i -> { _requestUnderWay = false; _progressBar.setVisibility(View.INVISIBLE); - }) - .subscribe(); + }) + .subscribe(); - // I'm using an RxBus purely to hear from a nested button click - // we don't really need Rx for this part. it's just easy ¯\_(ツ)_/¯ + // I'm using an RxBus purely to hear from a nested button click + // we don't really need Rx for this part. it's just easy ¯\_(ツ)_/¯ - Disposable d1 = _bus - .asFlowable() - .filter(o -> !_requestUnderWay) - .subscribe(event -> { + Disposable d1 = + _bus.asFlowable() + .filter(o -> !_requestUnderWay) + .subscribe( + event -> { if (event instanceof PaginationAutoAdapter.PageEvent) { - // trigger the paginator for the next event - int nextPage = _adapter.getItemCount(); - _paginator.onNext(nextPage); + // trigger the paginator for the next event + int nextPage = _adapter.getItemCount(); + _paginator.onNext(nextPage); } - }); - - _disposables.add(d1); - _disposables.add(d2); - - _paginator.onNext(0); - } - - @Override - public void onStop() { - super.onStop(); - _disposables.clear(); - } - - /** - * Fake Observable that simulates a network call and then sends down a list of items - */ - private Flowable> _itemsFromNetworkCall(int pageStart) { - return Flowable - .just(true) - .observeOn(AndroidSchedulers.mainThread()) - .delay(2, TimeUnit.SECONDS) - .map(dummy -> { - List items = new ArrayList<>(); - for (int i = 0; i < 10; i++) { - items.add("Item " + (pageStart + i)); - } - return items; - }); - } + }); + + _disposables.add(d1); + _disposables.add(d2); + + _paginator.onNext(0); + } + + @Override + public void onStop() { + super.onStop(); + _disposables.clear(); + } + + /** Fake Observable that simulates a network call and then sends down a list of items */ + private Flowable> _itemsFromNetworkCall(int pageStart) { + return Flowable.just(true) + .observeOn(AndroidSchedulers.mainThread()) + .delay(2, TimeUnit.SECONDS) + .map( + dummy -> { + List items = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + items.add("Item " + (pageStart + i)); + } + return items; + }); + } } diff --git a/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationFragment.java b/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationFragment.java index c7042d99..bfe727f1 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationFragment.java @@ -23,42 +23,47 @@ import java.util.List; import java.util.concurrent.TimeUnit; -public class PaginationFragment - extends BaseFragment { - - @BindView(R.id.list_paging) RecyclerView _pagingList; - @BindView(R.id.progress_paging) ProgressBar _progressBar; - private PaginationAdapter _adapter; - private RxBus _bus; - private CompositeDisposable _disposables; - private PublishProcessor _paginator; - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - _bus = ((MainActivity) getActivity()).getRxBusSingleton(); - - LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); - layoutManager.setOrientation(LinearLayoutManager.VERTICAL); - _pagingList.setLayoutManager(layoutManager); - - _adapter = new PaginationAdapter(_bus); - _pagingList.setAdapter(_adapter); - - _paginator = PublishProcessor.create(); - } - - @Override - public void onStart() { - super.onStart(); - _disposables = new CompositeDisposable(); - - Disposable d2 = _paginator - .onBackpressureDrop() - .concatMap(nextPage -> _itemsFromNetworkCall(nextPage + 1, 10)) - .observeOn(AndroidSchedulers.mainThread()) - .map(items -> { +public class PaginationFragment extends BaseFragment { + + @BindView(R.id.list_paging) + RecyclerView _pagingList; + + @BindView(R.id.progress_paging) + ProgressBar _progressBar; + + private PaginationAdapter _adapter; + private RxBus _bus; + private CompositeDisposable _disposables; + private PublishProcessor _paginator; + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + _bus = ((MainActivity) getActivity()).getRxBusSingleton(); + + LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + _pagingList.setLayoutManager(layoutManager); + + _adapter = new PaginationAdapter(_bus); + _pagingList.setAdapter(_adapter); + + _paginator = PublishProcessor.create(); + } + + @Override + public void onStart() { + super.onStart(); + _disposables = new CompositeDisposable(); + + Disposable d2 = + _paginator + .onBackpressureDrop() + .concatMap(nextPage -> _itemsFromNetworkCall(nextPage + 1, 10)) + .observeOn(AndroidSchedulers.mainThread()) + .map( + items -> { int start = _adapter.getItemCount() - 1; _adapter.addItems(items); @@ -67,60 +72,57 @@ public void onStart() { _progressBar.setVisibility(View.INVISIBLE); return items; - }) - .subscribe(); - - // I'm using an Rxbus purely to hear from a nested button click - // we don't really need Rx for this part. it's just easy ¯\_(ツ)_/¯ - Disposable d1 = _bus - .asFlowable() - .subscribe(event -> { + }) + .subscribe(); + + // I'm using an Rxbus purely to hear from a nested button click + // we don't really need Rx for this part. it's just easy ¯\_(ツ)_/¯ + Disposable d1 = + _bus.asFlowable() + .subscribe( + event -> { if (event instanceof PaginationAdapter.ItemBtnViewHolder.PageEvent) { - // trigger the paginator for the next event - int nextPage = _adapter.getItemCount() - 1; - _paginator.onNext(nextPage); - - } - }); - - _disposables.add(d1); - _disposables.add(d2); - } - - @Override - public void onStop() { - super.onStop(); - _disposables.clear(); - } - - /** - * Fake Observable that simulates a network call and then sends down a list of items - */ - private Flowable> _itemsFromNetworkCall(int start, int count) { - return Flowable - .just(true) - .observeOn(AndroidSchedulers.mainThread()) - .doOnNext(dummy -> _progressBar.setVisibility(View.VISIBLE)) - .delay(2, TimeUnit.SECONDS) - .map(dummy -> { - List items = new ArrayList<>(); - for (int i = 0; i < count; i++) { - items.add("Item " + (start + i)); + // trigger the paginator for the next event + int nextPage = _adapter.getItemCount() - 1; + _paginator.onNext(nextPage); } - return items; - }); - } - - // ----------------------------------------------------------------------------------- - // WIRING up the views required for this example - - @Override - public View onCreateView(LayoutInflater inflater, - @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View layout = inflater.inflate(R.layout.fragment_pagination, container, false); - ButterKnife.bind(this, layout); - return layout; - } + }); + + _disposables.add(d1); + _disposables.add(d2); + } + + @Override + public void onStop() { + super.onStop(); + _disposables.clear(); + } + + /** Fake Observable that simulates a network call and then sends down a list of items */ + private Flowable> _itemsFromNetworkCall(int start, int count) { + return Flowable.just(true) + .observeOn(AndroidSchedulers.mainThread()) + .doOnNext(dummy -> _progressBar.setVisibility(View.VISIBLE)) + .delay(2, TimeUnit.SECONDS) + .map( + dummy -> { + List items = new ArrayList<>(); + for (int i = 0; i < count; i++) { + items.add("Item " + (start + i)); + } + return items; + }); + } + + // ----------------------------------------------------------------------------------- + // WIRING up the views required for this example + + @Override + public View onCreateView( + LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.fragment_pagination, container, false); + ButterKnife.bind(this, layout); + return layout; + } } diff --git a/app/src/main/java/com/morihacky/android/rxjava/retrofit/Contributor.java b/app/src/main/java/com/morihacky/android/rxjava/retrofit/Contributor.java index ad7760fc..5bd61c7a 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/retrofit/Contributor.java +++ b/app/src/main/java/com/morihacky/android/rxjava/retrofit/Contributor.java @@ -1,6 +1,6 @@ package com.morihacky.android.rxjava.retrofit; public class Contributor { - public String login; - public long contributions; + public String login; + public long contributions; } diff --git a/app/src/main/java/com/morihacky/android/rxjava/retrofit/GithubApi.java b/app/src/main/java/com/morihacky/android/rxjava/retrofit/GithubApi.java index d42c2ef9..21e32e8e 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/retrofit/GithubApi.java +++ b/app/src/main/java/com/morihacky/android/rxjava/retrofit/GithubApi.java @@ -8,25 +8,19 @@ public interface GithubApi { - /** - * See https://developer.github.com/v3/repos/#list-contributors - */ - @GET("/repos/{owner}/{repo}/contributors") - Observable> contributors(@Path("owner") String owner, - @Path("repo") String repo); + /** See https://developer.github.com/v3/repos/#list-contributors */ + @GET("/repos/{owner}/{repo}/contributors") + Observable> contributors( + @Path("owner") String owner, @Path("repo") String repo); - @GET("/repos/{owner}/{repo}/contributors") - List getContributors(@Path("owner") String owner, @Path("repo") String repo); + @GET("/repos/{owner}/{repo}/contributors") + List getContributors(@Path("owner") String owner, @Path("repo") String repo); - /** - * See https://developer.github.com/v3/users/ - */ - @GET("/users/{user}") - Observable user(@Path("user") String user); + /** See https://developer.github.com/v3/users/ */ + @GET("/users/{user}") + Observable user(@Path("user") String user); - /** - * See https://developer.github.com/v3/users/ - */ - @GET("/users/{user}") - User getUser(@Path("user") String user); -} \ No newline at end of file + /** See https://developer.github.com/v3/users/ */ + @GET("/users/{user}") + User getUser(@Path("user") String user); +} diff --git a/app/src/main/java/com/morihacky/android/rxjava/retrofit/GithubService.java b/app/src/main/java/com/morihacky/android/rxjava/retrofit/GithubService.java index d7f24a88..3ab57571 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/retrofit/GithubService.java +++ b/app/src/main/java/com/morihacky/android/rxjava/retrofit/GithubService.java @@ -13,27 +13,34 @@ public class GithubService { - private GithubService() { + private GithubService() {} + + public static GithubApi createGithubService(final String githubToken) { + Retrofit.Builder builder = + new Retrofit.Builder() + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + .addConverterFactory(GsonConverterFactory.create()) + .baseUrl("https://api.github.com"); + + if (!TextUtils.isEmpty(githubToken)) { + + OkHttpClient client = + new OkHttpClient.Builder() + .addInterceptor( + chain -> { + Request request = chain.request(); + Request newReq = + request + .newBuilder() + .addHeader("Authorization", format("token %s", githubToken)) + .build(); + return chain.proceed(newReq); + }) + .build(); + + builder.client(client); } - public static GithubApi createGithubService(final String githubToken) { - Retrofit.Builder builder = new Retrofit.Builder().addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - .addConverterFactory(GsonConverterFactory.create()) - .baseUrl("https://api.github.com"); - - if (!TextUtils.isEmpty(githubToken)) { - - OkHttpClient client = new OkHttpClient.Builder().addInterceptor(chain -> { - Request request = chain.request(); - Request newReq = request.newBuilder() - .addHeader("Authorization", format("token %s", githubToken)) - .build(); - return chain.proceed(newReq); - }).build(); - - builder.client(client); - } - - return builder.build().create(GithubApi.class); - } + return builder.build().create(GithubApi.class); + } } diff --git a/app/src/main/java/com/morihacky/android/rxjava/retrofit/User.java b/app/src/main/java/com/morihacky/android/rxjava/retrofit/User.java index 32fa1043..90f7aa3d 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/retrofit/User.java +++ b/app/src/main/java/com/morihacky/android/rxjava/retrofit/User.java @@ -1,6 +1,6 @@ package com.morihacky.android.rxjava.retrofit; public class User { - public String name; - public String email; + public String name; + public String email; } diff --git a/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBus.java b/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBus.java index 12f97b9d..0e8f4fed 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBus.java +++ b/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBus.java @@ -6,22 +6,20 @@ import io.reactivex.BackpressureStrategy; import io.reactivex.Flowable; -/** - * courtesy: https://gist.github.com/benjchristensen/04eef9ca0851f3a5d7bf - */ +/** courtesy: https://gist.github.com/benjchristensen/04eef9ca0851f3a5d7bf */ public class RxBus { - private final Relay _bus = PublishRelay.create().toSerialized(); + private final Relay _bus = PublishRelay.create().toSerialized(); - public void send(Object o) { - _bus.accept(o); - } + public void send(Object o) { + _bus.accept(o); + } - public Flowable asFlowable() { - return _bus.toFlowable(BackpressureStrategy.LATEST); - } + public Flowable asFlowable() { + return _bus.toFlowable(BackpressureStrategy.LATEST); + } - public boolean hasObservers() { - return _bus.hasObservers(); - } -} \ No newline at end of file + public boolean hasObservers() { + return _bus.hasObservers(); + } +} diff --git a/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemoFragment.java b/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemoFragment.java index 8eac88b7..f08ea85c 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemoFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemoFragment.java @@ -9,31 +9,29 @@ import com.morihacky.android.rxjava.R; import com.morihacky.android.rxjava.fragments.BaseFragment; -public class RxBusDemoFragment - extends BaseFragment { +public class RxBusDemoFragment extends BaseFragment { - @Override - public View onCreateView(LayoutInflater inflater, - @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View layout = inflater.inflate(R.layout.fragment_rxbus_demo, container, false); - ButterKnife.bind(this, layout); - return layout; - } + @Override + public View onCreateView( + LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.fragment_rxbus_demo, container, false); + ButterKnife.bind(this, layout); + return layout; + } - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); - getActivity().getSupportFragmentManager() - .beginTransaction() - .replace(R.id.demo_rxbus_frag_1, - new RxBusDemo_TopFragment()).replace(R.id.demo_rxbus_frag_2, - new RxBusDemo_Bottom3Fragment()) - //.replace(R.id.demo_rxbus_frag_2, new RxBusDemo_Bottom2Fragment()) - //.replace(R.id.demo_rxbus_frag_2, new RxBusDemo_Bottom1Fragment()) - .commit(); - } + getActivity() + .getSupportFragmentManager() + .beginTransaction() + .replace(R.id.demo_rxbus_frag_1, new RxBusDemo_TopFragment()) + .replace(R.id.demo_rxbus_frag_2, new RxBusDemo_Bottom3Fragment()) + //.replace(R.id.demo_rxbus_frag_2, new RxBusDemo_Bottom2Fragment()) + //.replace(R.id.demo_rxbus_frag_2, new RxBusDemo_Bottom1Fragment()) + .commit(); + } - public static class TapEvent {} -} \ No newline at end of file + public static class TapEvent {} +} diff --git a/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom1Fragment.java b/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom1Fragment.java index 91bc5cdb..1eb1e2ec 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom1Fragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom1Fragment.java @@ -14,54 +14,53 @@ import com.morihacky.android.rxjava.fragments.BaseFragment; import io.reactivex.disposables.CompositeDisposable; -public class RxBusDemo_Bottom1Fragment - extends BaseFragment { +public class RxBusDemo_Bottom1Fragment extends BaseFragment { - @BindView(R.id.demo_rxbus_tap_txt) TextView _tapEventTxtShow; - private CompositeDisposable _disposables; - private RxBus _rxBus; + @BindView(R.id.demo_rxbus_tap_txt) + TextView _tapEventTxtShow; - @Override - public View onCreateView(LayoutInflater inflater, - @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View layout = inflater.inflate(R.layout.fragment_rxbus_bottom, container, false); - ButterKnife.bind(this, layout); - return layout; - } + private CompositeDisposable _disposables; + private RxBus _rxBus; - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - _rxBus = ((MainActivity) getActivity()).getRxBusSingleton(); - } + @Override + public View onCreateView( + LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.fragment_rxbus_bottom, container, false); + ButterKnife.bind(this, layout); + return layout; + } - @Override - public void onStart() { - super.onStart(); - _disposables = new CompositeDisposable(); + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + _rxBus = ((MainActivity) getActivity()).getRxBusSingleton(); + } - _disposables.add(_rxBus - .asFlowable() - .subscribe(event -> { - if (event instanceof RxBusDemoFragment.TapEvent) { - _showTapText(); - } - })); - } + @Override + public void onStart() { + super.onStart(); + _disposables = new CompositeDisposable(); - @Override - public void onStop() { - super.onStop(); - _disposables.clear(); - } + _disposables.add( + _rxBus + .asFlowable() + .subscribe( + event -> { + if (event instanceof RxBusDemoFragment.TapEvent) { + _showTapText(); + } + })); + } - private void _showTapText() { - _tapEventTxtShow.setVisibility(View.VISIBLE); - _tapEventTxtShow.setAlpha(1f); - ViewCompat - .animate(_tapEventTxtShow) - .alphaBy(-1f) - .setDuration(400); - } + @Override + public void onStop() { + super.onStop(); + _disposables.clear(); + } + + private void _showTapText() { + _tapEventTxtShow.setVisibility(View.VISIBLE); + _tapEventTxtShow.setAlpha(1f); + ViewCompat.animate(_tapEventTxtShow).alphaBy(-1f).setDuration(400); + } } diff --git a/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom2Fragment.java b/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom2Fragment.java index 51e2e3c1..7cb08f4d 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom2Fragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom2Fragment.java @@ -18,79 +18,82 @@ import java.util.List; import java.util.concurrent.TimeUnit; -public class RxBusDemo_Bottom2Fragment - extends BaseFragment { - - @BindView(R.id.demo_rxbus_tap_txt) TextView _tapEventTxtShow; - @BindView(R.id.demo_rxbus_tap_count) TextView _tapEventCountShow; - - private RxBus _rxBus; - private CompositeDisposable _disposables; - - @Override - public View onCreateView(LayoutInflater inflater, - @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View layout = inflater.inflate(R.layout.fragment_rxbus_bottom, container, false); - ButterKnife.bind(this, layout); - return layout; - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - _rxBus = ((MainActivity) getActivity()).getRxBusSingleton(); - } - - @Override - public void onStart() { - super.onStart(); - _disposables = new CompositeDisposable(); - - Flowable tapEventEmitter = _rxBus - .asFlowable() - .share(); - - _disposables.add(tapEventEmitter.subscribe(event -> { - if (event instanceof RxBusDemoFragment.TapEvent) { +public class RxBusDemo_Bottom2Fragment extends BaseFragment { + + @BindView(R.id.demo_rxbus_tap_txt) + TextView _tapEventTxtShow; + + @BindView(R.id.demo_rxbus_tap_count) + TextView _tapEventCountShow; + + private RxBus _rxBus; + private CompositeDisposable _disposables; + + @Override + public View onCreateView( + LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.fragment_rxbus_bottom, container, false); + ButterKnife.bind(this, layout); + return layout; + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + _rxBus = ((MainActivity) getActivity()).getRxBusSingleton(); + } + + @Override + public void onStart() { + super.onStart(); + _disposables = new CompositeDisposable(); + + Flowable tapEventEmitter = _rxBus.asFlowable().share(); + + _disposables.add( + tapEventEmitter.subscribe( + event -> { + if (event instanceof RxBusDemoFragment.TapEvent) { _showTapText(); - } - })); - - Flowable debouncedEmitter = tapEventEmitter.debounce(1, TimeUnit.SECONDS); - Flowable> debouncedBufferEmitter = tapEventEmitter.buffer(debouncedEmitter); - - _disposables.add(debouncedBufferEmitter - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(taps -> { - _showTapCount(taps.size()); - })); - } - - @Override - public void onStop() { - super.onStop(); - _disposables.clear(); - } - - // ----------------------------------------------------------------------------------- - // Helper to show the text via an animation - - private void _showTapText() { - _tapEventTxtShow.setVisibility(View.VISIBLE); - _tapEventTxtShow.setAlpha(1f); - ViewCompat.animate(_tapEventTxtShow).alphaBy(-1f).setDuration(400); - } - - private void _showTapCount(int size) { - _tapEventCountShow.setText(String.valueOf(size)); - _tapEventCountShow.setVisibility(View.VISIBLE); - _tapEventCountShow.setScaleX(1f); - _tapEventCountShow.setScaleY(1f); - ViewCompat.animate(_tapEventCountShow) - .scaleXBy(-1f) - .scaleYBy(-1f) - .setDuration(800) - .setStartDelay(100); - } + } + })); + + Flowable debouncedEmitter = tapEventEmitter.debounce(1, TimeUnit.SECONDS); + Flowable> debouncedBufferEmitter = tapEventEmitter.buffer(debouncedEmitter); + + _disposables.add( + debouncedBufferEmitter + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + taps -> { + _showTapCount(taps.size()); + })); + } + + @Override + public void onStop() { + super.onStop(); + _disposables.clear(); + } + + // ----------------------------------------------------------------------------------- + // Helper to show the text via an animation + + private void _showTapText() { + _tapEventTxtShow.setVisibility(View.VISIBLE); + _tapEventTxtShow.setAlpha(1f); + ViewCompat.animate(_tapEventTxtShow).alphaBy(-1f).setDuration(400); + } + + private void _showTapCount(int size) { + _tapEventCountShow.setText(String.valueOf(size)); + _tapEventCountShow.setVisibility(View.VISIBLE); + _tapEventCountShow.setScaleX(1f); + _tapEventCountShow.setScaleY(1f); + ViewCompat.animate(_tapEventCountShow) + .scaleXBy(-1f) + .scaleYBy(-1f) + .setDuration(800) + .setStartDelay(100); + } } diff --git a/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom3Fragment.java b/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom3Fragment.java index ec5ea58a..d45ec46e 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom3Fragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_Bottom3Fragment.java @@ -17,78 +17,83 @@ import io.reactivex.flowables.ConnectableFlowable; import java.util.concurrent.TimeUnit; -public class RxBusDemo_Bottom3Fragment - extends BaseFragment { - - @BindView(R.id.demo_rxbus_tap_txt) TextView _tapEventTxtShow; - @BindView(R.id.demo_rxbus_tap_count) TextView _tapEventCountShow; - private RxBus _rxBus; - private CompositeDisposable _disposables; - - @Override - public View onCreateView(LayoutInflater inflater, - @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View layout = inflater.inflate(R.layout.fragment_rxbus_bottom, container, false); - ButterKnife.bind(this, layout); - return layout; - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - _rxBus = ((MainActivity) getActivity()).getRxBusSingleton(); - } - - @Override - public void onStart() { - super.onStart(); - _disposables = new CompositeDisposable(); - - ConnectableFlowable tapEventEmitter = _rxBus.asFlowable().publish(); - - _disposables// - .add(tapEventEmitter.subscribe(event -> { - if (event instanceof RxBusDemoFragment.TapEvent) { - _showTapText(); - } - })); - - _disposables - .add(tapEventEmitter.publish(stream -> - stream.buffer(stream.debounce(1, TimeUnit.SECONDS))) - .observeOn(AndroidSchedulers.mainThread()).subscribe(taps -> { - _showTapCount(taps.size()); - })); - - _disposables.add(tapEventEmitter.connect()); - - } - - @Override - public void onStop() { - super.onStop(); - _disposables.clear(); - } - - // ----------------------------------------------------------------------------------- - // Helper to show the text via an animation - - private void _showTapText() { - _tapEventTxtShow.setVisibility(View.VISIBLE); - _tapEventTxtShow.setAlpha(1f); - ViewCompat.animate(_tapEventTxtShow).alphaBy(-1f).setDuration(400); - } - - private void _showTapCount(int size) { - _tapEventCountShow.setText(String.valueOf(size)); - _tapEventCountShow.setVisibility(View.VISIBLE); - _tapEventCountShow.setScaleX(1f); - _tapEventCountShow.setScaleY(1f); - ViewCompat.animate(_tapEventCountShow) - .scaleXBy(-1f) - .scaleYBy(-1f) - .setDuration(800) - .setStartDelay(100); - } +public class RxBusDemo_Bottom3Fragment extends BaseFragment { + + @BindView(R.id.demo_rxbus_tap_txt) + TextView _tapEventTxtShow; + + @BindView(R.id.demo_rxbus_tap_count) + TextView _tapEventCountShow; + + private RxBus _rxBus; + private CompositeDisposable _disposables; + + @Override + public View onCreateView( + LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.fragment_rxbus_bottom, container, false); + ButterKnife.bind(this, layout); + return layout; + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + _rxBus = ((MainActivity) getActivity()).getRxBusSingleton(); + } + + @Override + public void onStart() { + super.onStart(); + _disposables = new CompositeDisposable(); + + ConnectableFlowable tapEventEmitter = _rxBus.asFlowable().publish(); + + _disposables // + .add( + tapEventEmitter.subscribe( + event -> { + if (event instanceof RxBusDemoFragment.TapEvent) { + _showTapText(); + } + })); + + _disposables.add( + tapEventEmitter + .publish(stream -> stream.buffer(stream.debounce(1, TimeUnit.SECONDS))) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + taps -> { + _showTapCount(taps.size()); + })); + + _disposables.add(tapEventEmitter.connect()); + } + + @Override + public void onStop() { + super.onStop(); + _disposables.clear(); + } + + // ----------------------------------------------------------------------------------- + // Helper to show the text via an animation + + private void _showTapText() { + _tapEventTxtShow.setVisibility(View.VISIBLE); + _tapEventTxtShow.setAlpha(1f); + ViewCompat.animate(_tapEventTxtShow).alphaBy(-1f).setDuration(400); + } + + private void _showTapCount(int size) { + _tapEventCountShow.setText(String.valueOf(size)); + _tapEventCountShow.setVisibility(View.VISIBLE); + _tapEventCountShow.setScaleX(1f); + _tapEventCountShow.setScaleY(1f); + ViewCompat.animate(_tapEventCountShow) + .scaleXBy(-1f) + .scaleYBy(-1f) + .setDuration(800) + .setStartDelay(100); + } } diff --git a/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_TopFragment.java b/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_TopFragment.java index bab619fd..7d6c58fb 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_TopFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBusDemo_TopFragment.java @@ -11,30 +11,28 @@ import com.morihacky.android.rxjava.R; import com.morihacky.android.rxjava.fragments.BaseFragment; -public class RxBusDemo_TopFragment - extends BaseFragment { +public class RxBusDemo_TopFragment extends BaseFragment { - private RxBus _rxBus; + private RxBus _rxBus; - @Override - public View onCreateView(LayoutInflater inflater, - @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View layout = inflater.inflate(R.layout.fragment_rxbus_top, container, false); - ButterKnife.bind(this, layout); - return layout; - } + @Override + public View onCreateView( + LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.fragment_rxbus_top, container, false); + ButterKnife.bind(this, layout); + return layout; + } - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - _rxBus = ((MainActivity) getActivity()).getRxBusSingleton(); - } + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + _rxBus = ((MainActivity) getActivity()).getRxBusSingleton(); + } - @OnClick(R.id.btn_demo_rxbus_tap) - public void onTapButtonClicked() { - if (_rxBus.hasObservers()) { - _rxBus.send(new RxBusDemoFragment.TapEvent()); - } + @OnClick(R.id.btn_demo_rxbus_tap) + public void onTapButtonClicked() { + if (_rxBus.hasObservers()) { + _rxBus.send(new RxBusDemoFragment.TapEvent()); } + } } diff --git a/app/src/main/java/com/morihacky/android/rxjava/volley/MyVolley.java b/app/src/main/java/com/morihacky/android/rxjava/volley/MyVolley.java index 835a0287..a6ec55cf 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/volley/MyVolley.java +++ b/app/src/main/java/com/morihacky/android/rxjava/volley/MyVolley.java @@ -8,21 +8,21 @@ * Helper class that is used to provide references to initialized RequestQueue(s) and ImageLoader(s) */ public class MyVolley { - private static RequestQueue mRequestQueue; + private static RequestQueue mRequestQueue; - private MyVolley() { - // no instances - } + private MyVolley() { + // no instances + } - public static void init(Context context) { - mRequestQueue = Volley.newRequestQueue(context); - } + public static void init(Context context) { + mRequestQueue = Volley.newRequestQueue(context); + } - static RequestQueue getRequestQueue() { - if (mRequestQueue != null) { - return mRequestQueue; - } else { - throw new IllegalStateException("RequestQueue not initialized"); - } + static RequestQueue getRequestQueue() { + if (mRequestQueue != null) { + return mRequestQueue; + } else { + throw new IllegalStateException("RequestQueue not initialized"); } + } } diff --git a/app/src/main/java/com/morihacky/android/rxjava/volley/VolleyDemoFragment.java b/app/src/main/java/com/morihacky/android/rxjava/volley/VolleyDemoFragment.java index 9a8e9d2f..aaa55d08 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/volley/VolleyDemoFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/volley/VolleyDemoFragment.java @@ -33,145 +33,148 @@ import org.json.JSONObject; import timber.log.Timber; -public class VolleyDemoFragment - extends BaseFragment { - - public static final String TAG = "VolleyDemoFragment"; - - @BindView(R.id.list_threading_log) ListView _logsList; - - private List _logs; - private LogAdapter _adapter; - private Unbinder unbinder; - - private CompositeDisposable _disposables = new CompositeDisposable(); - - @Override - public View onCreateView(LayoutInflater inflater, - @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View layout = inflater.inflate(R.layout.fragment_volley, 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(); - } - - /** - * Creates and returns an observable generated from the Future returned from - * {@code getRouteData()}. The observable can then be subscribed to as shown in - * {@code startVolleyRequest()} - * @return Observable - */ - public Flowable newGetRouteData() { - return Flowable.defer(() -> { - try { - return Flowable.just(getRouteData()); - } catch (InterruptedException | ExecutionException e) { - Log.e("routes", e.getMessage()); - return Flowable.error(e); - } +public class VolleyDemoFragment extends BaseFragment { + + public static final String TAG = "VolleyDemoFragment"; + + @BindView(R.id.list_threading_log) + ListView _logsList; + + private List _logs; + private LogAdapter _adapter; + private Unbinder unbinder; + + private CompositeDisposable _disposables = new CompositeDisposable(); + + @Override + public View onCreateView( + LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.fragment_volley, 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(); + } + + /** + * Creates and returns an observable generated from the Future returned from {@code + * getRouteData()}. The observable can then be subscribed to as shown in {@code + * startVolleyRequest()} + * + * @return Observable + */ + public Flowable newGetRouteData() { + return Flowable.defer( + () -> { + try { + return Flowable.just(getRouteData()); + } catch (InterruptedException | ExecutionException e) { + Log.e("routes", e.getMessage()); + return Flowable.error(e); + } }); - } - - @OnClick(R.id.btn_start_operation) - void startRequest() { - startVolleyRequest(); - } - - private void startVolleyRequest() { - DisposableSubscriber d = new DisposableSubscriber() { - @Override - public void onNext(JSONObject jsonObject) { - Log.e(TAG, "onNext " + jsonObject.toString()); - _log("onNext " + jsonObject.toString()); - - } - - @Override - public void onError(Throwable e) { - VolleyError cause = (VolleyError) e.getCause(); - String s = new String(cause.networkResponse.data, Charset.forName("UTF-8")); - Log.e(TAG, s); - Log.e(TAG, cause.toString()); - _log("onError " + s); - - } - - @Override - public void onComplete() { - Log.e(TAG, "onCompleted"); - Timber.d("----- onCompleted"); - _log("onCompleted "); - } + } + + @OnClick(R.id.btn_start_operation) + void startRequest() { + startVolleyRequest(); + } + + private void startVolleyRequest() { + DisposableSubscriber d = + new DisposableSubscriber() { + @Override + public void onNext(JSONObject jsonObject) { + Log.e(TAG, "onNext " + jsonObject.toString()); + _log("onNext " + jsonObject.toString()); + } + + @Override + public void onError(Throwable e) { + VolleyError cause = (VolleyError) e.getCause(); + String s = new String(cause.networkResponse.data, Charset.forName("UTF-8")); + Log.e(TAG, s); + Log.e(TAG, cause.toString()); + _log("onError " + s); + } + + @Override + public void onComplete() { + Log.e(TAG, "onCompleted"); + Timber.d("----- onCompleted"); + _log("onCompleted "); + } }; - newGetRouteData() - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(d); - - _disposables.add(d); - } - - /** - * Converts the Asynchronous Request into a Synchronous Future that can be used to - * block via {@code Future.get()}. Observables require blocking/synchronous functions - * @return JSONObject - * @throws ExecutionException - * @throws InterruptedException - */ - private JSONObject getRouteData() throws ExecutionException, InterruptedException { - RequestFuture future = RequestFuture.newFuture(); - String url = "http://www.weather.com.cn/adat/sk/101010100.html"; - JsonObjectRequest req = new JsonObjectRequest(Request.Method.GET, url, future, future); - MyVolley.getRequestQueue().add(req); - return future.get(); - } - - // ----------------------------------------------------------------------------------- - // 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(() -> { + newGetRouteData() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(d); + + _disposables.add(d); + } + + /** + * Converts the Asynchronous Request into a Synchronous Future that can be used to block via + * {@code Future.get()}. Observables require blocking/synchronous functions + * + * @return JSONObject + * @throws ExecutionException + * @throws InterruptedException + */ + private JSONObject getRouteData() throws ExecutionException, InterruptedException { + RequestFuture future = RequestFuture.newFuture(); + String url = "http://www.weather.com.cn/adat/sk/101010100.html"; + JsonObjectRequest req = new JsonObjectRequest(Request.Method.GET, url, future, future); + MyVolley.getRequestQueue().add(req); + return future.get(); + } + + // ----------------------------------------------------------------------------------- + // 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/wiring/LogAdapter.java b/app/src/main/java/com/morihacky/android/rxjava/wiring/LogAdapter.java index 0c0ea1e9..cfa108f1 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/wiring/LogAdapter.java +++ b/app/src/main/java/com/morihacky/android/rxjava/wiring/LogAdapter.java @@ -5,10 +5,9 @@ import com.morihacky.android.rxjava.R; import java.util.List; -public class LogAdapter - extends ArrayAdapter { +public 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); + } } From 3fd2dfbfe807fc772589c401be6dd346cd49c5c7 Mon Sep 17 00:00:00 2001 From: Jonathan Caryl Date: Wed, 15 Mar 2017 15:04:36 +0000 Subject: [PATCH 07/22] further changes --- app/build.gradle | 25 +++++------ .../android/rxjava/MainActivity.java | 4 +- .../com/morihacky/android/rxjava/MyApp.java | 6 +++ .../rxjava/fragments/BufferDemoFragment.java | 5 +-- .../DebounceSearchEmitterFragment.java | 7 ++- .../fragments/ExponentialBackoffFragment.java | 6 +-- .../FormValidationCombineLatestFragment.java | 12 ++--- .../rxjava/fragments/RetrofitFragment.java | 6 +-- app/src/main/res/layout/fragment_buffer.xml | 5 +-- .../fragment_concurrency_schedulers.xml | 3 +- app/src/main/res/layout/fragment_debounce.xml | 3 +- .../main/res/layout/fragment_demo_timing.xml | 13 +++--- .../fragment_double_binding_textview.xml | 9 ++-- .../layout/fragment_exponential_backoff.xml | 5 +-- .../fragment_form_validation_comb_latest.xml | 9 ++-- app/src/main/res/layout/fragment_main.xml | 2 +- .../res/layout/fragment_network_detector.xml | 1 - .../main/res/layout/fragment_pagination.xml | 1 - app/src/main/res/layout/fragment_polling.xml | 5 +-- .../main/res/layout/fragment_pseudo_cache.xml | 15 ++++--- .../layout/fragment_pseudo_cache_concat.xml | 3 +- app/src/main/res/layout/fragment_retrofit.xml | 21 +++++---- .../fragment_retrofit_async_task_death.xml | 7 ++- .../res/layout/fragment_rotation_persist.xml | 3 +- .../main/res/layout/fragment_rxbus_bottom.xml | 4 +- .../main/res/layout/fragment_rxbus_demo.xml | 1 - .../res/layout/fragment_subject_timeout.xml | 5 +-- .../main/res/layout/fragment_timer_demo.xml | 3 +- app/src/main/res/layout/fragment_volley.xml | 5 +-- app/src/main/res/layout/item_btn.xml | 3 +- app/src/main/res/layout/item_log.xml | 8 ++-- app/src/main/res/layout/item_log_white.xml | 5 +-- app/src/main/res/values/strings.xml | 44 +++++++++++++++++++ 33 files changed, 139 insertions(+), 115 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 3472af89..b17fcd0b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,10 +4,7 @@ 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' } // Exclude the lombok version that the android plugin depends on. @@ -19,10 +16,11 @@ apply plugin: 'me.tatarka.retrolambda' apply plugin: 'com.f2prateek.javafmt' ext { - okhttpVersion = "3.0.1" - retrofitVersion = "2.0.0" - sdkVersion = 24 - supportLibVersion = "25.2.0" + okhttpVersion = '3.6.0' + retrofitVersion = "2.2.0" + sdkVersion = 25 + supportLibVersion = '25.3.0' + leakCanaryVersion = '1.5' butterKnifeVersion = '8.5.1' } @@ -34,7 +32,7 @@ dependencies { compile 'com.github.kaushikgopal:CoreTextUtils:c703fa12b6' compile "com.jakewharton:butterknife:$butterKnifeVersion" annotationProcessor "com.jakewharton:butterknife-compiler:$butterKnifeVersion" - compile 'com.jakewharton.timber:timber:2.4.2' + 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}" @@ -44,18 +42,15 @@ dependencies { // ---------------------------------- // 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.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' // ---------------------------------- 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 8c5df2f4..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,13 +2,13 @@ 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; 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 99adc071..a3b025ac 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/MyApp.java +++ b/app/src/main/java/com/morihacky/android/rxjava/MyApp.java @@ -23,6 +23,12 @@ public static RefWatcher getRefWatcher() { public void onCreate() { super.onCreate(); + if (LeakCanary.isInAnalyzerProcess(this)) { + // This process is dedicated to LeakCanary for heap analysis. + // You should not init your app in this process. + return; + } + _instance = (MyApp) getApplicationContext(); _refWatcher = LeakCanary.install(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 85f618ef..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; @@ -20,7 +20,6 @@ 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; @@ -91,7 +90,7 @@ public void onDestroyView() { // Main Rx entities private Disposable _getBufferedDisposable() { - return RxJavaInterop.toV2Observable(RxView.clickEvents(_tapBtn)) + return RxView.clicks(_tapBtn) .map( onClickEvent -> { Timber.d("--------- GOT A TAP"); 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 129f7b11..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,8 +12,8 @@ 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; @@ -23,7 +23,6 @@ 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; @@ -75,7 +74,7 @@ public void onActivityCreated(@Nullable Bundle savedInstanceState) { _setupLogger(); _disposable = - RxJavaInterop.toV2Observable(RxTextView.textChangeEvents(_inputSearchText)) + RxTextView.textChangeEvents(_inputSearchText) .debounce(400, TimeUnit.MILLISECONDS) // default Scheduler is Computation .filter(changes -> isNotNullOrEmpty(changes.text().toString())) .observeOn(AndroidSchedulers.mainThread()) 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 0516b934..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 @@ -13,9 +13,9 @@ 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; @@ -24,7 +24,6 @@ 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; @@ -131,8 +130,7 @@ public void onComplete() { .delay( integer -> { // Rx-y way of doing the Fibonnaci :P - return RxJavaInterop.toV2Flowable( - MathObservable.sumInteger(rx.Observable.range(1, integer))) + return MathFlowable.sumInt(Flowable.range(1, integer)) .flatMap( targetSecondDelay -> Flowable.just(integer).delay(targetSecondDelay, TimeUnit.SECONDS)); 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 07f8972d..48ac13f3 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 @@ -9,11 +9,12 @@ import android.widget.TextView; import butterknife.BindView; import butterknife.ButterKnife; -import com.jakewharton.rxbinding.widget.RxTextView; + +import com.jakewharton.rxbinding2.widget.RxTextView; import com.morihacky.android.rxjava.R; import butterknife.Unbinder; -import hu.akarnokd.rxjava.interop.RxJavaInterop; +import io.reactivex.BackpressureStrategy; import io.reactivex.Flowable; import io.reactivex.subscribers.DisposableSubscriber; import timber.log.Timber; @@ -47,10 +48,9 @@ public View onCreateView( View layout = inflater.inflate(R.layout.fragment_form_validation_comb_latest, container, false); unbinder = 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)); + _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(); 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 cb9eeb38..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 @@ -158,9 +158,9 @@ public void onError(Throwable e) { } @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( diff --git a/app/src/main/res/layout/fragment_buffer.xml b/app/src/main/res/layout/fragment_buffer.xml index f2bbaadf..86d70150 100644 --- a/app/src/main/res/layout/fragment_buffer.xml +++ b/app/src/main/res/layout/fragment_buffer.xml @@ -1,5 +1,4 @@ - - - diff --git a/app/src/main/res/layout/fragment_demo_timing.xml b/app/src/main/res/layout/fragment_demo_timing.xml index e83be2be..0cb4286e 100644 --- a/app/src/main/res/layout/fragment_demo_timing.xml +++ b/app/src/main/res/layout/fragment_demo_timing.xml @@ -1,5 +1,4 @@ -