diff --git a/app/build.gradle b/app/build.gradle index edbcd31c..a2953236 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,10 +1,10 @@ buildscript { repositories { -// mavenCentral() + mavenCentral() jcenter() } dependencies { - classpath 'me.tatarka:gradle-retrolambda:3.6.0' + classpath 'me.tatarka:gradle-retrolambda:3.7.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}" } @@ -38,7 +38,7 @@ dependencies { compile "android.arch.lifecycle:runtime:${archComponentsVersion}" compile "android.arch.lifecycle:extensions:${archComponentsVersion}" - kapt "android.arch.lifecycle:compiler:${archComponentsVersion}" + kapt "android.arch.lifecycle:compiler:${archComponentsVersion}" // ---------------------------------- // Rx dependencies @@ -90,4 +90,5 @@ android { packagingOptions { pickFirst 'META-INF/rxjava.properties' } + buildToolsVersion '26.0.2' } \ No newline at end of file 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 068a393d..ad3393bf 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/MainActivity.java +++ b/app/src/main/java/com/morihacky/android/rxjava/MainActivity.java @@ -3,6 +3,7 @@ import android.os.Bundle; import android.support.v4.app.Fragment; 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; @@ -10,50 +11,51 @@ public class MainActivity extends AppCompatActivity { - private RxBus _rxBus = null; + private RxBus _rxBus = null; - @Override - public void onBackPressed() { - super.onBackPressed(); - _removeWorkerFragments(); - } + @Override + public void onBackPressed() { + super.onBackPressed(); + _removeWorkerFragments(); + } - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); - if (savedInstanceState == null) { - getSupportFragmentManager() - .beginTransaction() - .replace(android.R.id.content, new MainFragment(), this.toString()) - .commit(); + if (savedInstanceState == null) { + getSupportFragmentManager() + .beginTransaction() + .replace(android.R.id.content, new MainFragment(), this.toString()) + .commit(); + } } - } - // This is better done with a DI Library like Dagger - public RxBus getRxBusSingleton() { - if (_rxBus == null) { - _rxBus = new RxBus(); + // This is better done with a DI Library like Dagger + public RxBus getRxBusSingleton() { + if (_rxBus == null) { + _rxBus = new RxBus(); } - return _rxBus; - } + return _rxBus; + } - private void _removeWorkerFragments() { - Fragment frag = - getSupportFragmentManager() - .findFragmentByTag(RotationPersist1WorkerFragment.class.getName()); + private void _removeWorkerFragments() { + Fragment frag = + getSupportFragmentManager() + .findFragmentByTag(RotationPersist1WorkerFragment.class.getName()); - if (frag != null) { - getSupportFragmentManager().beginTransaction().remove(frag).commit(); - } + 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(); + } } - } + } 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 23a90b23..c7ddf378 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/MyApp.java +++ b/app/src/main/java/com/morihacky/android/rxjava/MyApp.java @@ -1,43 +1,45 @@ package com.morihacky.android.rxjava; import android.support.multidex.MultiDexApplication; + import com.morihacky.android.rxjava.volley.MyVolley; import com.squareup.leakcanary.LeakCanary; import com.squareup.leakcanary.RefWatcher; + import timber.log.Timber; public class MyApp extends MultiDexApplication { - private static MyApp _instance; - private RefWatcher _refWatcher; + private static MyApp _instance; + private RefWatcher _refWatcher; - public static MyApp get() { - return _instance; - } + public static MyApp get() { + return _instance; + } - public static RefWatcher getRefWatcher() { - return MyApp.get()._refWatcher; - } + public static RefWatcher getRefWatcher() { + return MyApp.get()._refWatcher; + } - @Override - public void onCreate() { - super.onCreate(); + @Override + public void onCreate() { + super.onCreate(); - if (LeakCanary.isInAnalyzerProcess(this)) { - // This process is dedicated to LeakCanary for heap analysis. - // You should not init your app in this process. - return; - } + 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); + _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 4ce242f3..3f515368 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 @@ -1,15 +1,16 @@ package com.morihacky.android.rxjava.fragments; import android.support.v4.app.Fragment; + import com.morihacky.android.rxjava.MyApp; import com.squareup.leakcanary.RefWatcher; 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 bf51b85c..9b4a9257 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 @@ -42,119 +42,119 @@ */ public class BufferDemoFragment extends BaseFragment { - @BindView(R.id.list_threading_log) - ListView _logsList; - - @BindView(R.id.btn_start_operation) - Button _tapBtn; - - private LogAdapter _adapter; - private List _logs; - - private Disposable _disposable; - private Unbinder unbinder; - - @Override - public void onResume() { - super.onResume(); - _disposable = _getBufferedDisposable(); - } - - @Override - public void onPause() { - super.onPause(); - _disposable.dispose(); - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - _setupLogger(); - } - - @Override - public View onCreateView( - LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View layout = inflater.inflate(R.layout.fragment_buffer, container, false); - unbinder = ButterKnife.bind(this, layout); - return layout; - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - unbinder.unbind(); - } - - // ----------------------------------------------------------------------------------- - // Main Rx entities - - private Disposable _getBufferedDisposable() { - return RxView.clicks(_tapBtn) - .map( - onClickEvent -> { - Timber.d("--------- GOT A TAP"); - _log("GOT A TAP"); - return 1; - }) - .buffer(2, TimeUnit.SECONDS) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeWith( - new DisposableObserver>() { - - @Override - public void onComplete() { - // fyi: you'll never reach here - Timber.d("----- onCompleted"); - } - - @Override - public void onError(Throwable e) { - Timber.e(e, "--------- Woops on error!"); - _log("Dang error! check your logs"); - } - - @Override - public void onNext(List integers) { - Timber.d("--------- onNext"); - if (integers.size() > 0) { - _log(String.format("%d taps", integers.size())); - } else { - Timber.d("--------- No taps received "); - } - } - }); - } - - // ----------------------------------------------------------------------------------- - // Methods that help wiring up the example (irrelevant to RxJava) - - private void _setupLogger() { - _logs = new ArrayList<>(); - _adapter = new LogAdapter(getActivity(), new ArrayList<>()); - _logsList.setAdapter(_adapter); - } - - private void _log(String logMsg) { - - if (_isCurrentlyOnMainThread()) { - _logs.add(0, logMsg + " (main thread) "); - _adapter.clear(); - _adapter.addAll(_logs); - } else { - _logs.add(0, logMsg + " (NOT main thread) "); - - // You can only do below stuff on main thread. - new Handler(Looper.getMainLooper()) - .post( - () -> { + @BindView(R.id.list_threading_log) + ListView _logsList; + + @BindView(R.id.btn_start_operation) + Button _tapBtn; + + private LogAdapter _adapter; + private List _logs; + + private Disposable _disposable; + private Unbinder unbinder; + + @Override + public void onResume() { + super.onResume(); + _disposable = _getBufferedDisposable(); + } + + @Override + public void onPause() { + super.onPause(); + _disposable.dispose(); + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + _setupLogger(); + } + + @Override + public View onCreateView( + LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.fragment_buffer, container, false); + unbinder = ButterKnife.bind(this, layout); + return layout; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + // ----------------------------------------------------------------------------------- + // Main Rx entities + + private Disposable _getBufferedDisposable() { + return RxView.clicks(_tapBtn) + .map( + onClickEvent -> { + Timber.d("--------- GOT A TAP"); + _log("GOT A TAP"); + return 1; + }) + .buffer(2, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeWith( + new DisposableObserver>() { + + @Override + public void onComplete() { + // fyi: you'll never reach here + Timber.d("----- onCompleted"); + } + + @Override + public void onError(Throwable e) { + Timber.e(e, "--------- Woops on error!"); + _log("Dang error! check your logs"); + } + + @Override + public void onNext(List integers) { + Timber.d("--------- onNext"); + if (integers.size() > 0) { + _log(String.format("%d taps", integers.size())); + } else { + Timber.d("--------- No taps received "); + } + } + }); + } + + // ----------------------------------------------------------------------------------- + // Methods that help wiring up the example (irrelevant to RxJava) + + private void _setupLogger() { + _logs = new ArrayList<>(); + _adapter = new LogAdapter(getActivity(), new ArrayList<>()); + _logsList.setAdapter(_adapter); + } + + private void _log(String logMsg) { + + if (_isCurrentlyOnMainThread()) { + _logs.add(0, logMsg + " (main thread) "); + _adapter.clear(); + _adapter.addAll(_logs); + } else { + _logs.add(0, logMsg + " (NOT main thread) "); + + // You can only do below stuff on main thread. + new Handler(Looper.getMainLooper()) + .post( + () -> { _adapter.clear(); _adapter.addAll(_logs); - }); + }); + } } - } - private boolean _isCurrentlyOnMainThread() { - return Looper.myLooper() == Looper.getMainLooper(); - } + private boolean _isCurrentlyOnMainThread() { + return Looper.myLooper() == Looper.getMainLooper(); + } } diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/ConcurrencyWithSchedulersDemoFragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/ConcurrencyWithSchedulersDemoFragment.java index 9a9a61ea..461f92f6 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 @@ -2,7 +2,6 @@ import android.content.Context; import android.os.Bundle; -import android.os.Handler; import android.os.Looper; import android.support.annotation.Nullable; import android.view.LayoutInflater; @@ -11,155 +10,156 @@ import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.ProgressBar; + +import com.morihacky.android.rxjava.R; + +import java.util.ArrayList; +import java.util.List; + 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; import io.reactivex.observers.DisposableObserver; import io.reactivex.schedulers.Schedulers; -import java.util.ArrayList; -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"); + @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(); } - } - private void _log(String logMsg) { + @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"); - if (_isCurrentlyOnMainThread()) { - _logs.add(0, logMsg + " (main thread) "); - _adapter.clear(); - _adapter.addAll(_logs); - } else { - _logs.add(0, logMsg + " (NOT main thread) "); + DisposableObserver d = _getDisposableObserver(); - // You can only do below stuff on main thread. - new Handler(Looper.getMainLooper()) - .post( - () -> { + _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) { + + if (_isCurrentlyOnMainThread()) { + _logs.add(0, logMsg + " (main thread) "); + _adapter.clear(); + _adapter.addAll(_logs); + } else { + _logs.add(0, logMsg + " (NOT main thread) "); + + getActivity().runOnUiThread(() -> { _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); + } } - } } 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 2d62cff7..3e9f4ca7 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 @@ -34,112 +34,112 @@ public class DebounceSearchEmitterFragment extends BaseFragment { - @BindView(R.id.list_threading_log) - ListView _logsList; - - @BindView(R.id.input_txt_debounce) - EditText _inputSearchText; - - private LogAdapter _adapter; - private List _logs; - - private Disposable _disposable; - private Unbinder unbinder; - - @Override - public void onDestroy() { - super.onDestroy(); - _disposable.dispose(); - unbinder.unbind(); - } - - @Override - public View onCreateView( - LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View layout = inflater.inflate(R.layout.fragment_debounce, container, false); - unbinder = ButterKnife.bind(this, layout); - return layout; - } - - @OnClick(R.id.clr_debounce) - public void onClearLog() { - _logs = new ArrayList<>(); - _adapter.clear(); - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - - super.onActivityCreated(savedInstanceState); - _setupLogger(); - - _disposable = - RxTextView.textChangeEvents(_inputSearchText) - .debounce(400, TimeUnit.MILLISECONDS) // default Scheduler is Computation - .filter(changes -> isNotNullOrEmpty(changes.text().toString())) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeWith(_getSearchObserver()); - } - - // ----------------------------------------------------------------------------------- - // Main Rx entities - - private DisposableObserver _getSearchObserver() { - return new DisposableObserver() { - @Override - public void onComplete() { - Timber.d("--------- onComplete"); - } - - @Override - public void onError(Throwable e) { - Timber.e(e, "--------- Woops on error!"); - _log("Dang error. check your logs"); - } - - @Override - public void onNext(TextViewTextChangeEvent onTextChangeEvent) { - _log(format("Searching for %s", onTextChangeEvent.text().toString())); - } - }; - } - - // ----------------------------------------------------------------------------------- - // Method that help wiring up the example (irrelevant to RxJava) - - private void _setupLogger() { - _logs = new ArrayList<>(); - _adapter = new LogAdapter(getActivity(), new ArrayList<>()); - _logsList.setAdapter(_adapter); - } - - private void _log(String logMsg) { - - if (_isCurrentlyOnMainThread()) { - _logs.add(0, logMsg + " (main thread) "); - _adapter.clear(); - _adapter.addAll(_logs); - } else { - _logs.add(0, logMsg + " (NOT main thread) "); - - // You can only do below stuff on main thread. - new Handler(Looper.getMainLooper()) - .post( - () -> { + @BindView(R.id.list_threading_log) + ListView _logsList; + + @BindView(R.id.input_txt_debounce) + EditText _inputSearchText; + + private LogAdapter _adapter; + private List _logs; + + private Disposable _disposable; + private Unbinder unbinder; + + @Override + public void onDestroy() { + super.onDestroy(); + _disposable.dispose(); + unbinder.unbind(); + } + + @Override + public View onCreateView( + LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.fragment_debounce, container, false); + unbinder = ButterKnife.bind(this, layout); + return layout; + } + + @OnClick(R.id.clr_debounce) + public void onClearLog() { + _logs = new ArrayList<>(); + _adapter.clear(); + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + + super.onActivityCreated(savedInstanceState); + _setupLogger(); + + _disposable = + RxTextView.textChangeEvents(_inputSearchText) + .debounce(400, TimeUnit.MILLISECONDS) // default Scheduler is Computation + .filter(changes -> isNotNullOrEmpty(changes.text().toString())) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeWith(_getSearchObserver()); + } + + // ----------------------------------------------------------------------------------- + // Main Rx entities + + private DisposableObserver _getSearchObserver() { + return new DisposableObserver() { + @Override + public void onComplete() { + Timber.d("--------- onComplete"); + } + + @Override + public void onError(Throwable e) { + Timber.e(e, "--------- Woops on error!"); + _log("Dang error. check your logs"); + } + + @Override + public void onNext(TextViewTextChangeEvent onTextChangeEvent) { + _log(format("Searching for %s", onTextChangeEvent.text().toString())); + } + }; + } + + // ----------------------------------------------------------------------------------- + // Method that help wiring up the example (irrelevant to RxJava) + + private void _setupLogger() { + _logs = new ArrayList<>(); + _adapter = new LogAdapter(getActivity(), new ArrayList<>()); + _logsList.setAdapter(_adapter); + } + + private void _log(String logMsg) { + + if (_isCurrentlyOnMainThread()) { + _logs.add(0, logMsg + " (main thread) "); + _adapter.clear(); + _adapter.addAll(_logs); + } else { + _logs.add(0, logMsg + " (NOT main thread) "); + + // You can only do below stuff on main thread. + new Handler(Looper.getMainLooper()) + .post( + () -> { _adapter.clear(); _adapter.addAll(_logs); - }); + }); + } } - } - private boolean _isCurrentlyOnMainThread() { - return Looper.myLooper() == Looper.getMainLooper(); - } + private boolean _isCurrentlyOnMainThread() { + return Looper.myLooper() == Looper.getMainLooper(); + } - private class LogAdapter extends ArrayAdapter { + private class LogAdapter extends ArrayAdapter { - public LogAdapter(Context context, List logs) { - super(context, R.layout.item_log, R.id.item_log, logs); + public LogAdapter(Context context, List logs) { + super(context, R.layout.item_log, R.id.item_log, logs); + } } - } } 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 883f043e..befbda63 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,11 +7,12 @@ import android.view.ViewGroup; import android.widget.EditText; import android.widget.TextView; + +import com.morihacky.android.rxjava.R; + 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,59 +21,59 @@ public class DoubleBindingTextViewFragment extends BaseFragment { - @BindView(R.id.double_binding_num1) - EditText _number1; + @BindView(R.id.double_binding_num1) + EditText _number1; - @BindView(R.id.double_binding_num2) - EditText _number2; + @BindView(R.id.double_binding_num2) + EditText _number2; - @BindView(R.id.double_binding_result) - TextView _result; + @BindView(R.id.double_binding_result) + TextView _result; - Disposable _disposable; - PublishProcessor _resultEmitterSubject; - private Unbinder unbinder; + 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); - unbinder = ButterKnife.bind(this, layout); + @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); - _resultEmitterSubject = PublishProcessor.create(); + _resultEmitterSubject = PublishProcessor.create(); - _disposable = - _resultEmitterSubject.subscribe( - aFloat -> { - _result.setText(String.valueOf(aFloat)); - }); + _disposable = + _resultEmitterSubject.subscribe( + aFloat -> { + _result.setText(String.valueOf(aFloat)); + }); - onNumberChanged(); - _number2.requestFocus(); + onNumberChanged(); + _number2.requestFocus(); - return layout; - } + return layout; + } - @OnTextChanged({R.id.double_binding_num1, R.id.double_binding_num2}) - public void onNumberChanged() { - float num1 = 0; - float num2 = 0; + @OnTextChanged({R.id.double_binding_num1, R.id.double_binding_num2}) + public void onNumberChanged() { + float num1 = 0; + float num2 = 0; - if (!isEmpty(_number1.getText().toString())) { - num1 = Float.parseFloat(_number1.getText().toString()); + if (!isEmpty(_number1.getText().toString())) { + num1 = Float.parseFloat(_number1.getText().toString()); } - if (!isEmpty(_number2.getText().toString())) { - num2 = Float.parseFloat(_number2.getText().toString()); + if (!isEmpty(_number2.getText().toString())) { + num2 = Float.parseFloat(_number2.getText().toString()); } - _resultEmitterSubject.onNext(num1 + num2); - } + _resultEmitterSubject.onNext(num1 + num2); + } - @Override - public void onDestroyView() { - super.onDestroyView(); - _disposable.dispose(); - unbinder.unbind(); - } + @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 775feaef..e86b6161 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 @@ -8,227 +8,228 @@ import android.view.ViewGroup; import android.widget.ListView; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; import com.morihacky.android.rxjava.R; import com.morihacky.android.rxjava.wiring.LogAdapter; +import org.reactivestreams.Publisher; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; import butterknife.Unbinder; import hu.akarnokd.rxjava2.math.MathFlowable; import io.reactivex.Flowable; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.functions.Function; import io.reactivex.subscribers.DisposableSubscriber; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; -import org.reactivestreams.Publisher; 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!"); - } + @BindView(R.id.list_threading_log) + ListView _logList; + Unbinder unbinder; + private LogAdapter _adapter; + private CompositeDisposable _disposables = new CompositeDisposable(); + private List _logs; + + @Override + public View onCreateView( + LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.fragment_exponential_backoff, container, false); + 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 MathFlowable.sumInt(Flowable.range(1, integer)) - .flatMap( - targetSecondDelay -> - Flowable.just(integer).delay(targetSecondDelay, TimeUnit.SECONDS)); - }) - .doOnSubscribe( - s -> - _log( - String.format( - "Execute 4 tasks with delay - time now: [xx:%02d]", _getSecondHand()))) - .subscribe(disposableSubscriber); - - _disposables.add(disposableSubscriber); - } - - // ----------------------------------------------------------------------------------- - - private int _getSecondHand() { - long millis = System.currentTimeMillis(); - return (int) - (TimeUnit.MILLISECONDS.toSeconds(millis) - - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))); - } - - // ----------------------------------------------------------------------------------- - - private void _setupLogger() { - _logs = new ArrayList<>(); - _adapter = new LogAdapter(getActivity(), new ArrayList<>()); - _logList.setAdapter(_adapter); - } - - private void _log(String logMsg) { - _logs.add(logMsg); - - // You can only do below stuff on main thread. - new Handler(getMainLooper()) - .post( - () -> { - _adapter.clear(); - _adapter.addAll(_logs); - }); - } - - // ----------------------------------------------------------------------------------- - - // 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; - - public RetryWithDelay(final int maxRetries, final int retryDelayMillis) { - _maxRetries = maxRetries; - _retryDelayMillis = retryDelayMillis; - _retryCount = 0; + Flowable.range(1, 4) + .delay( + integer -> { + // Rx-y way of doing the Fibonnaci :P + return MathFlowable.sumInt(Flowable.range(1, integer)) + .flatMap( + targetSecondDelay -> + Flowable.just(integer).delay(targetSecondDelay, TimeUnit.SECONDS)); + }) + .doOnSubscribe( + s -> + _log( + String.format( + "Execute 4 tasks with delay - time now: [xx:%02d]", _getSecondHand()))) + .subscribe(disposableSubscriber); + + _disposables.add(disposableSubscriber); } - // 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) { + private int _getSecondHand() { + long millis = System.currentTimeMillis(); + return (int) + (TimeUnit.MILLISECONDS.toSeconds(millis) + - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))); + } - // 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) { + private void _setupLogger() { + _logs = new ArrayList<>(); + _adapter = new LogAdapter(getActivity(), new ArrayList<>()); + _logList.setAdapter(_adapter); + } + + private void _log(String logMsg) { + _logs.add(logMsg); - // When this Observable calls onNext, the original - // Observable will be retried (i.e. re-subscribed) + // You can only do below stuff on main thread. + new Handler(getMainLooper()) + .post( + () -> { + _adapter.clear(); + _adapter.addAll(_logs); + }); + } - Timber.d("Retrying in %d ms", _retryCount * _retryDelayMillis); - _log(String.format("Retrying in %d ms", _retryCount * _retryDelayMillis)); + // ----------------------------------------------------------------------------------- - return Flowable.timer(_retryCount * _retryDelayMillis, TimeUnit.MILLISECONDS); - } + // 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!! - Timber.d("Argh! i give up"); + // It's 12am in the morning and i feel lazy dammit !!! - // 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); - } - }); + //public static class RetryWithDelay + public class RetryWithDelay implements Function, Publisher> { + + private final int _maxRetries; + private final int _retryDelayMillis; + private int _retryCount; + + 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) { + + // 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) { + + // 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)); + + return Flowable.timer(_retryCount * _retryDelayMillis, TimeUnit.MILLISECONDS); + } + + 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); + } + }); + } } - } } 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 efc4c2f8..243fd3a9 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/FormValidationCombineLatestFragment.java +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/FormValidationCombineLatestFragment.java @@ -1,8 +1,5 @@ package com.morihacky.android.rxjava.fragments; -import static android.text.TextUtils.isEmpty; -import static android.util.Patterns.EMAIL_ADDRESS; - import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; @@ -11,113 +8,118 @@ import android.view.ViewGroup; import android.widget.EditText; import android.widget.TextView; + +import com.jakewharton.rxbinding2.widget.RxTextView; +import com.morihacky.android.rxjava.R; + import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder; -import com.jakewharton.rxbinding2.widget.RxTextView; -import com.morihacky.android.rxjava.R; import io.reactivex.BackpressureStrategy; import io.reactivex.Flowable; import io.reactivex.subscribers.DisposableSubscriber; import timber.log.Timber; +import static android.text.TextUtils.isEmpty; +import static android.util.Patterns.EMAIL_ADDRESS; + public class FormValidationCombineLatestFragment extends BaseFragment { - @BindView(R.id.btn_demo_form_valid) - TextView _btnValidIndicator; - - @BindView(R.id.demo_combl_email) - EditText _email; - - @BindView(R.id.demo_combl_password) - EditText _password; - - @BindView(R.id.demo_combl_num) - EditText _number; - - private DisposableSubscriber _disposableObserver = null; - private Flowable _emailChangeObservable; - private Flowable _numberChangeObservable; - private Flowable _passwordChangeObservable; - private Unbinder unbinder; - - @Override - public View onCreateView( - LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View layout = inflater.inflate(R.layout.fragment_form_validation_comb_latest, container, false); - unbinder = ButterKnife.bind(this, layout); - - _emailChangeObservable = - RxTextView.textChanges(_email).skip(1).toFlowable(BackpressureStrategy.LATEST); - _passwordChangeObservable = - RxTextView.textChanges(_password).skip(1).toFlowable(BackpressureStrategy.LATEST); - _numberChangeObservable = - RxTextView.textChanges(_number).skip(1).toFlowable(BackpressureStrategy.LATEST); - - _combineLatestEvents(); - - return layout; - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - unbinder.unbind(); - _disposableObserver.dispose(); - } - - private void _combineLatestEvents() { - - _disposableObserver = - new DisposableSubscriber() { - @Override - public void onNext(Boolean formValid) { - if (formValid) { - _btnValidIndicator.setBackgroundColor( - ContextCompat.getColor(getContext(), R.color.blue)); - } else { - _btnValidIndicator.setBackgroundColor( - ContextCompat.getColor(getContext(), R.color.gray)); + @BindView(R.id.btn_demo_form_valid) + TextView _btnValidIndicator; + + @BindView(R.id.demo_combl_email) + EditText _email; + + @BindView(R.id.demo_combl_password) + EditText _password; + + @BindView(R.id.demo_combl_num) + EditText _number; + + private DisposableSubscriber _disposableObserver = null; + private Flowable _emailChangeObservable; + private Flowable _numberChangeObservable; + private Flowable _passwordChangeObservable; + private Unbinder unbinder; + + @Override + public View onCreateView( + LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.fragment_form_validation_comb_latest, container, false); + unbinder = ButterKnife.bind(this, layout); + + _emailChangeObservable = + RxTextView.textChanges(_email).skip(1).toFlowable(BackpressureStrategy.LATEST); + _passwordChangeObservable = + RxTextView.textChanges(_password).skip(1).toFlowable(BackpressureStrategy.LATEST); + _numberChangeObservable = + RxTextView.textChanges(_number).skip(1).toFlowable(BackpressureStrategy.LATEST); + + _combineLatestEvents(); + + return layout; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + _disposableObserver.dispose(); + } + + private void _combineLatestEvents() { + + _disposableObserver = + new DisposableSubscriber() { + @Override + public void onNext(Boolean formValid) { + if (formValid) { + _btnValidIndicator.setBackgroundColor( + ContextCompat.getColor(getContext(), R.color.blue)); + } else { + _btnValidIndicator.setBackgroundColor( + ContextCompat.getColor(getContext(), R.color.gray)); } - } - - @Override - public void onError(Throwable e) { - Timber.e(e, "there was an error"); - } - - @Override - public void 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); - } + } + + @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); + } } 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 75f68fa2..15cfd4ec 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,22 +7,23 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import butterknife.ButterKnife; -import butterknife.OnClick; -import butterknife.Unbinder; import com.morihacky.android.rxjava.R; import com.morihacky.android.rxjava.pagination.PaginationAutoFragment; import com.morihacky.android.rxjava.rxbus.RxBusDemoFragment; import com.morihacky.android.rxjava.volley.VolleyDemoFragment; +import butterknife.ButterKnife; +import butterknife.OnClick; +import butterknife.Unbinder; + public class MainFragment extends BaseFragment { private Unbinder unbinder; @Override public View onCreateView( - LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + 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; @@ -130,10 +131,10 @@ void demoMulticastPlayground() { 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(); + .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 af1392d4..6eb9fa8e 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,137 +15,139 @@ import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ListView; -import butterknife.BindView; -import butterknife.ButterKnife; + import com.morihacky.android.rxjava.R; +import java.util.ArrayList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; import butterknife.Unbinder; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.processors.PublishProcessor; -import java.util.ArrayList; -import java.util.List; public class NetworkDetectorFragment extends BaseFragment { - @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 -> { + @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"); + log("You are online"); } else { - log("You are offline"); + 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); + } } - } } 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 5eb8b187..ec646cf0 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,228 +10,231 @@ import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ListView; + +import com.morihacky.android.rxjava.R; + +import org.reactivestreams.Publisher; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.TimeUnit; + 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; import io.reactivex.functions.Function; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.concurrent.TimeUnit; -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 -> { - _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); - } - - @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"); - } - _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 static final int INITIAL_DELAY = 0; + private static final int POLLING_INTERVAL = 1000; + private static final int POLL_COUNT = 8; - private void _setupLogger() { - _logs = new ArrayList<>(); - _adapter = new LogAdapter(getActivity(), new ArrayList<>()); - _logsList.setAdapter(_adapter); - _counter = 0; - } + @BindView(R.id.list_threading_log) + ListView _logsList; - private boolean _isCurrentlyOnMainThread() { - return Looper.myLooper() == Looper.getMainLooper(); - } + private LogAdapter _adapter; + private int _counter = 0; + private CompositeDisposable _disposables; + private List _logs; + private Unbinder unbinder; - //public static class RepeatWithDelay - public class RepeatWithDelay implements Function, Publisher> { + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); - private final int _repeatLimit; - private final int _pollingInterval; - private int _repeatCount = 1; + _disposables = new CompositeDisposable(); + } - RepeatWithDelay(int repeatLimit, int pollingInterval) { - _pollingInterval = pollingInterval; - _repeatLimit = repeatLimit; + @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; } - // this is a notificationhandler, all we care about is - // the emission "type" not emission "content" - // only onNext triggers a re-subscription + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + _setupLogger(); + } @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); + 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); + } + + @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"); + } + _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; } - } - private class LogAdapter extends ArrayAdapter { + private boolean _isCurrentlyOnMainThread() { + return Looper.myLooper() == Looper.getMainLooper(); + } - public LogAdapter(Context context, List logs) { - super(context, R.layout.item_log, R.id.item_log, logs); + //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); + } + }); + } + } + + private class LogAdapter extends ArrayAdapter { + + public LogAdapter(Context context, List logs) { + super(context, R.layout.item_log, R.id.item_log, logs); + } } - } } 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 a214ce41..6d6627c9 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 @@ -34,299 +34,299 @@ 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); + @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)); + } + }); } - 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()) // + // ----------------------------------------------------------------------------------- + // 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()) // + .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()) // .post(() -> adapterSubscriptionInfo.add("(network) completed"))); - } + } + + private List mapAsList(HashMap map) { + List list = new ArrayList<>(); - 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); + } - for (String username : map.keySet()) { - String rowLog = String.format("%s [%d]", username, contributionMap.get(username)); - list.add(rowLog); + return list; } - 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; - } + 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 3871437d..928959e4 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 @@ -30,115 +30,115 @@ 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); + @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; } - return list; - } + @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() { - private Observable> _getCachedData() { + List> list = new ArrayList<>(); - List> list = new ArrayList<>(); + Pair dataWithAgePair; - Pair dataWithAgePair; + for (String username : _contributionMap.keySet()) { + Contributor c = new Contributor(); + c.login = username; + c.contributions = _contributionMap.get(username); - for (String username : _contributionMap.keySet()) { - Contributor c = new Contributor(); - c.login = username; - c.contributions = _contributionMap.get(username); + dataWithAgePair = new Pair<>(c, System.currentTimeMillis()); + list.add(dataWithAgePair); + } - dataWithAgePair = new Pair<>(c, System.currentTimeMillis()); - list.add(dataWithAgePair); + return Observable.fromIterable(list); } - 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); - } + 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 baa391ed..5cad3eeb 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 @@ -30,48 +30,48 @@ public class RetrofitAsyncTaskDeathFragment extends Fragment { - @BindView(R.id.btn_demo_retrofit_async_death_username) - EditText _username; + @BindView(R.id.btn_demo_retrofit_async_death_username) + EditText _username; - @BindView(R.id.log_list) - ListView _resultList; + @BindView(R.id.log_list) + ListView _resultList; - private GithubApi _githubService; - private ArrayAdapter _adapter; - private Unbinder unbinder; + private GithubApi _githubService; + private ArrayAdapter _adapter; + private Unbinder unbinder; - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); - String githubToken = getResources().getString(R.string.github_oauth_token); - _githubService = GithubService.createGithubService(githubToken); - } + String githubToken = getResources().getString(R.string.github_oauth_token); + _githubService = GithubService.createGithubService(githubToken); + } - @Override - public View onCreateView( - LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle 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); + 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); + _adapter = + new ArrayAdapter<>(getActivity(), R.layout.item_log, R.id.item_log, new ArrayList<>()); + //_adapter.setNotifyOnChange(true); + _resultList.setAdapter(_adapter); - return layout; - } + return layout; + } - @Override - public void onDestroyView() { - super.onDestroyView(); - unbinder.unbind(); - } + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } - @OnClick(R.id.btn_demo_retrofit_async_death) - public void onGetGithubUserClicked() { - _adapter.clear(); + @OnClick(R.id.btn_demo_retrofit_async_death) + public void onGetGithubUserClicked() { + _adapter.clear(); /*new AsyncTask() { @Override @@ -85,37 +85,39 @@ protected void onPostExecute(User user) { } }.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)); - } - }); - } + _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 { + private class GetGithubUser extends AsyncTask { - @Override - protected User doInBackground(String... params) { - return _githubService.getUser(params[0]); + @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)); + @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 0626e5b0..543329bf 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 @@ -36,149 +36,149 @@ 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>() { + @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.first; - Contributor contributor = pair.second; + User user = pair.first; + Contributor contributor = pair.second; - _adapter.add( - format( - "%s(%s) has made %d contributions to %s", + _adapter.add( + format( + "%s(%s) has made %d contributions to %s", user.name, user.email, contributor.contributions, _repo.getText().toString())); - _adapter.notifyDataSetChanged(); + _adapter.notifyDataSetChanged(); - Timber.d( - "%s(%s) has made %d contributions to %s", - user.name, - user.email, - contributor.contributions, - _repo.getText().toString()); + Timber.d( + "%s(%s) has made %d contributions to %s", + user.name, + user.email, + contributor.contributions, + _repo.getText().toString()); } - })); - } + })); + } } diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist1Fragment.java b/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist1Fragment.java index 00882958..8f15bfdb 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,7 +1,5 @@ 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; @@ -10,129 +8,134 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ListView; + +import com.morihacky.android.rxjava.R; +import com.morihacky.android.rxjava.wiring.LogAdapter; + +import java.util.ArrayList; +import java.util.List; + import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.Unbinder; -import com.morihacky.android.rxjava.R; -import com.morihacky.android.rxjava.wiring.LogAdapter; import io.reactivex.Flowable; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.subscribers.DisposableSubscriber; -import java.util.ArrayList; -import java.util.List; import timber.log.Timber; +import static android.os.Looper.getMainLooper; + public class RotationPersist1Fragment extends BaseFragment - implements RotationPersist1WorkerFragment.IAmYourMaster { + 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); - }); - } + 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 d16adc14..8757b812 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 @@ -3,79 +3,88 @@ import android.content.Context; import android.os.Bundle; import android.support.v4.app.Fragment; + import com.morihacky.android.rxjava.MainActivity; + +import java.util.concurrent.TimeUnit; + import io.reactivex.Flowable; import io.reactivex.disposables.Disposable; import io.reactivex.flowables.ConnectableFlowable; -import java.util.concurrent.TimeUnit; 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 :("); + 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 :("); + } } - } - /** 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; - } + if (_storedIntsFlowable != null) { + return; + } - Flowable intsObservable = - Flowable.interval(1, TimeUnit.SECONDS).map(Long::intValue).take(20); + Flowable intsObservable = + Flowable.interval(1, TimeUnit.SECONDS).map(Long::intValue).take(20); - _storedIntsFlowable = intsObservable.publish(); - _storedIntsDisposable = _storedIntsFlowable.connect(); - } + _storedIntsFlowable = intsObservable.publish(); + _storedIntsDisposable = _storedIntsFlowable.connect(); + } - /** The Worker fragment has started doing it's thing */ - @Override - public void onResume() { - super.onResume(); - _masterFrag.observeResults(_storedIntsFlowable); - } + /** + * 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(); - } + @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; - } + /** + * 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); + 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 6e523013..eb72983e 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,7 +1,5 @@ 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; @@ -10,115 +8,120 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ListView; + +import com.morihacky.android.rxjava.R; +import com.morihacky.android.rxjava.wiring.LogAdapter; + +import java.util.ArrayList; +import java.util.List; + import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; -import com.morihacky.android.rxjava.R; -import com.morihacky.android.rxjava.wiring.LogAdapter; import io.reactivex.Flowable; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.subscribers.DisposableSubscriber; -import java.util.ArrayList; -import java.util.List; import timber.log.Timber; +import static android.os.Looper.getMainLooper; + public class RotationPersist2Fragment extends BaseFragment - implements RotationPersist2WorkerFragment.IAmYourMaster { + 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); - }); - } + 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 cdbe6cd3..91b214b5 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,78 +3,87 @@ import android.content.Context; import android.os.Bundle; import android.support.v4.app.Fragment; + import com.morihacky.android.rxjava.MainActivity; + +import java.util.concurrent.TimeUnit; + import io.reactivex.Flowable; import io.reactivex.processors.PublishProcessor; -import java.util.concurrent.TimeUnit; 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 :("); + 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); - _intStream = PublishProcessor.create(); - _lifeCycleStream = PublishProcessor.create(); + _intStream = PublishProcessor.create(); + _lifeCycleStream = PublishProcessor.create(); - // Retain this fragment across configuration changes. - setRetainInstance(true); + // Retain this fragment across configuration changes. + setRetainInstance(true); - _intStream.takeUntil(_lifeCycleStream); + _intStream.takeUntil(_lifeCycleStream); - Flowable.interval(1, TimeUnit.SECONDS).map(Long::intValue).take(20).subscribe(_intStream); - } + 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); - } + /** + * 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(); - } + @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; - } + /** + * 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); + public interface IAmYourMaster { + void setStream(Flowable intStream); } } diff --git a/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist3Fragment.kt b/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist3Fragment.kt index a69e0426..560f9075 100644 --- a/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist3Fragment.kt +++ b/app/src/main/java/com/morihacky/android/rxjava/fragments/RotationPersist3Fragment.kt @@ -34,6 +34,7 @@ class RotationPersist3Fragment : BaseFragment() { // ----------------------------------------------------------------------------------- + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) sharedViewModel = ViewModelProviders.of(activity).get(SharedViewModel::class.java) 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 abeace6b..a25d5c08 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,176 +8,179 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ListView; + +import com.morihacky.android.rxjava.R; +import com.morihacky.android.rxjava.wiring.LogAdapter; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; -import com.morihacky.android.rxjava.R; -import com.morihacky.android.rxjava.wiring.LogAdapter; import io.reactivex.Observable; import io.reactivex.ObservableEmitter; import io.reactivex.ObservableOnSubscribe; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.observers.DisposableObserver; import io.reactivex.schedulers.Schedulers; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; import timber.log.Timber; 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; + 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); - } - - @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(); + _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(); - } + 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() { + 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")); - } + @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( - () -> { + } + + 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(); - } + 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 55fb027c..aa20e5b8 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,22 +7,24 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ListView; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; + import com.morihacky.android.rxjava.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; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.concurrent.TimeUnit; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import butterknife.Unbinder; +import io.reactivex.Flowable; +import io.reactivex.subscribers.DefaultSubscriber; +import io.reactivex.subscribers.DisposableSubscriber; import timber.log.Timber; import static android.os.Looper.getMainLooper; @@ -30,207 +32,207 @@ 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; + @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(); } - _log(String.format("B2 [%s] --- BTN click", _getCurrentTimestamp())); + @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; + } + + _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); - } + 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; + @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())); + _log(String.format("C3 [%s] --- BTN click", _getCurrentTimestamp())); - _subscriber2 = - new DisposableSubscriber() { - @Override - public void onNext(Long number) { - _log(String.format("C3 [%s] NEXT", _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 onComplete() { + _log(String.format("C3 [%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"); + } }; - Flowable.interval(0, 1, TimeUnit.SECONDS).subscribe(_subscriber2); - } - - @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())); - } - }); - } - - @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()); - } + Flowable.interval(0, 1, TimeUnit.SECONDS).subscribe(_subscriber2); + } + + @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())); + } + }); + } + + @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 48cc49fd..5239ec1c 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,88 +13,91 @@ 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 - } - - private static class ItemLogViewHolder extends RecyclerView.ViewHolder { - ItemLogViewHolder(View itemView) { - super(itemView); + @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); + } } - static ItemLogViewHolder create(ViewGroup parent) { - return new ItemLogViewHolder( - LayoutInflater.from(parent.getContext()).inflate(R.layout.item_log, parent, false)); + @Override + public int getItemCount() { + return _items.size() + 1; // add 1 for paging button } - void bindContent(String content) { - ((TextView) itemView).setText(content); - } - } + private static class ItemLogViewHolder extends RecyclerView.ViewHolder { + ItemLogViewHolder(View itemView) { + super(itemView); + } - static class ItemBtnViewHolder extends RecyclerView.ViewHolder { - ItemBtnViewHolder(View itemView) { - super(itemView); - } + static ItemLogViewHolder create(ViewGroup parent) { + return new ItemLogViewHolder( + LayoutInflater.from(parent.getContext()).inflate(R.layout.item_log, parent, false)); + } - static ItemBtnViewHolder create(ViewGroup parent) { - return new ItemBtnViewHolder( - LayoutInflater.from(parent.getContext()).inflate(R.layout.item_btn, parent, false)); + void bindContent(String content) { + ((TextView) itemView).setText(content); + } } - void bindContent(RxBus bus) { - ((Button) itemView).setText(R.string.btn_demo_pagination_more); - itemView.setOnClickListener(v -> bus.send(new ItemBtnViewHolder.PageEvent())); - } + 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 ItemBtnViewHolder.PageEvent())); + } - static class 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 75d8adeb..7bb2ac5f 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 @@ -5,65 +5,68 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; + import com.morihacky.android.rxjava.R; import com.morihacky.android.rxjava.rxbus.RxBus; + import java.util.ArrayList; import java.util.List; 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 e90d923b..5f734cd8 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,128 +8,133 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; -import butterknife.BindView; -import butterknife.ButterKnife; + 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.BindView; +import butterknife.ButterKnife; import io.reactivex.Flowable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.Disposable; import io.reactivex.processors.PublishProcessor; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; public class PaginationAutoFragment extends BaseFragment { - @BindView(R.id.list_paging) - RecyclerView _pagingList; + @BindView(R.id.list_paging) + RecyclerView _pagingList; - @BindView(R.id.progress_paging) - ProgressBar _progressBar; + @BindView(R.id.progress_paging) + ProgressBar _progressBar; - private PaginationAutoAdapter _adapter; - private RxBus _bus; - private CompositeDisposable _disposables; - private PublishProcessor _paginator; - private boolean _requestUnderWay = false; + 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 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); + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); - _bus = ((MainActivity) getActivity()).getRxBusSingleton(); + _bus = ((MainActivity) getActivity()).getRxBusSingleton(); - LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); - layoutManager.setOrientation(LinearLayoutManager.VERTICAL); - _pagingList.setLayoutManager(layoutManager); + LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + _pagingList.setLayoutManager(layoutManager); - _adapter = new PaginationAutoAdapter(_bus); - _pagingList.setAdapter(_adapter); + _adapter = new PaginationAutoAdapter(_bus); + _pagingList.setAdapter(_adapter); - _paginator = PublishProcessor.create(); - } + _paginator = PublishProcessor.create(); + } - @Override - public void onStart() { - super.onStart(); - _disposables = new CompositeDisposable(); + @Override + public void onStart() { + super.onStart(); + _disposables = new CompositeDisposable(); - Disposable d2 = - _paginator - .onBackpressureDrop() - .doOnNext( - i -> { + 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 bfe727f1..b8b4c419 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,62 +8,65 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; -import butterknife.BindView; -import butterknife.ButterKnife; + 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.BindView; +import butterknife.ButterKnife; import io.reactivex.Flowable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.Disposable; import io.reactivex.processors.PublishProcessor; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; public class PaginationFragment extends BaseFragment { - @BindView(R.id.list_paging) - RecyclerView _pagingList; + @BindView(R.id.list_paging) + RecyclerView _pagingList; - @BindView(R.id.progress_paging) - ProgressBar _progressBar; + @BindView(R.id.progress_paging) + ProgressBar _progressBar; - private PaginationAdapter _adapter; - private RxBus _bus; - private CompositeDisposable _disposables; - private PublishProcessor _paginator; + private PaginationAdapter _adapter; + private RxBus _bus; + private CompositeDisposable _disposables; + private PublishProcessor _paginator; - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); - _bus = ((MainActivity) getActivity()).getRxBusSingleton(); + _bus = ((MainActivity) getActivity()).getRxBusSingleton(); - LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); - layoutManager.setOrientation(LinearLayoutManager.VERTICAL); - _pagingList.setLayoutManager(layoutManager); + LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + _pagingList.setLayoutManager(layoutManager); - _adapter = new PaginationAdapter(_bus); - _pagingList.setAdapter(_adapter); + _adapter = new PaginationAdapter(_bus); + _pagingList.setAdapter(_adapter); - _paginator = PublishProcessor.create(); - } + _paginator = PublishProcessor.create(); + } + + @Override + public void onStart() { + super.onStart(); + _disposables = new CompositeDisposable(); - @Override - public void onStart() { - super.onStart(); - _disposables = new CompositeDisposable(); - - Disposable d2 = - _paginator - .onBackpressureDrop() - .concatMap(nextPage -> _itemsFromNetworkCall(nextPage + 1, 10)) - .observeOn(AndroidSchedulers.mainThread()) - .map( - items -> { + Disposable d2 = + _paginator + .onBackpressureDrop() + .concatMap(nextPage -> _itemsFromNetworkCall(nextPage + 1, 10)) + .observeOn(AndroidSchedulers.mainThread()) + .map( + items -> { int start = _adapter.getItemCount() - 1; _adapter.addItems(items); @@ -72,57 +75,59 @@ 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); + // 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)); - } - 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 5bd61c7a..ad7760fc 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 21e32e8e..9e078377 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,19 +8,25 @@ 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); + /** + * 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 3ab57571..2a966573 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,34 +13,35 @@ public class 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)) + 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(); - return chain.proceed(newReq); - }) - .build(); - builder.client(client); + 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 90f7aa3d..32fa1043 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 0e8f4fed..d5917bf0 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,20 +6,22 @@ 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(); - } + 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 f08ea85c..339d11ab 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 @@ -5,33 +5,36 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import butterknife.ButterKnife; + import com.morihacky.android.rxjava.R; import com.morihacky.android.rxjava.fragments.BaseFragment; +import butterknife.ButterKnife; + 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 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(); - } - - public static class TapEvent {} + @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); + + 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 { + } } 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 1eb1e2ec..588ff026 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,60 +7,62 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import butterknife.BindView; -import butterknife.ButterKnife; + import com.morihacky.android.rxjava.MainActivity; import com.morihacky.android.rxjava.R; import com.morihacky.android.rxjava.fragments.BaseFragment; + +import butterknife.BindView; +import butterknife.ButterKnife; import io.reactivex.disposables.CompositeDisposable; public class RxBusDemo_Bottom1Fragment extends BaseFragment { - @BindView(R.id.demo_rxbus_tap_txt) - TextView _tapEventTxtShow; + @BindView(R.id.demo_rxbus_tap_txt) + TextView _tapEventTxtShow; - private CompositeDisposable _disposables; - private RxBus _rxBus; + private CompositeDisposable _disposables; + private RxBus _rxBus; - @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 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 onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + _rxBus = ((MainActivity) getActivity()).getRxBusSingleton(); + } - @Override - public void onStart() { - super.onStart(); - _disposables = new CompositeDisposable(); + @Override + public void onStart() { + super.onStart(); + _disposables = new CompositeDisposable(); - _disposables.add( - _rxBus - .asFlowable() - .subscribe( - event -> { - if (event instanceof RxBusDemoFragment.TapEvent) { - _showTapText(); - } - })); - } + _disposables.add( + _rxBus + .asFlowable() + .subscribe( + event -> { + if (event instanceof RxBusDemoFragment.TapEvent) { + _showTapText(); + } + })); + } - @Override - public void onStop() { - super.onStop(); - _disposables.clear(); - } + @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); - } + 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 7cb08f4d..49a5e863 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,93 +7,96 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import butterknife.BindView; -import butterknife.ButterKnife; + import com.morihacky.android.rxjava.MainActivity; import com.morihacky.android.rxjava.R; import com.morihacky.android.rxjava.fragments.BaseFragment; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import butterknife.BindView; +import butterknife.ButterKnife; import io.reactivex.Flowable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; -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_txt) + TextView _tapEventTxtShow; - @BindView(R.id.demo_rxbus_tap_count) - TextView _tapEventCountShow; + @BindView(R.id.demo_rxbus_tap_count) + TextView _tapEventCountShow; - private RxBus _rxBus; - private CompositeDisposable _disposables; + 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 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 onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + _rxBus = ((MainActivity) getActivity()).getRxBusSingleton(); + } - @Override - public void onStart() { - super.onStart(); - _disposables = new CompositeDisposable(); + @Override + public void onStart() { + super.onStart(); + _disposables = new CompositeDisposable(); - Flowable tapEventEmitter = _rxBus.asFlowable().share(); + Flowable tapEventEmitter = _rxBus.asFlowable().share(); - _disposables.add( - tapEventEmitter.subscribe( - event -> { - if (event instanceof RxBusDemoFragment.TapEvent) { + _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 d45ec46e..8452af21 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,93 +7,96 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import butterknife.BindView; -import butterknife.ButterKnife; + import com.morihacky.android.rxjava.MainActivity; import com.morihacky.android.rxjava.R; import com.morihacky.android.rxjava.fragments.BaseFragment; + +import java.util.concurrent.TimeUnit; + +import butterknife.BindView; +import butterknife.ButterKnife; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; 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); - } + @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 7d6c58fb..dca4e0f6 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 @@ -5,34 +5,36 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import butterknife.ButterKnife; -import butterknife.OnClick; + import com.morihacky.android.rxjava.MainActivity; import com.morihacky.android.rxjava.R; import com.morihacky.android.rxjava.fragments.BaseFragment; +import butterknife.ButterKnife; +import butterknife.OnClick; + public class RxBusDemo_TopFragment extends BaseFragment { - 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 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()); + 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 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()); + } } - } } 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 a6ec55cf..c046ed94 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 @@ -1,6 +1,7 @@ package com.morihacky.android.rxjava.volley; import android.content.Context; + import com.android.volley.RequestQueue; import com.android.volley.toolbox.Volley; @@ -8,21 +9,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 aaa55d08..d7fa369f 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,9 +9,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ListView; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; + import com.android.volley.Request; import com.android.volley.VolleyError; import com.android.volley.toolbox.JsonObjectRequest; @@ -20,161 +18,166 @@ import com.morihacky.android.rxjava.fragments.BaseFragment; import com.morihacky.android.rxjava.wiring.LogAdapter; +import org.json.JSONObject; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; import butterknife.Unbinder; import io.reactivex.Flowable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.schedulers.Schedulers; import io.reactivex.subscribers.DisposableSubscriber; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutionException; -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); - } - }); - } - - @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()); - } + public static final String TAG = "VolleyDemoFragment"; - @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); - } + @BindView(R.id.list_threading_log) + ListView _logsList; + + private List _logs; + private LogAdapter _adapter; + private Unbinder unbinder; + + private CompositeDisposable _disposables = new CompositeDisposable(); - @Override - public void onComplete() { - Log.e(TAG, "onCompleted"); - Timber.d("----- onCompleted"); - _log("onCompleted "); + @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 "); } - }; - - 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); + _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 cfa108f1..b796fd9e 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 @@ -2,12 +2,14 @@ import android.content.Context; import android.widget.ArrayAdapter; + import com.morihacky.android.rxjava.R; + import java.util.List; 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); + } } diff --git a/app/src/main/res/layout/fragment_buffer.xml b/app/src/main/res/layout/fragment_buffer.xml index 3464ac5b..c4dee42b 100644 --- a/app/src/main/res/layout/fragment_buffer.xml +++ b/app/src/main/res/layout/fragment_buffer.xml @@ -1,34 +1,34 @@