SlideShare a Scribd company logo
1 of 280
Download to read offline
The Art of Rx
Матвей Мальков
2
Обо мне
3
Обо мне
4
Обо мне
5
Обо мне
Èñêóññòâî ðåàêòèâíîãî
ïðîãðàììèðîâàíèÿ
Èñêóññòâî – âûñîêàÿ ñòåïåíü
ìàñòåðñòâà â êàêîé-ëèáî
ñôåðå äåÿòåëüíîñòè.
Íàø ãëàâíûé íàâûê – óìåíèå
äóìàòü
9
Умение думать. Практика
• î ÷åì äóìàòü?
9
Умение думать. Практика
• î ÷åì äóìàòü?
• êàê äóìàòü?
9
Умение думать. Практика
10
О чем думать мобильному разработчику
• ýíåðãîïîòðåáëåíèå
10
О чем думать мобильному разработчику
• ýíåðãîïîòðåáëåíèå
• ïëàâíîñòü èíòåðôåéñà (60 fps)
10
О чем думать мобильному разработчику
• ýíåðãîïîòðåáëåíèå
• ïëàâíîñòü èíòåðôåéñà (60 fps)
• ôðàãìåíòàöèÿ óñòðîéñòâ
10
О чем думать мобильному разработчику
• ýíåðãîïîòðåáëåíèå
• ïëàâíîñòü èíòåðôåéñà (60 fps)
• ôðàãìåíòàöèÿ óñòðîéñòâ
• ïîòðåáëåíèå ïàìÿòè
10
О чем думать мобильному разработчику
11
Как думать мобильному разработчику?
• êàê ïîëüçîâàòåëü
11
Как думать мобильному разработчику?
• êàê ïîëüçîâàòåëü
• êàê äèçàéíåð
11
Как думать мобильному разработчику?
• êàê ïîëüçîâàòåëü
• êàê äèçàéíåð
• êàê ïðåäëàãàåò ôóíäàìåíòàëüíûé ôðåéìâîðê
11
Как думать мобильному разработчику?
12
Фундаментальный фреймворк
• äåëàåò ðàçðàáîòêó ïðîùå/ëó÷øå/áûñòðåå
12
Фундаментальный фреймворк
• äåëàåò ðàçðàáîòêó ïðîùå/ëó÷øå/áûñòðåå
• ïðèâíîñèò ÷òî-òî êîíöåïòóàëüíî íîâîå
12
Фундаментальный фреймворк
• äåëàåò ðàçðàáîòêó ïðîùå/ëó÷øå/áûñòðåå
• ïðèâíîñèò ÷òî-òî êîíöåïòóàëüíî íîâîå
• ïðîðàñòàåò âî âñå ïîäñèñòåìû
12
Фундаментальный фреймворк
• äåëàåò ðàçðàáîòêó ïðîùå/ëó÷øå/áûñòðåå
• ïðèâíîñèò ÷òî-òî êîíöåïòóàëüíî íîâîå
• ïðîðàñòàåò âî âñå ïîäñèñòåìû
• ñëîæíî óáðàòü
12
Фундаментальный фреймворк
• äåëàåò ðàçðàáîòêó ïðîùå/ëó÷øå/áûñòðåå
• ïðèâíîñèò ÷òî-òî êîíöåïòóàëüíî íîâîå
• ïðîðàñòàåò âî âñå ïîäñèñòåìû
• ñëîæíî óáðàòü
• òðåáóåò íàâûêîâ îáðàùåíèÿ
12
Фундаментальный фреймворк
Íàø ëþáèìûé ôóíäàìåíòàëüíûé
ôðåéìâîðê – RxJava
Î ÷eì äóìàòü, èñïîëüçóÿ RxJava?
Î êîíòðàêòàõ
16
О контрактах
• ïðîáëåìû:
16
О контрактах
• ïðîáëåìû:
• ïîíèìàíèå
16
О контрактах
• ïðîáëåìû:
• ïîíèìàíèå
• ñîáëþäåíèå
16
О контрактах
• ïðîáëåìû:
• ïîíèìàíèå
• ñîáëþäåíèå
• âàæíî:
16
О контрактах
• ïðîáëåìû:
• ïîíèìàíèå
• ñîáëþäåíèå
• âàæíî:
• îñíîâû
16
О контрактах
17
Нотификации
• onNext – 0, n èëè inf
17
Нотификации
• onNext – 0, n èëè inf
• onCompleted – 0 èëè 1
17
Нотификации
• onNext – 0, n èëè inf
• onCompleted – 0 èëè 1
• onError – 0 èëè 1
17
Нотификации
• onNext – 0, n èëè inf
• onCompleted – 0 èëè 1
• onError – 0 èëè 1
• onCompleted + onError <= 1
17
Нотификации
18
Подписка и отписка
• íå íóæíî îòïèñûâàòüñÿ ïîñëå çàâåðøåíèÿ
18
Подписка и отписка
• íå íóæíî îòïèñûâàòüñÿ ïîñëå çàâåðøåíèÿ
• ïðè îòïèñêå çàâåðøåíèå íå ãàðàíòèðîâàíî
18
Подписка и отписка
19
Observable<Response> obs = Observable

.interval(1, TimeUnit.SECONDS)

.map(this ::sendPing)

.cache();









20
Observable<Response> obs = Observable

.interval(1, TimeUnit.SECONDS)

.map(this ::sendPing)

.cache();









21
Observable<Response> obs = Observable

.interval(1, TimeUnit.SECONDS)

.map(this ::sendPing)

.cache();









22
Observable<Response> obs = Observable

.interval(1, TimeUnit.SECONDS)

.map(this ::sendPing)

.cache();









23
Observable<Response> obs = Observable

.interval(1, TimeUnit.SECONDS)

.map(this ::sendPing)

.cache();



Subscription sub = obs.subscribe();





24
Observable<Response> obs = Observable

.interval(1, TimeUnit.SECONDS)

.map(this ::sendPing)

.cache();



Subscription sub = obs.subscribe();



//позже

sub.unsubscribe();
25
Observable<Response> obs = Observable

.interval(1, TimeUnit.SECONDS)

.map(this ::sendPing)

.cache();



Subscription sub = obs.subscribe();



//позже

sub.unsubscribe();
Note: You sacrifice the ability to
unsubscribe from the origin
26
Observable<Response> obs = Observable

.interval(1, TimeUnit.SECONDS)

.map(this ::sendPing)

.cache();



Subscription sub = obs.subscribe();



