SlideShare ist ein Scribd-Unternehmen logo
1 von 76
Reactive Extensions
Programming
云应用 / 刘俊
# 关于我
 魅族打杂工程师
Android
Java
Groovy
Kotlin
Lua
C/C++
Gradle
Mobile Game
QQ音乐8级皇冠
QQ会员快要8级
游戏人生超过10K荣誉点
JweenLau[AT]gmail.com
SNS
golang
python
swift
什么是
Reactive
Extensions
?
# ReactiveX
ReactiveX 是集 观察者模式, 迭代器
模式和函数式编程所有优点于一体
的编程思想(程序设计模式)
# 观察者模式
 源: Observable
 View.setOnClickListener(listener)
 api.getData(参数, 回调)
 观察者: Observer
 OnClickListener
 回调
源
观察者1 观察者2 观察者3
# 迭代器模式
 集合: Iteratable
 Collection
 Set
 中间层:
 抽象集合
 具体迭代实现
 迭代器:
 Iterator
 Cursor
迭代器(抽象迭代器 / 游标Cursor等)
next
hasNext
remove
迭代器具体实现
前序迭代
中序迭代
后续迭代
…
抽象集合
CRUD抽象接口
具体集合数据
数据结构
算法
# 函数式
 函数是头等公民,可用于传参
 Lambda表达式 和 闭包
 递归 和 尾递归
 空指针Wrapper
 无状态,避免可变对象
 High-Order函数: 函数输入/函数输出
 (fun1 -> fun2) -> fun3
 operators 、functionals
 会以Kotlin / Groovy语言再分享一次
fun crop
fun rotate
↓
↓
↑
# ReactiveX
ReactiveX 是集 观察者模式, 迭代器
模式和函数式编程所有优点于一体
的编程思想
Reactive Programming –
响应式编程
# Reactive Programming V2.0
 Message-Driven
 Responsive
 Resilient
 Elastic
参考manifesto
React to user
React to load data React to failure
React to
events & messages
# ReactiveX
 函数式
 避免复杂的状态模式代码,使用最简单的输入/输出两种函数来处理数据流
 少即时多
 Operators大多数情况下可以将非常复杂的业务逻辑变成几行简单的代码
 异步错误处理
 异常强大的错误处理机制,远超try/catch
 超简单的多线程模型
 Rx的Observables和Schedulers可以让开发者不用关心底层复杂的线程处
理,锁等并发相关问题
# Rx的世界
 Observable<Data>
 Subscriber /
Observer
 Subscription
 Schedulers
 Operators
Observable
• -- data1 -- data2 -- data3 -- | --------------------------->
Subscriber
• -- onNext(data1) -- onNext(data2) -- onNext(data3)
• -- onComplete -> |
• -- onError -> X
Subscription
• unsubscribe
• isUnsubscribed
## Observable
 Observable可被Subscriber订阅
 类似于 view可以被设置onClick监听器
 Observable将数据push给所有subscribers
 类似于 报社 每天早上给订阅的家庭 递送 报纸、杂志
 集 迭代器 与 被观察者 于一体的数据stream或者sequence
 Observable内是一个数据序列,依次push给subscribe到自己的观察者们
## Observable
Observable Stream A
Observable Stream B
Operator +
Transformation
subscriber.
onNext
subscriber.
onError
subscriber.
onComplete
## Subscriber
 Subscriber/Observer 响应 Observable push过来的消息
 Observable.subscribe(subscriber) 来订阅Observable
 Subscriber
 onNext: - data1 -- data2 -- data3-…
 onError: --X (stream异常终止)
 onComplete: --| (stream成功结束)
### Show Me The Code!
Observable.
just(1, 2, 3).
subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
System.out.print("-" + integer + "-");
}
});
Observable.just(1, 2, 3).subscribe{ print("-$it-") }
-1--2--3-
### Show Me The Code!
Observable.just(1, 2, 3).
subscribe(
{ print("-$it-") },
{ println("-Error-X") },
{ println("-Complete-|")}
)
-1--2--3--Complete-|
### Show Me The Code!
Observable.just(1, 2, 3).
doOnNext{
if (it == 3)
throw IllegalStateException("3 is not welcome!")
}.
doOnError{ print("-${it.getMessage()}-") }.
subscribe(
{ print("-$it-") },
{ println("-Error-X") },
{ println("-Complete-|")}
)
-1--2--3 is not welcome!--Error-X
## Subscription
 Observable.subscribe(subscriber)
 返回的就是订阅的 Subscription
 Subscription
 unsubscribe: 取消订阅
 isUnsubscribed
 CompositeSubscription
 add(subscription)
 unsubscribe()
 remove(subscription)
 clear()
### Show Me The Code!
val subscription = Observable.interval(1, TimeUnit.SECONDS).
take(10).
subscribe{ print("-$it-") }
Observable.timer(4, TimeUnit.SECONDS).
subscribe{
subscription.unsubscribe()
println("-unsubscribe-;")
}
-0--1--2--3--unsubscribe-;
@ Amdahl’s Law
 异构程度越高,程序
速度越快。
 多线程或多核处理器
在1024之前,越多,
程序速度越快
 业务95%异构并行度
的时候,相比单线程
处理任务,最高能提
升20倍的速度
ReactiveX
如何提升P与N
?
# Rx的世界
 Observable<Data>
 Subscriber / Observer
 Subscription
 Schedulers
 Operators
## Schedulers
 Rx的线程池
 Operator中执行的任务,可以指定线程池
 Observable也可以通过subscribeOn来指定Observable的任务
在某线程池中执行
 Observable可以通过observeOn来指定订阅者/观察者们,在哪
