引言:
说到异步操作,我们会想到Android的AsyncTask和Handler。今天我们要说的是RxJava............2
观察者模式(Observer)完美的将观察者和被观察的对象分离开。举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。一对多(一对多,即一个被观察者可以被多个观察者监听。)
响应式编程在RxJava中,响应式编程具体表现为一个观察者(Observer)订阅一个可观察对象(Observable),通过创建可观察对象发射数据流,经过一系列操作符(Operators)加工处理和线程调度器(Scheduler)在不同线程间的转发,最后由观察者接受并做出响应的一个过程。
RxJava2的基本使用
在 build.gradle 中加上:
compile 'io.reactivex.rxjava2:rxjava:2.0.1' compile 'io.reactivex.rxjava2:rxandroid:2.0.1' |
创建RxJava三步曲:
1.创建被观察者对象Observable;
2.创建观者对象Observer;
3.创建订阅关系;
private void testOne() {
//创建被观察者对象
Observable observable = Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
e.onNext("hello");
Log.i("testOne", "发送 hello");
e.onNext("world");
Log.i("testOne", "发送 world");
e.onComplete();
Log.i("testOne", "调用 onComplete");
}
});
//创建观者对象
Observer observer = new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log.d("testOne", "onSubscribe");
disposable = d;
}
@Override
public void onNext(String s) {
Log.d("testOne", "onNext data is :" + s);
if (s.equals("hello")) {
disposable.dispose();//取消订阅
}
}
@Override
public void onError(Throwable e) {
Log.d("testOne", "onError data is :" + e.toString());
}
@Override
public void onComplete() {
Log.d("testOne", "onComplete");
}
};
//创建订阅关系
observable.subscribe(observer);
}
onNext:用来发送数据,可多次调用,每调用一次发送一条数据
onError:用来发送异常通知,只发送一次,若多次调用只发送第一条
onComplete:用来发送完成通知,只发送一次,若多次调用只发送第一条
onError与onComplete互斥,两个方法只能调用一个不能同时调用
RxJava2的线程调度器
Scheduler(调度器),它是RxJava用来控制线程。
当我们没有设置的时候,RxJava遵循哪个线程产生就在哪个线程消费的原则,也就是说线程不会产生变化,始终在同一个。
但是我们一般使用RxJava都是后台执行,前台调用。
RxJava 线程调度器 | 说明 |
Schedulers.io( ) | 用于IO密集型的操作,例如读写SD卡文件,查询数据库,访问网络等,具有线程缓存机制,在此调度器接收到任务后,先检查线程缓存池中,是否有空闲的线程,如果有,则复用,如果没有则创建新的线程,并加入到线程池中,如果每次都没有空闲线程使用,可以无上限的创建新线程。 |
Schedulers.newThread( ) | 在每执行一个任务时创建一个新的线程,不具有线程缓存机制,因为创建一个新的线程比复用一个线程更耗时耗力,虽然使用Schedulers.io( )的地方,都可以使用Schedulers.newThread( ),但是,Schedulers.newThread( )的效率没有Schedulers.io( )高。 |
Schedulers.computation() | 用于CPU 密集型计算任务,即不会被 I/O 等操作限制性能的耗时操作,例如xml,json文件的解析,Bitmap图片的压缩取样等,具有固定的线程池,大小为CPU的核数。不可以用于I/O操作,因为I/O操作的等待时间会浪费CPU。 |
Schedulers.trampoline() | 在当前线程立即执行任务,如果当前线程有任务在执行,则会将其暂停,等插入进来的任务执行完之后,再将未完成的任务接着执行。 |
Schedulers.single() | 拥有一个线程单例,所有的任务都在这一个线程中执行,当此线程中有任务执行时,其他任务将会按照先进先出的顺序依次执行。 |
Scheduler.from(@NonNull Executor executor) | 指定一个线程调度器,由此调度器来控制任务的执行策略 |
AndroidSchedulers.mainThread() | 在Android UI线程中执行任务,为Android开发定制。RxAndroid 提供 |
注:在RxJava2中,废弃了RxJava1中的Schedulers.immediate( )在RxJava1中,Schedulers.immediate( )的作用为在当前线程立即执行任务,功能等同于RxJava2中的Schedulers.trampoline( )。而Schedulers.trampoline( )在RxJava1中的作用是当其它排队的任务完成后,在当前线程排队开始执行接到的任务,有点像RxJava2中的Schedulers.single(),但也不完全相同,因为Schedulers.single()不是在当前线程而是在一个线程单例中排队执行任务。
private void testTwo() {
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
Log.e("testTwo", "observable work thread is" + Thread.currentThread().getName());
e.onNext("hello");
e.onNext("world");
e.onComplete();
}
}).subscribeOn(Schedulers.io())//切换到io线程
.observeOn(AndroidSchedulers.mainThread())//切换到主线程
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log.e("testTwo", "Observer onSubscribe work thread is" + Thread.currentThread().getName());
disposable = d;
}
@Override
public void onNext(String s) {
Log.e("testTwo", "Observer onNext work thread is" + Thread.currentThread().getName());
Log.d("testTwo", "onNext data is :" + s);
}
@Override
public void onError(Throwable e) {
Log.d("testTwo", "onError data is :" + e.toString());
}
@Override
public void onComplete() {
Log.d("testTwo", "onComplete");
}
});
}
RxJava2的操作符
RxJava的强大性就来自于它所定义的操作符。
操作符图谱:
场景1:做一个倒计时发送验证码的按钮
Demo中所有到的操作符:
操作符 | 说明 |
interval | 延时几秒,每隔几秒开始执行 |
take | 超过多少秒停止执行 |
map | 类型转换 |
doOnSubscribe | 在执行的过程中 |
public void testThree() {
final long count = 10; // 设置10秒
Observable.interval(0, 1, TimeUnit.SECONDS)//延时几秒,每隔几秒开始执行
.take(count + 1)//超过多少秒停止执行
.map(new Function<Long, String>() {//类型转换 map操作符通过指定一个Func对象,将Observable转换为一个新的Observable对象并发射,观察者将收到新的Observable处理。
@Override
public String apply(Long aLong) throws Exception {
Log.i("testThree", "aLong=" + aLong);
return String.valueOf(count - aLong).toString();
}
})
.observeOn(AndroidSchedulers.mainThread())//在主线程运行
.doOnSubscribe(new Consumer<Disposable>() {//在执行的过程中
@Override
public void accept(@NonNull Disposable disposable) throws Exception {
button.setEnabled(false);
button.setTextColor(Color.GRAY);
}
})
.subscribe(new Observer<String>() {//订阅
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String aLong) {
button.setText(aLong);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
button.setEnabled(true);
button.setTextColor(Color.RED);
button.setText("发送验证码");
}
});
}
场景2:我们假设有这个一场景:每个学校都有成绩统计系统,有这样一个需求,我们要抽取一个班,打印该班的每个同学的每一门课程成绩。
操作符 | 说明 |
fromIterable | 逐次发射list的中的数据 |
flatMap | 将一个Observable转换为另一个Observable发射出去 |
private void newTest() {
Observable.fromIterable(getStudents())//逐次发射list的中的数据
.flatMap(new Function<Student, ObservableSource<Source>>() {
@Override
public ObservableSource<Source> apply(Student student) throws Exception {
return Observable.fromIterable(student.mSources);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Source>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Source source) {
String content = "sourceName:" + source.name + " source score:" + source.score;
Log.i("newTest", content);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
场景...:RxJava的操作符很强大,根据不同场景不同需求,自由组合,天空才是它的极限。
总结:
传统是自己主动控制去得到数据,主动控制数据得流向(展示/参数),然后将数据和数据的流向代码组装起来。Rxjava中的响应式编程是被观察者拿到数据主动传递给观察者,将展示层和数据处理层分离,解耦了各个模块,通过不同线程操控代码运作配合变换过滤等api操作实现数据流传播。
异步、简洁(逻辑、代码读写)。内部支持多线程操作,强大的map和flatmap保证了依赖上一次接口数据进行二次处理时不会发生嵌套,将各个模块分离。随着程序逻辑的复杂,依然保持简洁。解耦了各个模块操作,单一化,不嵌套
源码:
package com.example.semisky.rxjavademostu;
import android.graphics.Color;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import org.reactivestreams.Publisher;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import io.reactivex.Flowable;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.ObservableSource;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
public class MainActivity extends AppCompatActivity {
private Button button;
private Disposable disposable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.send_sms);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//testOne();
//testTwo();
//testThree();
//oldTest();
newTest();
}
});
}
private void testOne() {
//创建被观察者对象
Observable observable = Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
e.onNext("hello");
Log.i("testOne", "发送 hello");
e.onNext("world");
Log.i("testOne", "发送 world");
e.onComplete();
Log.i("testOne", "调用 onComplete");
}
});
//创建观者对象
Observer observer = new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log.d("testOne", "onSubscribe");
disposable = d;
}
@Override
public void onNext(String s) {
Log.d("testOne", "onNext data is :" + s);
if (s.equals("hello")) {
disposable.dispose();//取消订阅
}
}
@Override
public void onError(Throwable e) {
Log.d("testOne", "onError data is :" + e.toString());
}
@Override
public void onComplete() {
Log.d("testOne", "onComplete");
}
};
//创建订阅关系
observable.subscribe(observer);
}
private void testTwo() {
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
Log.e("testTwo", "observable work thread is" + Thread.currentThread().getName());
e.onNext("hello");
e.onNext("world");
e.onComplete();
}
}).subscribeOn(Schedulers.io())//切换到io线程
.observeOn(AndroidSchedulers.mainThread())//切换到主线程
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log.e("testTwo", "Observer onSubscribe work thread is" + Thread.currentThread().getName());
disposable = d;
}
@Override
public void onNext(String s) {
Log.e("testTwo", "Observer onNext work thread is" + Thread.currentThread().getName());
Log.d("testTwo", "onNext data is :" + s);
}
@Override
public void onError(Throwable e) {
Log.d("testTwo", "onError data is :" + e.toString());
}
@Override
public void onComplete() {
Log.d("testTwo", "onComplete");
}
});
}
public void testThree() {
final long count = 10; // 设置10秒
Observable.interval(0, 1, TimeUnit.SECONDS)//延时几秒,每隔几秒开始执行
.take(count + 1)//超过多少秒停止执行
.map(new Function<Long, String>() {//类型转换 map操作符通过指定一个Func对象,将Observable转换为一个新的Observable对象并发射,观察者将收到新的Observable处理。
@Override
public String apply(Long aLong) throws Exception {
Log.i("testThree", "aLong=" + aLong);
return String.valueOf(count - aLong).toString();
}
})
.observeOn(AndroidSchedulers.mainThread())//在主线程运行
.doOnSubscribe(new Consumer<Disposable>() {//在执行的过程中
@Override
public void accept(@NonNull Disposable disposable) throws Exception {
button.setEnabled(false);
button.setTextColor(Color.GRAY);
}
})
.subscribe(new Observer<String>() {//订阅
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String aLong) {
button.setText(aLong);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
button.setEnabled(true);
button.setTextColor(Color.RED);
button.setText("发送验证码");
}
});
}
class Student {
public String name;//学生名字
public int id;
public List<Source> mSources;//每个学生的所有课程
public Student(String name, int id, List<Source> sources) {
this.name = name;
this.id = id;
mSources = sources;
}
}
class Source {
public int sourceId;//id
public String name;//课程名
public int score;//成绩
public Source(int sourceId, String name, int score) {
this.sourceId = sourceId;
this.name = name;
this.score = score;
}
}
private void oldTest() {
//开启一个线程
new Thread(new Runnable() {
@Override
public void run() {
// 模拟从服务器获取班级所有同学信息
List<Student> students = getStudents();
for (int i = 0; i < students.size(); i++) {
List<Source> sources = students.get(i).mSources;
Log.i("oldTest====", sources.size() + "name:" + students.get(i).name);
for (int index = 0; index < sources.size(); index++) {
final Source source = sources.get(index);
runOnUiThread(new Runnable() {
@Override
public void run() {
//主线程更改UI
String content = "sourceName:" + source.name + " source score:" + source.score;
Log.i("oldTest", content);
}
});
}
}
}
}).start();
}
private void newTest() {
Observable.fromIterable(getStudents())//逐次发射list的中的数据
.flatMap(new Function<Student, ObservableSource<Source>>() {
@Override
public ObservableSource<Source> apply(Student student) throws Exception {
return Observable.fromIterable(student.mSources);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Source>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Source source) {
String content = "sourceName:" + source.name + " source score:" + source.score;
Log.i("newTest", content);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
private List<Student> getStudents() {
List<Student> students = new ArrayList<>();
for (int i = 0; i < 2; i++) {
List<Source> sources = new ArrayList<>();
for (int j = 0; j < 3; j++) {
sources.add(new Source(j, "学科" + j, 80 + j));
}
students.add(new Student("李" + i, i, sources));
}
return students;
}
}