From 718493d4928b192119cc443622c796b516d4a5da Mon Sep 17 00:00:00 2001 From: Fabin Paul Date: Wed, 16 Mar 2016 15:32:45 +0530 Subject: [PATCH 001/105] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1bc599dc..58a774e8 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ Since it was a presentation, Jake only put up the most important code snippets i ### Orchestrating Observables. Make parallel network calls, then combine the result into a single data point (flatmap + zip) -The below ascii diagram expresses the intention of our next example with panache. f1,f2,3,f4,f5 are essentially network calls that when made, give back a result that's needed for a future calculation. +The below ascii diagram expresses the intention of our next example with panache. f1,f2,f3,f4,f5 are essentially network calls that when made, give back a result that's needed for a future calculation. (flatmap) From 6a7f657285cf04b413ef4d7ec88eceec849540c4 Mon Sep 17 00:00:00 2001 From: Kaushik Gopal Date: Thu, 7 Apr 2016 23:35:21 -0700 Subject: [PATCH 002/105] --wip-- --- app/build.gradle | 15 +++++++++++---- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index b4654798..39713e83 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -26,15 +26,18 @@ dependencies { } android { - compileSdkVersion 23 - buildToolsVersion '23.0.2' + compileSdkVersion 'android-N' + buildToolsVersion '24.0.0-rc1' defaultConfig { applicationId "com.morihacky.android.rxjava" - minSdkVersion 15 - targetSdkVersion 22 + minSdkVersion 'N' + targetSdkVersion 'N' versionCode 1 versionName "1.0" + jackOptions { + enabled true + } } buildTypes { release { @@ -42,4 +45,8 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } } \ No newline at end of file diff --git a/build.gradle b/build.gradle index 69e94a11..93757fe5 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:1.3.1' + classpath 'com.android.tools.build:gradle:2.1.0-alpha5' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6d8cccc2..8b688c92 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Feb 25 15:10:50 PST 2016 +#Thu Apr 07 23:27:28 PDT 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip From a1cd646cf546e9ea773882c9af2f16886641cc30 Mon Sep 17 00:00:00 2001 From: Kaushik Gopal Date: Fri, 8 Apr 2016 00:04:52 -0700 Subject: [PATCH 003/105] chore: upgrade to jack compiler + ref: to lambdas and meth refs --- .../rxjava/fragments/BufferDemoFragment.java | 25 +-- ...ConcurrencyWithSchedulersDemoFragment.java | 26 ++- .../DebounceSearchEmitterFragment.java | 28 ++-- .../DoubleBindingTextViewFragment.java | 14 +- .../fragments/ExponentialBackoffFragment.java | 51 ++---- .../FormValidationCombineLatestFragment.java | 46 +++--- .../rxjava/fragments/PollingFragment.java | 151 ++++++++---------- .../fragments/PseudoCacheConcatFragment.java | 11 +- .../fragments/PseudoCacheMergeFragment.java | 17 +- .../RetrofitAsyncTaskDeathFragment.java | 2 +- .../rxjava/fragments/RetrofitFragment.java | 42 ++--- .../fragments/RotationPersist1Fragment.java | 12 +- .../RotationPersist1WorkerFragment.java | 8 +- .../fragments/RotationPersist2Fragment.java | 53 +++--- .../RotationPersist2WorkerFragment.java | 19 +-- .../rxjava/fragments/TimeoutDemoFragment.java | 12 +- .../rxjava/fragments/TimingDemoFragment.java | 12 +- .../rxjava/retrofit/GithubService.java | 25 ++- .../rxbus/RxBusDemo_Bottom1Fragment.java | 10 +- .../rxbus/RxBusDemo_Bottom2Fragment.java | 17 +- .../rxbus/RxBusDemo_Bottom3Fragment.java | 31 ++-- .../rxjava/volley/VolleyDemoFragment.java | 32 ++-- 22 files changed, 230 insertions(+), 414 deletions(-) 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 79262789..d52e3571 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 @@ -11,7 +11,6 @@ import android.widget.ListView; import com.jakewharton.rxbinding.view.RxView; -import com.jakewharton.rxbinding.view.ViewClickEvent; import com.morihacky.android.rxjava.R; import com.morihacky.android.rxjava.wiring.LogAdapter; @@ -24,7 +23,6 @@ import rx.Observer; import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; -import rx.functions.Func1; import timber.log.Timber; /** @@ -89,13 +87,10 @@ public View onCreateView(LayoutInflater inflater, private Subscription _getBufferedSubscription() { return RxView.clickEvents(_tapBtn) - .map(new Func1() { - @Override - public Integer call(ViewClickEvent onClickEvent) { - Timber.d("--------- GOT A TAP"); - _log("GOT A TAP"); - return 1; - } + .map(onClickEvent -> { + Timber.d("--------- GOT A TAP"); + _log("GOT A TAP"); + return 1; }) .buffer(2, TimeUnit.SECONDS) .observeOn(AndroidSchedulers.mainThread()) @@ -130,7 +125,7 @@ public void onNext(List integers) { private void _setupLogger() { _logs = new ArrayList<>(); - _adapter = new LogAdapter(getActivity(), new ArrayList()); + _adapter = new LogAdapter(getActivity(), new ArrayList<>()); _logsList.setAdapter(_adapter); } @@ -144,13 +139,9 @@ private void _log(String logMsg) { _logs.add(0, logMsg + " (NOT main thread) "); // You can only do below stuff on main thread. - new Handler(Looper.getMainLooper()).post(new Runnable() { - - @Override - public void run() { - _adapter.clear(); - _adapter.addAll(_logs); - } + new Handler(Looper.getMainLooper()).post(() -> { + _adapter.clear(); + _adapter.addAll(_logs); }); } } 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 dec37204..41d2c9d8 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 @@ -25,7 +25,6 @@ import rx.Observer; import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; -import rx.functions.Func1; import rx.schedulers.Schedulers; import timber.log.Timber; @@ -74,13 +73,10 @@ public void startLongOperation() { } private Observable _getObservable() { - return Observable.just(true).map(new Func1() { - @Override - public Boolean call(Boolean aBoolean) { - _log("Within Observable"); - _doSomeLongOperation_thatBlocksCurrentThread(); - return aBoolean; - } + return Observable.just(true).map(aBoolean -> { + _log("Within Observable"); + _doSomeLongOperation_thatBlocksCurrentThread(); + return aBoolean; }); } @@ -137,20 +133,16 @@ private void _log(String logMsg) { _logs.add(0, logMsg + " (NOT main thread) "); // You can only do below stuff on main thread. - new Handler(Looper.getMainLooper()).post(new Runnable() { - - @Override - public void run() { - _adapter.clear(); - _adapter.addAll(_logs); - } + new Handler(Looper.getMainLooper()).post(() -> { + _adapter.clear(); + _adapter.addAll(_logs); }); } } private void _setupLogger() { - _logs = new ArrayList(); - _adapter = new LogAdapter(getActivity(), new ArrayList()); + _logs = new ArrayList<>(); + _adapter = new LogAdapter(getActivity(), new ArrayList<>()); _logsList.setAdapter(_adapter); } 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 791fad24..aa105020 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 @@ -23,13 +23,12 @@ import butterknife.Bind; import butterknife.ButterKnife; import butterknife.OnClick; -import co.kaush.core.util.CoreNullnessUtils; import rx.Observer; import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; -import rx.functions.Func1; import timber.log.Timber; +import static co.kaush.core.util.CoreNullnessUtils.isNotNullOrEmpty; import static java.lang.String.format; public class DebounceSearchEmitterFragment @@ -71,15 +70,10 @@ public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); _setupLogger(); - _subscription = RxTextView.textChangeEvents(_inputSearchText)// + _subscription = RxTextView.textChangeEvents(_inputSearchText) .debounce(400, TimeUnit.MILLISECONDS)// default Scheduler is Computation - .filter(new Func1() { - @Override - public Boolean call(TextViewTextChangeEvent changes) { - return CoreNullnessUtils.isNotNullOrEmpty(_inputSearchText.getText().toString()); - } - }) - .observeOn(AndroidSchedulers.mainThread())// + .filter(changes -> isNotNullOrEmpty(_inputSearchText.getText().toString())) + .observeOn(AndroidSchedulers.mainThread()) .subscribe(_getSearchObserver()); } @@ -110,8 +104,8 @@ public void onNext(TextViewTextChangeEvent onTextChangeEvent) { // Method that help wiring up the example (irrelevant to RxJava) private void _setupLogger() { - _logs = new ArrayList(); - _adapter = new LogAdapter(getActivity(), new ArrayList()); + _logs = new ArrayList<>(); + _adapter = new LogAdapter(getActivity(), new ArrayList<>()); _logsList.setAdapter(_adapter); } @@ -125,13 +119,9 @@ private void _log(String logMsg) { _logs.add(0, logMsg + " (NOT main thread) "); // You can only do below stuff on main thread. - new Handler(Looper.getMainLooper()).post(new Runnable() { - - @Override - public void run() { - _adapter.clear(); - _adapter.addAll(_logs); - } + new Handler(Looper.getMainLooper()).post(() -> { + _adapter.clear(); + _adapter.addAll(_logs); }); } } 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 fa4e4601..a79fb2b5 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 @@ -14,7 +14,6 @@ import butterknife.ButterKnife; import butterknife.OnTextChanged; import rx.Subscription; -import rx.functions.Action1; import rx.subjects.PublishSubject; import static android.text.TextUtils.isEmpty; @@ -37,12 +36,11 @@ public View onCreateView(LayoutInflater inflater, ButterKnife.bind(this, layout); _resultEmitterSubject = PublishSubject.create(); - _subscription = _resultEmitterSubject.asObservable().subscribe(new Action1() { - @Override - public void call(Float aFloat) { - _result.setText(String.valueOf(aFloat)); - } - }); + _subscription = _resultEmitterSubject// + .asObservable()// + .subscribe(aFloat -> { + _result.setText(String.valueOf(aFloat)); + }); onNumberChanged(); _number2.requestFocus(); @@ -50,7 +48,7 @@ public void call(Float aFloat) { return layout; } - @OnTextChanged({ R.id.double_binding_num1, R.id.double_binding_num2 }) + @OnTextChanged({R.id.double_binding_num1, R.id.double_binding_num2}) public void onNumberChanged() { float num1 = 0; float num2 = 0; 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 e3facad5..a1a6374a 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 @@ -20,7 +20,6 @@ import butterknife.OnClick; import rx.Observable; import rx.Observer; -import rx.functions.Action0; import rx.functions.Func1; import rx.observables.MathObservable; import rx.subscriptions.CompositeSubscription; @@ -76,12 +75,8 @@ public void startRetryingWithExponentialBackoffStrategy() { Observable// .error(new RuntimeException("testing")) // always fails .retryWhen(new RetryWithDelay(5, 1000)) // notice this is called only onError (onNext values sent are ignored) - .doOnSubscribe(new Action0() { - @Override - public void call() { - _log("Attempting the impossible 5 times in intervals of 1s"); - } - })// + .doOnSubscribe(() -> + _log("Attempting the impossible 5 times in intervals of 1s"))// .subscribe(new Observer() { @Override public void onCompleted() { @@ -109,28 +104,16 @@ public void startExecutingWithExponentialBackoffDelay() { _subscriptions.add(// Observable.range(1, 4)// - .delay(new Func1>() { - @Override - public Observable call(final Integer integer) { - // Rx-y way of doing the Fibonnaci :P - return MathObservable// - .sumInteger(Observable.range(1, integer)) - .flatMap(new Func1>() { - @Override - public Observable call(Integer targetSecondDelay) { - return Observable.just(integer) - .delay(targetSecondDelay, TimeUnit.SECONDS); - } - }); - } - })// - .doOnSubscribe(new Action0() { - @Override - public void call() { - _log(String.format("Execute 4 tasks with delay - time now: [xx:%02d]", - _getSecondHand())); - } + .delay(integer -> { + // Rx-y way of doing the Fibonnaci :P + return MathObservable// + .sumInteger(Observable.range(1, integer)) + .flatMap(targetSecondDelay -> Observable.just(integer) + .delay(targetSecondDelay, TimeUnit.SECONDS)); })// + .doOnSubscribe(() -> + _log(String.format("Execute 4 tasks with delay - time now: [xx:%02d]", + _getSecondHand())))// .subscribe(new Observer() { @Override public void onCompleted() { @@ -167,7 +150,7 @@ private int _getSecondHand() { private void _setupLogger() { _logs = new ArrayList<>(); - _adapter = new LogAdapter(getActivity(), new ArrayList()); + _adapter = new LogAdapter(getActivity(), new ArrayList<>()); _logList.setAdapter(_adapter); } @@ -175,13 +158,9 @@ private void _log(String logMsg) { _logs.add(logMsg); // You can only do below stuff on main thread. - new Handler(getMainLooper()).post(new Runnable() { - - @Override - public void run() { - _adapter.clear(); - _adapter.addAll(_logs); - } + new Handler(getMainLooper()).post(() -> { + _adapter.clear(); + _adapter.addAll(_logs); }); } 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 c7841dd7..1a3157bf 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 @@ -16,7 +16,6 @@ import rx.Observable; import rx.Observer; import rx.Subscription; -import rx.functions.Func3; import timber.log.Timber; import static android.text.TextUtils.isEmpty; @@ -65,35 +64,30 @@ private void _combineLatestEvents() { _subscription = Observable.combineLatest(_emailChangeObservable, _passwordChangeObservable, _numberChangeObservable, - new Func3() { - @Override - public Boolean call(CharSequence newEmail, - CharSequence newPassword, - CharSequence 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!"); - } + (newEmail, newPassword, newNumber) -> { - boolean numValid = !isEmpty(newNumber); - if (numValid) { - int num = Integer.parseInt(newNumber.toString()); - numValid = num > 0 && num <= 100; - } - if (!numValid) { - _number.setError("Invalid Number!"); - } + boolean emailValid = !isEmpty(newEmail) && + EMAIL_ADDRESS.matcher(newEmail).matches(); + if (!emailValid) { + _email.setError("Invalid Email!"); + } - return emailValid && passValid && numValid; + 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(new Observer() { @Override 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 fedc9cd6..3f4bb82a 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 @@ -22,8 +22,6 @@ import butterknife.ButterKnife; import butterknife.OnClick; import rx.Observable; -import rx.functions.Action0; -import rx.functions.Action1; import rx.functions.Func1; import rx.subscriptions.CompositeSubscription; import timber.log.Timber; @@ -80,24 +78,13 @@ public void onStartSimplePollingClicked() { _subscriptions.add(// Observable.interval(INITIAL_DELAY, POLLING_INTERVAL, TimeUnit.MILLISECONDS) - .map(new Func1() { - @Override - public String call(Long heartBeat) { - return _doNetworkCallAndGetStringResult(heartBeat); - } - }).take(pollCount) - .doOnSubscribe(new Action0() { - @Override - public void call() { - _log(String.format("Start simple polling - %s", _counter)); - } - }) - .subscribe(new Action1() { - @Override - public void call(String taskName) { - _log(String.format(Locale.US, "Executing polled task [%s] now time : [xx:%02d]", - taskName, _getSecondHand())); - } + .map(this::_doNetworkCallAndGetStringResult)// + .take(pollCount) + .doOnSubscribe(() -> + _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())); }) ); } @@ -115,17 +102,11 @@ public void onStartIncreasinglyDelayedPolling() { _subscriptions.add(// Observable.just(1) .repeatWhen(new RepeatWithDelay(pollCount, pollingInterval)) - .subscribe(new Action1() { - @Override - public void call(Object o) { - _log(String.format(Locale.US, "Executing polled task now time : [xx:%02d]", - _getSecondHand())); - } - }, new Action1() { - @Override - public void call(Throwable e) { - Timber.d(e, "arrrr. Error"); - } + .subscribe(o -> { + _log(String.format(Locale.US, "Executing polled task now time : [xx:%02d]", + _getSecondHand())); + }, e -> { + Timber.d(e, "arrrr. Error"); }) ); } @@ -140,54 +121,6 @@ public void call(Throwable e) { // It's 12am in the morning and i feel lazy dammit !!! - //public static class RepeatWithDelay - public class RepeatWithDelay - implements Func1, Observable> { - - 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 Observable call(Observable inputObservable) { - - // 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 Func1>() { - @Override - public Observable call(Void blah) { - - - if (_repeatCount >= _repeatLimit) { - // terminate the sequence cause we reached the limit - _log("Completing sequence"); - return Observable.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 Observable.timer(_repeatCount * _pollingInterval, - TimeUnit.MILLISECONDS); - } - }); - } - } - - // ----------------------------------------------------------------------------------- - // Method that help wiring up the example (irrelevant to RxJava) - private String _doNetworkCallAndGetStringResult(long attempt) { try { if (attempt == 4) { @@ -206,6 +139,9 @@ private String _doNetworkCallAndGetStringResult(long attempt) { 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) - @@ -221,20 +157,16 @@ private void _log(String logMsg) { _logs.add(0, logMsg + " (NOT main thread) "); // You can only do below stuff on main thread. - new Handler(Looper.getMainLooper()).post(new Runnable() { - - @Override - public void run() { - _adapter.clear(); - _adapter.addAll(_logs); - } + new Handler(Looper.getMainLooper()).post(() -> { + _adapter.clear(); + _adapter.addAll(_logs); }); } } private void _setupLogger() { _logs = new ArrayList<>(); - _adapter = new LogAdapter(getActivity(), new ArrayList()); + _adapter = new LogAdapter(getActivity(), new ArrayList<>()); _logsList.setAdapter(_adapter); _counter = 0; } @@ -243,6 +175,51 @@ private boolean _isCurrentlyOnMainThread() { return Looper.myLooper() == Looper.getMainLooper(); } + //public static class RepeatWithDelay + public class RepeatWithDelay + implements Func1, Observable> { + + 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 Observable call(Observable inputObservable) { + + // 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 Func1>() { + @Override + public Observable call(Void blah) { + + + if (_repeatCount >= _repeatLimit) { + // terminate the sequence cause we reached the limit + _log("Completing sequence"); + return Observable.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 Observable.timer(_repeatCount * _pollingInterval, + TimeUnit.MILLISECONDS); + } + }); + } + } + private class LogAdapter extends ArrayAdapter { diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheConcatFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheConcatFragment.java index fbd6f179..e9f85d85 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheConcatFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheConcatFragment.java @@ -22,9 +22,7 @@ import butterknife.OnClick; import rx.Observable; import rx.Subscriber; -import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; -import rx.functions.Func1; import timber.log.Timber; public class PseudoCacheConcatFragment @@ -56,7 +54,7 @@ public void onDemoPseudoCacheClicked() { _adapter = new ArrayAdapter<>(getActivity(), R.layout.item_log, R.id.item_log, - new ArrayList()); + new ArrayList<>()); _resultList.setAdapter(_adapter); _initializeCache(); @@ -112,12 +110,7 @@ private Observable _getFreshData() { String githubToken = getResources().getString(R.string.github_oauth_token); GithubApi githubService = GithubService.createGithubService(githubToken); return githubService.contributors("square", "retrofit") - .flatMap(new Func1, Observable>() { - @Override - public Observable call(List contributors) { - return Observable.from(contributors); - } - }); + .flatMap(Observable::from); } private void _initializeCache() { 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 6c4a6fc6..fc21f5b8 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 @@ -24,7 +24,6 @@ import rx.Observable; import rx.Subscriber; import rx.android.schedulers.AndroidSchedulers; -import rx.functions.Func1; import rx.schedulers.Schedulers; import timber.log.Timber; @@ -55,7 +54,7 @@ public void onDestroyView() { @OnClick(R.id.btn_start_pseudo_cache) public void onDemoPseudoCacheClicked() { - _adapter = new ArrayAdapter<>(getActivity(), R.layout.item_log, R.id.item_log, new ArrayList()); + _adapter = new ArrayAdapter<>(getActivity(), R.layout.item_log, R.id.item_log, new ArrayList<>()); _resultList.setAdapter(_adapter); _initializeCache(); @@ -126,18 +125,8 @@ private Observable> _getFreshData() { GithubApi githubService = GithubService.createGithubService(githubToken); return githubService.contributors("square", "retrofit") - .flatMap(new Func1, Observable>() { - @Override - public Observable call(List contributors) { - return Observable.from(contributors); - } - }) - .map(new Func1>() { - @Override - public Pair call(Contributor contributor) { - return new Pair<>(contributor, System.currentTimeMillis()); - } - }); + .flatMap(Observable::from) + .map(contributor -> new Pair<>(contributor, System.currentTimeMillis())); } private void _initializeCache() { 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 718d9601..5b42e099 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 @@ -57,7 +57,7 @@ public View onCreateView(LayoutInflater inflater, _adapter = new ArrayAdapter<>(getActivity(), R.layout.item_log, R.id.item_log, - new ArrayList()); + new ArrayList<>()); //_adapter.setNotifyOnChange(true); _resultList.setAdapter(_adapter); 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 04c1dde2..e67695aa 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 @@ -26,8 +26,6 @@ import rx.Observable; import rx.Observer; import rx.android.schedulers.AndroidSchedulers; -import rx.functions.Func1; -import rx.functions.Func2; import rx.schedulers.Schedulers; import rx.subscriptions.CompositeSubscription; import timber.log.Timber; @@ -57,13 +55,13 @@ public void onCreate(Bundle savedInstanceState) { @Override public View onCreateView(LayoutInflater inflater, - @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { View layout = inflater.inflate(R.layout.fragment_retrofit, container, false); ButterKnife.bind(this, layout); - _adapter = new ArrayAdapter<>(getActivity(), R.layout.item_log, R.id.item_log, new ArrayList()); + _adapter = new ArrayAdapter<>(getActivity(), R.layout.item_log, R.id.item_log, new ArrayList<>()); //_adapter.setNotifyOnChange(true); _resultList.setAdapter(_adapter); @@ -123,32 +121,14 @@ public void onListContributorsWithFullUserInfoClicked() { _adapter.clear(); _subscriptions.add(_githubService.contributors(_username.getText().toString(), _repo.getText().toString()) - .flatMap(new Func1, Observable>() { - @Override - public Observable call(List contributors) { - return Observable.from(contributors); - } - }) - .flatMap(new Func1>>() { - @Override - public Observable> call(Contributor contributor) { - Observable _userObservable = _githubService.user(contributor.login) - .filter(new Func1() { - @Override - public Boolean call(User user) { - return !isEmpty(user.name) && !isEmpty(user.email); - } - }); - - return Observable.zip(_userObservable, - Observable.just(contributor), - new Func2>() { - @Override - public Pair call(User user, Contributor contributor) { - return new Pair<>(user, contributor); - } - }); - } + .flatMap(Observable::from) + .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()) 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 6cde3680..dd48d1b8 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 @@ -120,7 +120,7 @@ public void onDestroyView() { private void _setupLogger() { _logs = new ArrayList<>(); - _adapter = new LogAdapter(getActivity(), new ArrayList()); + _adapter = new LogAdapter(getActivity(), new ArrayList<>()); _logList.setAdapter(_adapter); } @@ -128,13 +128,9 @@ private void _log(String logMsg) { _logs.add(0, logMsg); // You can only do below stuff on main thread. - new Handler(getMainLooper()).post(new Runnable() { - - @Override - public void run() { - _adapter.clear(); - _adapter.addAll(_logs); - } + 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 4c727e1c..2d3ad1b0 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 @@ -11,7 +11,6 @@ import rx.Observable; import rx.Subscription; -import rx.functions.Func1; import rx.observables.ConnectableObservable; public class RotationPersist1WorkerFragment @@ -58,12 +57,7 @@ public void onCreate(Bundle savedInstanceState) { Observable intsObservable =// Observable.interval(1, TimeUnit.SECONDS)// - .map(new Func1() { - @Override - public Integer call(Long aLong) { - return aLong.intValue(); - } - })// + .map(Long::intValue)// .take(20); // ----------------------------------------------------------------------------------- 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 aadeabb2..ebbd88fc 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 @@ -20,7 +20,6 @@ import butterknife.OnClick; import rx.Observable; import rx.Observer; -import rx.functions.Action0; import rx.subscriptions.CompositeSubscription; import timber.log.Timber; @@ -62,28 +61,24 @@ public void startOperationFromWorkerFrag() { public void setStream(Observable intStream) { _subscriptions.add(// - intStream.doOnSubscribe(new Action0() { - @Override - public void call() { - _log("Subscribing to intsObservable"); - } - }).subscribe(new Observer() { - @Override - public void onCompleted() { - _log("Observable is complete"); - } - - @Override - public void onError(Throwable e) { - Timber.e(e, "Error in worker demo frag observable"); - _log("Dang! something went wrong."); - } - - @Override - public void onNext(Integer integer) { - _log(String.format("Worker frag spits out - %d", integer)); - } - })); + intStream.doOnSubscribe(() -> _log("Subscribing to intsObservable")) + .subscribe(new Observer() { + @Override + public void onCompleted() { + _log("Observable is complete"); + } + + @Override + public void onError(Throwable e) { + Timber.e(e, "Error in worker demo frag observable"); + _log("Dang! something went wrong."); + } + + @Override + public void onNext(Integer integer) { + _log(String.format("Worker frag spits out - %d", integer)); + } + })); } // ----------------------------------------------------------------------------------- @@ -113,7 +108,7 @@ public void onPause() { private void _setupLogger() { _logs = new ArrayList<>(); - _adapter = new LogAdapter(getActivity(), new ArrayList()); + _adapter = new LogAdapter(getActivity(), new ArrayList<>()); _logList.setAdapter(_adapter); } @@ -121,13 +116,9 @@ private void _log(String logMsg) { _logs.add(0, logMsg); // You can only do below stuff on main thread. - new Handler(getMainLooper()).post(new Runnable() { - - @Override - public void run() { - _adapter.clear(); - _adapter.addAll(_logs); - } + new Handler(getMainLooper()).post(() -> { + _adapter.clear(); + _adapter.addAll(_logs); }); } } \ No newline at end of file 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 313d7467..9b82f881 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 @@ -3,12 +3,14 @@ import android.app.Activity; import android.os.Bundle; import android.support.v4.app.Fragment; + import com.morihacky.android.rxjava.MainActivity; + import java.util.List; import java.util.concurrent.TimeUnit; + import rx.Observable; import rx.Subscription; -import rx.functions.Func1; import rx.subjects.PublishSubject; import rx.subjects.Subject; @@ -22,7 +24,7 @@ public class RotationPersist2WorkerFragment /** * 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 @@ -51,15 +53,10 @@ public void onCreate(Bundle savedInstanceState) { // Retain this fragment across configuration changes. setRetainInstance(true); - _storedIntsSubscription =// - Observable.interval(1, TimeUnit.SECONDS)// - .map(new Func1() { - @Override - public Integer call(Long aLong) { - return aLong.intValue(); - } - })// - .take(20)// + _storedIntsSubscription = + Observable.interval(1, TimeUnit.SECONDS) + .map(Long::intValue) + .take(20) .subscribe(_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 480a6e20..03e86031 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 @@ -150,7 +150,7 @@ public void onNext(String taskType) { private void _setupLogger() { _logs = new ArrayList<>(); - _adapter = new LogAdapter(getActivity(), new ArrayList()); + _adapter = new LogAdapter(getActivity(), new ArrayList<>()); _logsList.setAdapter(_adapter); } @@ -164,13 +164,9 @@ private void _log(String logMsg) { _logs.add(0, logMsg + " (NOT main thread) "); // You can only do below stuff on main thread. - new Handler(Looper.getMainLooper()).post(new Runnable() { - - @Override - public void run() { - _adapter.clear(); - _adapter.addAll(_logs); - } + new Handler(Looper.getMainLooper()).post(() -> { + _adapter.clear(); + _adapter.addAll(_logs); }); } } 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 92556f0e..b34f6f15 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 @@ -184,7 +184,7 @@ public void OnClearLog() { private void _setupLogger() { _logs = new ArrayList<>(); - _adapter = new LogAdapter(getActivity(), new ArrayList()); + _adapter = new LogAdapter(getActivity(), new ArrayList<>()); _logsList.setAdapter(_adapter); } @@ -192,13 +192,9 @@ 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(new Runnable() { - - @Override - public void run() { - _adapter.clear(); - _adapter.addAll(_logs); - } + new Handler(getMainLooper()).post(() -> { + _adapter.clear(); + _adapter.addAll(_logs); }); } 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 021faa07..de14d432 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 @@ -2,12 +2,8 @@ import android.text.TextUtils; -import java.io.IOException; - -import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.Request; -import okhttp3.Response; import retrofit2.GsonConverterFactory; import retrofit2.Retrofit; import retrofit2.RxJavaCallAdapterFactory; @@ -16,23 +12,22 @@ public class GithubService { - private GithubService() { } + private GithubService() { + } public static GithubApi createGithubService(final String githubToken) { Retrofit.Builder builder = new Retrofit.Builder().addCallAdapterFactory(RxJavaCallAdapterFactory.create()) - .addConverterFactory(GsonConverterFactory.create()) - .baseUrl("https://api.github.com"); + .addConverterFactory(GsonConverterFactory.create()) + .baseUrl("https://api.github.com"); if (!TextUtils.isEmpty(githubToken)) { - OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new Interceptor() { - @Override public Response intercept(Chain chain) throws IOException { - Request request = chain.request(); - Request newReq = request.newBuilder() - .addHeader("Authorization", format("token %s", githubToken)) - .build(); - return chain.proceed(newReq); - } + 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); 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 c46fb544..6fbbfd3e 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,7 +14,6 @@ import butterknife.Bind; import butterknife.ButterKnife; -import rx.functions.Action1; import rx.subscriptions.CompositeSubscription; public class RxBusDemo_Bottom1Fragment @@ -46,12 +45,9 @@ public void onStart() { _subscriptions// .add(_rxBus.toObserverable()// - .subscribe(new Action1() { - @Override - public void call(Object event) { - if (event instanceof RxBusDemoFragment.TapEvent) { - _showTapText(); - } + .subscribe(event -> { + if (event instanceof RxBusDemoFragment.TapEvent) { + _showTapText(); } })); } 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 d5beaae2..68570e1e 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 @@ -19,7 +19,6 @@ import butterknife.ButterKnife; import rx.Observable; import rx.android.schedulers.AndroidSchedulers; -import rx.functions.Action1; import rx.subscriptions.CompositeSubscription; public class RxBusDemo_Bottom2Fragment @@ -53,12 +52,9 @@ public void onStart() { Observable tapEventEmitter = _rxBus.toObserverable().share(); _subscriptions// - .add(tapEventEmitter.subscribe(new Action1() { - @Override - public void call(Object event) { - if (event instanceof RxBusDemoFragment.TapEvent) { - _showTapText(); - } + .add(tapEventEmitter.subscribe(event -> { + if (event instanceof RxBusDemoFragment.TapEvent) { + _showTapText(); } })); @@ -68,11 +64,8 @@ public void call(Object event) { _subscriptions// .add(debouncedBufferEmitter// .observeOn(AndroidSchedulers.mainThread())// - .subscribe(new Action1>() { - @Override - public void call(List taps) { - _showTapCount(taps.size()); - } + .subscribe(taps -> { + _showTapCount(taps.size()); })); } 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 b956d58b..6eb189d1 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 @@ -12,15 +12,11 @@ import com.morihacky.android.rxjava.R; import com.morihacky.android.rxjava.fragments.BaseFragment; -import java.util.List; import java.util.concurrent.TimeUnit; import butterknife.Bind; import butterknife.ButterKnife; -import rx.Observable; import rx.android.schedulers.AndroidSchedulers; -import rx.functions.Action1; -import rx.functions.Func1; import rx.observables.ConnectableObservable; import rx.subscriptions.CompositeSubscription; @@ -55,27 +51,18 @@ public void onStart() { ConnectableObservable tapEventEmitter = _rxBus.toObserverable().publish(); _subscriptions// - .add(tapEventEmitter.subscribe(new Action1() { - @Override - public void call(Object event) { - if (event instanceof RxBusDemoFragment.TapEvent) { - _showTapText(); - } + .add(tapEventEmitter.subscribe(event -> { + if (event instanceof RxBusDemoFragment.TapEvent) { + _showTapText(); } })); - _subscriptions// - .add(tapEventEmitter.publish(new Func1, Observable>>() { - @Override - public Observable> call(Observable stream) { - return stream.buffer(stream.debounce(1, TimeUnit.SECONDS)); - } - }).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1>() { - @Override - public void call(List taps) { - _showTapCount(taps.size()); - } - })); + _subscriptions + .add(tapEventEmitter.publish(stream -> + stream.buffer(stream.debounce(1, TimeUnit.SECONDS))) + .observeOn(AndroidSchedulers.mainThread()).subscribe(taps -> { + _showTapCount(taps.size()); + })); _subscriptions.add(tapEventEmitter.connect()); 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 2860a85e..7e00d4e5 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 @@ -31,7 +31,6 @@ import rx.Observable; import rx.Observer; import rx.android.schedulers.AndroidSchedulers; -import rx.functions.Func0; import rx.schedulers.Schedulers; import rx.subscriptions.CompositeSubscription; import timber.log.Timber; @@ -50,8 +49,8 @@ public class VolleyDemoFragment @Override public View onCreateView(LayoutInflater inflater, - @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { View layout = inflater.inflate(R.layout.fragment_volley, container, false); ButterKnife.bind(this, layout); return layout; @@ -76,15 +75,12 @@ public void onDestroyView() { } public Observable newGetRouteData() { - return Observable.defer(new Func0>() { - @Override - public Observable call() { - try { - return Observable.just(getRouteData()); - } catch (InterruptedException | ExecutionException e) { - Log.e("routes", e.getMessage()); - return Observable.error(e); - } + return Observable.defer(() -> { + try { + return Observable.just(getRouteData()); + } catch (InterruptedException | ExecutionException e) { + Log.e("routes", e.getMessage()); + return Observable.error(e); } }); } @@ -138,7 +134,7 @@ private JSONObject getRouteData() throws ExecutionException, InterruptedExceptio private void _setupLogger() { _logs = new ArrayList<>(); - _adapter = new LogAdapter(getActivity(), new ArrayList()); + _adapter = new LogAdapter(getActivity(), new ArrayList<>()); _logsList.setAdapter(_adapter); } @@ -152,13 +148,9 @@ private void _log(String logMsg) { _logs.add(0, logMsg + " (NOT main thread) "); // You can only do below stuff on main thread. - new Handler(Looper.getMainLooper()).post(new Runnable() { - - @Override - public void run() { - _adapter.clear(); - _adapter.addAll(_logs); - } + new Handler(Looper.getMainLooper()).post(() -> { + _adapter.clear(); + _adapter.addAll(_logs); }); } } From a89840c1954f2f701bdc16a64033882abba4c18f Mon Sep 17 00:00:00 2001 From: Mitchell Tilbrook Date: Fri, 15 Apr 2016 16:30:56 +1000 Subject: [PATCH 004/105] upgrade: retrofit 2.0.0-beta3 -> 2.0.0 --- app/build.gradle | 6 +++--- .../morihacky/android/rxjava/retrofit/GithubService.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index b4654798..bad891a1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -14,9 +14,9 @@ dependencies { compile 'com.jakewharton.rxbinding:rxbinding:0.2.0' compile 'com.jakewharton:butterknife:7.0.1' compile 'com.jakewharton.timber:timber:2.4.2' - compile 'com.squareup.retrofit2:retrofit:2.0.0-beta3' - compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta3' - compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta3' + compile 'com.squareup.retrofit2:retrofit:2.0.0' + compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0' + compile 'com.squareup.retrofit2:converter-gson:2.0.0' compile 'com.squareup.okhttp3:okhttp:3.0.1' compile 'com.squareup.okhttp3:okhttp-urlconnection:3.0.1' compile 'com.mcxiaoke.volley:library:1.0.19' 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 021faa07..82de2f5b 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 @@ -8,9 +8,9 @@ import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; -import retrofit2.GsonConverterFactory; import retrofit2.Retrofit; -import retrofit2.RxJavaCallAdapterFactory; +import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; +import retrofit2.converter.gson.GsonConverterFactory; import static java.lang.String.format; From 2056294cd485c5804478fed2fb58c80553326dc9 Mon Sep 17 00:00:00 2001 From: Mitchell Tilbrook Date: Fri, 15 Apr 2016 17:09:01 +1000 Subject: [PATCH 005/105] upgrade: build tools, support library, and target api --- app/build.gradle | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index b4654798..e12abb50 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,8 +1,12 @@ apply plugin: 'com.android.application' +buildscript { + ext.android_support = '23.3.0' +} + dependencies { - compile 'com.android.support:support-v13:23.2.1' - compile 'com.android.support:appcompat-v7:23.2.1' + compile "com.android.support:support-v13:$android_support" + compile "com.android.support:appcompat-v7:$android_support" compile 'io.reactivex:rxandroid:1.0.1' // Because RxAndroid releases are few and far between, it is recommended you also @@ -27,12 +31,12 @@ dependencies { android { compileSdkVersion 23 - buildToolsVersion '23.0.2' + buildToolsVersion '23.0.3' defaultConfig { applicationId "com.morihacky.android.rxjava" minSdkVersion 15 - targetSdkVersion 22 + targetSdkVersion 23 versionCode 1 versionName "1.0" } From d3ac5512ea271aa4b427f1d1349e5492bd32cdf2 Mon Sep 17 00:00:00 2001 From: Jose Miguel Mendez Date: Sun, 24 Apr 2016 01:07:13 -0400 Subject: [PATCH 006/105] Removed unused priority variable, was causing confusion If you need to set priority, you have to extend the Request class and override the `getPriority()` function. This seems outside of the scope of this example --- .../com/morihacky/android/rxjava/volley/VolleyDemoFragment.java | 1 - 1 file changed, 1 deletion(-) 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 2860a85e..bb9beaf5 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 @@ -127,7 +127,6 @@ public void onNext(JSONObject jsonObject) { private JSONObject getRouteData() throws ExecutionException, InterruptedException { RequestFuture future = RequestFuture.newFuture(); String url = "http://www.weather.com.cn/adat/sk/101010100.html"; - final Request.Priority priority = Request.Priority.IMMEDIATE; JsonObjectRequest req = new JsonObjectRequest(Request.Method.GET, url, future, future); MyVolley.getRequestQueue().add(req); return future.get(); From c2124daa1c89c0d295e332e0f63bcef7c0c63e0f Mon Sep 17 00:00:00 2001 From: Jose Miguel Mendez Date: Sun, 24 Apr 2016 01:18:08 -0400 Subject: [PATCH 007/105] Added Javadoc to give more context Found it a bit confusing trying to wrangle through the code --- .../android/rxjava/volley/VolleyDemoFragment.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) 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 bb9beaf5..95304c15 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 @@ -75,6 +75,12 @@ public void onDestroyView() { ButterKnife.unbind(this); } + /** + * 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 Observable newGetRouteData() { return Observable.defer(new Func0>() { @Override @@ -123,7 +129,13 @@ public void onNext(JSONObject jsonObject) { } })); } - + /** + * 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"; From a65412698d7b0c283fb16112db8818d0b3f0cffb Mon Sep 17 00:00:00 2001 From: Rashiq Date: Sun, 1 May 2016 14:47:26 +0200 Subject: [PATCH 008/105] Fix typo --- app/src/main/java/com/morihacky/android/rxjava/rxbus/RxBus.java | 2 +- .../android/rxjava/rxbus/RxBusDemo_Bottom1Fragment.java | 2 +- .../android/rxjava/rxbus/RxBusDemo_Bottom2Fragment.java | 2 +- .../android/rxjava/rxbus/RxBusDemo_Bottom3Fragment.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) 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 83f61f46..a324b065 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 @@ -20,7 +20,7 @@ public void send(Object o) { _bus.onNext(o); } - public Observable toObserverable() { + public Observable toObservable() { return _bus; } 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 c46fb544..7718fce7 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 @@ -45,7 +45,7 @@ public void onStart() { _subscriptions = new CompositeSubscription(); _subscriptions// - .add(_rxBus.toObserverable()// + .add(_rxBus.toObservable()// .subscribe(new Action1() { @Override public void call(Object event) { 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 d5beaae2..738b4636 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 @@ -50,7 +50,7 @@ public void onStart() { super.onStart(); _subscriptions = new CompositeSubscription(); - Observable tapEventEmitter = _rxBus.toObserverable().share(); + Observable tapEventEmitter = _rxBus.toObservable().share(); _subscriptions// .add(tapEventEmitter.subscribe(new Action1() { 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 b956d58b..ad3593da 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 @@ -52,7 +52,7 @@ public void onStart() { super.onStart(); _subscriptions = new CompositeSubscription(); - ConnectableObservable tapEventEmitter = _rxBus.toObserverable().publish(); + ConnectableObservable tapEventEmitter = _rxBus.toObservable().publish(); _subscriptions// .add(tapEventEmitter.subscribe(new Action1() { From c29a5d703098b5a8a705e379f4c0721bfb60e753 Mon Sep 17 00:00:00 2001 From: Craig Russell Date: Tue, 3 May 2016 14:05:55 +0100 Subject: [PATCH 009/105] remove duplicate `compile 'io.reactivex:rxjava-math:1.0.0'` was defined twice --- app/build.gradle | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index b4654798..ab0bd652 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,7 +9,6 @@ dependencies { // explicitly depend on RxJava's latest version for bug fixes and new features. compile 'io.reactivex:rxjava:1.0.14' compile 'io.reactivex:rxjava-math:1.0.0' - compile 'io.reactivex:rxjava-math:1.0.0' compile 'com.github.kaushikgopal:CoreTextUtils:c703fa12b6' compile 'com.jakewharton.rxbinding:rxbinding:0.2.0' compile 'com.jakewharton:butterknife:7.0.1' @@ -42,4 +41,4 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } -} \ No newline at end of file +} From b83abd13e20e397035dc4a24eb4a1105ee6bf418 Mon Sep 17 00:00:00 2001 From: Kaushik Gopal Date: Tue, 17 May 2016 07:54:02 -0700 Subject: [PATCH 010/105] fix: upgrade gradle plugin --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 93757fe5..3a089e4b 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:2.1.0-alpha5' + classpath 'com.android.tools.build:gradle:2.1.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files From 97721da4b13a028b5b7b29fec8db4eb15b5e6ad0 Mon Sep 17 00:00:00 2001 From: Zhangchong <287424013@qq.com> Date: Fri, 17 Jun 2016 00:13:42 +0800 Subject: [PATCH 011/105] Update PseudoCacheConcatFragment.java set correct scheduler for network request. --- .../android/rxjava/fragments/PseudoCacheConcatFragment.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheConcatFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheConcatFragment.java index fbd6f179..fd282918 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheConcatFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/PseudoCacheConcatFragment.java @@ -62,6 +62,7 @@ public void onDemoPseudoCacheClicked() { _initializeCache(); Observable.concat(_getCachedData(), _getFreshData()) + .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber() { @Override From 2efb58ac7aeaad6776e3c035b8e9176aaae1635c Mon Sep 17 00:00:00 2001 From: KG Date: Sun, 21 Aug 2016 12:52:12 -0700 Subject: [PATCH 012/105] fix: casting --- .../android/rxjava/fragments/RetrofitFragment.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) 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 e67695aa..4a0a31bb 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 @@ -25,6 +25,7 @@ import butterknife.OnClick; import rx.Observable; import rx.Observer; +import rx.Subscriber; import rx.android.schedulers.AndroidSchedulers; import rx.schedulers.Schedulers; import rx.subscriptions.CompositeSubscription; @@ -132,7 +133,7 @@ public void onListContributorsWithFullUserInfoClicked() { }) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Observer>() { + .subscribe(new Subscriber() { @Override public void onCompleted() { Timber.d("Retrofit call 2 completed "); @@ -144,9 +145,9 @@ public void onError(Throwable e) { } @Override - public void onNext(Pair pair) { - User user = pair.first; - Contributor contributor = pair.second; + public void onNext(Pair pair) { + User user = ((Pair)pair).first; + Contributor contributor = ((Pair)pair).second; _adapter.add(format("%s(%s) has made %d contributions to %s", user.name, From c66b826c389253a2dc80d4a16b592db7a127c42b Mon Sep 17 00:00:00 2001 From: KG Date: Sun, 21 Aug 2016 13:07:31 -0700 Subject: [PATCH 013/105] chore: update bulid.gradle --- app/build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 39713e83..31d2329e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -26,13 +26,13 @@ dependencies { } android { - compileSdkVersion 'android-N' - buildToolsVersion '24.0.0-rc1' + compileSdkVersion 23 + buildToolsVersion '24rc4' defaultConfig { applicationId "com.morihacky.android.rxjava" - minSdkVersion 'N' - targetSdkVersion 'N' + minSdkVersion 15 + targetSdkVersion 24 versionCode 1 versionName "1.0" jackOptions { From c370300bc77875d51c27e6bb6989a1faeec76312 Mon Sep 17 00:00:00 2001 From: KG Date: Sun, 21 Aug 2016 13:39:56 -0700 Subject: [PATCH 014/105] chore: jack -> retrolambda --- app/build.gradle | 28 ++++++++++++++----- .../fragments/ExponentialBackoffFragment.java | 6 ++-- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 31d2329e..70e0ed80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,4 +1,21 @@ +buildscript { + repositories { +// mavenCentral() + 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' + } + + // Exclude the lombok version that the android plugin depends on. + configurations.classpath.exclude group: 'com.android.tools.external.lombok' +} + apply plugin: 'com.android.application' +apply plugin: 'me.tatarka.retrolambda' dependencies { compile 'com.android.support:support-v13:23.2.1' @@ -27,17 +44,14 @@ dependencies { android { compileSdkVersion 23 - buildToolsVersion '24rc4' + buildToolsVersion '23.0.3' defaultConfig { applicationId "com.morihacky.android.rxjava" minSdkVersion 15 - targetSdkVersion 24 - versionCode 1 - versionName "1.0" - jackOptions { - enabled true - } + targetSdkVersion 23 + versionCode 2 + versionName "1.2" } buildTypes { release { 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 a1a6374a..8d60342b 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 @@ -20,6 +20,7 @@ import butterknife.OnClick; import rx.Observable; import rx.Observer; +import rx.Subscriber; import rx.functions.Func1; import rx.observables.MathObservable; import rx.subscriptions.CompositeSubscription; @@ -75,8 +76,7 @@ public void startRetryingWithExponentialBackoffStrategy() { Observable// .error(new RuntimeException("testing")) // always fails .retryWhen(new RetryWithDelay(5, 1000)) // notice this is called only onError (onNext values sent are ignored) - .doOnSubscribe(() -> - _log("Attempting the impossible 5 times in intervals of 1s"))// + .doOnSubscribe(() -> _log("Attempting the impossible 5 times in intervals of 1s"))// .subscribe(new Observer() { @Override public void onCompleted() { @@ -114,7 +114,7 @@ public void startExecutingWithExponentialBackoffDelay() { .doOnSubscribe(() -> _log(String.format("Execute 4 tasks with delay - time now: [xx:%02d]", _getSecondHand())))// - .subscribe(new Observer() { + .subscribe(new Subscriber() { @Override public void onCompleted() { Timber.d("onCompleted"); From ebf16cddd218ac6fb5c62e585edca6a11d400420 Mon Sep 17 00:00:00 2001 From: Kaushik Gopal Date: Sat, 1 Oct 2016 19:12:25 -0700 Subject: [PATCH 015/105] chore: bump up AS versions --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 3a089e4b..a06fef3a 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:2.1.0' + classpath 'com.android.tools.build:gradle:2.2.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.properties b/gradle/wrapper/gradle-wrapper.properties index 8b688c92..a0a2dce4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Apr 07 23:27:28 PDT 2016 +#Sat Oct 01 19:11:24 PDT 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip From aa77a492eff4dfffb1b1c79724b6ea682788275a Mon Sep 17 00:00:00 2001 From: Kaushik Gopal Date: Fri, 7 Oct 2016 18:17:43 -0700 Subject: [PATCH 016/105] chore: add design support library --- app/build.gradle | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 76827558..41e1c44f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -17,9 +17,14 @@ buildscript { apply plugin: 'com.android.application' apply plugin: 'me.tatarka.retrolambda' +ext { + supportLibVersion = "24.2.1" +} + dependencies { - compile 'com.android.support:support-v13:23.2.1' - compile 'com.android.support:appcompat-v7:23.2.1' + compile "com.android.support:support-v13:${supportLibVersion}" + compile "com.android.support:appcompat-v7:${supportLibVersion}" + compile "com.android.support:recyclerview-v7:${supportLibVersion}" compile 'io.reactivex:rxandroid:1.2.0' // Because RxAndroid releases are few and far between, it is recommended you also From c847664e83acd5635bf8fd1747cda167ba0c7422 Mon Sep 17 00:00:00 2001 From: Kaushik Gopal Date: Fri, 7 Oct 2016 18:25:28 -0700 Subject: [PATCH 017/105] feat: add a simple pagination example drop dead simple pagination example using the power of Subjects addresses #8 (and a closed #6) --- .../rxjava/fragments/MainFragment.java | 10 +- .../rxjava/pagination/PaginationFragment.java | 215 ++++++++++++++++++ app/src/main/res/layout/fragment_main.xml | 8 + .../main/res/layout/fragment_pagination.xml | 32 +++ app/src/main/res/layout/item_btn.xml | 12 + app/src/main/res/layout/item_log.xml | 11 +- app/src/main/res/values/strings.xml | 3 + 7 files changed, 286 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationFragment.java create mode 100644 app/src/main/res/layout/fragment_pagination.xml create mode 100644 app/src/main/res/layout/item_btn.xml 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 b8df6c3e..cb48e4ef 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 @@ -7,14 +7,15 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; + import com.morihacky.android.rxjava.R; +import com.morihacky.android.rxjava.pagination.PaginationFragment; import com.morihacky.android.rxjava.rxbus.RxBusDemoFragment; +import com.morihacky.android.rxjava.volley.VolleyDemoFragment; import butterknife.ButterKnife; import butterknife.OnClick; -import com.morihacky.android.rxjava.volley.VolleyDemoFragment; - public class MainFragment extends BaseFragment { @@ -94,6 +95,11 @@ void demoRotationPersist() { //clickedOn(new RotationPersist1Fragment()); } + @OnClick(R.id.btn_demo_pagination) + void demoPaging() { + clickedOn(new PaginationFragment()); + } + @OnClick(R.id.btn_demo_volley) void demoVolleyRequest() { clickedOn(new VolleyDemoFragment()); 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 new file mode 100644 index 00000000..38aa9220 --- /dev/null +++ b/app/src/main/java/com/morihacky/android/rxjava/pagination/PaginationFragment.java @@ -0,0 +1,215 @@ +package com.morihacky.android.rxjava.pagination; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ProgressBar; +import android.widget.TextView; + +import com.morihacky.android.rxjava.MainActivity; +import com.morihacky.android.rxjava.R; +import com.morihacky.android.rxjava.fragments.BaseFragment; +import com.morihacky.android.rxjava.rxbus.RxBus; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import butterknife.Bind; +import butterknife.ButterKnife; +import rx.Observable; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +import rx.subjects.PublishSubject; +import rx.subscriptions.CompositeSubscription; + +public class PaginationFragment extends BaseFragment { + + @Bind(R.id.list_paging) RecyclerView _pagingList; + @Bind(R.id.progress_paging) ProgressBar _progressBar; + + private CompositeSubscription _subscriptions; + private TestAdapter _adapter; + private RxBus _bus; + private PublishSubject _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 TestAdapter(_bus); + _pagingList.setAdapter(_adapter); + + _paginator = PublishSubject.create(); + } + + @Override + public void onStart() { + super.onStart(); + _subscriptions = new CompositeSubscription(); + + Subscription s2 =// + _paginator// + .flatMap(nextPage -> _itemsFromNetworkCall(nextPage + 1, 10))// + .observeOn(AndroidSchedulers.mainThread()) + .map(items -> { + int start = _adapter.getItemCount() - 1; + + _adapter.addItems(items); + _adapter.notifyItemRangeInserted(start, 10); + + _progressBar.setVisibility(View.INVISIBLE); + return null; + })// + .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 ¯\_(ツ)_/¯ + Subscription s1 = _bus.toObserverable().subscribe(event -> { + if (event instanceof ItemBtnViewHolder.PageEvent) { + + // trigger the paginator for the next event + int nextPage = _adapter.getItemCount() - 1; + _paginator.onNext(nextPage); + + } + }); + + _subscriptions.add(s1); + _subscriptions.add(s2); + } + + @Override + public void onStop() { + super.onStop(); + _subscriptions.clear(); + } + + /** + * Fake Observable that simulates a network call and then sends down a list of items + */ + private Observable> _itemsFromNetworkCall(int start, int count) { + return Observable.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; + } + + + private static class TestAdapter extends RecyclerView.Adapter { + + static final int ITEM_LOG = 0; + static final int ITEM_BTN = 1; + + final List _items = new ArrayList<>(); + final RxBus _bus; + + TestAdapter(RxBus bus) { + _bus = bus; + } + + void addItems(List items) { + _items.addAll(items); + } + + @Override + public int getItemViewType(int position) { + if (position == _items.size()) { + return ITEM_BTN; + } + + return ITEM_LOG; + } + + @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 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 int getItemCount() { + return _items.size() + 1; // add 1 for paging button + } + } + + 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)); + } + + void bindContent(String content) { + ((TextView) itemView).setText(content); + } + } + + private static class ItemBtnViewHolder extends RecyclerView.ViewHolder { + ItemBtnViewHolder(View itemView) { + super(itemView); + } + + static ItemBtnViewHolder create(ViewGroup parent) { + return new ItemBtnViewHolder(LayoutInflater.from(parent.getContext()) + .inflate(R.layout.item_btn, parent, false)); + } + + void bindContent(RxBus bus) { + ((Button) itemView).setText(R.string.btn_demo_pagination_more); + itemView.setOnClickListener(v -> bus.send(new PageEvent())); + } + + static class PageEvent { + } + } +} diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml index 66fc53f4..96aa931a 100644 --- a/app/src/main/res/layout/fragment_main.xml +++ b/app/src/main/res/layout/fragment_main.xml @@ -99,11 +99,19 @@ android:layout_width="match_parent" android:text="@string/btn_demo_rotation_persist" /> +