个线程执行onNext, onComplete, onError
### Schedulers
Scheduler purpose
Schedulers.computation( ) CPU运算任务(event-loop, callback处理)专用线程
池,线程数量等于CPU核数
Schedulers.from(executor) 构造自定义的Schedulers
Schedulers.immediate( ) 立刻在当前线程执行任务
Schedulers.io( ) 默认是CachedThreadScheduler,异步I/O操作,网络
请求,等阻塞UI的操作,都可以在这里执行,线程池
内线程数量根据需要增长,如果是一般的CPU运算任
务,使用Schedulers.computation( )
Schedulers.newThread( ) 为当前任务单独生成一个线程来执行
Schedulers.trampoline( ) 按任务队列在当前线程执行任务
### Schedulers
operator Scheduler
take(time, unit) computation
takeLast(time, unit) computation
throttle computation
timeInterval immediate
timeout(timeoutSelector) immediate
timeout(timeout, timeUnit) computation
timer computation
timestamp immediate
window computation
operator Scheduler
buffer(timespan) computation
debounce(timeout, unit) computation
delay(delay, unit) computation
interval computation
repeat trampoline
replay(time, unit) computation
retry trampoline
sample(period, unit) computation
skip(time, unit) computation
skipLast(time, unit) computation
### Show Me The Code!
Tips: worker集并行任务管理与subscriber能力于一体
val worker = Schedulers.newThread().createWorker()
worker.schedule{
yourWork()
}
// some time later...
worker.unsubscribe()
### Show Me The Code!
Tips: worker也可以将schedule任务的订阅状态解耦出来
val worker = Schedulers.newThread().createWorker()
val mySubscription = worker.schedule{
while(!worker.isUnsubscribed()) {
status = yourWork()
if(QUIT == status) { worker.unsubscribe()}
}
}
// some time later ...
mySubscription.unsubscribe()
### Show Me The Code!
Tips: 递归/循环执行某任务, 直到取消订阅,
游戏循环绘制线程、socket读写线程等
worker.schedule(object : Action0 {
override fun call() {
yourDrawScreenWork()
// recurse until unsubscribed (schedule will do nothing if unsubscribed)
worker.schedule(this)
}
})
// some time later...
worker.unsubscribe();
然而我们
不需要写
Schedulers
代码!
## Schedulers
Scheduler purpose
Schedulers.computation( ) CPU运算任务(event-loop, callback处理)专用线程
池,线程数量等于CPU核数
Schedulers.from(executor) 构造自定义的Schedulers
Schedulers.immediate( ) 立刻在当前线程执行任务
Schedulers.io( ) 默认是CachedThreadScheduler,异步I/O操作,网络
请求,等阻塞UI的操作,都可以在这里执行,线程池
内线程数量根据需要增长,如果是一般的CPU运算任
务,使用Schedulers.computation( )
Schedulers.newThread( ) 为当前任务单独生成一个线程来执行
Schedulers.trampoline( ) 按任务队列在当前线程执行任务
## Show Me The Code!
Tips: interval take timer等Operator操作默认在
Schedulers.computation线程池中执行
val subscription = Observable.interval(1, TimeUnit.SECONDS).
take(10).
subscribe{ print("-$it-") }
Observable.timer(4, TimeUnit.SECONDS).
subscribe{
subscription.unsubscribe()
println("-unsubscribe-;")
}
Schedulers.
computation
-0--1--2--3--unsubscribe-;
## Show Me The Code!
Tips: -0--1--2--3- 是在主线程中输出的
observeOn->指定Subscriber的监听函数在哪个线程池中执行
subscribeOn->指定当前Observable的数据stream处理操作在哪个
线程池中执行
val subscription = Observable.interval(1, TimeUnit.SECONDS).
take(10).
subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread()).
subscribe{ print("-$it-") }
Observable.timer(4, TimeUnit.SECONDS).subscribe{
subscription.unsubscribe()
println("-unsubscribe-;")
}
Subscriber.
onNext
-0--1--2--3--unsubscribe-;
## Schedulers
operator Scheduler
take(time, unit) computation
takeLast(time, unit) computation
throttle computation
timeInterval immediate
timeout(timeoutSelector) immediate
timeout(timeout, timeUnit) computation
timer computation
timestamp immediate
window computation
operator Scheduler
buffer(timespan) computation
debounce(timeout, unit) computation
delay(delay, unit) computation
interval computation
repeat trampoline
replay(time, unit) computation
retry trampoline
sample(period, unit) computation
skip(time, unit) computation
skipLast(time, unit) computation
## Operators
 各种花式创建Observable
 将一个Observable转换成另一个Observable
 对Observable的数据进行 过滤 / 改变 / 组装 等等
 对Observable进行 联接 / 合并 / 转换 / 筛选 等等
 Rx提供了大量非常方便的Operators
 你也可以自己自定义Operator
### 创建Observable
 just: 将几个特定数据创建成Observable
 from: 将Array/List/Future等数据结构创建成Observable
 create: 创建自定义数据的Observable
 timer: 延迟一段时间后,传递0:Number的Observable
 interval: 每隔一段时间,传递以0开始的序列的Observable
 range: 将某段数字范围当作序列创建Observable
 repeat: 将某个序列循环重复的Observable
 defer: 延迟返回某个Observable(将已有代码变成Observable)
### Show Me The Code!
val subscription = Observable.interval(1, TimeUnit.SECONDS).
take(10).
subscribe{ print("-$it-") }
Observable.timer(4, TimeUnit.SECONDS).subscribe{
subscription.unsubscribe()
println("-unsubscribe-;")
}
-0--1--2--3--unsubscribe-;
### Show Me The Code!
Observable.create {subscriber: Subscriber<in Int> ->
subscriber.onNext(1)
subscriber.onNext(2)
subscriber.onNext(3)
subscriber.onCompleted()
}.subscribe {
println("Got $it")
}
Observable.range(1, 3).subscribe{println("Got $it")}
Got 1
Got 2
Got 3
### Android Studio
tips: Completion快捷键, 逆天的文档提示
## Operator分类
分类 Operators
连接 join, startWith, merge, concat, zip…
条件判断 amb, skipUntil, skipWhile, takeUntil,
takeWhile, defaultIfEmpty…
过滤 filter, first, last, take, skip, elementAt, sample,
throttle, timeout, distinct, distinctUntilChange,
ofType, ignoreElements, …
转换 map, flatMap, switchMap, scan, groupBy,
buffer, window, …
聚合/集合 concat, count, reduce, collect, toList, toMap,
toSortedList, …
创建Observable just, from, create, defer, timer, never, …
更详细的分类 戳我
### map
tips: 将Observable中的数据挨个儿转换
### map
Observable.range(97, 26).
map(new Func1<Integer, Character>() {
@Override
public Character call(Integer integer) {
return Character.valueOf(
(char)(int)integer);
}
}).
subscribe(new Action1<Character>() {
@Override
public void call(Character character) {
System.out.print(character);
}
});
Observable.range(97, 26).map{it.toChar()}.subscribe{print(it)}
将26个小写英文字母ascii
码转换为字符输出
简直不忍直视 →_→
abcdefghijklmnopqrstuvwxyz
### merge
tips: 将两个Observable合并成一个
### merge
Next: 1
Next: 3
Next: 5
Next: 2
Next: 4
Next: 6
Sequence complete.
val odds = Observable.just(1, 3, 5).
subscribeOn(Schedulers.computation())
val evens = Observable.just(2, 4, 6)
Observable.merge(odds, evens).subscribe(
{println("Next: $it")},
{println("Error: ${it.getMessage()}")},
{println("Sequence complete.")}
)
tips: odds.mergeWith(evens) 等价于
Observable.merge(odds, evens)
### 组合操作
Observable.
range(0, Int.MAX_VALUE).
map{ "value_$it"}.
skip(10).
take(5).
map{"${it}_xfrom" }
### throttle / debounce
tips:
debounce-> 每一段时间内只取一个
Eg-> 250毫秒内只响应一次点击事件(Monkey测试|点击过滤)
clickStream.debounce(250, TimeUnit.MILLISECONDS)
### buffer
tips: 每隔一段时间内, 最多只取x个
### buffer
tips: 以某个 observable 作为
终止边界选择器, 将每个终
止边界前的数据buffer成一
个list
### 组合操作
clickStream.
buffer{
clickStream.throttleWithTimeout(
250, TimeUnit.MILLISECONDS)
}.
map({it.size()}).
filter({it >= 2})
获取用户多次点击 行为
## 更多
 Subject: Observable 与 Subscriber 之间的一个代理, 同时扮演
Observable与Observer的角色, Subject观察一个或多个
Observable转换成另一种特定的Observable
 Producer: 创建Observable的时候, 数据流的生产者
 Single: Observable的stream中只有一个数据的时候, Single可
以把Subscriber缩减掉onCompleted, 只剩下onSuccess,
onError
恭喜你, 到此为止
RX已经可以开动
# 超级玛丽
 时间是一个Observable Stream
 键盘是一个Observable Stream
 绘图事件纷发是一个Observable
Stream
 任何东西都可以是 Observable
