资料 简书 Weavey的三篇入门
https://www.jianshu.com/p/5e93c9101dc5
https://www.jianshu.com/p/240f1c8ebf9d
https://www.jianshu.com/p/5c221c58e141
简书 nanchen2251 的RxJava 2.0 专栏 2.0的新变化
https://www.jianshu.com/p/0cd258eecf60
扔物线 给 Android 开发者的 RxJava 详解
http://gank.io/post/560e15be2dca930e00da1083#toc_4
Season_zlc 给初学者的RxJava2.0教程(一)
https://www.jianshu.com/p/464fa025229e
贵公子 这是一篇 清晰 & 易懂的Rxjava 入门教程
https://blog.csdn.net/u013651026/article/details/79367606
RxAndroid 响应式框架介绍与使用说明
rxAndroid添加了Android的主线程,对android系统做了兼容
学习处理rxjava内存泄漏
解决RxJava内存泄漏(前篇):RxLifecycle详解及原理分析
Android架构中添加AutoDispose解决RxJava内存泄漏
添加依赖
dependencies {
// Android 支持 Rxjava
// 此处一定要注意使用RxJava2的版本
compile 'io.reactivex.rxjava2:rxjava:2.0.1'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
// Android 支持 Retrofit
compile 'com.squareup.retrofit2:retrofit:2.1.0'
// 衔接 Retrofit & RxJava
// 此处一定要注意使用RxJava2的版本
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
// 支持Gson解析
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
}
写一个简单的rxjava实例
@BindView(R.id.ev_name)
EditText evName;
@BindView(R.id.ev_password)
EditText evPassword;
@BindView(R.id.progressBar)
ProgressBar progressBar;
private static final String TAG = "MainActivity";
@OnClick({R.id.b_login})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.b_login:
Log.i(TAG, "onViewClicked: clicked");
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
Log.i(TAG, "subscribe: send value=" + "aaa");
emitter.onNext("aaa");
Log.i(TAG, "subscribe: send value=" + "123456");
emitter.onNext("123456");
Log.i(TAG, "subscribe: completed");
emitter.onComplete();
}
}).subscribe(new Observer() {
int i = 0;
@Override
public void onSubscribe(Disposable d) {
Log.i(TAG, "onSubscribe: start receive");
progressBar.setVisibility(View.VISIBLE);
}
@Override
public void onNext(String s) {
i++;
Log.i(TAG, "onNext: s=" + s);
switch (i) {
case 1:
evName.setText(s);
break;
case 2:
evPassword.setText(s);
break;
}
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
progressBar.setVisibility(View.GONE);
Log.i(TAG, "onComplete: receive completed");
}
});
break;
}
控制台输出
MainActivity: onViewClicked: clicked
onSubscribe: start receive
subscribe: send value=aaa
MainActivity: onNext: s=aaa
MainActivity: subscribe: send value=123456
onNext: s=123456
MainActivity: subscribe: completed
MainActivity: onComplete: receive completed
记得添加网络权限
问题1 程序崩溃问题
•背景:在发送网络请求时 退出当前Activity
•冲突:此时如果回到主线程更新 UI,App会崩溃
这是由于网络连接,数据库拉取等耗时操作应该在后台线程,更新UI操作需要回到主线程
不指定线程的时候,默认事件的生产和消费是在当前同一个线程
解决办法,指定线程
observable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe();
常用的线程
• Schedulers.io() 代表io操作的线程, 通常用于网络,读写文件等io密集型的操作;
• Schedulers.computation() 代表CPU计算密集型的操作, 例如需要大量计算的操作;
• Schedulers.newThread() 代表一个常规的新线程;
• AndroidSchedulers.mainThread() 代表Android的主线程
Schedulers.immediate() 作用于当前线程运行,相当于你在哪个线程执行代码就在哪个线程运行
问题 2 内存泄漏
暂未更改,具体请参考上方链接
第三方库RxLifecycle以及最新的AutoDispose库
解决RxJava内存泄漏(前篇):RxLifecycle详解及原理分析
Android架构中添加AutoDispose解决RxJava内存泄漏
即使注册了RxLifecycle,rxjava自己解除绑定,叶辉保证执行Observer的onComplete()方法,onCompleted()中需要对控件id判别null
<--特别注意:2种方法的区别,即Subscriber 抽象类与Observer 接口的区别 -->
// 相同点:二者基本使用方式完全一致(实质上,在RxJava的 subscribe 过程中,Observer总是会先被转换成Subscriber再使用)
// 不同点:Subscriber抽象类对 Observer 接口进行了扩展,新增了两个方法:
// 1. onStart():在还未响应事件前调用,用于做一些初始化工作
// 2. unsubscribe():用于取消订阅。在该方法被调用后,观察者将不再接收 & 响应事件
// 调用该方法前,先使用 isUnsubscribed() 判断状态,确定被观察者Observable是否还持有观察者Subscriber的引用,
解决办法1当 Activity退出时,在onDestory()方法中,调用 Disposable.dispose()切断观察者和被观察者的连接,使得观察者无法收到事件 & 响应事件
当出现多个Disposable时,可采用RxJava内置容器CompositeDisposable进行统一管理
先初始化一个容器
每次订阅都要把新订阅产生的disposable添加到容器CompositeDisposable
在ondestory中清空容器
//CompositeDisposable容器获取
compositeDisposable = new CompositeDisposable();
// 添加Disposable到CompositeDisposable容器
compositeDisposable.add()
// 清空CompositeDisposable容器
compositeDisposable.clear()
Disposable的获取
一种是消费者
disposable = ...().subscribe(new Consumer() {
@Override
public void accept(String s) throws Exception {
progressBar.dismiss();
if (s.length() == 0) {
layoutResultNone.setVisibility(View.VISIBLE);
} else {
layoutResult.setVisibility(View.VISIBLE);
tvBrokerNameValue.setText(s);
tvPhoneNumberValue.setText(query);
}
}
});
一种是标准的被观察者
...().subscribe(new Observer>() {
Disposable mDisposable;
@Override
public void onSubscribe(Disposable d) {
mDisposable=d;
//compositeDisposable.add(d);
}
}
解决办法2
用RxLifecycle组件解决
Activity/Fragment需继承RxAppCompatActivity/RxFragment,目前支持的有RxAppCompatActivity、RxFragment、RxDialogFragment、RxFragmentActivity。
参考https://www.jianshu.com/p/7fae42861b8d
绑定订阅关系时,在subscribeOn方法之后使用compose操作符,这样在活动销毁时,会自动解除订阅关系
依赖
implementation 'com.trello.rxlifecycle2:rxlifecycle-components:2.2.2'
使用
public class MainActivity extends RxAppCompatActivity{
...
//默认onDestory()中解除订阅
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(this.>bindToLifecycle())
.subscribe();
//指定在pause中解除订阅
//还可以指定在create...等生命阶段
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(this.>bindUntilEvent(ActivityEvent.PAUSE))
.subscribe();
}
Rxjava
更多技巧,参考
https://gank.io/post/560e15be2dca930e00da1083#toc_6
map()变换
防抖动 防止重复发起同一个请求
throttleFirst()
: 在每次事件触发后的一定时间间隔内丢弃新的事件。常用作去抖动过滤,例如按钮的点击监听器:RxView.clickEvents(button) // RxBinding 代码,后面的文章有解释 .throttleFirst(500, TimeUnit.MILLISECONDS) // 设置防抖间隔为 500ms .subscribe(subscriber);
妈妈再也不怕我的用户手抖点开两个重复的界面啦。
更多操作符资料,参考https://www.jianshu.com/p/8426d4778546
doOnSubscribe() 用于在发送开始前,显示一个进度条
在前面讲 Subscriber
的时候,提到过 Subscriber
的 onStart()
可以用作流程开始前的初始化。然而 onStart()
由于在 subscribe()
发生时就被调用了,因此不能指定线程,而是只能执行在 subscribe()
被调用时的线程。这就导致如果 onStart()
中含有对线程有要求的代码(例如在界面上显示一个 ProgressBar,这必须在主线程执行),将会有线程非法的风险,因为有时你无法预测 subscribe()
将会在什么线程执行。
而与 Subscriber.onStart()
相对应的,有一个方法 Observable.doOnSubscribe()
。它和 Subscriber.onStart()
同样是在 subscribe()
调用后而且在事件发送前执行,但区别在于它可以指定线程。默认情况下, doOnSubscribe()
执行在 subscribe()
发生的线程;而如果在 doOnSubscribe()
之后有 subscribeOn()
的话,它将执行在离它最近的 subscribeOn()
所指定的线程。
Observable.create(onSubscribe)
.subscribeOn(Schedulers.io())
.doOnSubscribe(new Action0() {
@Override
public void call() {
progressBar.setVisibility(View.VISIBLE); // 需要在主线程执行
}
})
.subscribeOn(AndroidSchedulers.mainThread()) // 指定主线程
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
如上,在 doOnSubscribe()
的后面跟一个 subscribeOn()
,就能指定准备工作的线程了。
具体线程参考这里 RxJava中的doOnSubscribe默认执行线程分析
没有doOnSubscribe()的时候,subscribeOn()
只有第一次起作用
有doOnSubscribe()的时候,doOnSubscribe()会被之后的第一个subscribeOn()改变指定线程
多个doOnSubscribe()的时候,执行顺序是按照从下向上的顺序执行的
防抖动
在指定时间(6s)内,只发送第一个点击事件,6s内后续的点击事件抛弃
实现方法1
在onClick()方法中自己计算时间自己计算时间
private long lastClickTime = 0;
//1、上次点击的时间
@Override
public void onClick(View v) {
//2、判断距离上次点击小于2秒
if (System.currentTimeMillis() - lastClickTime <= 2000) {
//3、记录这次点击时间
lastClickTime = System.currentTimeMillis();
}
}
实现方法2
利用throttleFirst操作符
不过需要引入对应控件的rxBinding库,利用rxBinding把点击事件转换成observable才能实现
实现方法3
自己实现一个定时器
,模仿throttleFirst操作符,每次发起网络请求时,自己启动一个定时器,当定时器计时耗尽,才允许发起新的网络请求
不过需要注意在活动的onDestroy()方法中及时释放线程,以免内存泄漏.
map和flatMaap区分
1、map和flatMap都是接受一个函数作为参数(Func1)
2、map函数只有一个参数,参数一般是Func1,Func1的< I,O >I,O模版分别为输入和输出值的类型,实现Func1的call方法对I类型进行处理后返回O类型数据
3、flatMap函数也只有一个参数,也是Func1,Func1的< I,O >I,O模版分别为输入和输出值的类型,实现Func1的call方法对I类型进行处理后返回O类型数据,不过这里O为Observable类型