RX Java 1 is simple to use

Keywords: Mobile Retrofit network OkHttp Programming

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.
stay

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!!

Posted by fusioneko on Fri, 17 May 2019 02:17:49 -0700