Stream
## 时间是一个Observable Stream
val clock = Observable.interval(1, TimeUnit.SECONDS)
-0--1--2--3--4--5--...
fun countDownClock(limit : Int) =
clock.map{limit - it}.takeWhile{it > 0}
-limit--(limit-1)--(limit-2)--…--3--2--1--|
### takeWhile
Tips: 还有 takeUntil, skipWhile, skipUntil
take, skip, takeFirst, takeLast, skipFirst, skipLast
## 超级玛丽倒计时太简单了
countDownClock(255).subscribe {
timerView.setText("Time left: $it")
}
Tips: 你应该将界面刷新 bring到 绘制线程
countDownClock(255).
observeOn(MyRenderScheduler.draw())
subscribe {
timerView.setText("Time left: $it")
}
例如: Android使用原生TextView的话
observeOn(AndroidScheduler.mainThread())
## 键盘是一个Observable Stream
override fun dispatchKeyEvent(e: KeyEvent): Boolean {
keyboard.onNext(e)
return super.dispatchKeyEvent(e)
}
val keyboard = PublishSubject.create<KeyEvent>()
### PublishSubject
一个Hot Observable, 不管有没有subscriber订阅, 都在emit数
据, 每个subscriber订阅到PublishSubject的时候, 开始监听这
个时刻起的数据
## Hot & Cold Observables
Hot Observable Cold Observable
区别 创建之后就开始emit数据 当有subscriber订阅到此
Observable的时候, 才开
始emit数据
Observable 绝大多数Observable都是
Hot Observable
ConnectableObservable
Operators 绝大多数Operator不改变
Observable的特性
publish, refCount
share = publish + refCount
replay
tips: Cold Observable常用于pull型逻辑, 比如Http请求
不过Rx更好的 Single 实现, 例如 Retrofit
## 键盘与时间绑定
val sample : Observable<in Pair<Int, KeyEvent>> =
clock.publish { _clock->
keyboard.map{key->
_clock.map{i-> Pair(i, key)}
}
}.switchMap{it}
对于每一次键盘按下
与时钟配对
每当有新按键事件, 切换到最新的
Tips: clock.publish 保证每一次匹配时间与键盘, 时间都是一直
延续下去的, 而不是每次都从零开始 (共享subscription)
### 家庭教师
时间 t, 速度 v, 加速度 a, 位移 s
位移公式: s = v0 + ½ ·a·t² (我们按时间等分拆解)
∑ Δs = ∑ Δs · Δt
Δs = Δv · Δt
加速度 Δa = Δv / Δt
那么 vn = vn-1 + Δa Δt
Δs = vn-1 Δt+ Δa Δt²
当我们取 Δt = 1 的时候, 每个时间分片内的位移
Δs = Δvn = vn-1 + Δa
## 向←向→
val arrows = keyboard.filter {
intArrayOf(KeyEvent.ACTION_DOWN,
KeyEvent.ACTION_UP).
contains(it.getAction()) &&
intArrayOf(KeyEvent.KEYCODE_DPAD_LEFT,
KeyEvent.KEYCODE_DPAD_RIGHT).
contains(it.getKeyCode())
}.distinctUntilChanged()
过滤键盘 ← → 方向按键
### distinctUtilChanged
Tips: 过滤重复的数据
## Δa:向←减速,向→加速
fun deltaAcceleration(acceleration : Int) = clock.publish { _clock ->
arrows.map { key ->
_clock.map { _ -> Int
if (key.getAction() == KeyEvent.ACTION_UP)
(-acceleration / 2)
else if (key.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT)
-acceleration
else acceleration
}
}.switchMap{it}
}
模拟惯性减速
向←减速
向→加速
tips: 如果是格斗游戏, 按键还需要存放到 按键堆栈 中处理连招指令
## Walk, Mario!
tips: Mario总是在场景(Scene)中间, 走动的时候, 是场景往左
移动, 地图制作者或设计师管场景叫 关卡
## 地板
public open class Ground {
val tile : Bitmap = getImage("tile")
val height = tile.getHeight()
val nrTiles = Math.ceil(screenWidth / tile.getWidth()) as Int + 1
fun onDraw(canvas : Canvas) = (0..nrTiles).map {
canvas.drawBitmap(tile, tile.getWidth() * it as Float, 0 as Float, paint)
}
}
## 走起来
val v0 = 0
val s0 = 0
val acceleration = 3
deltaAcceleration(acceleration).
scan(v0) { vi, a-> vi + a }.
scan(s0) { si, vi-> si + vi }.
subscribe {
ground.setTranslateX(it)
}
Δa
vi = vi-1 + Δa·Δt
si = si-1 + vi · Δt
### scan
Tips: 前一次运行的输出结果, 保留为下一次运行的输入数据
类似动态语言(例如groovy)中的 inject 函数(high-order函数)
### scan(R, fun)
Tips: 接受一个初始化数据参与scan, 例如玛丽初始化速度v0, 参
与scan单位时间内加速度引起的速度变更, 初始化位移s0参与单
位时间内速度变化引起的位移变化
## Jump, Mario!
v0
v1 = v0 - g
v2 = v1 – g
= 0
v3 = v2 - g
v4 = v3 – g
= -v0
## 跳起来
open class Mario{
// …
val junmps : PublishSubject<in Int> = PublishSubject.create()
fun init() {
junmps.flatMap { v0 ->
clock.scan(v0) { vi, _ -> vi - gravity}.
takeUntil(junmps)
}.subscribe { dy -> setTranslationY(dy as Float) }
}
}
tips: 重力速度公式: vi = vi-1 + gΔt (此处Δt = 1, g = -g)
## 触发Jump
val keyPressed = keyboard.filter{it.getAction() == KeyEvent.ACTION_DOWN}
val spaceBar = keyPressed.filter{it.getKeyCode() == KeyEvent.KEYCODE_SPACE}
val jumpSpeed = 30
spaceBar.filter { mario.translateY >= mario.homeY }.
doOnEach{/* SoundPool.play(R.raw.mario_jump) */ }.
subscribe { mario.junmps.onNext(jumpSpeed) }
如果Mario在地上
通知Mario跳起来
跳的音效
空格按下的时候
## 碰撞检测
Observable<Position>
data class Position(
val x : Int, val y : Int,
val width : Int, val height : Int)
Observable.combineLatest(
mario.position, coin.position) {
marioPos, coinPos ->
collides(marioPos, coinPos)
}.buffer(2, 1).filter {
it.get(0) != it.get(1)
}fun collides
(posA, posB)
: Boolean
{
// ….碰撞检测
}
### combineLatest
Tips: 组合两个Observable的最后数据根据特定规则生成新的数据
Excel表格 x + y = z 公式, 无论x, y怎么变动, z也跟着变动
对, 就是这样, RxJava中combineLatest最多支持9个Observable
### buffer
Tips: 缓存Observable的数据, 批量push
例如写数据库的时候, 可以buffer一批数据在一定时间限
制内一次写入,
批量操作, 回滚/回顾型逻辑, 都靠buffer
# 超级玛丽
 好了, 大家已经学会 1 + 1 = 2 了
 那么, 请大家尝试推导适用于26维
空间超弦定理公式
# 引用
 http://reactivex.io/
 http://kotlinlang.org/docs/reference/
 http://www.slideshare.net/andreycheptsov/a-playful-
introduction-to-rx
 http://www.slideshare.net/allegrotech/rxjava-introduction-
context
 http://rxmarbles.com/#debounceWithSelector
 http://www.mariouniverse.com/fg/supermario-scene-36
Q&A
云应用/刘俊

Weitere ähnliche Inhalte

Was ist angesagt?

Monitor is all for ops
Monitor is all for opsMonitor is all for ops
Monitor is all for ops琛琳 饶
 
淺談 Groovy 與 Gradle
淺談 Groovy 與 Gradle淺談 Groovy 與 Gradle
淺談 Groovy 與 GradleJustin Lin
 
Java 8 與 retrolambda
Java 8 與 retrolambdaJava 8 與 retrolambda
Java 8 與 retrolambdaJustin Lin
 
