From: http://blog.danlew.net/2014/10/08/grokking-rxjava-part-4/
嘿,小伙伴们,今天,我继续死磕自己。
RxAndroid是RxJava的一个针对Android平台的扩展,它包含了一些能简化Android开发的工具。
首先,AndroidSchedulers提供了针对Android的线程系统的调度器。需要在UI线程中运行某些代码?很简单,只需要使用AndroidSchedulers.mainThread();
retrofitService.getImage(url)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedules.mainThread())
.subscribe(bitmap - > myImageView.setImageBitmap(bitmap));
如果你已经创建了自己的Handler,你可以使用Handler.ThreadScheduler1将一个调度器链接到你的handler上。
接着要介绍的就是AndroidObservable,他提供了很多的功能来配合Android的生命周期。
bindActivity()和bindFragment()方法默认使用AndroidSchedulers.mainThread()来执行观察者代码,这两个方法会在Activity或者Fragment结束的时候通知被观察者发出新的消息。
AndroidObservable.bindActivit(this,retrofitService.getImage(url))
.subscribeOn(Schedulers.io())
.subscribe(bitmap - > myImageView.setImageBitmap(bitmap));
我自己也很喜欢AndroidObservable.fromBrodcast()方法,它允许你创建类似于BroadcastReceiver的Observable对象。下面的例子展示了如何在网络变化的时候被通知到:
InterFilter filter = new IntentFilter(ConnectivityManager.COMMECTIVITY_ACTION);
AndroidObservable.fromBroadcast(context,filter)
.subscribe(intent - > handleConectivityChange(intent));
最后要介绍的是ViewObservable,使用它可以给View添加一些绑定。如果你想每次点击View的时候都收到一个事件,可以使用ViewObservable.clicks(), 或者你想监听TextView内容的变化,可以使用ViewObservable.text().
ViewObservable.clicks(mCardNameEditText,false)
.subscribe(view - > handleClick(view));
Retrofit
大名鼎鼎的Retrofit库内置了对RxJava的支持。通常可以通过使用一个Callback对象来获取异步的结果:
@GET("/user/{id}/photo") void getUserPhoto(@Path("id") int id, Callback cb);
使用RxJava, 你可以直接返回一个Observable对象。
@GET("/user/{id}/photo")
Observable getUserPhoto(@Path("id") int id);
现在你可以随意使用Observable对象了。你不仅可以获取数据,还可以进行变换。
Retrofit对Observable的支持使得它可以将很多个简单的REST请求结合起来。比如我们有一个请求是获取照片的,还有一个请求是获取元数据的,我们就可以将这两个请求并发的发出,并且等待两个结果都返回之后再处理:
Observavle.zip(
service.getUserPhoto(id),
service.getPhotoMetadata(id),
(photo, metadata) - > createPhotoWithData(photo,metadata))
.subscribe(photoWithData - > showPhoto(photoWithData));
在之前的文章我展示过一个类似的例子 (使用flatMap())。这里我只是想展示使用RxJava + Retrofit 可以多么简单的组合多个REST请求。
遗留代码,运行极慢的代码
Retrofit可以返回Observable对象,但是如果你使用的别的库并不支持这样怎么办?或者说一个内部的内码,你想把他们转换成Observable,有什么简单的方法吗?
觉大多数时候,Observable.just() 和 Observable.from() 能够帮助你从遗留的代码中创建 Observable 对象:
private Object oldMethod() {....}
把原来的老的方法返回一个Object类型,然后把这个返回的对象放入Observable.just()中去
public Observable newMethod(){
return Observable.just(oldMethod());
}
上面的例子中如果oldMethod()足够快是没有什么问题的,但是如果很慢呢?调用oldMethod()将会阻塞主他所在的线程。
为了解决这个问题,可以参考我一直使用的方法 使用defer() 来包装在线程中的运行缓慢的代码:
private Object slowBlockingMethod(){...}
public Observable newMethod(){
return Observavoe.defer( () ->
Observable.just(slowBlockingMethod())
);
}
现在,newMethod() 的调用就不会阻塞了,除非你订阅了返回的observable对象。
生命周期
使用RxJava内置的缓存机制。这样你就可以对同一个Observable对象执行unsubsctibe/resubscribe,却不重复运行的到Observable的代码。cache()或者 (replay()) 会继续执行网络请求 ( 甚至你调用了 unsubscribe也不会停止)。 这就是说你可以在Activity重新创建的时候从cache()的返回值 创建一个新的Observable对象。
Observavle request = service.getUserPhoto(id).cache();
Subscription sub = request.subscribe(photo - > handleUserPhoto(photo));
//当这个Activity 生命周期结束时候, sub.unsubscribe();
// 当这个Activity开始这个生命周期的时候,sub.subscribe();
request.subscribe(photo - > handlerUsdrPhoto(photo));
注意,这两次sub是使用的同一个缓存请求。当然在哪里去缓存请求的结果还是需要你自己来做,和其他的生命周期相关的解决方案一旦形成,就必须在生命周期外的某个地方存储 (retained fragment 或者单例等等)。
复合订阅关系的处理
一个很常见的模式就是使用CompositeSubscription来持有所有的Subscriptions, 然后在onDestory()或者onDestoryView() 里取消所有的订阅。
private CompositeSubscription mCompositeSubscription
= new CompositeSubscription;
private void doSomething(){
mCompositeSubscription.add(
AndroidObservable.bindActivity(this, Observable.just("Hello, World!"))
.subscribe(s - > System.out.println(s))
);
@Override
Protected void onDestory(){
mCompositeSubscription.unsubscribe();
}
}
更多内容请关注我的个人微信公众号:前端开发技术栈