//позже

sub.unsubscribe();
Note: You sacrifice the ability to
unsubscribe from the origin
27
О контрактах
• îòïðàâêà íîòèôèêàöèé
27
О контрактах
• îòïðàâêà íîòèôèêàöèé
• çàâåðøåíèå ñ îøèáêîé
27
О контрактах
• îòïðàâêà íîòèôèêàöèé
• çàâåðøåíèå ñ îøèáêîé
• ïîëíûé ñïèñîê : http://reactivex.io/documentation/contract.html
27
О контрактах
28
Состояние системы
• èçîëèðîâàííî
28
Состояние системы
• èçîëèðîâàííî
• îäèí èñòî÷íèê
28
Состояние системы
• èçîëèðîâàííî
• îäèí èñòî÷íèê
• íåèçìåíÿåìî
28
Состояние системы
• èçîëèðîâàííî
• îäèí èñòî÷íèê
• íåèçìåíÿåìî
• ïîä÷èíÿåòñÿ êîíòðàêòó Observable
28
Состояние системы
29
nameEditTextChanges.subscribe(this ::updateName);
30
nameEditTextChanges.subscribe(this ::updateName);
PublishSubject<Integer> nameEditTextChanges =

PublishSubject.create();
31
nameEditTextChanges.subscribe(this ::updateName);
PublishSubject<Integer> nameEditTextChanges =

PublishSubject.create();
nameEditTextChanges.onNext("хаха, обманул!");
Subject – âîçìîæíîå íàðóøåíèå
êîíòðàêòà
Subject – âîçìîæíîå íàðóøåíèå
êîíòðàêòà
• èçîëèðîâàííî
• îäèí èñòî÷íèê
• íåèçìåíÿåìî
• ïîä÷èíÿåòñÿ êîíòðàêòó Observable
34
Состояние системы
35
Subjects
• ñîåäèíåíèå èìïåðàòèâíîãî è ðåàêòèâíîãî ìèðà
35
Subjects
• ñîåäèíåíèå èìïåðàòèâíîãî è ðåàêòèâíîãî ìèðà
• êîãäà íåâîçìîæíî ñäåëàòü ïî äðóãîìó
35
Subjects
• ñîåäèíåíèå èìïåðàòèâíîãî è ðåàêòèâíîãî ìèðà
• êîãäà íåâîçìîæíî ñäåëàòü ïî äðóãîìó
• ýòî âàø ñëó÷àé? ÍÅÒ!
35
Subjects
• ñîåäèíåíèå èìïåðàòèâíîãî è ðåàêòèâíîãî ìèðà
• êîãäà íåâîçìîæíî ñäåëàòü ïî äðóãîìó
• ýòî âàø ñëó÷àé? ÍÅÒ!
• âñå òàêè âàø? Íåò, ýòî íå òàê!
35
Subjects
• ñîåäèíåíèå èìïåðàòèâíîãî è ðåàêòèâíîãî ìèðà
• êîãäà íåâîçìîæíî ñäåëàòü ïî äðóãîìó
• ýòî âàø ñëó÷àé? ÍÅÒ!
• âñå òàêè âàø? Íåò, ýòî íå òàê!
• ìåíüøå – ëó÷øå
35
Subjects
О тредах
37
О тредах
• ïðîáëåìû
37
О тредах
• ïðîáëåìû
• íåò ïîíèìàÿ ðàáîòû
37
О тредах
• ïðîáëåìû
• íåò ïîíèìàÿ ðàáîòû
• ñóþò subscribeOn è observeOn âåçäå ïîäðÿä
37
О тредах
• ïðîáëåìû
• íåò ïîíèìàÿ ðàáîòû
• ñóþò subscribeOn è observeOn âåçäå ïîäðÿä
• âàæíî :
37
О тредах
• ïðîáëåìû
• íåò ïîíèìàÿ ðàáîòû
• ñóþò subscribeOn è observeOn âåçäå ïîäðÿä
• âàæíî :
• ðàçáèðàòüñÿ
37
О тредах
38
Scheduler
• ïëàíèðîâêà çàäà÷
38
Scheduler
• ïëàíèðîâêà çàäà÷
• ðàáîòà ñ òðåäàìè
38
Scheduler
• ïëàíèðîâêà çàäà÷
• ðàáîòà ñ òðåäàìè
• subscribeOn
38
Scheduler
• ïëàíèðîâêà çàäà÷
• ðàáîòà ñ òðåäàìè
• subscribeOn
• observeOn
38
Scheduler
Äîãìû
observeOn
subscribeOn
1. observeOn ìåíÿåò Scheduler äëÿ
âñåãî, ÷òî íèæå ïî êîäó
2. subscribeOn ìåíÿåò Scheduler ñ
ñàìîãî âåðõà öåïî÷êè
3. Êàæäûé ñëåäóþùèé observeOn
çàìåíÿåò ïðåäûäóùèé
4. subscribeOn àêòóàëåí äî
ïåðâîãî observeOn
Âñåãäà äóìàéòå î òîì,
â êàêîì òðåäå âûïîëíÿåòñÿ ôóíêöèÿ
45
Observable<Response> requestObs = userDbChanges

.filter(u -> u.age < 18)

.map(this ::toRequestModel)

.map(this ::doRequest)

.onErrorReturn(this ::doRecoverReq)

.map(this ::cacheAndModify);

//ui thread

requestObs.subscribe(this ::showOnUi);
46
Observable<Response> requestObs = userDbChanges

.filter(u -> u.age < 18)

.map(this ::toRequestModel)

.map(this ::doRequest)

.onErrorReturn(this ::doRecoverReq)

.map(this ::cacheAndModify);

//ui thread

requestObs.subscribe(this ::showOnUi);
47
Observable<Response> requestObs = userDbChanges

.filter(u -> u.age < 18)
.map(this ::toRequestModel)

.observeOn(networkScheduler)

.map(this ::doRequest)

.onErrorReturn(this ::doRecoverReq)

.subscribeOn(Schedulers.computation())

.observeOn(mainThread)

.map(this ::toUiModel);

//ui thread

requestObs.subscribe(this ::showOnUi);
48
Observable<Response> requestObs = userDbChanges

.filter(u -> u.age < 18)
.map(this ::toRequestModel)

.observeOn(networkScheduler)

.map(this ::doRequest)

.onErrorReturn(this ::doRecoverReq)

.subscribeOn(Schedulers.computation())

.observeOn(mainThread)

.map(this ::toUiModel);