深入剖析Concurrent hashmap中的同步机制(上)
深入剖析Concurrent hashmap中的同步机制(上)深入剖析Concurrent hashmap中的同步机制(上)
深入剖析Concurrent hashmap中的同步机制(上)wang hongjiang
 
Java Crash分析(2012-05-10)
Java Crash分析(2012-05-10)Java Crash分析(2012-05-10)
Java Crash分析(2012-05-10)Kris Mok
 
Free rtos workshop1@nuu
Free rtos workshop1@nuuFree rtos workshop1@nuu
Free rtos workshop1@nuu紀榮 陳
 
Java7 fork join framework and closures
Java7 fork join framework and closuresJava7 fork join framework and closures
Java7 fork join framework and closureswang hongjiang
 
Effective linux.3.(diagnosis)
Effective linux.3.(diagnosis)Effective linux.3.(diagnosis)
Effective linux.3.(diagnosis)wang hongjiang
 
Java SE 8 的 Lambda 連鎖效應 - 語法、風格與程式庫
Java SE 8 的 Lambda 連鎖效應 - 語法、風格與程式庫Java SE 8 的 Lambda 連鎖效應 - 語法、風格與程式庫
Java SE 8 的 Lambda 連鎖效應 - 語法、風格與程式庫Justin Lin
 
并发编程实践
并发编程实践并发编程实践
并发编程实践longhao
 
Golang server design pattern
Golang server design patternGolang server design pattern
Golang server design pattern理 傅
 
Lucene 全文检索实践
Lucene 全文检索实践Lucene 全文检索实践
Lucene 全文检索实践yiditushe
 
DNS协议与应用简介
DNS协议与应用简介DNS协议与应用简介
DNS协议与应用简介琛琳 饶
 
Exodus重构和向apollo迁移
Exodus重构和向apollo迁移Exodus重构和向apollo迁移
Exodus重构和向apollo迁移wang hongjiang
 
IOS入门分享
IOS入门分享IOS入门分享
IOS入门分享zenyuhao
 

Was ist angesagt? (20)

Monitor is all for ops
Monitor is all for opsMonitor is all for ops
Monitor is all for ops
 
淺談 Groovy 與 Gradle
淺談 Groovy 與 Gradle淺談 Groovy 與 Gradle
淺談 Groovy 與 Gradle
 
Jvm内存管理基础
Jvm内存管理基础Jvm内存管理基础
Jvm内存管理基础
 
Ali-tomcat
Ali-tomcatAli-tomcat
Ali-tomcat
 
Java 8 與 retrolambda
Java 8 與 retrolambdaJava 8 與 retrolambda
Java 8 與 retrolambda
 
深入剖析Concurrent hashmap中的同步机制(上)
深入剖析Concurrent hashmap中的同步机制(上)深入剖析Concurrent hashmap中的同步机制(上)
深入剖析Concurrent hashmap中的同步机制(上)
 
Java Crash分析(2012-05-10)
Java Crash分析(2012-05-10)Java Crash分析(2012-05-10)
Java Crash分析(2012-05-10)
 
Free rtos workshop1@nuu
Free rtos workshop1@nuuFree rtos workshop1@nuu
Free rtos workshop1@nuu
 
Exodus2 大局观
Exodus2 大局观Exodus2 大局观
Exodus2 大局观
 
Java7 fork join framework and closures
Java7 fork join framework and closuresJava7 fork join framework and closures
Java7 fork join framework and closures
 
Aswan&hump
Aswan&humpAswan&hump
Aswan&hump
 
Effective linux.3.(diagnosis)
Effective linux.3.(diagnosis)Effective linux.3.(diagnosis)
Effective linux.3.(diagnosis)
 
Execution
ExecutionExecution
Execution
 
Java SE 8 的 Lambda 連鎖效應 - 語法、風格與程式庫
Java SE 8 的 Lambda 連鎖效應 - 語法、風格與程式庫Java SE 8 的 Lambda 連鎖效應 - 語法、風格與程式庫
Java SE 8 的 Lambda 連鎖效應 - 語法、風格與程式庫
 
并发编程实践
并发编程实践并发编程实践
并发编程实践
 
Golang server design pattern
Golang server design patternGolang server design pattern
Golang server design pattern
 
Lucene 全文检索实践
Lucene 全文检索实践Lucene 全文检索实践
Lucene 全文检索实践
 
DNS协议与应用简介
DNS协议与应用简介DNS协议与应用简介
DNS协议与应用简介
 
Exodus重构和向apollo迁移
Exodus重构和向apollo迁移Exodus重构和向apollo迁移
Exodus重构和向apollo迁移
 
IOS入门分享
IOS入门分享IOS入门分享
IOS入门分享
 

Andere mochten auch

Android gradle 从入门到gg 3
Android gradle 从入门到gg 3Android gradle 从入门到gg 3
Android gradle 从入门到gg 3Jun Liu
 
Android gradle 从入门到gg 0
Android gradle 从入门到gg 0Android gradle 从入门到gg 0
Android gradle 从入门到gg 0Jun Liu
 
Rxjava 介紹與 Android 中的 RxJava
Rxjava 介紹與 Android 中的 RxJavaRxjava 介紹與 Android 中的 RxJava
Rxjava 介紹與 Android 中的 RxJavaKros Huang
 
不同尺寸與解析度的螢幕下,Android 程式 UI 的設計與解決方式
不同尺寸與解析度的螢幕下,Android 程式 UI 的設計與解決方式不同尺寸與解析度的螢幕下,Android 程式 UI 的設計與解決方式
不同尺寸與解析度的螢幕下,Android 程式 UI 的設計與解決方式信宏 陳
 
Android gradle 从入门到gg 1
Android gradle 从入门到gg 1Android gradle 从入门到gg 1
Android gradle 从入门到gg 1Jun Liu
 
Android gradle 从入门到gg 2
Android gradle 从入门到gg 2Android gradle 从入门到gg 2
Android gradle 从入门到gg 2Jun Liu
 
A Playful Introduction to Rx
A Playful Introduction to RxA Playful Introduction to Rx
A Playful Introduction to RxAndrey Cheptsov
 
大型App面臨的挑戰
大型App面臨的挑戰大型App面臨的挑戰
大型App面臨的挑戰Chih-Chung Lee
 
RxJava 2.0 介紹
RxJava 2.0 介紹RxJava 2.0 介紹
RxJava 2.0 介紹Kros Huang
 
大鱼架构演进
大鱼架构演进大鱼架构演进
大鱼架构演进Jun Liu
 
[DEPRECATED]Gradle the android
[DEPRECATED]Gradle the android[DEPRECATED]Gradle the android
[DEPRECATED]Gradle the androidJun Liu
 
Gradle,the new build system for android
Gradle,the new build system for androidGradle,the new build system for android
Gradle,the new build system for androidzhang ghui
 
RxJava - introduction & design
RxJava - introduction & designRxJava - introduction & design
RxJava - introduction & designallegro.tech
 
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法Yoshifumi Kawai
 
AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践
AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践
AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践Yoshifumi Kawai
 
Reactive Programming by UniRx for Asynchronous & Event Processing
Reactive Programming by UniRx for Asynchronous & Event ProcessingReactive Programming by UniRx for Asynchronous & Event Processing
Reactive Programming by UniRx for Asynchronous & Event ProcessingYoshifumi Kawai
 
Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方
Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方
Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方Yoshifumi Kawai
 
Writing DSL's in Scala
Writing DSL's in ScalaWriting DSL's in Scala
Writing DSL's in ScalaAbhijit Sharma
 
