Article directory
Preface
RXJava is an open source library based on the observer pattern. The observer pattern here is contrary to the normal observer pattern in life. The observer pattern in life is that the observer actively observes the observee and handles it when the observee changes, such as teachers and students. In computer programming, the observer mode requires the observer to report the self-determined state on his own initiative and notify the observer when the observer changes. There are three actions: subscription, notification and unsubscribe.
The following steps are needed to implement the observer model:
- 1 Create an Observable Object
- 2 Observed subscribe to Observer subscribe
- 3. Notify the observer to process doOnNext when the observee changes
- 4 When the observer mode is not used, the observee cancels the subscription relationship with the observer.
For instructions and more usage of RxJava, please check the following two blogs. This article only describes common usage instructions.
RxJava for Android developers
https://gank.io/post/560e15be2dca930e00da1083
RxJava 2.0 -- From Abandoning to Getting Started
https://www.jianshu.com/p/cd3557b1a474
Environmental configuration
Add the following configuration to the build.gradle file under the app of the project. Because we need to demonstrate how to use it with Retrofit2 later, we also add the configuration of Retrofit2.
//RxJava implementation 'io.reactivex:rxjava:1.1.6' implementation 'io.reactivex:rxandroid:1.2.0' //Retrofit 2.0.0-beta2 implementation 'com.squareup.retrofit2:retrofit:2.1.0' implementation 'com.squareup.okhttp:okhttp:2.5.0' implementation 'com.squareup.okio:okio:1.6.0' implementation 'com.google.code.gson:gson:2.4' implementation 'com.squareup.retrofit2:converter-gson:2.0.0-beta4' implementation "com.squareup.retrofit2:adapter-rxjava:2.1.0"
Observable
Simple Subscription and Observation
String[] args = {"a", "b", "c"}; //A simple example to implement subscriptions and observations on IO threads Observable.from(args) .subscribeOn(Schedulers.io()) //Specify which thread to implement the subscription .observeOn(Schedulers.io()) //Specify which thread to implement the observation .doOnNext(new Action1<String>() { @Override public void call(String s) { //Because observations are specified on IO threads, if UI operations are performed here, an exception will be thrown. Log.i("RxDemo", s); } }).subscribe();
The output of the program is as follows:
I/RxDemo: a I/RxDemo: b I/RxDemo: c
Here we need to note that because we specify in the code that the subscription behavior occurs on the IO thread, that is to say, the operation performed by the observer is on the IO thread, the observer is specified that the notification receiving behavior occurs on the IO thread, and the notification callback sent by the observer is on the IO thread. UI operation cannot be performed in the notification function doOnNext here, No. It can cause anomalies.
Interthreaded switching
Observable.from(args) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread())//Observation on UI threads .doOnNext(new Action1<String>() { @Override public void call(String s) { //If UI operations are required, the observer needs to switch to the UI thread for observation. Toast.makeText(getBaseContext(), s, Toast.LENGTH_SHORT).show(); } }).subscribe();
Here we specify in the code that the subscription behavior occurs on the main thread, that is to say, the operation performed by the observer is on the main thread, the observer is specified that the notification receiving behavior occurs on the main thread, and the notification callback sent by the observer is on the main thread, so the UI operation can be carried out in the notification function doOnNext without causing any abnormalities.
Complete life cycle
Observable.from(args) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .doOnNext(new Action1<String>() { @Override public void call(String s) { Log.i(TAG, s); } }) .doOnSubscribe(new Action0() { @Override public void call() { Log.i(TAG, "doOnSubscribe-->Start loading"); } }) .doOnTerminate(new Action0() { @Override public void call() { Log.i(TAG, "onTerminate-->Load complete"); } }) .doOnCompleted(new Action0() { @Override public void call() { Log.i(TAG, "onCompleted-->End loading"); } }) .doOnError(new Action1<Throwable>() { @Override public void call(Throwable throwable) { Log.i(TAG, "An exception has occurred. The exception error is: " + throwable.getMessage()); } }) .doAfterTerminate(new Action0() { @Override public void call() { Log.i(TAG, "doAfterTerminate-->The process is over."); } }) .subscribe();
The following functions are called throughout the observer cycle
- doOnSubscribe is called after the subscription creation is complete
- doOnNext is called after Obserable calls onNext
- doOnTerminate is called before Obserable calls onCompleted.
- doOnCompleted is called after Obserable calls onCompleted
- doOnError is called after Obserable calls onError, and the process is interrupted.
- doAfterTerminate is called after Obserable calls onCompleted.
Here onError and onCompleted are mutually exclusive, and only one of the same processes will be invoked.
Run the program, log input as follows:
I/RxDemo: doOnSubscribe-->Start loading I/RxDemo: a I/RxDemo: b I/RxDemo: c I/RxDemo: onTerminate-->Load complete I/RxDemo: onCompleted-->End loading I/RxDemo: doAfterTerminate-->The process is over.
exception handling
Observable.from(args) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .doOnSubscribe(new Action0() { @Override public void call() { Log.i(TAG, "doOnSubscribe"); } }) .doOnTerminate(new Action0() { @Override public void call() { Log.i(TAG, "doOnTerminate stay OnError Previous call"); } }) .doAfterTerminate(new Action0() { @Override public void call() { Log.i(TAG, "doAfterTerminate stay OnError Then call"); } }) .subscribe(new Action1<String>() { @Override public void call(String s) { Log.i("RxDemo", s); int a = 1 / 0; } }, new Action1<Throwable>() { @Override public void call(Throwable throwable) { Log.i(TAG, "An exception has occurred. The exception error is: " + throwable.getMessage()); } }, new Action0() { @Override public void call() { Log.i(TAG, "onComplete"); } });
Run the program, log input as follows:
I/RxDemo: doOnSubscribe I/RxDemo: a I/RxDemo: An exception has occurred. The exception error is: divide by zero
The above example shows that if an exception occurs in doOnNext, doOnError will occur because the business is interrupted, so doOnTerminate, doOnCompleted, doAfterTerminate will not be called.
Observable Management
RxJava provides Composite Subscription to manage Observable, such as:
- CompoeSubscription. add (observable) manages Observable.
- CompoeSubscription. clear () clears and stops all executing Observable
Simple example
//Managing Observable private CompositeSubscription compositeSubscription = new CompositeSubscription(); compositeSubscription.add( Observable.interval(0, 1000, TimeUnit.MILLISECONDS) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.io()) .subscribe(time -> { if(null == mActivity){ KLog.i("mActivity is null"); compositeSubscription.clear(); }else{ KLog.i("mActivity is not null"); } }, throwable -> KLog.i("occour exception, " + throwable.getMessage()) ) );
RXJava in conjunction with Retrofit
Retrofit is a annotated network request framework. It can realize many kinds of network requests easily and quickly by combining itself with OKHttp. The combination of RXJava and RXJava makes it easier to implement network switching and chain programming of network requests.
Define Retrofit interface class
import retrofit2.http.GET; import retrofit2.http.Query; import rx.Observable; public interface PoetryTestAPI { @GET("/getSongPoetry") Observable<PoetryList> getPoetryList(@Query("page") int page, @Query("count") int count); }
Initialize the Retrofit class
/*Retrofit2 is used uniformly here, so the configuration needs to be the same as the one that has been modified to retrofit2. Contains retrofit, convert-gson, adapter-rxjava. See the signature's environment configuration for specific configuration` */ Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.apiopen.top") //Add Gson conversion adapter .addConverterFactory(GsonConverterFactory.create()) //Add Rx Java adapter .addCallAdapterFactory( RxJavaCallAdapterFactory.create()) .build(); PoetryTestAPI poetryTestAPI = retrofit.create(PoetryTestAPI.class);
Simple network requests
poetryTestAPI.getPoetryList(1, 10) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .doOnSubscribe(() -> { Log.i(TAG,"Start loading data..."); }) .doOnTerminate(() ->{ Log.i(TAG,"Data loading is completed and parsing is in progress..."); }) .doOnCompleted(() -> { Log.i(TAG,"Data loaded!!"); }) .doAfterTerminate(() -> { Log.i(TAG,"Data query completed!!"); }) .subscribe(new Action1<PoetryList>() { @Override public void call(PoetryList poetryList) { Log.i(TAG,"doOnNext"); if(null != poetryList) { Log.i(TAG, new Gson().toJson(poetryList)); } } }, new Action1<Throwable>() { @Override public void call(Throwable throwable) { Log.i(TAG, "An exception has occurred. The exception error is: " + throwable.getMessage()); } });
Running program, input as follows:
Start loading data... doOnNext "code":200,"message", "Success", "result": [{authors","Song Taizu","content":" Want to come out of the bright and hot, mountains and mountains like fire. | Must go up to the sky, but chase the remnants of the stars to catch up with the moon. "title": "Japanese Poetry"},...]} _____________ Data loading is completed and parsing is in progress. The data is loaded!! Data query finished!!
Optimizing network requests
Define a converter
/* * Define a converter for thread switching between subscribers and observers * Observable.Transformer<T, R> * @param <T> the first argument type * @param <R> the result type * */ Observable.Transformer<Object, Object> composeTransformer = observable -> observable.throttleFirst( 500, TimeUnit.MILLISECONDS) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread());
Using Lamdba expressions
1 Here, if you need to use Lamdba expression, you need to use jdk1.8, otherwise you will report an error prompt.
**Lamdba express are not supported at language level '7' **
2 Lamdab expression format'(parameter list) - > {code block}'or `parameter name - > {code block}'
poetryTestAPI.getPoetryList(1, 10) .compose(composeTransformer) .doOnSubscribe(() -> Log.i(TAG, "Start executing data!!")) .doAfterTerminate(() -> Log.i(TAG, "Data query completed!!")) .subscribe((Object poetryList) -> { Log.i(TAG, "doOnNext"); if (null != poetryList) { Log.i(TAG, new Gson().toJson(poetryList)); } }, (Throwable throwable) ->{ Log.i(TAG, "An exception has occurred. The exception error is: " + throwable.getMessage()); } );
perhaps
poetryTestAPI.getPoetryList(1, 10) .compose(composeTransformer) .doOnSubscribe(() -> Log.i(TAG, "Start loading data!!")) .doAfterTerminate(() -> Log.i(TAG, "Loading data completion!!")) .subscribe(list -> { Log.i(TAG, "doOnNext"); if (null != list) { Log.i(TAG, new Gson().toJson(list)); } }, throwable -> { Log.i(TAG, "An exception has occurred. The exception error is: " + throwable.getMessage()); });
Running program, input as follows:
Start loading data... doOnNext "code":200,"message", "Success", "result": [{authors","Song Taizu","content":" Want to come out of the bright and hot, mountains and mountains like fire. | Must go up to the sky, but chase the remnants of the stars to catch up with the moon. "title": "Japanese Poetry"},...]} _____________ Data query finished!!