项目小版本上线,抽空简单学习了下久仰大名的RxJavahtml
1、引入
我的以为rxjava的特色:
- 强大灵活的事件流处理(多线程/多事件/复合对象)
- 强大灵活优雅简洁的异步
- 链式调用
- 可自动Lambda化
实现:RxJava 是经过一种扩展的观察者模式来实现的
类比 |
类比 |
实际 |
实际 |
职责 |
演讲者 |
Button |
(可)被订阅者
(同右)
|
(可)被观察者
Observable
|
决定何时触发事件以及触发怎样的事件 |
听众 |
OnClickListener |
订阅者
Subscriber
|
观察者
Observer
|
决定事件触发的时候将有怎样的行为 |
买票 |
setOnClickListener() |
订阅
subscribe
|
注册 |
|
命令 |
onClick() |
事件 |
事件 |
|
演讲者只有Observable一种类,可是听众有Subscriber和Observer两种类,有点跟演讲者一个听众不少相似
与传统观察者模式不一样, RxJava 的事件回调方法除了普通事件 onNext() (至关于 onClick() / onEvent())以外,还定义了两个特殊的事件:onCompleted() 和 onError()。
- 不少onNext()
- onCompleted(): 事件队列完结。RxJava 不只把每一个事件单独处理,还会把它们看作一个队列。RxJava 规定,当不会再有新的onNext() 发出时,须要触发 onCompleted() 方法做为标志。
- onError(): 事件队列异常。在事件处理过程当中出异常时,onError() 会被触发,同时队列自动终止,不容许再有事件发出。
在一个正确运行的事件序列中, onCompleted() 和 onError() 有且只有一个,而且是事件序列中的最后一个。须要注意的是,onCompleted() 和 onError() 两者也是互斥的,即在队列中调用了其中一个,就不该该再调用另外一个。
2、实现方式
步骤:
- 建立演讲者
- 建立听众
- 买票
一、建立演讲者
建立演讲者的方式有点特殊,它不是经过new的方法,而是经过一系列不一样的内部静态工厂方法来建立的,最普通的有create( ) 方法
1.1.create( ) 方法建立
- 不是经过new的方法,而是一个内部静态工厂方法create( )来建立,这个方法须要传入一个 OnSubscribe 对象做为参数
- 不过换个角度,把它当成一个须要传入一个参数的构造方法就行了(虽然内部是有点其余货的)
- 方法具体是:Observable<T> create ( OnSubscribe<T> f )
- 这个 OnSubscribe 类自己是Observable的内部类
- 这个对象在create( )时传入后会存储在返回的 Observable 对象中
- 当 Observable 被订阅的时候,OnSubscribe 的 call() 方法会自动被调用
- 这个call方法会遍历传入全部的听众o,这些听众都实现了听众的那三个约定方法,在这里就能够执行本身须要的业务代码,并在须要的时候回调听众的那三个约定方法
- 换个角度说,OnSubscribe 的做用至关于一个计划表或者说事件发生器
- 这个泛型T是输出类型,也就是会传给听众的类型
简写:
Observable observable = Observable.create(new OnSubscribe() {
@Override
public void call(Object o) {
}
});
|
具体的实际的写法:
- 传入听众的表示格式是这样:Subscriber<? super String> subscriber(前面的泛型是string类)
- 这个例子很简单:
- 事件的内容是字符串,而不是一些复杂的对象
- 事件的内容是已经定好了的,而不像有的观察者模式同样是待肯定的(例如网络请求的结果在请求返回以前是未知的)
- 全部事件在一瞬间被所有发送出去,而不是夹杂一些肯定或不肯定的时间间隔或者通过某种触发器来触发的
Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello");
subscriber.onNext("Hi");
subscriber.onCompleted();
}
});
|
1.2.两个快捷建立静态工厂方法 just( ) , from( )
1.2.1.Observable<T> just( T t1, T t2 )
- 这个方法有10个重载,分别能够传入1个到10个参数(orz)
- 这是一个简便方法,会将传入的参数依次发送出来
- 能够写成基本的 create( ) 形式
Observable observable = Observable.just("Hello", "Hi");
|
等于上面的 create( ):
Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello");
subscriber.onNext("Hi");
subscriber.onCompleted();
}
});
|
1.2.2.
Observable<T> from( T[ ] array )
Observable<T> from( Iterable<? extends T> array )
- 将传入的数组或 Iterable 拆分红具体对象后,依次发送出来
- 能够写成基本的 create( ) 形式
String[] words = {"Hello", "Hi"};
Observable observable = Observable.from(words);
|
二、建立听众
这个有几种方式
2.1.经过rx包中的 Observer 接口
- 注意不是java中util包中的接口
Observer<String> observer = new Observer<String>() {
@Override
public void onNext(String s) {}
@Override
public void onCompleted() {}
@Override
public void onError(Throwable e) {}
};
|
2.2.经过rx包中的 Subscriber 抽象类[推荐]
- 它实现了 Observer 接口,并进行了一些扩展
- 使用方法跟Observer同样,并且必须实现的方法就是 Observer 接口中的方法,在订阅(subscribe)的时候,Observer 也老是会先被转换成一个 Subscriber 再使用,因此基本建议能够用Observer的地方都用Subscriber吧
- 这个抽象类扩展了两个可选的方法:
- onStart( )
- 它会在 subscribe 刚开始,而事件还未发送以前被调用,能够用于作一些准备工做,例如数据的清零或重置
- 须要注意的是,若是对准备工做的线程有要求(例如弹出一个显示进度的对话框,这必须在主线程执行), onStart() 就不适用了,由于它老是在 subscribe 所发生的线程被调用,而不能指定线程。要在指定的线程来作准备工做,可使用 doOnSubscribe() 方法
- unsubscribe( )
- 这个方法用于取消订阅。在这个方法被调用后,Subscriber 将再也不接收事件
- 通常在这个方法调用前,可使用 isUnsubscribed() 先判断一下状态
- unsubscribe() 这个方法很重要,由于在 subscribe() 以后, Observable 会持有 Subscriber 的引用,这个引用若是不能及时被释放,将有内存泄露的风险。因此最好保持一个原则:要在再也不使用的时候尽快在合适的地方(例如 onPause() onStop() 等方法中)调用unsubscribe() 来解除引用关系,以免内存泄露的发生
- 这个泛型T是输入类型,也就是听众能接收的类型
Subscriber<String> subscriber = new Subscriber<String>() {
@Override
public void onNext(String s) {}
@Override
public void onCompleted() {}
@Override
public void onError(Throwable e) {}
};
|
2.3.快捷建立方法:ActionX 接口[推荐]
听众也有快捷的建立方式,那就是经过ActionX 接口
- ActionX 接口有不少,Action0 和 Action1 最经常使用,还有Action2, Action3,X表明传入的参数的数目
- 他们实际上是对具备不一样传入参数、可是无返回值的方法的包装接口
- subscribe()会根据这些ActionX对象生成正常的Subscriber
以0和1为例
- Action0
- Action0 是 RxJava 的一个接口,它只有一个方法 call(),这个方法是无参无返回值的
- 因为 onCompleted() 方法也是无参无返回值的,所以 Action0 能够被当成一个包装对象,将 onCompleted() 的内容打包起来将本身做为一个参数传入 subscribe() 以实现不完整定义的回调
- 这样其实也能够看作将 onCompleted() 方法做为参数传进了subscribe(),至关于其余某些语言中的『闭包』
- Action1
- Action1 也是一个接口,它一样只有一个方法 call(T param),这个方法也无返回值,但有一个参数;
- 与 Action0 同理,因为 onNext(T obj) 和 onError(Throwable error) 也是单参数无返回值的,所以 Action1能够将 onNext(obj) 和 onError(error) 打包起来传入 subscribe() 以实现不完整定义的回调
正常使用方式是:
- new 出 action 对象
- 组合塞进 subsribe 方法
经过Action0、Action1构造三种方法的包装对象
// onNext()
Action1<String> action1 = new Action1<String>() {
@Override
public void call(String s) {}
};
// onError()
Action1<Throwable> action2 = new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {}
};
// onCompleted()
Action0 action3 = new Action0() {
@Override
public void call() {}
};
|
// 自动建立 Subscriber ,并使用 action1 来定义 onNext()
observable.subscribe(action1);
// 自动建立 Subscriber ,并使用 action1 和 action2 来定义 onNext() 和 onError()
observable.subscribe(action1, action2);
// 自动建立 Subscriber ,并使用 action一、 action2 和 action3 来定义 onNext()、 onError() 和 onCompleted()
observable.subscribe(action1, action2, action3);
|
若是只是要onNext( ) ,这样使用匿名类也很清晰
Observable.just("1","2","3")
.subscribe(new Action1<String>() {
@Override
public void call(String name) {
Log.d(tag, name);
}
});
|
三、买票(进行订阅)
建立了 Observable 和 Observer 以后,再用 subscribe() 方法将它们联结起来,整条链子就能够工做了
代码形式很简单:
observable.subscribe(subscriber);
|
- 有人可能会注意到, subscribe() 这个方法有点怪:它看起来是『observalbe 订阅了 subscriber』而不是『subscriber 订阅了 observalbe』,这看起来就像『杂志订阅了读者』同样颠倒了对象关系。这让人读起来有点别扭
- 由于若是把 API 设计成 subscriber.subscribe(observable) ,虽然更加符合思惟逻辑,但对流式 API 的设计就形成影响了,由于对于流事件,是有一个生产者和一系列消费者的,因此生产者放前边,后边跟一串消费者才是更流的形式
- 这种形式其实跟普通的java观察者模式很像,演讲者.add(听众)
3、快速使用及举例
使用rxjava首先是引入依赖:
1.基本的rxjava:
compile 'io.reactivex:rxjava:1.0.14'
2.带android特性的rxjava:
compile 'io.reactivex:rxandroid:1.0.1'
3.支持rxjava的网络加载库retrofit
compile 'com.squareup.retrofit:retrofit:1.9.0'
|
而后几个简单的例子:
1.真正最简单的例子:打印几个字符串
- 三步走
- 最简单的just方法
- 一个普通的subscriber
Observable.just("1","2","3").subscribe(new Subscriber<String>() {
@Override
public void onNext(String s) {
Log.d(tag, s);
}
@Override
public void onCompleted() {}
@Override
public void onError(Throwable e) {}
});
|
2.复杂一点点:给ImageView set 图片
- 需求:
- 实现:
- 仍是基本的三步走,稍微注意下格式(流式结构)
final Drawable drawable = getActivity().getResources().getDrawable(R.drawable.1);
final ImageView imageView = new ImageView(getActivity());
Observable.create(new Observable.OnSubscribe<Drawable>() {
@Override
public void call(Subscriber<? super Drawable> subscriber) {
subscriber.onNext(drawable);
subscriber.onCompleted();
}
}).subscribe(new Subscriber<Drawable>() {
@Override
public void onNext(Drawable drawable) {
imageView.setImageDrawable(drawable);
}
@Override
public void onCompleted() {}
@Override
public void onError(Throwable e) {
Log.d(tag, "error!");
}
});
|
4、线程控制:Scheduler 和 subscribeOn()、observeOn()
- 在不指定线程的状况下, RxJava 遵循的是线程不变的原则
- 即:在哪一个线程调用 subscribe(),就在哪一个线程生产事件;在哪一个线程生产事件,就在哪一个线程消费事件。
- 若是须要切换线程,就须要用到 Scheduler (调度器)
1.Scheduler
RxJava 经过Scheduler来指定每一段代码应该运行在什么样的线程
RxJava 已经内置了几个 Scheduler ,它们已经适合大多数的使用场景:
- Schedulers.immediate()
- 直接在当前线程运行,至关于不指定线程
- 这是默认的 Scheduler
- Schedulers.newThread()
- 老是启用新线程,并在新线程执行操做
- Schedulers.io( )
- I/O 操做(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler
- 行为模式和 newThread() 差很少,区别在于 io() 的内部实现是是用一个无数量上限的线程池,能够重用空闲的线程,所以多数状况下 io() 比 newThread() 更有效率
- 不要把计算工做放在 io() 中,能够避免建立没必要要的线程
- Schedulers.computation( )
- 计算所使用的 Scheduler,这个计算指的是 CPU 密集型计算,即不会被 I/O 等操做限制性能的操做,例如图形的计算
- 这个 Scheduler 使用的固定的线程池,大小为 CPU 核数
- 不要把 I/O 操做放在 computation() 中,不然 I/O 操做的等待时间会浪费 CPU
- Android 还有一个专用的 AndroidSchedulers.mainThread()
- 它指定的操做将在 Android 主线程运行
2.subscribeOn() 和 observeOn()
有了这几个 Scheduler ,就可使用 subscribeOn() 和 observeOn() 两个方法来对线程进行控制了
- subscribeOn( )
- 指定 subscribe() 所发生的线程,即 Observable.OnSubscribe 被激活时所处的线程
- 而这其实就是事件产生的线程,也就是Observable活动的线程
- (看到这难免有点乱,Observable活动在subscribeOn指定的线程,那这里就只能用[Observable.OnSubscribe 被激活]这件事来记了)
- observeOn( )
- 指定 Subscriber 所运行在的线程。或者叫作事件消费的线程
- (一样正好相反)
3.例子
Observable.just(1, 2, 3, 4)
.subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程
.observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer number) {
Log.d(tag, "number:" + number);
}
});
|
- 这种在subscribe() 以前写上两句 subscribeOn(Scheduler.io()) 和 observeOn(AndroidSchedulers.mainThread()) 的使用方式很是套路
- 它适用于多数的 『后台线程取数据,主线程显示』的程序策略
- 前面加载图片的代码中应该要加上这两句的
|
4.拓展
4.1.事件消费的线程可屡次变换
- observeOn() 指定的是 Subscriber 的线程,而这个 Subscriber 不必定是最终subscribe() 时的Subscriber ,而是 observeOn() 执行时的当前 Observable 所对应的 Subscriber ,即它的直接下级 Subscriber
- 换句话说,observeOn() 指定的是它以后的操做所在的线程
- 所以若是有屡次切换线程的需求,只要在每一个想要切换线程的位置调用一次 observeOn() 便可
- 以下,经过 observeOn() 的屡次调用,程序实现了线程的屡次切换
Observable.just(1, 2, 3, 4) // IO 线程,由 subscribeOn() 指定
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.newThread())
.map(mapOperator1) // 新线程,由 observeOn() 指定
.observeOn(Schedulers.io())
.map(mapOperator2) // IO 线程,由 observeOn() 指定
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber); // Android 主线程,由 observeOn() 指定
|
4.2.事件产生线程是固定的
不一样于 observeOn() , subscribeOn() 的位置虽然放在哪里均可以,但它是只能调用一次
当使用了多个subscribeOn() 的时候,只有第一个 subscribeOn() 起做用
4.3.流程开始前的初始化问题:【Subscriber 的 onStart( )】【Observable 的 doOnSubscribe( )】
- 在前面讲 Subscriber 的时候,提到过 Subscriber 的 onStart() 能够用做流程开始前的初始化
- 然而 onStart() 因为在subscribe() 发生时就被调用了,也就是没有被observeOn() 指定线程,所以是执行在 subscribe() 被调用时的线程也就是原线程
- 这就致使若是 onStart() 中含有对线程有要求的代码(例如在界面上显示一个 ProgressBar,这必须在主线程执行),将会有线程非法的风险,由于有时你没法预测subscribe() 将会在什么线程执行
解决方法
- Observable(不是Subscriber的)有一个方法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);
|
5、变换
- RxJava 提供了对事件序列进行变换的支持,这是它的核心功能之一,也是大多数人说『RxJava 真是太好用了』的最大缘由
- 所谓变换,就是将事件序列中的对象或整个事件队列进行加工处理,转换成不一样的事件或事件序列
变换节点是由一个【变换算法】和一个【变换枢纽】构成的
- 变换算法是一系列方法,好比:map()、flatMap(),他们决定变换的方式,是随方法固定的
- 变换枢纽是一种相似管道枢纽的容器,里边由你写具体的变换细节;输入和输出就像管道,如何分流就像管道的布线
- 往一个变换算法里传入一个变换枢纽就组成了一个变换节点
1.变换枢纽
- 变换枢纽是FuncX系列接口的对象
- FuncX系列接口跟前面讲的ActionX系列接口很是像
- 他们是位于 rx.functions 包下的所有两个系列接口
- ActionX系列是能够传入1个或多个参数,可是无返回值的call方法的包装
- FuncX系列是能够传入1个或多个参数,可是有一个返回值的call方法的包装
- 正是两个方法的惟一区别(是否有返回值)决定了在rx链中二者不一样的角色
- ActionX系列因为没有返回值,因此只能做为链的终点,也就是为观众服务,能够被组合构成观众
- FuncX系列因为有返回值,但他又不能做为链的起点,因此就天然成了咱们这里要说的新角色:链的中继者,或者说变换器
- FuncX系列的泛型位置是这样:前面的全部参数是输入参数,最后一个参数是输出参数
2.变换算法
2.1.map( )
- map() 方法将参数中的 String 对象转换成一个 Bitmap 对象后返回
- 在通过 map() 方法后,事件的参数类型也由 String转为了 Bitmap
Observable.just("images/logo.png") // 输入类型 String
.map(new Func1<String, Bitmap>() {
@Override
public Bitmap call(String filePath) { // 参数类型 String
return getBitmapFromPath(filePath); // 返回类型 Bitmap
}
})
.subscribe(new Action1<Bitmap>() {
@Override
public void call(Bitmap bitmap) { // 参数类型 Bitmap
showBitmap(bitmap);
}
});
|
2.2.flatMap( )
这是一个颇有用但不太好难理解的变换
2.2.1.情景推导
首先假设这么一种需求:有一个数据结构『学生』,如今须要打印出一组学生的名字
用上面提到的map方法实现起来很简单:
Student[] students = new Student[10];
Observable.from(students)
.map(new Func1<Student, String>() {
@Override
public String call(Student student) {
return student.getName();
}
})
.subscribe(new Subscriber<String>() {
@Override
public void onNext(String name) {
Log.d(tag, name);
}
...
});
|
再假设:若是要打印出每一个学生所须要修的全部课程的名称呢?(需求的区别在于,每一个学生只有一个名字,但却有多个课程)
这个时候用不了map了,先用普通方式实现一下:
Student[] students = new Student[10];
Observable.from(students)
.subscribe(new Subscriber<Student>() {
@Override
public void onNext(Student student) {
List<Course> courses = student.getCourses();
for (int i = 0; i < courses.size(); i++) {
Course course = courses.get(i);
Log.d(tag, course.getName());
}
}
...
});
|
2.2.2.引入
- 上面实现却是实现了,可是这个for循环的存在难免显得有点不太优雅
- 若是不想在 Subscriber 中使用 for 循环,而是但愿在 Subscriber 中直接接收单个的 Course 对象呢(这对于代码复用很重要)?
- 用 map() 显然是不行的,由于 map() 是一对一的转化,而我如今的要求是一对多的转化。那怎么才能把一个 Student 转化成多个 Course 呢?
- 这个时候,就须要用 flatMap( ) 了
2.2.3.实现
Student[] students = new Student[10];
Observable.from(students)
.flatMap(new Func1<Student, Observable<Course>>() {
@Override
public Observable<Course> call(Student student) {
return Observable.from(student.getCourses());
}
})
.subscribe(new Subscriber<Course>() {
@Override
public void onNext(Course course) {
Log.d(tag, course.getName());
}
...
});
|
- flatMap() 和 map() 有一个相同点:也是把传入的参数转化以后返回另外一个对象
- 不一样的是, flatMap() 中返回的是个 Observable 对象,而且这个 Observable 对象并非被直接发送到了 Subscriber 的回调方法中,而是
- 先使用传入的事件对象建立一个 Observable 对象
- 可是并不发送这个 Observable, 而是将它激活(subscribe),因而它开始发送事件
- 每个建立出来的子Observable 发送的事件,都被汇入同一个 Observable ,而这个 Observable 负责将这些事件统一交给 Subscriber 的回调方法
- 上面这三个步骤,把事件拆成了两级,经过一组新建立的 Observable 将初始的对象『铺平』以后经过统一路径分发了下去
- 这个『铺平』就是 flatMap() 所谓的 flat
- 每一个list就像卷起的纸,flatMap就是把一卷卷纸展开再连在一块儿
2.3.throttleFirst( )
在每次事件触发后的必定时间间隔内丢弃新的事件。经常使用做去抖动过滤,例如按钮的点击监听器
妈妈不再怕个人用户手抖点开两个重复的界面啦
RxView.clickEvents(button) // RxBinding 代码,后面的文章有解释
.throttleFirst(500, TimeUnit.MILLISECONDS) // 设置防抖间隔为 500ms
.subscribe(subscriber);
|
6、应用
1.Retrofit
2. RxBinding
- RxBinding 是 Jake Wharton 的一个开源库,它提供了一套在 Android 平台上的基于 RxJava 的 Binding API
- 所谓 Binding,就是相似设置 OnClickListener 、设置 TextWatcher 这样的注册绑定对象的 API
举个设置点击监听的例子。使用 RxBinding ,能够把事件监听用这样的方法来设置:
Button button = ...;
RxView.clickEvents(button) // 以 Observable 形式来反馈点击事件
.subscribe(new Action1<ViewClickEvent>() {
@Override
public void call(ViewClickEvent event) {
}
});
|
看起来除了形式变了没什么区别,实质上也是这样。甚至若是你看一下它的源码,你会发现它连实现都没什么惊喜:它的内部是直接用一个包裹着的 setOnClickListener() 来实现的。
然而,仅仅这一个形式的改变,却刚好就是 RxBinding 的目的:扩展性。
经过RxBinding 把点击监听转换成 Observable 以后,就有了对它进行扩展的可能。
扩展的方式有不少,根据需求而定。一个例子是前面提到过的 throttleFirst() ,用于去抖动,也就是消除手抖致使的快速连环点击:
RxView.clickEvents(button)
.throttleFirst(500, TimeUnit.MILLISECONDS)
.subscribe(clickAction);
|
3. 各类异步操做
前面举的 Retrofit 和 RxBinding 的例子,是两个能够提供现成的 Observable 的库。而若是你有某些异步操做没法用这些库来自动生成 Observable,也彻底能够本身写。例如数据库的读写、大图片的载入、文件压缩/解压等各类须要放在后台工做的耗时操做,均可以用 RxJava 来实现,有了以前几章的例子,这里应该不用再举例了。
4. RxBus
RxBus 名字看起来像一个库,但它并非一个库,而是一种模式,它的思想是使用 RxJava 来实现了 EventBus ,而让你再也不须要使用Otto 或者 GreenRobot 的 EventBus。至于什么是 RxBus,能够看这篇文章。顺便说一句,Flipboard 已经用 RxBus 替换掉了 Otto,目前为止没有不良反应。
附录
1.关于观察者模式
其实以为这个名字很是容易误解:观察者模式里两个角色,观察者和被观察者,两个方面会让人误解:
- 主被动关系,每每会有人以为观察者是主动观察,其实否则
- 名字就是一字之差,容易混淆,形成理解障碍
第二点就不说了,来讨论下第一点,其实里边一个是事件发出者,一个是被事件驱动者,主被动关系是反过来的,应该是 主人和仆人,指挥官和小兵,演讲者和听众,button和onclicklistener 的关系,观察者实际上是被动触发的,而不是主动观察
观察者模式用button和onclicklistener的模型来类比真是很是形象好理解(由于:1经常使用,平易近人;2很是符合)
对设置 OnClickListener 来讲, View 是被观察者, OnClickListener 是观察者,两者经过 setOnClickListener() 方法达成订阅关系。订阅以后用户点击按钮的瞬间,Android Framework 就会将点击事件发送给已经注册的 OnClickListener 。采起这样被动的观察方式,既省去了反复检索状态的资源消耗,也可以获得最高的反馈速度。
- Button -> 被观察者
- OnClickListener -> 观察者
- setOnClickListener() -> 订阅
- onClick() -> 事件
参考资料:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/1012/3572.htmljava