簡單上手Android studio
簡單上手Android studio簡單上手Android studio
簡單上手Android studio琨堯 林
 

Andere mochten auch (20)

Android gradle 从入门到gg 3
Android gradle 从入门到gg 3Android gradle 从入门到gg 3
Android gradle 从入门到gg 3
 
Android gradle 从入门到gg 0
Android gradle 从入门到gg 0Android gradle 从入门到gg 0
Android gradle 从入门到gg 0
 
Rxjava 介紹與 Android 中的 RxJava
Rxjava 介紹與 Android 中的 RxJavaRxjava 介紹與 Android 中的 RxJava
Rxjava 介紹與 Android 中的 RxJava
 
不同尺寸與解析度的螢幕下,Android 程式 UI 的設計與解決方式
不同尺寸與解析度的螢幕下,Android 程式 UI 的設計與解決方式不同尺寸與解析度的螢幕下,Android 程式 UI 的設計與解決方式
不同尺寸與解析度的螢幕下,Android 程式 UI 的設計與解決方式
 
Android gradle 从入门到gg 1
Android gradle 从入门到gg 1Android gradle 从入门到gg 1
Android gradle 从入门到gg 1
 
Android gradle 从入门到gg 2
Android gradle 从入门到gg 2Android gradle 从入门到gg 2
Android gradle 从入门到gg 2
 
A Playful Introduction to Rx
A Playful Introduction to RxA Playful Introduction to Rx
A Playful Introduction to Rx
 
大型App面臨的挑戰
大型App面臨的挑戰大型App面臨的挑戰
大型App面臨的挑戰
 
作業系統
作業系統作業系統
作業系統
 
RxJava 2.0 介紹
RxJava 2.0 介紹RxJava 2.0 介紹
RxJava 2.0 介紹
 
大鱼架构演进
大鱼架构演进大鱼架构演进
大鱼架构演进
 
[DEPRECATED]Gradle the android
[DEPRECATED]Gradle the android[DEPRECATED]Gradle the android
[DEPRECATED]Gradle the android
 
Gradle,the new build system for android
Gradle,the new build system for androidGradle,the new build system for android
Gradle,the new build system for android
 
RxJava - introduction & design
RxJava - introduction & designRxJava - introduction & design
RxJava - introduction & design
 
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
 
AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践
AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践
AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践
 
Reactive Programming by UniRx for Asynchronous & Event Processing
Reactive Programming by UniRx for Asynchronous & Event ProcessingReactive Programming by UniRx for Asynchronous & Event Processing
Reactive Programming by UniRx for Asynchronous & Event Processing
 
Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方
Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方
Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方
 
Writing DSL's in Scala
Writing DSL's in ScalaWriting DSL's in Scala
Writing DSL's in Scala
 
簡單上手Android studio
簡單上手Android studio簡單上手Android studio
簡單上手Android studio
 

Ähnlich wie Reactive X 响应式编程

The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)jeffz
 
异步编程与浏览器执行模型
异步编程与浏览器执行模型异步编程与浏览器执行模型
异步编程与浏览器执行模型keelii
 
C++中级培训胶片
C++中级培训胶片C++中级培训胶片
C++中级培训胶片ff1
 
Java华为面试题
Java华为面试题Java华为面试题
Java华为面试题yiditushe
 
Osc scott linux下的数据库优化for_postgresql
Osc scott linux下的数据库优化for_postgresqlOsc scott linux下的数据库优化for_postgresql
Osc scott linux下的数据库优化for_postgresqlOpenSourceCamp
 
Python 入門
Python 入門 Python 入門
Python 入門 Andy Yao
 
2023-netconf-deploy-azure-function-with-KEDA-on-aks
2023-netconf-deploy-azure-function-with-KEDA-on-aks2023-netconf-deploy-azure-function-with-KEDA-on-aks
2023-netconf-deploy-azure-function-with-KEDA-on-aksRoberson Liou
 
網站設計100步
網站設計100步網站設計100步
網站設計100步evercislide
 
漫談 Source Control Management
漫談 Source Control Management漫談 Source Control Management
漫談 Source Control ManagementWen-Shih Chao
 
千呼萬喚始出來的Java SE 7
千呼萬喚始出來的Java SE 7千呼萬喚始出來的Java SE 7
千呼萬喚始出來的Java SE 7javatwo2011
 
Net Parallel Programming .NET平行處理與執行序
Net Parallel Programming .NET平行處理與執行序Net Parallel Programming .NET平行處理與執行序
Net Parallel Programming .NET平行處理與執行序HO-HSUN LIN
 
認識 C++11 新標準及使用 AMP 函式庫作平行運算
認識 C++11 新標準及使用 AMP 函式庫作平行運算認識 C++11 新標準及使用 AMP 函式庫作平行運算
認識 C++11 新標準及使用 AMP 函式庫作平行運算建興 王
 
竞赛中C++语言拾遗
竞赛中C++语言拾遗竞赛中C++语言拾遗
竞赛中C++语言拾遗乐群 陈
 
181201_CoAP_coding365
181201_CoAP_coding365181201_CoAP_coding365
181201_CoAP_coding365Peter Yi
 
twMVC#27 | C# 7.0 新功能介紹
twMVC#27 | C# 7.0 新功能介紹twMVC#27 | C# 7.0 新功能介紹
twMVC#27 | C# 7.0 新功能介紹twMVC
 
线程与并发
线程与并发线程与并发
线程与并发Tony Deng
 
ES5 introduction
ES5 introductionES5 introduction
ES5 introductionotakustay
 

Ähnlich wie Reactive X 响应式编程 (20)

The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)
 
Optimzing mysql
Optimzing mysqlOptimzing mysql
Optimzing mysql
 
Dev307
Dev307Dev307
Dev307
 
异步编程与浏览器执行模型
异步编程与浏览器执行模型异步编程与浏览器执行模型
异步编程与浏览器执行模型
 
C++中级培训胶片
C++中级培训胶片C++中级培训胶片
C++中级培训胶片
 
Java华为面试题
Java华为面试题Java华为面试题
Java华为面试题
 
Osc scott linux下的数据库优化for_postgresql
Osc scott linux下的数据库优化for_postgresqlOsc scott linux下的数据库优化for_postgresql
Osc scott linux下的数据库优化for_postgresql
 
Python 入門
Python 入門 Python 入門
Python 入門
 
2023-netconf-deploy-azure-function-with-KEDA-on-aks
2023-netconf-deploy-azure-function-with-KEDA-on-aks2023-netconf-deploy-azure-function-with-KEDA-on-aks
2023-netconf-deploy-azure-function-with-KEDA-on-aks
 
網站設計100步
網站設計100步網站設計100步
網站設計100步
 
漫談 Source Control Management
漫談 Source Control Management漫談 Source Control Management
漫談 Source Control Management
 
千呼萬喚始出來的Java SE 7
千呼萬喚始出來的Java SE 7千呼萬喚始出來的Java SE 7
千呼萬喚始出來的Java SE 7
 
Net Parallel Programming .NET平行處理與執行序
Net Parallel Programming .NET平行處理與執行序Net Parallel Programming .NET平行處理與執行序
Net Parallel Programming .NET平行處理與執行序
 
認識 C++11 新標準及使用 AMP 函式庫作平行運算
認識 C++11 新標準及使用 AMP 函式庫作平行運算認識 C++11 新標準及使用 AMP 函式庫作平行運算
認識 C++11 新標準及使用 AMP 函式庫作平行運算
 
Glider
GliderGlider
Glider
 
竞赛中C++语言拾遗
竞赛中C++语言拾遗竞赛中C++语言拾遗
竞赛中C++语言拾遗
 
