Original link
In the first-in-one article, I've probably introduced how Rxjava is used. I'll show you how to use Rxjava in Android.
Rxandroid
Rxandroid is an extension of Rxjava for Android platforms. It contains tools that simplify the development of Android.
First, Androidschedulers provides a scheduler for the threading system of Android. Need to run some code in the UI thread? Very simple, only need to use Androidschedulers.mainthread ():
retrofitService.getImage(url) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(bitmap -> myImageView.setImageBitmap(bitmap));
If you have created your own handler, you can use HandlerThreadScheduler1 to link a scheduler to your handler.
The next thing to talk about is androidobservable, which provides multiple features to match Android's life cycle. The Bindactivity () and Bindfragment () methods use Androidschedulers.mainthread () to execute the Observer code by default. Both methods notify the observer to stop sending new messages at the end of the activity or fragment.
AndroidObservable.bindActivity(this, retrofitService.getImage(url)) .subscribeOn(Schedulers.io()) .subscribe(bitmap -> myImageView.setImageBitmap(bitmap);
I like it myself. The Androidobservable.frombroadcast () method, which allows you to create a observable object similar to Broadcastreceiver. The following example shows how to be notified when the network changes:
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);AndroidObservable.fromBroadcast(context, filter) .subscribe(intent -> handleConnectivityChange(intent));
The final introduction is viewobservable, which can be used to add some bindings to the view. If you want to receive an event every time you click on the view, you can use Viewobservable.clicks (), or you want to listen for TextView content changes, you can use Viewobservable.text ().
false) .subscribe(view -> handleClick(view));
Retrofit
The famous retrofit library has built-in support for Rxjava. Typically, a call can be made by using a callback object to get the result asynchronously:
@GET("/user/{id}/photo")void getUserPhoto(@Path("id"int id, Callback<Photo> cb);
With Rxjava, you can return directly to a observable object.
@GET("/user/{id}/photo")Observable<Photo> getUserPhoto(@Path("id"int id);
Now you are free to use the observable object. Not only can you get the data, you can also transform it.
Retrofit's support for observable makes it easy to combine multiple rest requests. For example, we have a request to get a photo, and a request is to get the metadata, we can send these two requests concurrently, and wait for two results to return after the processing:
Observable.zip( service.getUserPhoto(id), service.getPhotoMetadata(id), (photo, metadata) -> createPhotoWithData(photo, metadata)) .subscribe(photoWithData -> showPhoto(photoWithData));
In the second article I showed a similar example (using Flatmap ()). Here I just want to show how easy it is to combine multiple rest requests using Rxjava+retrofit.
Legacy code, running extremely slow code
Retrofit can return observable objects, but what if the other libraries you use do not support this? or an internal code, you want to convert them into observable? What's the easy way?
Most of the time Observable.just () and Observable.from () can help you create Observable objects from legacy code:
privateoldMethod() { ... }publicnewMethod() { return Observable.just(oldMethod());}
In the above example, if Oldmethod () is fast enough, it's not a problem, but what if it's slow? Calling Oldmethod () will block the thread on which he is located.
To solve this problem, refer to the method I have been using – using defer () to wrap the slow code:
privateslowBlockingMethod() { ... }publicnewMethod() { return Observable.defer(() -> Observable.just(slowBlockingMethod()));}
Now, the call to Newmethod () is not blocked unless you subscribe to the returned observable object.
Life cycle
I left the hardest in the end. How is the life cycle of the activity handled? There are two main questions:
1. Continue the previous subscription after the configuration changes (such as turning the screen).
For example, you use retrofit to make a rest request, and then you want to show the results in the ListView. What if the user spins the screen when the network request is made? Of course you want to continue with the request, but what?
2.Observable holds context-led memory leaks
The problem is that when you create a subscription, you hold a reference to the context in some way, especially when you interact with the view, which is too easy to happen! If the observable does not end in time, the memory footprint will become larger.
Unfortunately, there is no silver bullet to solve these two problems, but here are some guidelines you can refer to.
The solution to the first problem is to use the Rxjava built-in caching mechanism so that you can perform unsubscribe/resubscribe on the same observable object without having to run the observable code repeatedly. The cache () (or Replay ()) will continue to execute the network request (even if you call unsubscribe and will not stop). This means that you can create a new observable object from the return value of the cache () when the activity is recreated.
Observable <Photo> request = Service.getuserphoto (ID). cache (); Subscription sub = request.subscribe (photo, Handleuserphoto (photo)); //... When the Activity is being recreated ... Sub.unsubscribe (); //... Once the Activity is recreated ... Request.subscribe (photo) Handleuserphoto
Note that the two sub is the same cached request that was used. Of course where to store the result of the request or do it yourself, and all other life-cycle-related solutions A tiger must be stored somewhere outside the life cycle. (retained fragment or singleton, etc.).
A solution to the second problem is to unsubscribe at some point in the life cycle. A very common pattern is to use Compositesubscription to hold all subscriptions, and then cancel all subscriptions in OnDestroy () or Ondestroyview ().
private CompositeSubscription mCompositeSubscription = new CompositeSubscription();private void doSomething() { mCompositeSubscription.add( AndroidObservable.bindActivity(this, Observable.just("Hello, World!")) .subscribe(s -> System.out.println(s)));}@Overrideprotected void onDestroy() { super.onDestroy(); mCompositeSubscription.unsubscribe();}
You can create a Compositesubscription object in the base class of activity/fragment and use it in subclasses.
Attention! Once you call Compositesubscription.unsubscribe (), the Compositesubscription object is unavailable, and if you want to use Compositesubscription, You have to create a new object.
The solution for both problems requires adding extra code, and if anyone has a better plan, please let me know.
Summarize
Rxjava is still a very new project, Rxandroid. Rxandroid is still active in development, and there are few good examples. I bet a year from now some of my suggestions will be considered obsolete.
In layman's Rxjava four-use responsive programming in Android