Objective
The previous tutorial explained the use of the most basic RxJava2, and in this section we will learn Rxjava powerful threading controls.
Business
Or in the previous example, two pipes:
RxJava
Normally, upstream and downstream are working in the same thread, that is, upstream in which line Cheng events, downstream on which thread receives the event.
How to understand, take Android, for example, all actions of an activity are run in the main thread by default, such as the name of the current thread we typed in OnCreate:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.d(TAG, Thread.currentThread().getName()); }
The result is:
D/TAG: main
Back in Rxjava, when we create an upstream observable in the main thread to send events, the upstream default sends events on the main thread.
When we go to the main thread to create a downstream observer to receive the event, the downstream default is to receive the event in the main thread to see the code:
@OverrideProtectedvoidOnCreate(Bundle savedinstancestate) {Super.oncreate (savedinstancestate); Setcontentview (R.layout.activity_main); observable<integer> Observable = Observable.create (New Observableonsubscribe<integer> () {@OverridePublicvoidsubscribe (observableemitter<integer> emitter) throws Exception {log.d (TAG, "Observable thread is:" + Thread.CurrentThread (). GetName ()); LOG.D (TAG, "Emit 1"); Emitter.onnext (1);}); consumer<integer> Consumer = new consumer<integer> () { @Override public void accept (integer integer) throws Exception {log.d (TAG, "Observer thread is:" + Thread.CurrentThread (). GetName ()); LOG.D (TAG, "OnNext:" + Integer);}}; Observable.subscribe (consumer); }
Create the upstream and downstream in the main thread, and then connect them together, printing out the thread they are on, and running the result:
1 D/TAG: Observer thread is :main D/TAG: onNext: 1
This verifies that the upstream and downstream defaults are working on the same thread.
This is certainly not enough to meet our needs, we want more is a situation, in the sub-thread to do time-consuming operation, and then back to the main thread to manipulate the UI, the picture is described as the following image:
Thread.png
In this diagram, we use a yellow water pipe to denote a sub-thread, and a dark blue pipe represents the main thread.
To achieve this, we need to change the thread that sends the event upstream, let it send the event to the child thread, and then change the downstream thread to get it to the main thread to receive the event. This can be done easily by Rxjava the built-in thread scheduler. Next look at a piece of code:
@OverrideProtectedvoidOnCreate(Bundle savedinstancestate) {Super.oncreate (savedinstancestate); Setcontentview (R.layout.activity_main); observable<integer> Observable = Observable.create (New Observableonsubscribe<integer> () {@OverridePublicvoidSubscribe(observableemitter<integer> emitter)throws Exception {log.d (TAG, "Observable thread is:" + Thread.CurrentThread (). GetName ()); LOG.D (TAG, "Emit 1"); Emitter.onnext (1);}); consumer<integer> Consumer = new consumer<integer> () { @Override public void accept (integer integer) throws Exception {log.d (TAG, "Observer thread is:" + Thread.CurrentThread (). GetName ()); LOG.D (TAG, "OnNext:" + Integer);}}; Observable.subscribeon (Schedulers.newthread ()). Observeon (Androidschedulers.mainthread ()). Subscribe (consumer); }
It's just an example, but we've just added a little bit of stuff, and we're going to look at the results of the operation:
D/TAG: Observable thread is : RxNewThreadScheduler-2 D/TAG: emit 1 D/TAG: Observer thread is :main D/TAG: onNext: 1
As you can see, the thread of the upstream send event does change, it is the event that is sent in a called RxNewThreadScheduler-2
thread, and the downstream still receives the event in the main thread, which means that our purpose is reached, and then we see how it is done.
Compared to the previous piece of code, this code simply adds two lines of code:
.subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread())
As a beginner's introductory tutorial, and will not post a lot of source code to analyze, so just want to let everyone remember a few points, has reached how to use the correct purpose is our goal.
In a nutshell, the subscribeOn()
thread that specifies the upstream send event observeOn()
specifies the thread that receives the event downstream.
Specifying the upstream thread multiple times is only valid for the first time, that is, multiple invocations are subscribeOn()
only valid for the first time, and the rest are ignored.
It is possible to specify a downstream thread multiple times, that is, each time a call is made, observeOn()
the downstream thread switches once.
As an example:
observable.subscribeOn(Schedulers.newThread()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .observeOn(Schedulers.io()) .subscribe(consumer);
This code specifies two threads for upstream send events, newthread and IO threads, and two threads in the downstream, main and IO threads, respectively. The result of the operation is:
D/TAG: Observable thread is : RxNewThreadScheduler-3D/TAG: emit 1 D/TAG: Observer thread is :RxCachedThreadScheduler-1D/TAG: onNext: 1
As you can see, although the upstream specified two threads, but only the first time the specified valid, still in the RxNewThreadScheduler
thread, and downstream ran to the RxCachedThreadScheduler
middle, the cachethread is actually an IO thread pool.
To see the downstream thread switching process more clearly, we add a log:
Observable.subscribeon (Schedulers.newthread ()). Subscribeon (Schedulers.io ()). Observeon (Android Oidschedulers.mainthread ()). Doonnext (New Consumer<integer> () {@Overridepublic void accept(integer integer) throws Exception {log.d (TAG, "after Observeon (Mainthread)", Current thread is: "+ thread.currentthread (). GetName ());}}). Observeon (Schedulers.io ()). Doonnext (new consumer<integer> () { @Override public void Accept(integer integer) throws Exception {log.d (TAG, "after Observeon (IO), current thread is:" + thread.) CurrentThread (). GetName ()); }}). Subscribe (consumer);
After we switch the downstream thread, we print out the current thread and run the result:
D/TAG: Observable thread is : RxNewThreadScheduler-1 D/TAG: emit 1 D/TAG: After observeOn(mainThread), current thread is: main D/TAG: After observeOn(io), current thread is : RxCachedThreadScheduler-2 D/TAG: Observer thread is :RxCachedThreadScheduler-2 D/TAG: onNext: 1
As you can see, each time a thread is called it observeOn()
switches once, so if we have a similar requirement, we know how to handle it.
In Rxjava, a number of threading options have been built in for us to choose from, such as
- Schedulers.io () A thread representing IO operations, typically used for IO-intensive operations such as network, read-write files, etc.
- Schedulers.computation () represents CPU-intensive operations, such as operations that require a lot of computation
- Schedulers.newthread () represents a regular new thread
- Androidschedulers.mainthread () represents the main thread of Android
These built-in scheduler are sufficient to meet the needs of our development, so we should use the built-in options to use a thread pool to maintain these threads within Rxjava, all of which are more efficient.
Practice
For our Android developers, often put some time-consuming operations in the background, such as network requests or read and write files, operations database and so on, wait until the operation is completed back to the main thread to update the UI, with the above basis, then we can now easily do such a number of operations.
Here are a few common scenarios.
Network requests
There are a few of the most famous network request libraries in Android, and the reason why retrofit can stand out is because it supports Rxjava's way of calling, and here's a brief explanation of its basic usage.
To use retrofit, first add the Gradle configuration:
//retrofit compile ‘com.squareup.retrofit2:retrofit:2.1.0‘ //Gson converter compile ‘com.squareup.retrofit2:converter-gson:2.1.0‘ //RxJava2 Adapter compile ‘com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0‘ //okhttp compile ‘com.squareup.okhttp3:okhttp:3.4.1‘ compile ‘com.squareup.okhttp3:logging-interceptor:3.4.1‘
The API interface is then defined:
public interface Api { @GET Observable<LoginResponse> login(@Body LoginRequest request); @GET Observable<RegisterResponse> register(@Body RegisterRequest request);}
Then create a retrofit client:
private Static Retrofit create () {Okhttpclient.builder Builder = new okhttpclient (). Newbuilder (); Builder.readtimeout (10, Timeunit.seconds); Builder.connecttimeout ( 9, timeunit.seconds); if (buildconfig.debug) {Httplogginginterceptor interceptor = New Httplogginginterceptor (); Interceptor.setlevel (HttpLoggingInterceptor.Level.BODY); Builder.addinterceptor (Interceptor); } return new retrofit.builder (). BASEURL (ENDPOINT). Client ( Builder.build ()). Addconverterfactory (Gsonconverterfactory.create ()). Addcalladapterfactory ( Rxjava2calladapterfactory.create ()). build ();}
The initiation of the request is simple:
API API = Retrofit.create (Api.class); Api.login (Request). Subscribeon (Schedulers.io ())Make a network request on the IO thread. Observeon (Androidschedulers.mainthread ())Go back to the main thread to process the request results. Subscribe (New Observer<loginresponse> () {@OverridePublicvoidOnsubscribe (disposable d) {} @Override public void onnext (Loginresponse value) {} @Override < Span class= "Hljs-keyword" >public void onerror (Throwable e) {toast.maketext (Mcontext, " Login Failed ", Toast.length_short). Show (); @Override public void oncomplete () {Toast.maketext (MContext, Span class= "hljs-string" > "login Successful", Toast.length_short). Show (); } });
Seems perfect, but we ignore a point, if the activity has exited in the process of request, this time if go back to the main thread to update the UI, then the app must crash, how to do it, we said in the last section Disposable
, say it is a switch, call its dispose()
Method will cut off the water pipe, so that the downstream can not receive the event, since the event is not received, then will not be updated UI. So we can save this in the activity Disposable
, and when the activity exits, it will be cut off.
So what if there's more than one, there's a container in the Rxjava, and Disposable
CompositeDisposable
every time we get one, we Disposable
call CompositeDisposable.add()
it to add it to the container, and at the exit, the call CompositeDisposable.clear()
can cut off all the pipes.
Read/write Database
It says the example of the network request, and then look at the read-write database, read and write the database is a time-consuming operation, so we also better put in the IO thread, this example is relatively simple, directly on the code:
Public observable<list<record>> readallrecords () {Return Observable.create (New Observableonsubscribe<list<record>> () {@Overridepublic void subscribe (observableemitter<list<record>> emitter) throws Exception { cursor cursor = null; try {cursor = Getreadabledatabase (). Rawquery ( "SELECT * from" + TABLE_NAME, new string[]{}); list<record> result = new arraylist<> (); while (Cursor.movetonext ()) {Result.add (Db.Record.read (cursor));} emitter.onnext ( result); Emitter.oncomplete (); } finally {if (cursor! = null) { Cursor.close (); }}}). Subscribeon (Schedulers.io ()). Observeon (Androidschedulers.mainthread ()); }
All right, here's the tutorial, and the next tutorial will teach you how to use the powerful operators in Rxjava. By using these operators it is easy to achieve the effect of various hanging bombing days. Please look forward to it.
Season_zlc
Links: http://www.jianshu.com/p/8818b98c44e2
Source: Pinterest
Copyright belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please specify the source.
RxJava2.0 Tutorial for Beginners (iii) (EXT)