181201_CoAP_coding365
181201_CoAP_coding365181201_CoAP_coding365
181201_CoAP_coding365
 
twMVC#27 | C# 7.0 新功能介紹
twMVC#27 | C# 7.0 新功能介紹twMVC#27 | C# 7.0 新功能介紹
twMVC#27 | C# 7.0 新功能介紹
 
线程与并发
线程与并发线程与并发
线程与并发
 
ES5 introduction
ES5 introductionES5 introduction
ES5 introduction
 

Reactive X 响应式编程

  • 2. # 关于我  魅族打杂工程师 Android Java Groovy Kotlin Lua C/C++ Gradle Mobile Game QQ音乐8级皇冠 QQ会员快要8级 游戏人生超过10K荣誉点 JweenLau[AT]gmail.com SNS golang python swift
  • 4. # ReactiveX ReactiveX 是集 观察者模式, 迭代器 模式和函数式编程所有优点于一体 的编程思想(程序设计模式)
  • 5. # 观察者模式  源: Observable  View.setOnClickListener(listener)  api.getData(参数, 回调)  观察者: Observer  OnClickListener  回调 源 观察者1 观察者2 观察者3
  • 6. # 迭代器模式  集合: Iteratable  Collection  Set  中间层:  抽象集合  具体迭代实现  迭代器:  Iterator  Cursor 迭代器(抽象迭代器 / 游标Cursor等) next hasNext remove 迭代器具体实现 前序迭代 中序迭代 后续迭代 … 抽象集合 CRUD抽象接口 具体集合数据 数据结构 算法
  • 7. # 函数式  函数是头等公民,可用于传参  Lambda表达式 和 闭包  递归 和 尾递归  空指针Wrapper  无状态,避免可变对象  High-Order函数: 函数输入/函数输出  (fun1 -> fun2) -> fun3  operators 、functionals  会以Kotlin / Groovy语言再分享一次 fun crop fun rotate ↓ ↓ ↑
  • 8. # ReactiveX ReactiveX 是集 观察者模式, 迭代器 模式和函数式编程所有优点于一体 的编程思想 Reactive Programming – 响应式编程
  • 9. # Reactive Programming V2.0  Message-Driven  Responsive  Resilient  Elastic 参考manifesto React to user React to load data React to failure React to events & messages
  • 10. # ReactiveX  函数式  避免复杂的状态模式代码,使用最简单的输入/输出两种函数来处理数据流  少即时多  Operators大多数情况下可以将非常复杂的业务逻辑变成几行简单的代码  异步错误处理  异常强大的错误处理机制,远超try/catch  超简单的多线程模型  Rx的Observables和Schedulers可以让开发者不用关心底层复杂的线程处 理,锁等并发相关问题
  • 11. # Rx的世界  Observable<Data>  Subscriber / Observer  Subscription  Schedulers  Operators Observable • -- data1 -- data2 -- data3 -- | ---------------------------> Subscriber • -- onNext(data1) -- onNext(data2) -- onNext(data3) • -- onComplete -> | • -- onError -> X Subscription • unsubscribe • isUnsubscribed
  • 12. ## Observable  Observable可被Subscriber订阅  类似于 view可以被设置onClick监听器  Observable将数据push给所有subscribers  类似于 报社 每天早上给订阅的家庭 递送 报纸、杂志  集 迭代器 与 被观察者 于一体的数据stream或者sequence  Observable内是一个数据序列,依次push给subscribe到自己的观察者们
  • 13. ## Observable Observable Stream A Observable Stream B Operator + Transformation subscriber. onNext subscriber. onError subscriber. onComplete
  • 14. ## Subscriber  Subscriber/Observer 响应 Observable push过来的消息  Observable.subscribe(subscriber) 来订阅Observable  Subscriber  onNext: - data1 -- data2 -- data3-…  onError: --X (stream异常终止)  onComplete: --| (stream成功结束)
  • 15. ### Show Me The Code! Observable. just(1, 2, 3). subscribe(new Action1<Integer>() { @Override public void call(Integer integer) { System.out.print("-" + integer + "-"); } }); Observable.just(1, 2, 3).subscribe{ print("-$it-") } -1--2--3-
  • 16. ### Show Me The Code! Observable.just(1, 2, 3). subscribe( { print("-$it-") }, { println("-Error-X") }, { println("-Complete-|")} ) -1--2--3--Complete-|
  • 17. ### Show Me The Code! Observable.just(1, 2, 3). doOnNext{ if (it == 3) throw IllegalStateException("3 is not welcome!") }. doOnError{ print("-${it.getMessage()}-") }. subscribe( { print("-$it-") }, { println("-Error-X") }, { println("-Complete-|")} ) -1--2--3 is not welcome!--Error-X
  • 18. ## Subscription  Observable.subscribe(subscriber)  返回的就是订阅的 Subscription  Subscription  unsubscribe: 取消订阅  isUnsubscribed  CompositeSubscription  add(subscription)  unsubscribe()  remove(subscription)  clear()
  • 19. ### Show Me The Code! val subscription = Observable.interval(1, TimeUnit.SECONDS). take(10). subscribe{ print("-$it-") } Observable.timer(4, TimeUnit.SECONDS). subscribe{ subscription.unsubscribe() println("-unsubscribe-;") } -0--1--2--3--unsubscribe-;
  • 20. @ Amdahl’s Law  异构程度越高,程序 速度越快。  多线程或多核处理器 在1024之前,越多, 程序速度越快  业务95%异构并行度 的时候,相比单线程 处理任务,最高能提 升20倍的速度
  • 22. # Rx的世界  Observable<Data>  Subscriber / Observer  Subscription  Schedulers  Operators
  • 23. ## Schedulers  Rx的线程池  Operator中执行的任务,可以指定线程池  Observable也可以通过subscribeOn来指定Observable的任务 在某线程池中执行  Observable可以通过observeOn来指定订阅者/观察者们,在哪 个线程执行onNext, onComplete, onError
  • 24. ### Schedulers Scheduler purpose Schedulers.computation( ) CPU运算任务(event-loop, callback处理)专用线程 池,线程数量等于CPU核数 Schedulers.from(executor) 构造自定义的Schedulers Schedulers.immediate( ) 立刻在当前线程执行任务 Schedulers.io( ) 默认是CachedThreadScheduler,异步I/O操作,网络 请求,等阻塞UI的操作,都可以在这里执行,线程池 内线程数量根据需要增长,如果是一般的CPU运算任 务,使用Schedulers.computation( ) Schedulers.newThread( ) 为当前任务单独生成一个线程来执行 Schedulers.trampoline( ) 按任务队列在当前线程执行任务
  • 25. ### Schedulers operator Scheduler take(time, unit) computation takeLast(time, unit) computation throttle computation timeInterval immediate timeout(timeoutSelector) immediate timeout(timeout, timeUnit) computation timer computation timestamp immediate window computation operator Scheduler buffer(timespan) computation debounce(timeout, unit) computation delay(delay, unit) computation interval computation repeat trampoline replay(time, unit) computation retry trampoline sample(period, unit) computation skip(time, unit) computation skipLast(time, unit) computation
  • 26. ### Show Me The Code! Tips: worker集并行任务管理与subscriber能力于一体 val worker = Schedulers.newThread().createWorker() worker.schedule{ yourWork() } // some time later... worker.unsubscribe()
  • 27. ### Show Me The Code! Tips: worker也可以将schedule任务的订阅状态解耦出来 val worker = Schedulers.newThread().createWorker() val mySubscription = worker.schedule{ while(!worker.isUnsubscribed()) { status = yourWork() if(QUIT == status) { worker.unsubscribe()} } } // some time later ... mySubscription.unsubscribe()
  • 28. ### Show Me The Code! Tips: 递归/循环执行某任务, 直到取消订阅, 游戏循环绘制线程、socket读写线程等 worker.schedule(object : Action0 { override fun call() { yourDrawScreenWork() // recurse until unsubscribed (schedule will do nothing if unsubscribed) worker.schedule(this) } }) // some time later... worker.unsubscribe();
  • 30. ## Schedulers Scheduler purpose Schedulers.computation( ) CPU运算任务(event-loop, callback处理)专用线程 池,线程数量等于CPU核数 Schedulers.from(executor) 构造自定义的Schedulers Schedulers.immediate( ) 立刻在当前线程执行任务 Schedulers.io( ) 默认是CachedThreadScheduler,异步I/O操作,网络 请求,等阻塞UI的操作,都可以在这里执行,线程池 内线程数量根据需要增长,如果是一般的CPU运算任 务,使用Schedulers.computation( ) Schedulers.newThread( ) 为当前任务单独生成一个线程来执行 Schedulers.trampoline( ) 按任务队列在当前线程执行任务
  • 31. ## Show Me The Code! Tips: interval take timer等Operator操作默认在 Schedulers.computation线程池中执行 val subscription = Observable.interval(1, TimeUnit.SECONDS). take(10). subscribe{ print("-$it-") } Observable.timer(4, TimeUnit.SECONDS). subscribe{ subscription.unsubscribe() println("-unsubscribe-;") } Schedulers. computation -0--1--2--3--unsubscribe-;
  • 32. ## Show Me The Code! Tips: -0--1--2--3- 是在主线程中输出的 observeOn->指定Subscriber的监听函数在哪个线程池中执行 subscribeOn->指定当前Observable的数据stream处理操作在哪个 线程池中执行 val subscription = Observable.interval(1, TimeUnit.SECONDS). take(10). subscribeOn(Schedulers.io()). observeOn(AndroidSchedulers.mainThread()). subscribe{ print("-$it-") } Observable.timer(4, TimeUnit.SECONDS).subscribe{ subscription.unsubscribe() println("-unsubscribe-;") } Subscriber. onNext -0--1--2--3--unsubscribe-;
  • 33. ## Schedulers operator Scheduler take(time, unit) computation takeLast(time, unit) computation throttle computation timeInterval immediate timeout(timeoutSelector) immediate timeout(timeout, timeUnit) computation timer computation timestamp immediate window computation operator Scheduler buffer(timespan) computation debounce(timeout, unit) computation delay(delay, unit) computation interval computation repeat trampoline replay(time, unit) computation retry trampoline sample(period, unit) computation skip(time, unit) computation skipLast(time, unit) computation
  • 34. ## Operators  各种花式创建Observable  将一个Observable转换成另一个Observable  对Observable的数据进行 过滤 / 改变 / 组装 等等  对Observable进行 联接 / 合并 / 转换 / 筛选 等等  Rx提供了大量非常方便的Operators  你也可以自己自定义Operator
  • 35. ### 创建Observable  just: 将几个特定数据创建成Observable  from: 将Array/List/Future等数据结构创建成Observable  create: 创建自定义数据的Observable  timer: 延迟一段时间后,传递0:Number的Observable  interval: 每隔一段时间,传递以0开始的序列的Observable  range: 将某段数字范围当作序列创建Observable  repeat: 将某个序列循环重复的Observable  defer: 延迟返回某个Observable(将已有代码变成Observable)
  • 36. ### Show Me The Code! val subscription = Observable.interval(1, TimeUnit.SECONDS). take(10). subscribe{ print("-$it-") } Observable.timer(4, TimeUnit.SECONDS).subscribe{ subscription.unsubscribe() println("-unsubscribe-;") } -0--1--2--3--unsubscribe-;
  • 37. ### Show Me The Code! Observable.create {subscriber: Subscriber<in Int> -> subscriber.onNext(1) subscriber.onNext(2) subscriber.onNext(3) subscriber.onCompleted() }.subscribe { println("Got $it") } Observable.range(1, 3).subscribe{println("Got $it")} Got 1 Got 2 Got 3
  • 38. ### Android Studio tips: Completion快捷键, 逆天的文档提示
  • 39. ## Operator分类 分类 Operators 连接 join, startWith, merge, concat, zip… 条件判断 amb, skipUntil, skipWhile, takeUntil, takeWhile, defaultIfEmpty… 过滤 filter, first, last, take, skip, elementAt, sample, throttle, timeout, distinct, distinctUntilChange, ofType, ignoreElements, … 转换 map, flatMap, switchMap, scan, groupBy, buffer, window, … 聚合/集合 concat, count, reduce, collect, toList, toMap, toSortedList, … 创建Observable just, from, create, defer, timer, never, … 更详细的分类 戳我
  • 41. ### map Observable.range(97, 26). map(new Func1<Integer, Character>() { @Override public Character call(Integer integer) { return Character.valueOf( (char)(int)integer); } }). subscribe(new Action1<Character>() { @Override public void call(Character character) { System.out.print(character); } }); Observable.range(97, 26).map{it.toChar()}.subscribe{print(it)} 将26个小写英文字母ascii 码转换为字符输出 简直不忍直视 →_→ abcdefghijklmnopqrstuvwxyz
  • 43. ### merge Next: 1 Next: 3 Next: 5 Next: 2 Next: 4 Next: 6 Sequence complete. val odds = Observable.just(1, 3, 5). subscribeOn(Schedulers.computation()) val evens = Observable.just(2, 4, 6) Observable.merge(odds, evens).subscribe( {println("Next: $it")}, {println("Error: ${it.getMessage()}")}, {println("Sequence complete.")} ) tips: odds.mergeWith(evens) 等价于 Observable.merge(odds, evens)
  • 44. ### 组合操作 Observable. range(0, Int.MAX_VALUE). map{ "value_$it"}. skip(10). take(5). map{"${it}_xfrom" }
  • 45. ### throttle / debounce tips: debounce-> 每一段时间内只取一个 Eg-> 250毫秒内只响应一次点击事件(Monkey测试|点击过滤) clickStream.debounce(250, TimeUnit.MILLISECONDS)
  • 47. ### buffer tips: 以某个 observable 作为 终止边界选择器, 将每个终 止边界前的数据buffer成一 个list
  • 49. ## 更多  Subject: Observable 与 Subscriber 之间的一个代理, 同时扮演 Observable与Observer的角色, Subject观察一个或多个 Observable转换成另一种特定的Observable  Producer: 创建Observable的时候, 数据流的生产者  Single: Observable的stream中只有一个数据的时候, Single可 以把Subscriber缩减掉onCompleted, 只剩下onSuccess, onError
  • 51. # 超级玛丽  时间是一个Observable Stream  键盘是一个Observable Stream  绘图事件纷发是一个Observable Stream  任何东西都可以是 Observable Stream
  • 52. ## 时间是一个Observable Stream val clock = Observable.interval(1, TimeUnit.SECONDS) -0--1--2--3--4--5--... fun countDownClock(limit : Int) = clock.map{limit - it}.takeWhile{it > 0} -limit--(limit-1)--(limit-2)--…--3--2--1--|
  • 53. ### takeWhile Tips: 还有 takeUntil, skipWhile, skipUntil take, skip, takeFirst, takeLast, skipFirst, skipLast
  • 54. ## 超级玛丽倒计时太简单了 countDownClock(255).subscribe { timerView.setText("Time left: $it") } Tips: 你应该将界面刷新 bring到 绘制线程 countDownClock(255). observeOn(MyRenderScheduler.draw()) subscribe { timerView.setText("Time left: $it") } 例如: Android使用原生TextView的话 observeOn(AndroidScheduler.mainThread())
  • 55. ## 键盘是一个Observable Stream override fun dispatchKeyEvent(e: KeyEvent): Boolean { keyboard.onNext(e) return super.dispatchKeyEvent(e) } val keyboard = PublishSubject.create<KeyEvent>()
  • 56. ### PublishSubject 一个Hot Observable, 不管有没有subscriber订阅, 都在emit数 据, 每个subscriber订阅到PublishSubject的时候, 开始监听这 个时刻起的数据
  • 57. ## Hot & Cold Observables Hot Observable Cold Observable 区别 创建之后就开始emit数据 当有subscriber订阅到此 Observable的时候, 才开 始emit数据 Observable 绝大多数Observable都是 Hot Observable ConnectableObservable Operators 绝大多数Operator不改变 Observable的特性 publish, refCount share = publish + refCount replay tips: Cold Observable常用于pull型逻辑, 比如Http请求 不过Rx更好的 Single 实现, 例如 Retrofit
  • 58. ## 键盘与时间绑定 val sample : Observable<in Pair<Int, KeyEvent>> = clock.publish { _clock-> keyboard.map{key-> _clock.map{i-> Pair(i, key)} } }.switchMap{it} 对于每一次键盘按下 与时钟配对 每当有新按键事件, 切换到最新的 Tips: clock.publish 保证每一次匹配时间与键盘, 时间都是一直 延续下去的, 而不是每次都从零开始 (共享subscription)
  • 59. ### 家庭教师 时间 t, 速度 v, 加速度 a, 位移 s 位移公式: s = v0 + ½ ·a·t² (我们按时间等分拆解) ∑ Δs = ∑ Δs · Δt Δs = Δv · Δt 加速度 Δa = Δv / Δt 那么 vn = vn-1 + Δa Δt Δs = vn-1 Δt+ Δa Δt² 当我们取 Δt = 1 的时候, 每个时间分片内的位移 Δs = Δvn = vn-1 + Δa
  • 60. ## 向←向→ val arrows = keyboard.filter { intArrayOf(KeyEvent.ACTION_DOWN, KeyEvent.ACTION_UP). contains(it.getAction()) && intArrayOf(KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT). contains(it.getKeyCode()) }.distinctUntilChanged() 过滤键盘 ← → 方向按键
  • 62. ## Δa:向←减速,向→加速 fun deltaAcceleration(acceleration : Int) = clock.publish { _clock -> arrows.map { key -> _clock.map { _ -> Int if (key.getAction() == KeyEvent.ACTION_UP) (-acceleration / 2) else if (key.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) -acceleration else acceleration } }.switchMap{it} } 模拟惯性减速 向←减速 向→加速 tips: 如果是格斗游戏, 按键还需要存放到 按键堆栈 中处理连招指令
  • 63. ## Walk, Mario! tips: Mario总是在场景(Scene)中间, 走动的时候, 是场景往左 移动, 地图制作者或设计师管场景叫 关卡
  • 64. ## 地板 public open class Ground { val tile : Bitmap = getImage("tile") val height = tile.getHeight() val nrTiles = Math.ceil(screenWidth / tile.getWidth()) as Int + 1 fun onDraw(canvas : Canvas) = (0..nrTiles).map { canvas.drawBitmap(tile, tile.getWidth() * it as Float, 0 as Float, paint) } }
  • 65. ## 走起来 val v0 = 0 val s0 = 0 val acceleration = 3 deltaAcceleration(acceleration). scan(v0) { vi, a-> vi + a }. scan(s0) { si, vi-> si + vi }. subscribe { ground.setTranslateX(it) } Δa vi = vi-1 + Δa·Δt si = si-1 + vi · Δt
  • 66. ### scan Tips: 前一次运行的输出结果, 保留为下一次运行的输入数据 类似动态语言(例如groovy)中的 inject 函数(high-order函数)
  • 67. ### scan(R, fun) Tips: 接受一个初始化数据参与scan, 例如玛丽初始化速度v0, 参 与scan单位时间内加速度引起的速度变更, 初始化位移s0参与单 位时间内速度变化引起的位移变化
  • 68. ## Jump, Mario! v0 v1 = v0 - g v2 = v1 – g = 0 v3 = v2 - g v4 = v3 – g = -v0
  • 69. ## 跳起来 open class Mario{ // … val junmps : PublishSubject<in Int> = PublishSubject.create() fun init() { junmps.flatMap { v0 -> clock.scan(v0) { vi, _ -> vi - gravity}. takeUntil(junmps) }.subscribe { dy -> setTranslationY(dy as Float) } } } tips: 重力速度公式: vi = vi-1 + gΔt (此处Δt = 1, g = -g)
  • 70. ## 触发Jump val keyPressed = keyboard.filter{it.getAction() == KeyEvent.ACTION_DOWN} val spaceBar = keyPressed.filter{it.getKeyCode() == KeyEvent.KEYCODE_SPACE} val jumpSpeed = 30 spaceBar.filter { mario.translateY >= mario.homeY }. doOnEach{/* SoundPool.play(R.raw.mario_jump) */ }. subscribe { mario.junmps.onNext(jumpSpeed) } 如果Mario在地上 通知Mario跳起来 跳的音效 空格按下的时候
  • 71. ## 碰撞检测 Observable<Position> data class Position( val x : Int, val y : Int, val width : Int, val height : Int) Observable.combineLatest( mario.position, coin.position) { marioPos, coinPos -> collides(marioPos, coinPos) }.buffer(2, 1).filter { it.get(0) != it.get(1) }fun collides (posA, posB) : Boolean { // ….碰撞检测 }
  • 72. ### combineLatest Tips: 组合两个Observable的最后数据根据特定规则生成新的数据 Excel表格 x + y = z 公式, 无论x, y怎么变动, z也跟着变动 对, 就是这样, RxJava中combineLatest最多支持9个Observable
  • 73. ### buffer Tips: 缓存Observable的数据, 批量push 例如写数据库的时候, 可以buffer一批数据在一定时间限 制内一次写入, 批量操作, 回滚/回顾型逻辑, 都靠buffer
  • 74. # 超级玛丽  好了, 大家已经学会 1 + 1 = 2 了  那么, 请大家尝试推导适用于26维 空间超弦定理公式
  • 75. # 引用  http://reactivex.io/  http://kotlinlang.org/docs/reference/  http://www.slideshare.net/andreycheptsov/a-playful- introduction-to-rx  http://www.slideshare.net/allegrotech/rxjava-introduction- context  http://rxmarbles.com/#debounceWithSelector  http://www.mariouniverse.com/fg/supermario-scene-36

Hinweis der Redaktion

  1. 观察者 被动响应 被观察对象的消息/事件/变更等等过程
  2. 消息驱动,类似Event-Driven 异步传递: Asynchronous Message Passing 非阻塞: Non-blocking 对业务透明: Location Transparency, 错误, 异常也是一种消息 back-pressure: 透明性在必要的时候, 消息传递过程中出现异常, 可以不阻塞响应过程
  3. Observable: 集迭代器与被观察者于一体的数据stream
  4. (1-P) 无法异步处理的部分 android上就是主线程 由于Android主线程做的事情太多, 所以这个值比较大, 所以流畅度不如iPhone P/N: 处理器接近无穷多的时候, 速度提升倍数等于 1/(1-P) golang语言: 以P=100%为目标