//ui thread

requestObs.subscribe(this ::showOnUi);
49
Observable<Response> requestObs = userDbChanges

.filter(u -> u.age < 18)
.map(this ::toRequestModel)

.observeOn(networkScheduler)

.map(this ::doRequest)

.onErrorReturn(this ::doRecoverReq)

.subscribeOn(Schedulers.computation())

.observeOn(mainThread)

.map(this ::toUiModel);

//ui thread

requestObs.subscribe(this ::showOnUi);
50
Observable<Response> requestObs = userDbChanges

.filter(u -> u.age < 18)
.map(this ::toRequestModel)

.observeOn(networkScheduler)

.map(this ::doRequest)

.onErrorReturn(this ::doRecoverReq)

.subscribeOn(Schedulers.computation())

.observeOn(mainThread)

.map(this ::toUiModel);

//ui thread

requestObs.subscribe(this ::showOnUi);
51
Observable<Response> requestObs = userDbChanges

.filter(u -> u.age < 18)
.map(this ::toRequestModel)

.observeOn(networkScheduler)

.map(this ::doRequest)

.onErrorReturn(this ::doRecoverReq)

.subscribeOn(Schedulers.computation())

.observeOn(mainThread)

.map(this ::toUiModel);

//ui thread

requestObs.subscribe(this ::showOnUi);
52
Observable<Response> requestObs = userDbChanges

.filter(u -> u.age < 18)
.map(this ::toRequestModel)

.observeOn(networkScheduler)

.map(this ::doRequest)

.onErrorReturn(this ::doRecoverReq)

.subscribeOn(Schedulers.computation())

.observeOn(mainThread)

.map(this ::toUiModel);

//ui thread

requestObs.subscribe(this ::showOnUi);
53
Observable<Response> requestObs = userDbChanges

.filter(u -> u.age < 18)
.map(this ::toRequestModel)

.observeOn(networkScheduler)

.map(this ::doRequest)

.onErrorReturn(this ::doRecoverReq)

.subscribeOn(Schedulers.computation())

.observeOn(mainThread)

.map(this ::toUiModel);

//ui thread

