我们很懒,所以我们就开发了很多很多的框架,用来节省我们的工作量、工作时间。异步操作难免是避不开的,官方提供的Handler机制以及AsyncTask ,都能实现异步操作,但是代码随着逻辑的增多而变得复杂,看上去混乱不堪有时候简直,所以,简洁高效的代码也是我们的追求。因此,为了异步,为了简洁,RxJava应运而生,来解决了以上的问题。
1.RxJava 地址以及添加
github地址:
https://github.com/ReactiveX/RxJava
https://github.com/ReactiveX/RxAndroid
依赖库添加:
compile ‘io.reactivex:rxjava:1.1.6’
compile ‘io.reactivex:rxandroid:1.2.1’
2.RxJava的用法示例
RxJava 有四个基本概念:Observable (可观察者,即被观察者)、 Observer (观察者)、 subscribe (订阅)、事件。Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer。
与传统观察者模式不同, RxJava 的事件回调方法除了普通事件 onNext() (相当于 onClick() / onEvent())之外,还定义了两个特殊的事件:onCompleted() 和 onError()。
onCompleted(): 事件队列完结。RxJava 不仅把每个事件单独处理,还会把它们看做一个队列。RxJava 规定,当不会再有新的 onNext() 发出时,需要触发 onCompleted() 方法作为标志。
onError(): 事件队列异常。在事件处理过程中出异常时,onError() 会被触发,同时队列自动终止,不允许再有事件发出。
在一个正确运行的事件序列中, onCompleted() 和 onError() 有且只有一个,并且是事件序列中的最后一个。需要注意的是,onCompleted() 和 onError() 二者也是互斥的,即在队列中调用了其中一个,就不应该再调用另一个。
2-1:基本实现
先来看一下最基础的用法,
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber super String> subscriber) {
Log.d(TAG, "call: threadId:"+Thread.currentThread().getId());
subscriber.onStart();
subscriber.onNext("Hello World!");
subscriber.onCompleted();
}
})
.subscribe(new Observer<String>() {
@Override
public void onCompleted() {
Log.d(TAG, "onCompleted: threadId:"+Thread.currentThread().getId());
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "onError: threadId:"+Thread.currentThread().getId());
}
@Override
public void onNext(String s) {
Log.d(TAG, "onNext: threadId:"+Thread.currentThread().getId());
Log.i(TAG, "onNext: s = "+s);
}
});
打印的结果如下所示:
09-03 11:43:57.322 16813-16813/? D/RxIavaDemo: call: threadId:1
09-03 11:43:57.322 16813-16813/? D/RxIavaDemo: onNext: threadId:1
09-03 11:43:57.322 16813-16813/? I/RxIavaDemo: onNext: s = Hello World!
09-03 11:43:57.322 16813-16813/? D/RxIavaDemo: onCompleted: threadId:1
从上可以看出,事件的处理和结果的接收都是在同一个线程里面处理的。但是,Rxjava的意义何在,异步呢?别急,看以下代码的处理,你就会发现了,异步原来是这么的简单。
Log.i(TAG, "testFunction: threadId:"+Thread.currentThread().getId());
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber super String> subscriber) {
Log.d(TAG, "call: threadId:"+Thread.currentThread().getId());
subscriber.onStart();
subscriber.onNext("Hello World!");
subscriber.onCompleted();
}})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
@Override
public void onCompleted() {
Log.d(TAG, "onCompleted: threadId:" + Thread.currentThread().getId());
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "onError: threadId:" + Thread.currentThread().getId());
}
@Override
public void onNext(String s) {
Log.d(TAG, "onNext: threadId:" + Thread.currentThread().getId());
Log.i(TAG, "onNext: s = " + s);
}
});
对比以上代码,我们简简单单的添加了两行代码:
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
那么接下俩看以下打印的结果如何:
09-03 11:51:11.354 18454-18454/? I/RxIavaDemo: testFunction: threadId:1
09-03 11:51:11.413 18454-18484/? D/RxIavaDemo: call: threadId:24076
09-03 11:51:11.444 18454-18454/? D/RxIavaDemo: onNext: threadId:1
09-03 11:51:11.444 18454-18454/? I/RxIavaDemo: onNext: s = Hello World!
09-03 11:51:11.444 18454-18454/? D/RxIavaDemo: onCompleted: threadId:1
看见了没,第二行threadId与其它的threadId很明显的不一样啊,说明我们在处理事件的时候,发生在了一个新的线程里面,而结果的接收,还是在主线程里面操作的。怎么样,只要添加两句话,异步立马就实现了,异步处理耗时操作,就是这么easy。
以上是RxJava的很基础很简单的一个用法,那么我们接着往下看,比如我们有一组需求把一个String数组的字符串,单个打印出来,我们用Rxjava怎么实现呢?看代码:
Log.i(TAG, "testFunction: threadId:"+Thread.currentThread().getId());
Observable.from(new String[]{"one","two","three","four"})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
@Override
public void onCompleted() {
Log.d(TAG, "onCompleted: threadId:" + Thread.currentThread().getId());
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "onError: threadId:" + Thread.currentThread().getId());
}
@Override
public void onNext(String s) {
Log.i(TAG, "onNext: s = " + s);
}
});
Observable的from方法是给我们封装好的,我们直接拿来用就可以了。具体参数含义以后再说,打印的结果看下:
09-03 11:59:40.799 20463-20463/? I/RxIavaDemo: testFunction: threadId:1
09-03 11:59:40.838 20463-20463/? I/RxIavaDemo: onNext: s = one
09-03 11:59:40.838 20463-20463/? I/RxIavaDemo: onNext: s = two
09-03 11:59:40.838 20463-20463/? I/RxIavaDemo: onNext: s = three
09-03 11:59:40.838 20463-20463/? I/RxIavaDemo: onNext: s = four
09-03 11:59:40.838 20463-20463/? D/RxIavaDemo: onCompleted: threadId:1
再来看一个官方提供的方法:
Log.i(TAG, "testFunction: threadId:"+Thread.currentThread().getId());
Observable.just("one","two","three","four")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
@Override
public void onCompleted() {
Log.d(TAG, "onCompleted: threadId:" + Thread.currentThread().getId());
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "onError: threadId:" + Thread.currentThread().getId());
}
@Override
public void onNext(String s) {
Log.i(TAG, "onNext: s = " + s);
}
});
打印结果如下:
09-03 14:06:32.051 9822-9822/? I/RxIavaDemo: testFunction: threadId:1
09-03 14:06:32.089 9822-9822/? I/RxIavaDemo: onNext: s = one
09-03 14:06:32.089 9822-9822/? I/RxIavaDemo: onNext: s = two
09-03 14:06:32.089 9822-9822/? I/RxIavaDemo: onNext: s = three
09-03 14:06:32.089 9822-9822/? I/RxIavaDemo: onNext: s = four
09-03 14:06:32.089 9822-9822/? D/RxIavaDemo: onCompleted: threadId:1
和上面的from一样,结果并无二致。
2-2:转换
以上的都是小儿科,现在最牛逼的地方来了。比如说,我想把一组字符串{“1”,“2”,“3”,“4”}转成int类型,该咋办呢?别急,看Rxjava是如何做到的,
Log.i(TAG, "testFunction: threadId:"+Thread.currentThread().getId());
Observable.just("1","2","3","4")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map(new Func1<String, Integer>() {
@Override
public Integer call(String s) {
return Integer.parseInt(s);
}
})
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
Log.i(TAG, "call: integer = "+integer);
}
});
很简单,添加一个map函数,在里面做string—>int类型的转换。下面看一下打印结果如何:
09-03 14:17:42.964 11974-11974/? I/RxIavaDemo: testFunction: threadId:1
09-03 14:17:43.002 11974-11974/? I/RxIavaDemo: call: integer = 1
09-03 14:17:43.002 11974-11974/? I/RxIavaDemo: call: integer = 2
09-03 14:17:43.002 11974-11974/? I/RxIavaDemo: call: integer = 3
09-03 14:17:43.002 11974-11974/? I/RxIavaDemo: call: integer = 4
map转换,是一对一的转换,像示例当中,我们把string转成int,但是当我们需要一对多的转换,该怎么做呢?比如说,定义一个学生类:Student.java:
public class Student{
private String name;
private List courses;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List getCourses() {
return courses;
}
public void setCourses(List courses) {
this.courses = courses;
}
}
里面定义了学生的名字,以及学生需要学习的课程数组。这个时候,我要打印课程列表的时候,该怎么办呢?首先,你可能会这样,
Student student1 = new Student();
student1.setName("Dandy");
List<String> courses = new ArrayList<>();
courses.add("语文");
courses.add("数学");
courses.add("英语");
student1.setCourses(courses);
Student student2 = new Student();
student2.setName("Seeker");
List<String> courses2 = new ArrayList<>();
courses2.add("化学");
courses2.add("地理");
courses2.add("政治");
student2.setCourses(courses2);
Observable.just(student1,student2)
.subscribe(new Action1<Student>() {
@Override
public void call(Student student) {
Log.i(TAG, "call: name = "+student.getName());
List<String> course = student.getCourses();
for(String str:course){
Log.i(TAG, "call: str = "+str);
}
}
});
打印的结果如下:
09-03 14:44:30.318 16819-16819/? I/RxIavaDemo: testFunction: threadId:1
09-03 14:44:30.325 16819-16819/? I/RxIavaDemo: call: name = Dandy
09-03 14:44:30.325 16819-16819/? I/RxIavaDemo: call: str = 语文
09-03 14:44:30.325 16819-16819/? I/RxIavaDemo: call: str = 数学
09-03 14:44:30.325 16819-16819/? I/RxIavaDemo: call: str = 英语
09-03 14:44:30.325 16819-16819/? I/RxIavaDemo: call: name = Seeker
09-03 14:44:30.325 16819-16819/? I/RxIavaDemo: call: str = 化学
09-03 14:44:30.325 16819-16819/? I/RxIavaDemo: call: str = 地理
09-03 14:44:30.325 16819-16819/? I/RxIavaDemo: call: str = 政治
到时候想了,我不想执行一个for循环,该怎么办呢?上面提到的,转换,对了,我们做转换不就成,简单的通俗的一点理解,我转换一次,是list,那么我再转换一次不就是string了吗,怎么写呢?看下嘛:
Observable.just(student1,student2)
.flatMap(new Func1>() {
@Override
public Observable call(Student student) {
return Observable.from(student.getCourses());
}
})
.subscribe(new Action1() {
@Override
public void call(String s) {
Log.i(TAG, "call: s = "+s);
}
});
这里我们用到了flatmap这一函数,按通俗的一点理解:我们首先把Student转成了Observable,然后呢,又把student.getCourses()转成string挨个打印出来,结果如下:
09-03 14:54:30.340 18833-18833/? I/RxIavaDemo: testFunction: threadId:1
09-03 14:54:30.359 18833-18833/? I/RxIavaDemo: call: s = 语文
09-03 14:54:30.359 18833-18833/? I/RxIavaDemo: call: s = 数学
09-03 14:54:30.359 18833-18833/? I/RxIavaDemo: call: s = 英语
09-03 14:54:30.359 18833-18833/? I/RxIavaDemo: call: s = 化学
09-03 14:54:30.359 18833-18833/? I/RxIavaDemo: call: s = 地理
09-03 14:54:30.359 18833-18833/? I/RxIavaDemo: call: s = 政治
显然,我们要实现的功能做到了。
RxJava就是这么简单,就是这样简洁,就是这么异步,额,这个异步吗,只要你想,就一定可以实现,通过以上简单的用法示例,现总结流程如下:
总结不一定准确,但是我理解就行了,嘎嘎!