Rxjava基础
现在很多Android App的开发开始使用Rxjava,但是Rxjava以学习曲线陡峭著称,入门有些困难。经过一段时间的学习和使用,这里来介绍一下我对Rxjava的理解。
说到Rxjava首先需要了解的两个东西,一个是Observable(被观察者,事件源)和 Subscriber(观察者,是 Observer的子类)。Observable发出一系列事件,Subscriber处理这些事件。首先来看一个基本的例子,我们如何创建并使用Observable。
Observable.create(new Observable.OnSubscribe<String>() {
@Override public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("hello");
}
}).subscribe(new Subscriber<String>()
{
@Override public void onCompleted() {
}
@Override public void onError(Throwable e) {
}
@Override public void onNext(String s) {
Log.d("rx-info", s);
}
});
创建Observable的最基本的方法是通过Observable.create() 来进行,当有Subscriber通过Observable.subscribe() 方法进行订阅之后Observable就会发射事件,注意必须要有订阅者订阅才会发射事件。发射的方式是通过调用 Observable中的 OnSubsribe 类型的成员来实现(每个Observable有一个final OnSubscribe<T> onSubscribe 成员,该成员是一个接口,后面详细说),在 Onsubsribe类型成员中调用 call() 方法,注意,这个call方法的参数就是 Observable.subscribe() 方法传入的 Subsriber实例。总的一句话就是在Obsubscribe 的 call方法中执行订阅者(Subscriber)的三个方法 onNext(), onCompleted() 和 onError()。
一开始就是一堆 Observable , Subscriber,subscribe() , OnSubscribe 估计看得头晕,因此我们需要先来对这些东西有一个了解。这里只列出一个帮助理解的大概。
public class Observable<T> { final OnSubscribe<T> onSubscribe;
protected Observable(OnSubscribe<T> f) {
this.onSubscribe = f;
} public final static <T> Observable<T> create(OnSubscribe<T> f) {
return new Observable<T>(hook.onCreate(f));
} public interface OnSubscribe<T> extends Action1<Subscriber<? super T>> {
// cover for generics insanity
} public final Subscription subscribe(Subscriber<? super T> subscriber) {
return Observable.subscribe(subscriber, this);
} public interface Operator<R, T> extends Func1<Subscriber<? super R>, Subscriber<? super T>> {
// cover for generics insanity
}
}
public interface Action1<T> extends Action {
void call(T t);
}
public interface Subscription {
void unsubscribe();
boolean isUnsubscribed();
}
public interface Observer<T> {
void onCompleted();
void onError(Throwable e);
void onNext(T t);
} public abstract class Subscriber<T> implements Observer<T>, Subscription {
//...
}
通过上面的代码帮助理清楚 Observable, Observer, Subscriber, OnSubsriber, subscribe() 之间的关系。这里额外提一下 Observable.subscribe() 方法有多个重载:
Subscription subscribe()
Subscription subscribe(Action1<? super T> onNext)
Subscription subscribe(Action1<? super T> onNext, Action1< java.lang .Throwable> onError)
Subscription subscribe(Action1<? super T> onNext, Action1< java.lang .Throwable> onError, Action0 onComplete)
Subscription subscribe(Observer<? super T> observer)
Subscription subscribe(Subscriber<? super T> subscriber)
其它的ActionX 和 FuncX 请大家自行去查阅定义。
介绍了基本的创建Observable和 Observable是怎么发射事件的之后,来介绍一下Rxjava的Operator和Operator的原理。
Rxjava的Operator常见的有map, flatMap, concat, merge之类的。这里就不介绍Operator的使用了,介绍一下其原理。介绍原理还是来看源码,以map为例。
首先看一下使用map的例子:
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("hello");
}
})
.map(new Func1<String, String>() {
@Override
public String call(String s) {
return s + "word";
}
})
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() { } @Override
public void onError(Throwable e) { } @Override
public void onNext(String s) {
Log.d("info-rx", s);
}
});
继续来看 map的定义:
public final <R> Observable<R> map(Func1<? super T, ? extends R> func) {
return lift(new OperatorMap<T, R>(func));
}
简单说一下Func1,其中的T表示传入的参数类型,R表示方法返回的参数类型。Operator的操作原理最核心的就是lift的实现。
public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) {
return new Observable<R>(new OnSubscribe<R>() {
@Override
public void call(Subscriber<? super R> o) {
try {
Subscriber<? super T> st = hook.onLift(operator).call(o);
try {
// new Subscriber created and being subscribed with so 'onStart' it
st.onStart();
onSubscribe.call(st);
} catch (Throwable e) {
// localized capture of errors rather than it skipping all operators
// and ending up in the try/catch of the subscribe method which then
// prevents onErrorResumeNext and other similar approaches to error handling
Exceptions.throwIfFatal(e);
st.onError(e);
}
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
// if the lift function failed all we can do is pass the error to the final Subscriber
// as we don't have the operator available to us
o.onError(e);
}
}
});
}
lift方法看起来太过复杂,稍作简化:
public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) {
return new Observable<R>(...);
}
lift方法实际是产生一个新的 Observable。在map()调用之后,我们操作的就是新的Observable对象,我们可以把它取名为Observable$2,我们这里调用subscribe就是Observable$2.subscribe,继续看到subscribe里,重要的几个调用:
hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);
return hook.onSubscribeReturn(subscriber);
注意,这里的observable是Observable$2!!也就是说,这里的onSubscribe是,lift中定义的!!
回过头来看lift方法中创建新Observable的过程:
return new Observable<R>(new OnSubscribe<R>() {
@Override
public void call(Subscriber<? super R> o) {
try {
Subscriber<? super T> st = hook.onLift(operator).call(o);
try {
// new Subscriber created and being subscribed with so 'onStart' it
st.onStart();
onSubscribe.call(st); //请注意我!! 这个onSubscribe是原始的OnSubScribe对象!!
} catch (Throwable e) {
// localized capture of errors rather than it skipping all operators
// and ending up in the try/catch of the subscribe method which then
// prevents onErrorResumeNext and other similar approaches to error handling
if (e instanceof OnErrorNotImplementedException) {
throw (OnErrorNotImplementedException) e;
}
st.onError(e);
}
} catch (Throwable e) {
if (e instanceof OnErrorNotImplementedException) {
throw (OnErrorNotImplementedException) e;
}
// if the lift function failed all we can do is pass the error to the final Subscriber
// as we don't have the operator available to us
o.onError(e);
}
}
});
一定一定要注意这段函数执行的上下文!,这段函数中的onSubscribe对象指向的是外部类,也就是第一个Observable的onSubScribe!而不是Observable$2中的onSubscribe,接下来看:
Subscriber<? super T> st = hook.onLift(operator).call(o);
这行代码,就是定义operator,生成一个经过operator操作过的Subscriber,看下OperatorMap这个类中的call方法:
@Override
public Subscriber<? super T> call(final Subscriber<? super R> o) {
return new Subscriber<T>(o) { @Override
public void onCompleted() {
o.onCompleted();
} @Override
public void onError(Throwable e) {
o.onError(e);
} @Override
public void onNext(T t) {
try {
o.onNext(transformer.call(t));
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
onError(OnErrorThrowable.addValueAsLastCause(e, t));
}
} };
}
没错,对传入的Subscriber做了一个代理,把转换后的值传入。这样就生成了一个代理的Subscriber,最后我们最外层的OnSubscribe对象对我们代理的Subscriber进行了调用:
@Override
public void call(Subscriber<? super String> subscriber) {
//此处的subscriber就是被map包裹(wrapper)后的对象。
subscriber.onNext("hello");
}
然后这个subscriber传入到内部,链式的通知,最后通知到我们在subscribe函数中定义的对象。
分析lift的原理,其实还是回到了一开始介绍的Observable必须要有订阅者进行订阅才能发射事件。lift方法会产生一个新的Observable,并且这个Observable位于原始Observable和后面的Subsriber之间,因此lift方法也需要提供一个新的Subscriber来使得新产生的Observable发射事件,这个新的Subsriber就是对事件链后方的Subscriber就行包装做一个代理。
详细使用Rxjava可参见:
Rxjava基础的更多相关文章
- RxJava2实战--第二章 RxJava基础知识
第二章 RxJava基础知识 1. Observable 1.1 RxJava的使用三步骤 创建Observable 创建Observer 使用subscribe()进行订阅 Observable.j ...
- 关于 RxJava 技术介绍
Awesome-RxJava RxJava resources Blog 给 Android 开发者的 RxJava 详解 -强烈推荐 扔物线的文章 讲解非常详细 NotRxJava懒人专用指南 -这 ...
- RxJava开发精要3-向响应式世界问好
原文出自<RxJava Essentials> 原文作者 : Ivan Morgillo 译文出自 : 开发技术前线 www.devtf.cn 转载声明: 本译文已授权开发者头条享有独家转 ...
- 我们为什么要在Android中使用RxJava
本文翻译来自–>Why should we use RxJava on Android 另外: 微凉一季 再另外: 微凉一季 感觉RxJava近期风生水起,不学习一下都不好意思了.洒家也是初学R ...
- RxJava和RxAndroid
现在RxJava和RxAndroid越来越火爆,自己在业余时间也学习了一下,感觉确实很好用,之前 为了完成页面刷新,数据请求,组件信息传递的时候,要使用handler,真的是逻辑思路很强,稍微不注意, ...
- 我的Android进阶之旅------>RxJava学习资料汇总
在响应式编程中,应该牢记以下两点: everything is a stream(一切皆流) don't break the chain(不要打断链式结构) 记住,可观测序列就像一条河,它们是流动的. ...
- 体验RxJava
RxJava是 ReactiveX在 Java上的开源的实现,简单概括,它就是一个实现异步操作的库,使用时最直观的感受就是在使用一个观察者模式的框架来完成我们的业务需求: 其实java已经有了现成的观 ...
- android常用框架收录
1.Volley.Retrofit 网络框架2.ormlite.GreenDao数据库框架3.AndroidAnnotations.butterknife.Dagger注解框架4.响应式编程 R ...
- 15 个 Android 通用流行框架大全(转)
1. 缓存 DiskLruCache Java实现基于LRU的磁盘缓存 2.图片加载 Android Universal Image Loader 一个强大的加载,缓存,展示图片的库 Picas ...
随机推荐
- python 库安装
用到再更新. #Windows 一 exe 安装包 http://www.lfd.uci.edu/~gohlke/pythonlibs/#scikit-learn 二 setup.py cmd 进入目 ...
- Unity粒子系统特性
经代码测试分析,unity粒子系统 Shiruken粒子系统的可编程性比较差.所有的Modules都无法通过代码控制. 可以用ParticleSystem.SetParticles设置粒子,但是设置进 ...
- mongoDB研究笔记:分片集群部署
前面几篇文章的分析复制集解决了数据库的备份与自动故障转移,但是围绕数据库的业务中当前还有两个方面的问题变得越来越重要.一是海量数据如何存储?二是如何高效的读写海量数据?尽管复制集也可以实现读写分析,如 ...
- MVC+EF6使用MySQL+CodeFirst的详细配置
环境: WIN7(64位旗舰版)+VS2012+MySQL5.6(32位版,在另一台服务器中,环境是win2003) 1.下载并安装MysqlforVisualStudio.zip,此软件功能是让VS ...
- Xamarin.Android绑定库分享
使用Xamarin.Android时,会用到各种第三方库,而这些库基本上是java编写的,要在Xamarin.Android中使用这些库,就需要通过Android Binding Project绑定对 ...
- 可在广域网部署运行的QQ高仿版 -- GG叽叽V3.4,增加系统设置、最近联系人、群功能(源码)
自从上次版本(GG叽叽V3.2,增加离线消息.离线文件功能)发布后,我个人觉得主要的大功能都实现得差不多了,接下来的几个版本将不断优化GG的细节,提高其可用性.这次版本更新的内容主要是为GG增加了系统 ...
- 算法:POJ1007 DNA sorting
这题比较简单,重点应该在如何减少循环次数. package practice; import java.io.BufferedInputStream; import java.util.Map; im ...
- SQL语句中,Conversion failed when converting datetime from character string.错误的解决办法
在项目开发过程中,我们经常要做一些以时间为条件的查询,比如查询指定时间范围内的历史记录,然而这些时间都是从UI传递过来的参数,所以我们写的sql语句就必须用到字符串拼接.当然,在C#中写SQL语句还好 ...
- 4、CC2541芯片中级教程-OSAL操作系统(简单AT指令实现+IIC软件和硬件实现驱动MPU6050)
本文根据一周CC2541笔记汇总得来—— 适合概览和知识快速索引—— 全部链接: 中级教程-OSAL操作系统\OSAL操作系统-实验01 OSAL初探 [插入]SourceInsight-工程建立方法 ...
- [ACM_动态规划] Palindrome
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28415#problem/D 题目大意:给一个长为n的字符串,问最少插入几个字符成回文串 ...