requestObs.subscribe(this ::showOnUi);
Âåëèêîëåïíûé subscribeOn
55
subscribeOn
public final Observable<T> subscribeOn(Scheduler scheduler) {


//какой-то неважный код


return nest().lift(new OperatorSubscribeOn<T>(scheduler));

}
56
subscribeOn
public final Observable<T> subscribeOn(Scheduler scheduler) {


//какой-то неважный код


return nest().lift(new OperatorSubscribeOn<T>(scheduler));

}
57
public final Observable<Observable<T >> nest() {

return just(this);

}
58
59
nest
60
nest
61
subscribeOn
public final Observable<T> subscribeOn(Scheduler scheduler) {


//какой-то неважный код


return nest().lift(new OperatorSubscribeOn<T>(scheduler));

}
62
subscribeOn
public final Observable<T> subscribeOn(Scheduler scheduler) {


//какой-то неважный код


return nest().lift(new OperatorSubscribeOn<T>(scheduler));

}
63
subscribeOn
public final Observable<T> subscribeOn(Scheduler scheduler) {


//какой-то неважный код


return nest().lift(new OperatorSubscribeOn<T>(scheduler));

}
64
public class OperatorSubscribeOn<T> implements Operator<T, Observable<T >> {



private final Scheduler scheduler;



public OperatorSubscribeOn(Scheduler scheduler) {

this.scheduler = scheduler;

}



@Override

public Subscriber<? super Observable<T >> call(final Subscriber<? super T> subscriber) {
…

}
65
public class OperatorSubscribeOn<T> implements Operator<T, Observable<T >> {



private final Scheduler scheduler;



public OperatorSubscribeOn(Scheduler scheduler) {

this.scheduler = scheduler;

}



@Override

public Subscriber<? super Observable<T >> call(final Subscriber<? super T> subscriber) {
…

}
принимаетвозвращает
66
public class OperatorSubscribeOn<T> implements Operator<T, Observable<T >> {



private final Scheduler scheduler;



public OperatorSubscribeOn(Scheduler scheduler) {

this.scheduler = scheduler;

}



@Override

public Subscriber<? super Observable<T >> call(final Subscriber<? super T> subscriber) {
…

}
67
@Override

public Subscriber<? super Observable<T >> call(final Subscriber<? super T> subscriber) {

final Worker inner = scheduler.createWorker();

subscriber.add(inner);

return new Subscriber<Observable<T >>(subscriber) {



@Override

public void onNext(final Observable<T> o) {

inner.schedule(new Action0() {



@Override

public void call() {

final Thread t = Thread.currentThread();

o.unsafeSubscribe(new Subscriber<T>(subscriber) {
//обычный inner subscribe
}





//тут еще оооочень много закрывающихся скобочек

}
68
@Override

public Subscriber<? super Observable<T >> call(final Subscriber<? super T> subscriber) {

final Worker inner = scheduler.createWorker();

subscriber.add(inner);

return new Subscriber<Observable<T >>(subscriber) {



@Override

public void onNext(final Observable<T> o) {

inner.schedule(new Action0() {



@Override

public void call() {

final Thread t = Thread.currentThread();

o.unsafeSubscribe(new Subscriber<T>(subscriber) {
//обычный inner subscribe
}





//тут еще оооочень много закрывающихся скобочек

}
69
@Override

public Subscriber<? super Observable<T >> call(final Subscriber<? super T> subscriber) {

final Worker inner = scheduler.createWorker();

subscriber.add(inner);

return new Subscriber<Observable<T >>(subscriber) {



@Override

public void onNext(final Observable<T> o) {

inner.schedule(new Action0() {



@Override

public void call() {

final Thread t = Thread.currentThread();

o.unsafeSubscribe(new Subscriber<T>(subscriber) {
//обычный inner subscribe
}





//тут еще оооочень много закрывающихся скобочек

}
70
@Override

public Subscriber<? super Observable<T >> call(final Subscriber<? super T> subscriber) {

final Worker inner = scheduler.createWorker();

subscriber.add(inner);

return new Subscriber<Observable<T >>(subscriber) {



@Override

public void onNext(final Observable<T> o) {

inner.schedule(new Action0() {



@Override

public void call() {

final Thread t = Thread.currentThread();

o.unsafeSubscribe(new Subscriber<T>(subscriber) {
//обычный inner subscribe
}





//тут еще оооочень много закрывающихся скобочек

}
71
@Override

public Subscriber<? super Observable<T >> call(final Subscriber<? super T> subscriber) {

final Worker inner = scheduler.createWorker();

subscriber.add(inner);

return new Subscriber<Observable<T >>(subscriber) {



@Override

public void onNext(final Observable<T> o) {

inner.schedule(new Action0() {



@Override

public void call() {

final Thread t = Thread.currentThread();

o.unsafeSubscribe(new Subscriber<T>(subscriber) {
//обычный inner subscribe
}





//тут еще оооочень много закрывающихся скобочек

}
Наш Observable
72
@Override

public Subscriber<? super Observable<T >> call(final Subscriber<? super T> subscriber) {

final Worker inner = scheduler.createWorker();

subscriber.add(inner);

return new Subscriber<Observable<T >>(subscriber) {



@Override

public void onNext(final Observable<T> o) {

inner.schedule(new Action0() {



@Override

public void call() {

final Thread t = Thread.currentThread();

o.unsafeSubscribe(new Subscriber<T>(subscriber) {
//обычный inner subscribe
}





//тут еще оооочень много закрывающихся скобочек

}
73
@Override

public Subscriber<? super Observable<T >> call(final Subscriber<? super T> subscriber) {

final Worker inner = scheduler.createWorker();

subscriber.add(inner);

return new Subscriber<Observable<T >>(subscriber) {



@Override

public void onNext(final Observable<T> o) {

inner.schedule(new Action0() {



@Override

public void call() {

final Thread t = Thread.currentThread();

o.unsafeSubscribe(new Subscriber<T>(subscriber) {
//обычный inner subscribe
}





//тут еще оооочень много закрывающихся скобочек

}
74
75
OperatorSubscribeOn(Scheduler)
76
OperatorSubscribeOn(Scheduler)
Ãåíèàëüíî!
78
Observable.just(1)

.subscribeOn(scheduler1)
.subscribeOn(scheduler2)

.subscribe();
79
Observable.just(1)

.subscribeOn(scheduler1)
.subscribeOn(scheduler2)

.subscribe(); //scheduler1
2. subscribeOn ìåíÿåò Scheduler ñ
ñàìîãî âåðõà öåïî÷êè
2. Ïåðâûé subscribeOn ìåíÿåò
Scheduler ñ ñàìîãî âåðõà öåïî÷êè
82
//computation

Observable<Long> o1 = Observable.interval(1, TimeUnit.SECONDS);

//network

Observable<Integer> o2 = Observable.just(1)

.observeOn(networkScheduler);



Observable.zip(o1, o2, o3, (r1, r2) -> r1 * r2);
83
//computation

Observable<Long> o1 = Observable.interval(1, TimeUnit.SECONDS);

//network

Observable<Integer> o2 = Observable.just(1)

.observeOn(networkScheduler);



Observable.zip(o1, o2, o3, (r1, r2) -> r1 * r2);
84
//computation

Observable<Long> o1 = Observable.interval(1, TimeUnit.SECONDS);

//network

Observable<Integer> o2 = Observable.just(1)

.observeOn(networkScheduler);



Observable.zip(o1, o2, o3, (r1, r2) -> r1 * r2);
//computation or network
85
final class InnerSubscriber extends Subscriber {



@Override

public void onNext(Object t) {

try {

items.onNext(t);

} catch (MissingBackpressureException e) {

onError(e);

}

tick();

}

};
86
final class InnerSubscriber extends Subscriber {



@Override

public void onNext(Object t) {

try {

items.onNext(t);

} catch (MissingBackpressureException e) {

onError(e);

}

tick();

}

};
87
void tick() {

//тут много кода, не имеющего сейчас значения


if (requested.get() > 0 && allHaveValues) {

try {

// всем потокам есть что zip’ать

child.onNext(zipFunction.call(vs));
}
// еще много кода и скобочки
88
void tick() {

//тут много кода, не имеющего сейчас значения


if (requested.get() > 0 && allHaveValues) {

try {

// всем потокам есть что zip’ать

child.onNext(zipFunction.call(vs));
}
// еще много кода и скобочки
89
void tick() {

//тут много кода, не имеющего сейчас значения


if (requested.get() > 0 && allHaveValues) {

try {

// всем потокам есть что zip’ать

child.onNext(zipFunction.call(vs));
}
// еще много кода и скобочки
Âñåãäà äóìàéòå î òîì,
â êàêîì òðåäå âûïîëíÿåòñÿ ôóíêöèÿ
О количестве элементов
92
Количество элементов
• ïðîáëåìû:
92
Количество элементов
• ïðîáëåìû:
• áîëüøå ýëåìåíòîâ – áîëüøå ìóñîðà
92
Количество элементов
• ïðîáëåìû:
• áîëüøå ýëåìåíòîâ – áîëüøå ìóñîðà
• RxJava ïîñòîÿííî âñå êîïèðóåò
92
Количество элементов
• ïðîáëåìû:
• áîëüøå ýëåìåíòîâ – áîëüøå ìóñîðà
• RxJava ïîñòîÿííî âñå êîïèðóåò
• âàæíî:
92
Количество элементов
• ïðîáëåìû:
• áîëüøå ýëåìåíòîâ – áîëüøå ìóñîðà
• RxJava ïîñòîÿííî âñå êîïèðóåò
• âàæíî:
• íå ïàíèêîâàòü
92
Количество элементов
• ïðîáëåìû:
• áîëüøå ýëåìåíòîâ – áîëüøå ìóñîðà
• RxJava ïîñòîÿííî âñå êîïèðóåò
• âàæíî:
• íå ïàíèêîâàòü
• çàáîòèòüñÿ î GC
92
Количество элементов
93
Не паниковать
• «×òî ñ GC?» : ñàìûé æàðêèé âîïðîñ
93
Не паниковать
• «×òî ñ GC?» : ñàìûé æàðêèé âîïðîñ
• êîïèðîâàíèå òîëüêî ïðè íîòèôèêàöèÿõ
93
Не паниковать
• «×òî ñ GC?» : ñàìûé æàðêèé âîïðîñ
• êîïèðîâàíèå òîëüêî ïðè íîòèôèêàöèÿõ
• âñå îïòèìèçèðîâàííî
93
Не паниковать
94
locationUpdates()

.distinctUntilChanged()

.subscribe();
95
locationUpdates()

.distinctUntilChanged()

.subscribe();
96
locationUpdates()

.distinctUntilChanged()

.subscribe();
touchEvents(view)

.filter(e -> e.x > minWidth && e.y > minHeight)

.doOnNext(this ::processEvents)

.subscribe();
97
locationUpdates()

.distinctUntilChanged()

.subscribe();
touchEvents(view)

.filter(e -> e.x > minWidth && e.y > minHeight)

.doOnNext(this ::processEvents)

.subscribe();
98
nameEditTextChanges

.map(this ::prepareForSending)

.map(this ::sendName)

.map(this ::cacheAndModify);
99
nameEditTextChanges

.map(this ::prepareForSending) //раз

.map(this ::sendName)

.map(this ::cacheAndModify);
100
nameEditTextChanges

.map(this ::prepareForSending) //раз

.map(this ::sendName) // два

.map(this ::cacheAndModify);
101
nameEditTextChanges

.map(this ::prepareForSending) //раз

.map(this ::sendName) // два

.map(this ::cacheAndModify); // три
102
nameEditTextChanges

.debounce(500, TimeUnit.MILLISECONDS)

.map(this ::prepareForSending)

.map(this ::sendName)

.map(this ::cacheAndModify);
103
debounce
• áåðåæåò GC
103
debounce
• áåðåæåò GC
• áåðåæåò òðàôèê ïîëüçîâàòåëÿ
103
debounce
• áåðåæåò GC
• áåðåæåò òðàôèê ïîëüçîâàòåëÿ
• áåðåæåò íàñ îò BackPressure
103
debounce
104
Backpressure
• îòäàþùèé òðåä äàåò ìíîãî
104
Backpressure
• îòäàþùèé òðåä äàåò ìíîãî
• ïðèíèìàþùèé òðåä íå óñïåâàåò
104
Backpressure
• îòäàþùèé òðåä äàåò ìíîãî
• ïðèíèìàþùèé òðåä íå óñïåâàåò
• â ìíîãîïîòî÷íîé ñðåäå ìíîãîâåðîÿòíî
104
Backpressure
• îòäàþùèé òðåä äàåò ìíîãî
• ïðèíèìàþùèé òðåä íå óñïåâàåò
• â ìíîãîïîòî÷íîé ñðåäå ìíîãîâåðîÿòíî
• ïåðâûé ïðèçíàê – observeOn
104
Backpressure
105
events
touchEvents(view)











106
events filter
touchEvents(view)

.filter(e -> e.x > minWidth)









107
events filter map
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)







108
events filter map observeOn
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)





109
events filter map observeOn
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)



map
110
events filter map observeOn
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

map map
111
events filter map observeOn
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
map map subscriber
112
events filter map observeOn
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
map map subscriber
113
events filter map observeOn
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
map map subscriber
114
events filter map observeOn
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
map map subscriber
115
events filter map observeOn
map map subscriber
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
116
events filter map observeOn
map map subscriber
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
117
events filter map observeOn
map map subscriber
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
118
events filter map observeOn
map map subscriber
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
119
events filter map observeOn
map map subscriber
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
120
events filter map observeOn
map map subscriber
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
121
events filter map observeOn
map map subscriber
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
122
events filter map observeOn
map map subscriber
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
123
events filter map observeOn
map map subscriber
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
124
events filter map observeOn
map map subscriber
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
125
events filter map observeOn
map map subscriber
2
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
126
events filter map observeOn
map map subscriber
2
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
127
events filter map observeOn
map map subscriber
2
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
128
events filter map observeOn
map map subscriber
2
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
129
events filter map observeOn
map map subscriber
3
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
130
events filter map observeOn
map map subscriber
3
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
131
events filter map observeOn
map map subscriber
3
Устал
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
132
events filter map observeOn
map map subscriber
3
Устал
touchEvents(view)

.filter(e -> e.x > minWidth)

.map(this ::normalize)

.observeOn(networkScheduler)

.map(this ::prepareForSending)

.map(this ::doMotionRequest)

.subscribe()
133
events filter map observeOn
map map subscriber
4
rx.exceptions.MissingBackpressureException
134
Observable.zip(

Observable.interval(10, TimeUnit.MILLISECONDS),

Observable.interval(20, TimeUnit.MILLISECONDS),

(r1, r2) -> r1 * r2

).subscribe();
135
Observable.zip(

Observable.interval(10, TimeUnit.MILLISECONDS),

Observable.interval(20, TimeUnit.MILLISECONDS),

(r1, r2) -> r1 * r2

).subscribe();
136
Observable.zip(

Observable.interval(10, TimeUnit.MILLISECONDS),

Observable.interval(20, TimeUnit.MILLISECONDS),

(r1, r2) -> r1 * r2

).subscribe();
137
Observable.zip(

Observable.interval(10, TimeUnit.MILLISECONDS),

Observable.interval(20, TimeUnit.MILLISECONDS),

(r1, r2) -> r1 * r2

).subscribe();
138
Observable.zip(

Observable.interval(10, TimeUnit.MILLISECONDS),

Observable.interval(20, TimeUnit.MILLISECONDS),

(r1, r2) -> r1 * r2

).subscribe();
rx.exceptions.MissingBackpressureException
139
Борьба с Backpressure
• debounce, throttle
139
Борьба с Backpressure
• debounce, throttle
• window, buffer
139
Борьба с Backpressure
• debounce, throttle
• window, buffer
• onBackpressureBuffer
139
Борьба с Backpressure
• debounce, throttle
• window, buffer
• onBackpressureBuffer
• onBackpressureDrop
139
Борьба с Backpressure
140
141
Âñåãäà äóìàéòå î òîì,
ñêîëüêî ýëåìåíòîâ âàì íóæíî
îò Observable
Êàê äóìàòü, èñïîëüçóÿ RxJava?
Как инженер
145
Как инженер
• íå áîéñÿ ðàñøèðÿòü ôðåéìâîðê
145
Как инженер
• íå áîéñÿ ðàñøèðÿòü ôðåéìâîðê
• ïîíèìàé, êàê îí ðàáîòàåò âíóòðè
145
Как инженер
146
DoOnNextAsync
• doOnNext == ñàéä ýôôåêò
146
DoOnNextAsync
• doOnNext == ñàéä ýôôåêò
• íå áëîêèðîâàòü âûïîëíåíèå ðîäèòåëÿ
146
DoOnNextAsync
• doOnNext == ñàéä ýôôåêò
• íå áëîêèðîâàòü âûïîëíåíèå ðîäèòåëÿ
• áûë ïðèâÿçàí ê æèçíåííîìó öèêëó ðîäèòåëÿ
146
DoOnNextAsync
• doOnNext == ñàéä ýôôåêò
• íå áëîêèðîâàòü âûïîëíåíèå ðîäèòåëÿ
• áûë ïðèâÿçàí ê æèçíåííîìó öèêëó ðîäèòåëÿ
• íå ÷åðåç Subjects
146
DoOnNextAsync
147
userDbChanges

.map(this ::doRequest)

.doOnNext(resp -> {

globalSubscription = createCacheObs(resp)
.subscribe();

})

.map(this ::doAnotherRequest);
148
userDbChanges

.map(this ::doRequest)

.doOnNext(resp -> {

globalSubscription = createCacheObs(resp)
.subscribe();

})

.map(this ::doAnotherRequest);
149
userDbChanges

.map(this ::doRequest)

.lift(new DoOnNextAsync <>(this ::cacheObs))

.map(this ::doAnotherRequest);
150
userDbChanges

.map(this ::doRequest)

.lift(new DoOnNextAsync <>(this ::cacheObs))

.map(this ::doAnotherRequest);
151
class DoOnNextAsync<F, T> implements Observable.Operator<F, F> {

private final Func1<F, Observable<T >> nested;



public DoOnNextAsync(Func1<F, Observable<T >> func) {

this.nested = func;

}

//больше кода дальше
152
class DoOnNextAsync<F, T> implements Observable.Operator<F, F> {

private final Func1<F, Observable<T >> nested;



public DoOnNextAsync(Func1<F, Observable<T >> func) {

this.nested = func;

}

//больше кода дальше
153
class DoOnNextAsync<F, T> implements Observable.Operator<F, F> {

private final Func1<F, Observable<T >> nested;



public DoOnNextAsync(Func1<F, Observable<T >> func) {

this.nested = func;

}

//больше кода дальше
154
@Override

public Subscriber<? super F> call(Subscriber<? super F> subscriber) {

return new Subscriber<F>() {



@Override

public void onNext(F next) {

if (!subscriber.isUnsubscribed()) {
Subscription s = nested.call(next).subscribe();

subscriber.add(s);

}

}
//тривиальные onError и onCompleted здесь

};

}
155
@Override

public Subscriber<? super F> call(Subscriber<? super F> subscriber) {

return new Subscriber<F>() {



@Override

public void onNext(F next) {

if (!subscriber.isUnsubscribed()) {
Subscription s = nested.call(next).subscribe();

subscriber.add(s);

}

}
//тривиальные onError и onCompleted здесь

};

}
156
@Override

public Subscriber<? super F> call(Subscriber<? super F> subscriber) {

return new Subscriber<F>() {



@Override

public void onNext(F next) {

if (!subscriber.isUnsubscribed()) {
Subscription s = nested.call(next).subscribe();

subscriber.add(s);

}

}
//тривиальные onError и onCompleted здесь

};

}
157
@Override

public Subscriber<? super F> call(Subscriber<? super F> subscriber) {

return new Subscriber<F>() {



@Override

public void onNext(F next) {

if (!subscriber.isUnsubscribed()) {
Subscription s = nested.call(next).subscribe();

subscriber.add(s);

}

}
//тривиальные onError и onCompleted здесь

};

}
158
@Override

public Subscriber<? super F> call(Subscriber<? super F> subscriber) {

return new Subscriber<F>() {



@Override

public void onNext(F next) {

if (!subscriber.isUnsubscribed()) {
Subscription s = nested.call(next).subscribe();

subscriber.add(s);

}

}
//тривиальные onError и onCompleted здесь

};

}
• Operator, lift,
• subscribeOn, observeOn
• nest, defer, create
159
Понимай, как работает внутри
Думай реактивно
161
Думать реактивно
• ñîåäèíÿòü èìïåðàòèâíûé è ðåàêòèâíûé ìèð
161
Думать реактивно
• ñîåäèíÿòü èìïåðàòèâíûé è ðåàêòèâíûé ìèð
• íå èñïîëüçîâàòü ñàáäæåêòû
161
Думать реактивно
• ñîåäèíÿòü èìïåðàòèâíûé è ðåàêòèâíûé ìèð
• íå èñïîëüçîâàòü ñàáäæåêòû
• îïèñûâàòü, «êàê äåëàòü», à íå «÷òî äåëàòü»
161
Думать реактивно
162
AutoLoadingRecyclerView
• íàó÷èòü RecycerView àâòîïîäãðóçêå
162
AutoLoadingRecyclerView
• íàó÷èòü RecycerView àâòîïîäãðóçêå
• ñäåëàòü ñ ïîìîùüþ RxJava
162
AutoLoadingRecyclerView
• íàó÷èòü RecycerView àâòîïîäãðóçêå
• ñäåëàòü ñ ïîìîùüþ RxJava
• â ðåàêòèâíîì ñòèëå
162
AutoLoadingRecyclerView
163
public class AutoLoadingRecyclerView<T> extends RecyclerView {



protected PublishSubject<Pair<Integer, Integer >> scrollLoadingChannel =

PublishSubject.create();



protected void startScrollingChannel() {

addOnScrollListener(new RecyclerView.OnScrollListener() {

@Override

public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

if (shouldLoad()) {

int offset = getAdapter().getItemCount();

scrollLoadingChannel.onNext(new Pair(offset, limit));

}

}

});

}
164
public class AutoLoadingRecyclerView<T> extends RecyclerView {



protected PublishSubject<Pair<Integer, Integer >> scrollLoadingChannel =

PublishSubject.create();



protected void startScrollingChannel() {

addOnScrollListener(new RecyclerView.OnScrollListener() {

@Override

public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

if (shouldLoad()) {

int offset = getAdapter().getItemCount();

scrollLoadingChannel.onNext(new Pair(offset, limit));

}

}

});

}
165
public class AutoLoadingRecyclerView<T> extends RecyclerView {



protected PublishSubject<Pair<Integer, Integer >> scrollLoadingChannel =

PublishSubject.create();



protected void startScrollingChannel() {

addOnScrollListener(new RecyclerView.OnScrollListener() {

@Override

public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

if (shouldLoad()) {

int offset = getAdapter().getItemCount();

scrollLoadingChannel.onNext(new Pair(offset, limit));

}

}

});

}
166
public class AutoLoadingRecyclerView<T> extends RecyclerView {



protected PublishSubject<Pair<Integer, Integer >> scrollLoadingChannel =

PublishSubject.create();



protected void startScrollingChannel() {

addOnScrollListener(new RecyclerView.OnScrollListener() {

@Override

public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

if (shouldLoad()) {

int offset = getAdapter().getItemCount();

scrollLoadingChannel.onNext(new Pair(offset, limit));

}

}

});

}
167
public class AutoLoadingRecyclerView<T> extends RecyclerView {



protected PublishSubject<Pair<Integer, Integer >> scrollLoadingChannel =

PublishSubject.create();



protected void startScrollingChannel() {

addOnScrollListener(new RecyclerView.OnScrollListener() {

@Override

public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

if (shouldLoad()) {

int offset = getAdapter().getItemCount();

scrollLoadingChannel.onNext(new Pair(offset, limit));

}

}

});

}
168
public class AutoLoadingRecyclerView<T> extends RecyclerView {



protected PublishSubject<OffsetAndLimit> scrollLoadingChannel =

PublishSubject.create();

protected Subscription loadNewItemsSubscription;

protected Subscription subscribeToLoadingChannelSubscription;
169
public class AutoLoadingRecyclerView<T> extends RecyclerView {



protected PublishSubject<OffsetAndLimit> scrollLoadingChannel =

PublishSubject.create();

protected Subscription loadNewItemsSubscription;

protected Subscription subscribeToLoadingChannelSubscription;
170
public class AutoLoadingRecyclerView<T> extends RecyclerView {



protected PublishSubject<OffsetAndLimit> scrollLoadingChannel =

PublishSubject.create();

protected Subscription loadNewItemsSubscription;

protected Subscription subscribeToLoadingChannelSubscription;
171
private static Observable<Integer>

getScrollObservable(RecyclerView recyclerView, int limit) {


return Observable.create(subscriber -> {

final RecyclerView.OnScrollListener sl = new RecyclerView.OnScrollListener() {

@Override

public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

if (!subscriber.isUnsubscribed() && shouldLoad()) {

subscriber.onNext(recyclerView.getAdapter().getItemCount());

}

}

};

recyclerView.addOnScrollListener(sl);

subscriber.add(Subscriptions.create(() -> recyclerView.removeOnScrollListener(sl)));

});

}
172
private static Observable<Integer>

getScrollObservable(RecyclerView recyclerView, int limit) {


return Observable.create(subscriber -> {

final RecyclerView.OnScrollListener sl = new RecyclerView.OnScrollListener() {

@Override

public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

if (!subscriber.isUnsubscribed() && shouldLoad()) {

subscriber.onNext(recyclerView.getAdapter().getItemCount());

}

}

};

recyclerView.addOnScrollListener(sl);

subscriber.add(Subscriptions.create(() -> recyclerView.removeOnScrollListener(sl)));

});

}
173
private static Observable<Integer>

getScrollObservable(RecyclerView recyclerView, int limit) {


return Observable.create(subscriber -> {

final RecyclerView.OnScrollListener sl = new RecyclerView.OnScrollListener() {

@Override

public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

if (!subscriber.isUnsubscribed() && shouldLoad()) {

subscriber.onNext(recyclerView.getAdapter().getItemCount());

}

}

};

recyclerView.addOnScrollListener(sl);

subscriber.add(Subscriptions.create(() -> recyclerView.removeOnScrollListener(sl)));

});

}
174
private static Observable<Integer>

getScrollObservable(RecyclerView recyclerView, int limit) {


return Observable.create(subscriber -> {

final RecyclerView.OnScrollListener sl = new RecyclerView.OnScrollListener() {

@Override

public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

if (!subscriber.isUnsubscribed() && shouldLoad()) {

subscriber.onNext(recyclerView.getAdapter().getItemCount());

}

}

};

recyclerView.addOnScrollListener(sl);

subscriber.add(Subscriptions.create(() -> recyclerView.removeOnScrollListener(sl)));

});

}
175
private static Observable<Integer>

getScrollObservable(RecyclerView recyclerView, int limit) {


return Observable.create(subscriber -> {

final RecyclerView.OnScrollListener sl = new RecyclerView.OnScrollListener() {

@Override

public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

if (!subscriber.isUnsubscribed() && shouldLoad()) {

subscriber.onNext(recyclerView.getAdapter().getItemCount());

}

}

};

recyclerView.addOnScrollListener(sl);

subscriber.add(Subscriptions.create(() -> recyclerView.removeOnScrollListener(sl)));

});

}
176
private static Observable<Integer>

getScrollObservable(RecyclerView recyclerView, int limit) {


return Observable.create(subscriber -> {

final RecyclerView.OnScrollListener sl = new RecyclerView.OnScrollListener() {

@Override

public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

if (!subscriber.isUnsubscribed() && shouldLoad()) {

subscriber.onNext(recyclerView.getAdapter().getItemCount());

}

}

};

recyclerView.addOnScrollListener(sl);

subscriber.add(Subscriptions.create(() -> recyclerView.removeOnScrollListener(sl)));

});

}
177
getScrollObservable()

.distinctUntilChanged()

.switchMap(offset -> getLoadingObservable(offset))

.subscribeOn(Schedulers

.from(BackgroundExecutor.getSafeBackgroundExecutor())

)

.observeOn(AndroidSchedulers.mainThread())

.subscribe(loadNewItemsSubscriber);
178
getScrollObservable()

.distinctUntilChanged()

.switchMap(offset -> getLoadingObservable(offset))

.subscribeOn(Schedulers

.from(BackgroundExecutor.getSafeBackgroundExecutor())

)

.observeOn(AndroidSchedulers.mainThread())

.subscribe(loadNewItemsSubscriber);
179
getScrollObservable()

.distinctUntilChanged()

.switchMap(offset -> getLoadingObservable(offset))

.subscribeOn(Schedulers

.from(BackgroundExecutor.getSafeBackgroundExecutor())

)

.observeOn(AndroidSchedulers.mainThread())

.subscribe(loadNewItemsSubscriber);
180
getScrollObservable()

.distinctUntilChanged()

.switchMap(offset -> getLoadingObservable(offset))

.subscribeOn(Schedulers

.from(BackgroundExecutor.getSafeBackgroundExecutor())

)

.observeOn(AndroidSchedulers.mainThread())

.subscribe(loadNewItemsSubscriber);
181
getScrollObservable()

.distinctUntilChanged()

.switchMap(offset -> getLoadingObservable(offset))

.subscribeOn(Schedulers

.from(BackgroundExecutor.getSafeBackgroundExecutor())

)

.observeOn(AndroidSchedulers.mainThread())

.subscribe(loadNewItemsSubscriber);
182
getScrollObservable()

.distinctUntilChanged()

.switchMap(offset -> getLoadingObservable(offset))

.subscribeOn(Schedulers

.from(BackgroundExecutor.getSafeBackgroundExecutor())

)

.observeOn(AndroidSchedulers.mainThread())

.subscribe(loadNewItemsSubscriber);
183
Думать реактивно
• èñïîëüçîâàòü ñòàíäàðòíûå ñðåäñòâà RxJava
183
Думать реактивно
• èñïîëüçîâàòü ñòàíäàðòíûå ñðåäñòâà RxJava
• íî íå ñàáäæåêòû
183
Думать реактивно
• èñïîëüçîâàòü ñòàíäàðòíûå ñðåäñòâà RxJava
• íî íå ñàáäæåêòû
• ïðè íåîáõîäèìîñòè – ïèñàòü ñâîå
183
Думать реактивно
• èñïîëüçîâàòü ñòàíäàðòíûå ñðåäñòâà RxJava
• íî íå ñàáäæåêòû
• ïðè íåîáõîäèìîñòè – ïèñàòü ñâîå
• îáîðà÷èâàòü ñîñòîÿíèå â Observable
183
Думать реактивно
• èñïîëüçîâàòü ñòàíäàðòíûå ñðåäñòâà RxJava
• íî íå ñàáäæåêòû
• ïðè íåîáõîäèìîñòè – ïèñàòü ñâîå
• îáîðà÷èâàòü ñîñòîÿíèå â Observable
• ñòàðàòüñÿ è íå ñäàâàòüñÿ
183
Думать реактивно
184
The Art of Rx
• äóìàòü î
184
The Art of Rx
• äóìàòü î
• î êîíòðàêòàõ
184
The Art of Rx
• äóìàòü î
• î êîíòðàêòàõ
• î òðåäàõ
184
The Art of Rx
• äóìàòü î
• î êîíòðàêòàõ
• î òðåäàõ
• î êîëè÷åñòâå ýëåìåíòîâ
184
The Art of Rx
• äóìàòü î
• î êîíòðàêòàõ
• î òðåäàõ
• î êîëè÷åñòâå ýëåìåíòîâ
• äóìàòü êàê
184
The Art of Rx
• äóìàòü î
• î êîíòðàêòàõ
• î òðåäàõ
• î êîëè÷åñòâå ýëåìåíòîâ
• äóìàòü êàê
• èíæåíåð
184
The Art of Rx
• äóìàòü î
• î êîíòðàêòàõ
• î òðåäàõ
• î êîëè÷åñòâå ýëåìåíòîâ
• äóìàòü êàê
• èíæåíåð
• ðåàêòèâíî
184
The Art of Rx
Ñòàòü ïðîôåññèîíàëîì – íåïðîñòî
Íå ëåíèòåñü
Äóìàéòå ìíîãî
Äóìàéòå ìíîãî
Î âàæíûõ âåùàõ
189
Ìàëüêîâ Ìàòâåé
Ñïàñèáî
matveyka_jj
Q & A

More Related Content

What's hot

20071014 introductory course_itsykson_lecture04
20071014 introductory course_itsykson_lecture0420071014 introductory course_itsykson_lecture04
20071014 introductory course_itsykson_lecture04
Computer Science Club
 
5mm2013 130913045236-phpapp02
5mm2013 130913045236-phpapp025mm2013 130913045236-phpapp02
5mm2013 130913045236-phpapp02
Bogdan Lantsuta
 
Лекц 7
Лекц 7Лекц 7
Лекц 7
Muuluu
 

What's hot (15)

20071014 introductory course_itsykson_lecture04
20071014 introductory course_itsykson_lecture0420071014 introductory course_itsykson_lecture04
20071014 introductory course_itsykson_lecture04
 
ñóðãàëòûí òààòàé îð÷èí á¿ðä¿¿ëýõ àðãà ç¿é
ñóðãàëòûí òààòàé îð÷èí á¿ðä¿¿ëýõ àðãà ç¿éñóðãàëòûí òààòàé îð÷èí á¿ðä¿¿ëýõ àðãà ç¿é
ñóðãàëòûí òààòàé îð÷èí á¿ðä¿¿ëýõ àðãà ç¿é
 
5mm2013 130913045236-phpapp02
5mm2013 130913045236-phpapp025mm2013 130913045236-phpapp02
5mm2013 130913045236-phpapp02
 
10-r angi
10-r angi10-r angi
10-r angi
 
Tobch Lecture
Tobch LectureTobch Lecture
Tobch Lecture
 
Lecture 9 [compatibility mode]
Lecture 9 [compatibility mode]Lecture 9 [compatibility mode]
Lecture 9 [compatibility mode]
 
4 klas-matematyka-lyshenko-2021-2
4 klas-matematyka-lyshenko-2021-24 klas-matematyka-lyshenko-2021-2
4 klas-matematyka-lyshenko-2021-2
 
Лекц №14 Төслийн эрсдлийн үнэлгээ
Лекц №14 Төслийн эрсдлийн үнэлгээЛекц №14 Төслийн эрсдлийн үнэлгээ
Лекц №14 Төслийн эрсдлийн үнэлгээ
 
Лекц 7
Лекц 7Лекц 7
Лекц 7
 
Ахиун шинжилгээ
Ахиун шинжилгээ Ахиун шинжилгээ
Ахиун шинжилгээ
 
20091108 mfcs itsykson_lecture06
20091108 mfcs itsykson_lecture0620091108 mfcs itsykson_lecture06
20091108 mfcs itsykson_lecture06
 
Bogdanovych mat p_4.ua_(035-14)_s
Bogdanovych mat p_4.ua_(035-14)_sBogdanovych mat p_4.ua_(035-14)_s
Bogdanovych mat p_4.ua_(035-14)_s
 
Логистический консалтинг: инвестиционный проект Apply logistic Consulting
Логистический консалтинг: инвестиционный проект Apply logistic ConsultingЛогистический консалтинг: инвестиционный проект Apply logistic Consulting
Логистический консалтинг: инвестиционный проект Apply logistic Consulting
 
Лекц №9 Төслийн зардлын тооцоо
Лекц №9 Төслийн зардлын тооцоо Лекц №9 Төслийн зардлын тооцоо
Лекц №9 Төслийн зардлын тооцоо
 
Бүлэг3
Бүлэг3Бүлэг3
Бүлэг3
 

The Art of Rx