SlideShare a Scribd company logo
1 of 193
Download to read offline
Реактивный двигатель вашего
Android приложения
Матвей Мальков
Обо мне
3
Обо мне
О чем доклад
5
• практика
6
О чем доклад
• практика
• проблемы
7
О чем доклад
• практика
• проблемы
• решения
8
О чем доклад
• практика
• проблемы
• решения
• android + RxJava
9
О чем доклад
Сейчас
11
User Interface
12
User Interface
TextView
EditText
EditText
Button Button
13
User Interface
TextView
EditText
EditText
Button Button
State
14
Data
15
Data
API
CacheDevice
DB
16
Data
State
API
CacheDevice
DB
17
Состояние системы
• мутабельно
18
Состояние системы
• мутабельно
• обновляется через callback
19
Состояние системы
• мутабельно
• обновляется через callback
• плохо композируется
20
Состояние системы
• мутабельно
• обновляется через callback
• плохо композируется
• явное
21
Состояние системы
Мутабельность
23
User user = new User("Jake Mobius");



/**

* 100 качественных строчек кода

*/



final String name = user.getName();

//этот assert легко может упасть

assert("Jake Mobius".equals(name));
24
// какой-то тред 

User user = new User("Jake Mobius");

fetchInfo(user);



final String name = user.getName();

//этот assert легко может упасть

assert("Jake Mobius".equals(name));
25
// какой-то тред 

User user = new User("Jake Mobius");

fetchInfo(user);



final String name = user.getName();

//этот assert легко может упасть

assert("Jake Mobius".equals(name));
// в это же время

// другой какой-то тред

user.setName("Jake Popik");
Обновляемость через callback
27
28
29
nameEditText.addTextChangedListener(new Watcher() {



@Override public void afterTextChanged(Editable editable) {

requestDuplicates(editable.toString(), new MyCallback() {



@Override public void onResponse(Response response){

checkResponseForDuplicates(response, new MyCallback() {



@Override public void onResponse(Response response) {

setHasDuplicates(calcDuplicates(response));

}

});

}

});

}

});
30
nameEditText.addTextChangedListener(new Watcher() {



@Override public void afterTextChanged(Editable editable) {

requestDuplicates(editable.toString(), new MyCallback() {



@Override public void onResponse(Response response){

checkResponseForDuplicates(response, new MyCallback() {



@Override public void onResponse(Response response) {

setHasDuplicates(calcDuplicates(response));

}

});

}

});

}

});
31
nameEditText.addTextChangedListener(new Watcher() {



@Override public void afterTextChanged(Editable editable) {

requestDuplicates(editable.toString(), new MyCallback() {



@Override public void onResponse(Response response){

checkResponseForDuplicates(response, new MyCallback() {



@Override public void onResponse(Response response) {

setHasDuplicates(calcDuplicates(response));

}

});

}

});

}

});
32
nameEditText.addTextChangedListener(new Watcher() {



@Override public void afterTextChanged(Editable editable) {

requestDuplicates(editable.toString(), new MyCallback() {



@Override public void onResponse(Response response){

checkResponseForDuplicates(response, new MyCallback() {



@Override public void onResponse(Response response) {

setHasDuplicates(calcDuplicates(response));

}

});

}

});

}

});
Плохая композируемость
34
35
passEditText.addTextChangedListener(new Watcher() {

@Override

public void afterTextChanged(Editable editable) {

lastPassText = editable.toString();

checkEqualityToEnableButton();

}

});



confirmEditText.addTextChangedListener(new Watcher() {

@Override

public void afterTextChanged(Editable editable) {

lastConfirmText = editable.toString();

checkEqualityToEnableButton();

}

});
36
passEditText.addTextChangedListener(new Watcher() {

@Override

public void afterTextChanged(Editable editable) {

lastPassText = editable.toString();

checkEqualityToEnableButton();

}

});



confirmEditText.addTextChangedListener(new Watcher() {

@Override

public void afterTextChanged(Editable editable) {

lastConfirmText = editable.toString();

checkEqualityToEnableButton();

}

});
37
38
nameEditText.addTextChangedListener(new Watcher() {



@Override public void afterTextChanged(Editable editable) {

lastIsNameEmpty = editable.toString().length() == 0;

requestDuplicates(editable.toString(), new MyCallback() {



@Override public void onResponse(Response response){

checkResponseForDuplicates(response, new MyCallback() {



@Override public void onResponse(Response response) {

lastIsHasDuplicates = calcDuplicates(response);

setHasDuplicates(lastIsHasDuplicates);

checkEqualityToEnableButton();

}

});

}

});

}

});
39
nameEditText.addTextChangedListener(new Watcher() {



@Override public void afterTextChanged(Editable editable) {

lastIsNameEmpty = editable.toString().length() == 0;

requestDuplicates(editable.toString(), new MyCallback() {



@Override public void onResponse(Response response){

checkResponseForDuplicates(response, new MyCallback() {



@Override public void onResponse(Response response) {

lastIsHasDuplicates = calcDuplicates(response);

setHasDuplicates(lastIsHasDuplicates);

checkEqualityToEnableButton();

}

});

}

});

}

});
40
nameEditText.addTextChangedListener(new Watcher() {



@Override public void afterTextChanged(Editable editable) {

lastIsNameEmpty = editable.toString().length() == 0;

requestDuplicates(editable.toString(), new MyCallback() {



@Override public void onResponse(Response response){

checkResponseForDuplicates(response, new MyCallback() {



@Override public void onResponse(Response response) {

lastIsHasDuplicates = calcDuplicates(response);

setHasDuplicates(lastIsHasDuplicates);

checkEqualityToEnableButton();

}

});

}

});

}

});
41
nameEditText.addTextChangedListener(new Watcher() {



@Override public void afterTextChanged(Editable editable) {

lastIsNameEmpty = editable.toString().length() == 0;

requestDuplicates(editable.toString(), new MyCallback() {



@Override public void onResponse(Response response){

checkResponseForDuplicates(response, new MyCallback() {



@Override public void onResponse(Response response) {

lastIsHasDuplicates = calcDuplicates(response);

setHasDuplicates(lastIsHasDuplicates);

checkEqualityToEnableButton();

}

});

}

});

}

});
Явное состояние
43
private String lastPassText;

private String lastConfirmText;

private boolean lastIsHasDuplicates;

private boolean lastIsNameEmpty;
44
lastPassText = editable.toString().trim();
45
lastPassText = editable.toString().trim();
46
lastPassText = editable.toString().trim();
47
private String lastPassText;

private String lastConfirmText;

private boolean lastIsHasDuplicates;

private boolean lastIsNameEmpty;



private String lastPassTrimmedString;
“Все может быть лучше”
“Пора стать реактивней”
50
Потоки данных
t
Данные Ошибка Конец
51
t
52
M
M
t
53
Mo
M Mo
t
54
Mob
M Mo Mob
t
55
Mobi
M Mo Mob Mobi
t
56
Mobiu
MobiuM Mo Mob Mobi
t
57
Mobius
MobiuM Mo Mob Mobi Mobius
t
• изолируют состояние
58
Потоки данных
• изолируют состояние
• прошлое
59
Потоки данных
• изолируют состояние
• прошлое
• настоящее
60
Потоки данных
• изолируют состояние
• прошлое
• настоящее
• будущее
61
Потоки данных
• изолируют состояние
• прошлое
• настоящее
• будущее
• неизменяемые
62
Потоки данных
• изолируют состояние
• прошлое
• настоящее
• будущее
• неизменяемые
• строго типизированные
63
Потоки данных
• EditTextObservable
64
Что может быть потоком?
• EditTextObservable
• ApiDataObservable
65
Что может быть потоком?
• EditTextObservable
• ApiDataObservable
• TouchObservable
66
Что может быть потоком?
• EditTextObservable
• ApiDataObservable
• TouchObservable
• Все, что захотите
67
Что может быть потоком?
RxJava
• reactive streams для java
69
RxJava
• reactive streams для java
• open source
• by Netflix
70
RxJava
• reactive streams для java
• open source
• by Netflix
• стабильная
71
RxJava
• reactive streams для java
• open source
• by Netflix
• стабильная
• почти
72
RxJava
Observable
74
Потоки данных
t
Данные Ошибка Конец
• создать
75
Observable можно
• создать
• изменить
76
Observable можно
• создать
• изменить
• получить значения
77
Observable можно
78
Создание
7
Observable<Integer> just = Observable.just(7);
t
79
Создание
6541 2 3 7
Observable<Integer> many = Observable

.from(Arrays.asList(1, 2, 3, 4, 5, 6, 7));
t
80
Создание
Observable.create(subscriber -> {

final List<Data> list = requestNewData();



for (final Data data : list) {

subscriber.onNext(data);

}

subscriber.onCompleted();

});
81
Создание
Observable.create(subscriber -> {

final List<Data> list = requestNewData();



for (final Data data : list) {

subscriber.onNext(data);

}

subscriber.onCompleted();

});
82
Создание
Observable.create(subscriber -> {

final List<Data> list = requestNewData();



for (final Data data : list) {

subscriber.onNext(data);

}

subscriber.onCompleted();

});
83
Создание
Observable.create(subscriber -> {

final List<Data> list = requestNewData();



for (final Data data : list) {

subscriber.onNext(data);

}

subscriber.onCompleted();

});
84
Подписка
t
85
Подписка
Кто-то №1
t
86
Подписка
Кто-то №1
M
t
M
87
Подписка
Кто-то №2
M
t
Кто-то №1
M
88
Подписка
Кто-то №2
M Mo
t
Mo
Кто-то №1
89
Подписка
Кто-то №2
M Mo Mob
t
Mob
Кто-то №1
90
91
Observable<String> nameObs = EditTextObservable.from(nameEditText);



Subscription nameSubs = nameObs

.doOnNext(name -> {

Log.i(TAG, "new user name : " + name);

})

.subscribe(name -> {

signUpTitle.setText("Sign up, " + name);

});
92
Observable<String> nameObs = EditTextObservable.from(nameEditText);



Subscription nameSubs = nameObs

.doOnNext(name -> {

Log.i(TAG, "new user name : " + name);

})

.subscribe(name -> {

signUpTitle.setText("Sign up, " + name);

});
93
Observable<String> nameObs = EditTextObservable.from(nameEditText);



Subscription nameSubs = nameObs

.doOnNext(name -> {

Log.i(TAG, "new user name : " + name);

})

.subscribe(name -> {

signUpTitle.setText("Sign up, " + name);

});
94
// когда больше не надо слушать этот EditText

nameSubs.unsubscribe();
Observable<String> nameObs = EditTextObservable.from(nameEditText);



Subscription nameSubs = nameObs

.doOnNext(name -> {

Log.i(TAG, "new user name : " + name);

})

.subscribe(name -> {

signUpTitle.setText("Sign up, " + name);

});
95
Операторы
• возвращают новый Observable
97
Операторы
• возвращают новый Observable
• применяются ко всему потоку
98
Операторы
Основы : map и flatMap
100
102
Observable<String> nameObs = EditTextObservable

.from(nameEditText);



nameObs.subscribe(name -> requestDuplicates(name));



Observable<String> rightTitleObservable = nameObs

.map(name -> {

if (TextUtils.isEmpty(name)) return name;

else return ", " + name;

});



rightTitleObservable.subscribe(name ->

signUpTitle.setText("Sign up" + name));
103
Observable<String> nameObs = EditTextObservable

.from(nameEditText);



nameObs.subscribe(name -> requestDuplicates(name));



Observable<String> rightTitleObservable = nameObs

.map(name -> {

if (TextUtils.isEmpty(name)) return name;

else return ", " + name;

});



rightTitleObservable.subscribe(name ->

signUpTitle.setText("Sign up" + name));
104
Observable<String> nameObs = EditTextObservable

.from(nameEditText);



nameObs.subscribe(name -> requestDuplicates(name));



Observable<String> rightTitleObservable = nameObs

.map(name -> {

if (TextUtils.isEmpty(name)) return name;

else return ", " + name;

});



rightTitleObservable.subscribe(name ->

signUpTitle.setText("Sign up" + name));
105
Observable<String> nameObs = EditTextObservable

.from(nameEditText);



nameObs.subscribe(name -> requestDuplicates(name));



Observable<String> rightTitleObservable = nameObs

.map(name -> {

if (TextUtils.isEmpty(name)) return name;

else return ", " + name;

});



rightTitleObservable.subscribe(name ->

signUpTitle.setText("Sign up" + name));
106
Observable<String> nameObs = EditTextObservable

.from(nameEditText);



nameObs.subscribe(name -> requestDuplicates(name));



Observable<String> rightTitleObservable = nameObs

.map(name -> {

if (TextUtils.isEmpty(name)) return name;

else return ", " + name;

});



rightTitleObservable.subscribe(name ->

signUpTitle.setText("Sign up" + name));
107
Observable<String> nameObs = EditTextObservable

.from(nameEditText);



nameObs.subscribe(name -> requestDuplicates(name));



Observable<String> rightTitleObservable = nameObs

.map(name -> {

if (TextUtils.isEmpty(name)) return name;

else return ", " + name;

});



rightTitleObservable.subscribe(name ->

signUpTitle.setText("Sign up" + name));
108
109
110
Debounce
Observable<String> nameObs = EditTextObservable

.from(nameEditText);



Observable<Boolean> duplicatesCheckObservable = nameObs

.debounce(500, TimeUnit.MILLISECONDS)

.map(name -> requestDuplicates(name))

.map(response -> checkResponseForDuplicates(response))

.map(checkedResp -> calcDuplicates(checkedResp))

.onErrorReturn(throwable -> false);



duplicatesCheckObservable.subscribe(isUnique -> { /*process*/ });
111
Debounce
Observable<String> nameObs = EditTextObservable

.from(nameEditText);



Observable<Boolean> duplicatesCheckObservable = nameObs

.debounce(500, TimeUnit.MILLISECONDS)

.map(name -> requestDuplicates(name))

.map(response -> checkResponseForDuplicates(response))

.map(checkedResp -> calcDuplicates(checkedResp))

.onErrorReturn(throwable -> false);



duplicatesCheckObservable.subscribe(isUnique -> { /*process*/ });
112
Debounce
Observable<String> nameObs = EditTextObservable

.from(nameEditText);



Observable<Boolean> duplicatesCheckObservable = nameObs

.debounce(500, TimeUnit.MILLISECONDS)

.map(name -> requestDuplicates(name))

.map(response -> checkResponseForDuplicates(response))

.map(checkedResp -> calcDuplicates(checkedResp))

.onErrorReturn(throwable -> false);



duplicatesCheckObservable.subscribe(isUnique -> { /*process*/ });
113
Debounce
Observable<String> nameObs = EditTextObservable

.from(nameEditText);



Observable<Boolean> duplicatesCheckObservable = nameObs

.debounce(500, TimeUnit.MILLISECONDS)

.map(name -> requestDuplicates(name))

.map(response -> checkResponseForDuplicates(response))

.map(checkedResp -> calcDuplicates(checkedResp))

.onErrorReturn(throwable -> false);



duplicatesCheckObservable.subscribe(isUnique -> { /*process*/ });
• выполняется когда надо
114
Наше решение
• выполняется когда надо
• экономит траффик
115
Наше решение
• выполняется когда надо
• экономит траффик
• не нагружает сервер
116
Наше решение
• выполняется когда надо
• экономит траффик
• не нагружает сервер
• без callback hell
117
Наше решение
• выполняется когда надо
• экономит траффик
• не нагружает сервер
• без callback hell
• легко обрабатывает ошибки
118
Наше решение
119
Прочие полезности
• debounce
121
Полезности
• debounce
• cache
122
Полезности
• debounce
• cache
• timeout
123
Полезности
• debounce
• cache
• timeout
• first
124
Полезности
• debounce
• cache
• timeout
• first
• distinct
125
Полезности
• debounce
• cache
• timeout
• first
• distinct
• skipLast
126
Полезности
• debounce
• cache
• timeout
• first
• distinct
• skipLast
• reduce
127
Полезности
• debounce
• cache
• timeout
• first
• distinct
• skipLast
• reduce
• cast
128
Полезности
• debounce
• cache
• timeout
• first
• distinct
• skipLast
• reduce
• cast
• averageDouble
129
Полезности
• debounce
• cache
• timeout
• first
• distinct
• skipLast
• reduce
• cast
• averageDouble
• takeWhile
130
Полезности
Комбинирование
132
133
134
Observable<Boolean> shouldEnableButtonObs = Observable

.combineLatest(

passObs.map(pass -> pass.trim()),

confirmObs.map(confirm -> confirm.trim()),

duplicatesCheckObservable,

(pass, confirmPass, isNameUnique) ->

TextUtils.equals(pass, confirmPass)

&& isNameUnique

);



shouldEnableButtonObs

.subscribe(enabled -> button.setEnabled(enabled));
135
Observable<Boolean> shouldEnableButtonObs = Observable

.combineLatest(

passObs.map(pass -> pass.trim()),

confirmObs.map(confirm -> confirm.trim()),

duplicatesCheckObservable,

(pass, confirmPass, isNameUnique) ->

TextUtils.equals(pass, confirmPass)

&& isNameUnique

);



shouldEnableButtonObs

.subscribe(enabled -> button.setEnabled(enabled));
136
Observable<Boolean> shouldEnableButtonObs = Observable

.combineLatest(

passObs.map(pass -> pass.trim()),

confirmObs.map(confirm -> confirm.trim()),

duplicatesCheckObservable,

(pass, confirmPass, isNameUnique) ->

TextUtils.equals(pass, confirmPass)

&& isNameUnique

);



shouldEnableButtonObs

.subscribe(enabled -> button.setEnabled(enabled));
137
Observable<Boolean> shouldEnableButtonObs = Observable

.combineLatest(

passObs.map(pass -> pass.trim()),

confirmObs.map(confirm -> confirm.trim()),

duplicatesCheckObservable,

(pass, confirmPass, isNameUnique) ->

TextUtils.equals(pass, confirmPass)

&& isNameUnique

);



shouldEnableButtonObs

.subscribe(enabled -> button.setEnabled(enabled));
138
Observable<Boolean> shouldEnableButtonObs = Observable

.combineLatest(

passObs.map(pass -> pass.trim()),

confirmObs.map(confirm -> confirm.trim()),

duplicatesCheckObservable,

(pass, confirmPass, isNameUnique) ->

TextUtils.equals(pass, confirmPass)

&& isNameUnique

);



shouldEnableButtonObs

.subscribe(enabled -> button.setEnabled(enabled));
139
А сколько у нас явного состояния?
141
// нисколько
• полезно знать все
142
Операции
• полезно знать все
• применение есть всем. Ищите!
143
Операции
• полезно знать все
• применение есть всем. Ищите!
• смотрите исходники
144
Операции
• полезно знать все
• применение есть всем. Ищите!
• смотрите исходники
• думайте!
145
Операции
Когда тредов > 1
Scheduler
• имеет пул потоков
148
Scheduler
• имеет пул потоков
• создает Scheduler.Worker
149
Scheduler
• имеет пул потоков
• создает Scheduler.Worker
• Worker –– цепочка последовательных
вычислений
150
Scheduler
subscribeOn
observeOn
1. observeOn для того,
что ниже по коду
2. subscribeOn для того,
что выше по коду
3. Каждый следующий observeOn
заменяет предыдущий
4. subscribeOn актуален только до
первого observeOn
Оба оператора все еще возвращают
новый поток
157
Observable<Boolean> duplicatesCheckObservable = nameObs

.debounce(500, TimeUnit.MILLISECONDS)

.map(name -> requestDuplicates(name))

.map(response -> checkResponseForDuplicates(response))

.map(checkedResp -> calcDuplicates(checkedResp))

.onErrorReturn(throwable -> false);

158
Observable<Boolean> duplicatesCheckObservable = nameObs

.debounce(500, TimeUnit.MILLISECONDS)

.map(name -> requestDuplicates(name))

.map(response -> checkResponseForDuplicates(response))

.map(checkedResp -> calcDuplicates(checkedResp))

.onErrorReturn(throwable -> false);

159
Observable<Boolean> duplicatesCheckObservable = nameObs

.debounce(500, TimeUnit.MILLISECONDS)

.observeOn(Schedulers.newThread())

.map(name -> requestDuplicates(name))

.map(response -> checkResponseForDuplicates(response))

.map(checkedResp -> calcDuplicates(checkedResp))

.subscribeOn(mainThread)

.observeOn(mainThread)

.onErrorReturn(throwable -> false);

160
Observable<Boolean> duplicatesCheckObservable = nameObs

.debounce(500, TimeUnit.MILLISECONDS)

.observeOn(Schedulers.newThread())

.map(name -> requestDuplicates(name))

.map(response -> checkResponseForDuplicates(response))

.map(checkedResp -> calcDuplicates(checkedResp))

.subscribeOn(mainThread)

.observeOn(mainThread)

.onErrorReturn(throwable -> false);

161
Observable<Boolean> duplicatesCheckObservable = nameObs

.debounce(500, TimeUnit.MILLISECONDS)

.observeOn(Schedulers.newThread())

.map(name -> requestDuplicates(name))

.map(response -> checkResponseForDuplicates(response))

.map(checkedResp -> calcDuplicates(checkedResp))

.subscribeOn(mainThread)

.observeOn(mainThread)

.onErrorReturn(throwable -> false);

162
Observable<Boolean> duplicatesCheckObservable = nameObs

.debounce(500, TimeUnit.MILLISECONDS)

.observeOn(Schedulers.newThread())

.map(name -> requestDuplicates(name))

.map(response -> checkResponseForDuplicates(response))

.map(checkedResp -> calcDuplicates(checkedResp))

.subscribeOn(mainThread)

.observeOn(mainThread)

.onErrorReturn(throwable -> false);

163
Observable<Boolean> duplicatesCheckObservable = nameObs

.debounce(500, TimeUnit.MILLISECONDS)

.observeOn(Schedulers.newThread())

.map(name -> requestDuplicates(name))

.map(response -> checkResponseForDuplicates(response))

.map(checkedResp -> calcDuplicates(checkedResp))

.subscribeOn(mainThread)

.observeOn(mainThread)

.onErrorReturn(throwable -> false);

164
Observable<Boolean> duplicatesCheckObservable = nameObs

.debounce(500, TimeUnit.MILLISECONDS)

.observeOn(Schedulers.newThread())

.map(name -> requestDuplicates(name))

.map(response -> checkResponseForDuplicates(response))

.map(checkedResp -> calcDuplicates(checkedResp))

.subscribeOn(mainThread)

.observeOn(mainThread)

.onErrorReturn(throwable -> false);

165
Observable<Boolean> duplicatesCheckObservable = nameObs

.debounce(500, TimeUnit.MILLISECONDS)

.observeOn(Schedulers.newThread())

.map(name -> requestDuplicates(name))

.map(response -> checkResponseForDuplicates(response))

.map(checkedResp -> calcDuplicates(checkedResp))

.subscribeOn(mainThread)

.observeOn(mainThread)

.onErrorReturn(throwable -> false);

166
Observable<Boolean> duplicatesCheckObservable = nameObs

.debounce(500, TimeUnit.MILLISECONDS)

.observeOn(Schedulers.newThread())

.map(name -> requestDuplicates(name))

.map(response -> checkResponseForDuplicates(response))

.map(checkedResp -> calcDuplicates(checkedResp))

.subscribeOn(mainThread)

.observeOn(mainThread)

.onErrorReturn(throwable -> false);



duplicatesCheckObservable.subscribe(isUnique -> { /*process*/ });
Ложечка дегтя
• объектов аллоцируется больше
168
Ложечка дегтя
• объектов аллоцируется больше
• сложно дебажить
169
Ложечка дегтя
• объектов аллоцируется больше
• сложно дебажить
• логируйте много
170
Ложечка дегтя
• объектов аллоцируется больше
• сложно дебажить
• логируйте много
• пишите правильно сразу
171
Ложечка дегтя
• объектов аллоцируется больше
• сложно дебажить
• логируйте много
• пишите правильно сразу
• сложно объяснить
172
Ложечка дегтя
• объектов аллоцируется больше
• сложно дебажить
• логируйте много
• пишите правильно сразу
• сложно объяснить
• сложно найти крутую команду
173
Ложечка дегтя
Итоги
• изолированное состояние
175
Итоги
• изолированное состояние
• легкая многопоточность
176
Итоги
• изолированное состояние
• легкая многопоточность
• легкое комбинирование
177
Итоги
• изолированное состояние
• легкая многопоточность
• легкое комбинирование
• понятность кода
178
Итоги
• изолированное состояние
• легкая многопоточность
• легкое комбинирование
• понятность кода
• стойкость к ошибкам
179
Итоги
Reactive Extension
Reactive Extension
Reactive Extension
Это круто!
Меняйтесь
За этим будущее
Спасибо
Матвей Мальков
malkov.matvey@gmail.com
matveyka_jj
Правильная реализация подсветки
кнопки
Observable<String> nameObs = EditTextObservable

.from(nameEditText);



Observable<Boolean> duplicatesCheckObservable2 = nameObs

.flatMap(name ->

DebouncedDuplicatesObservable

.from(name)

.startWith(false))

.onErrorReturn(thr -> false);



duplicatesCheckObservable2.

subscribe(isDubl -> { /*process*/ });
Observable<String> nameObs = EditTextObservable

.from(nameEditText);



Observable<Boolean> duplicatesCheckObservable2 = nameObs

.flatMap(name ->

DebouncedDuplicatesObservable

.from(name)

.startWith(false))

.onErrorReturn(thr -> false);



duplicatesCheckObservable2.

subscribe(isDubl -> { /*process*/ });
Observable<String> nameObs = EditTextObservable

.from(nameEditText);



Observable<Boolean> duplicatesCheckObservable2 = nameObs

.flatMap(name ->

DebouncedDuplicatesObservable

.from(name)

.startWith(false))

.onErrorReturn(thr -> false);



duplicatesCheckObservable2.

subscribe(isDubl -> { /*process*/ });
Observable<String> nameObs = EditTextObservable

.from(nameEditText);



Observable<Boolean> duplicatesCheckObservable2 = nameObs

.flatMap(name ->

DebouncedDuplicatesObservable

.from(name)

.startWith(false))

.onErrorReturn(thr -> false);



duplicatesCheckObservable2.

subscribe(isDubl -> { /*process*/ });
• Reactive Streams
• Akka Stream
• Reactor
• Ratpack
• RxJava
• Reactive Manifesto
192
Ссылки
• Reactive Extensions
• Reactive Extensions for JavaScript
• Reactive Cocoa
• Rx.py
• Rx.php
193
Ссылки

More Related Content

What's hot

Проблемы производительности open source библиотек
Проблемы производительности open source библиотекПроблемы производительности open source библиотек
Проблемы производительности open source библиотекVladimir Sitnikov
 
Эволюционный дизайн. Joker Students Day 2016
Эволюционный дизайн. Joker Students Day 2016Эволюционный дизайн. Joker Students Day 2016
Эволюционный дизайн. Joker Students Day 2016Кирилл Толкачёв
 
Implement your own profiler with blackjack and fun
Implement your own profiler with blackjack and funImplement your own profiler with blackjack and fun
Implement your own profiler with blackjack and funVladimir Sitnikov
 
Киллер-фича языка C# — конструкция async/await
Киллер-фича языка C# — конструкция async/awaitКиллер-фича языка C# — конструкция async/await
Киллер-фича языка C# — конструкция async/awaitByndyusoft
 
A step-by-step approach toward high quality OutOfMemoryError analysis
A step-by-step approach toward high quality OutOfMemoryError analysisA step-by-step approach toward high quality OutOfMemoryError analysis
A step-by-step approach toward high quality OutOfMemoryError analysisVladimir Sitnikov
 
BDD girls Battle: Cucumber VS. JBehave
BDD girls Battle: Cucumber VS. JBehaveBDD girls Battle: Cucumber VS. JBehave
BDD girls Battle: Cucumber VS. JBehaveSQALab
 
Подводные камни в нагрузочном тестировании
Подводные камни в нагрузочном тестированииПодводные камни в нагрузочном тестировании
Подводные камни в нагрузочном тестированииVladimir Sitnikov
 
Graal, Truffle, SubstrateVM and other perks: what are those and why do you ne...
Graal, Truffle, SubstrateVM and other perks: what are those and why do you ne...Graal, Truffle, SubstrateVM and other perks: what are those and why do you ne...
Graal, Truffle, SubstrateVM and other perks: what are those and why do you ne...Oleg Chirukhin
 
Контроль качества верстки или как начать делать Makeup
Контроль качества верстки или как начать делать MakeupКонтроль качества верстки или как начать делать Makeup
Контроль качества верстки или как начать делать MakeupTimophy Chaptykov
 
Что нам стоит DAL построить? Акуляков Артём D2D Just.NET
Что нам стоит DAL построить? Акуляков Артём D2D Just.NETЧто нам стоит DAL построить? Акуляков Артём D2D Just.NET
Что нам стоит DAL построить? Акуляков Артём D2D Just.NETDev2Dev
 
PostgreSQL и JDBC: выжимаем все соки
PostgreSQL и JDBC: выжимаем все сокиPostgreSQL и JDBC: выжимаем все соки
PostgreSQL и JDBC: выжимаем все сокиVladimir Sitnikov
 
Selenium grid on-demand
Selenium grid on-demandSelenium grid on-demand
Selenium grid on-demandSQALab
 
Юлия Цисык «RESTFul API в вашем.NET приложении: как, зачем и почему?»
Юлия Цисык «RESTFul API в вашем.NET приложении: как, зачем и почему?»Юлия Цисык «RESTFul API в вашем.NET приложении: как, зачем и почему?»
Юлия Цисык «RESTFul API в вашем.NET приложении: как, зачем и почему?»Yulia Tsisyk
 
Разбор сложных случаев OutOfMemoryError
Разбор сложных случаев OutOfMemoryErrorРазбор сложных случаев OutOfMemoryError
Разбор сложных случаев OutOfMemoryErrorVladimir Sitnikov
 
Alexander manuhin selenium_php_v2.0
Alexander manuhin selenium_php_v2.0Alexander manuhin selenium_php_v2.0
Alexander manuhin selenium_php_v2.0matroskin1980
 
Continuous Delivery with Jenkins: Lessons Learned
Continuous Delivery with Jenkins: Lessons LearnedContinuous Delivery with Jenkins: Lessons Learned
Continuous Delivery with Jenkins: Lessons LearnedAleksandr Tarasov
 
Артём Ерошенко «Рецепт приготовления облачных тестингов»
Артём Ерошенко «Рецепт приготовления облачных тестингов»Артём Ерошенко «Рецепт приготовления облачных тестингов»
Артём Ерошенко «Рецепт приготовления облачных тестингов»WrikeTechClub
 
Selenium, а давай подождем?
Selenium, а давай подождем?Selenium, а давай подождем?
Selenium, а давай подождем?SQALab
 

What's hot (19)

Проблемы производительности open source библиотек
Проблемы производительности open source библиотекПроблемы производительности open source библиотек
Проблемы производительности open source библиотек
 
Эволюционный дизайн. Joker Students Day 2016
Эволюционный дизайн. Joker Students Day 2016Эволюционный дизайн. Joker Students Day 2016
Эволюционный дизайн. Joker Students Day 2016
 
Implement your own profiler with blackjack and fun
Implement your own profiler with blackjack and funImplement your own profiler with blackjack and fun
Implement your own profiler with blackjack and fun
 
Киллер-фича языка C# — конструкция async/await
Киллер-фича языка C# — конструкция async/awaitКиллер-фича языка C# — конструкция async/await
Киллер-фича языка C# — конструкция async/await
 
A step-by-step approach toward high quality OutOfMemoryError analysis
A step-by-step approach toward high quality OutOfMemoryError analysisA step-by-step approach toward high quality OutOfMemoryError analysis
A step-by-step approach toward high quality OutOfMemoryError analysis
 
BDD girls Battle: Cucumber VS. JBehave
BDD girls Battle: Cucumber VS. JBehaveBDD girls Battle: Cucumber VS. JBehave
BDD girls Battle: Cucumber VS. JBehave
 
Подводные камни в нагрузочном тестировании
Подводные камни в нагрузочном тестированииПодводные камни в нагрузочном тестировании
Подводные камни в нагрузочном тестировании
 
Graal, Truffle, SubstrateVM and other perks: what are those and why do you ne...
Graal, Truffle, SubstrateVM and other perks: what are those and why do you ne...Graal, Truffle, SubstrateVM and other perks: what are those and why do you ne...
Graal, Truffle, SubstrateVM and other perks: what are those and why do you ne...
 
Контроль качества верстки или как начать делать Makeup
Контроль качества верстки или как начать делать MakeupКонтроль качества верстки или как начать делать Makeup
Контроль качества верстки или как начать делать Makeup
 
Что нам стоит DAL построить? Акуляков Артём D2D Just.NET
Что нам стоит DAL построить? Акуляков Артём D2D Just.NETЧто нам стоит DAL построить? Акуляков Артём D2D Just.NET
Что нам стоит DAL построить? Акуляков Артём D2D Just.NET
 
PostgreSQL и JDBC: выжимаем все соки
PostgreSQL и JDBC: выжимаем все сокиPostgreSQL и JDBC: выжимаем все соки
PostgreSQL и JDBC: выжимаем все соки
 
Selenium grid on-demand
Selenium grid on-demandSelenium grid on-demand
Selenium grid on-demand
 
Юлия Цисык «RESTFul API в вашем.NET приложении: как, зачем и почему?»
Юлия Цисык «RESTFul API в вашем.NET приложении: как, зачем и почему?»Юлия Цисык «RESTFul API в вашем.NET приложении: как, зачем и почему?»
Юлия Цисык «RESTFul API в вашем.NET приложении: как, зачем и почему?»
 
Regular expressions
Regular expressionsRegular expressions
Regular expressions
 
Разбор сложных случаев OutOfMemoryError
Разбор сложных случаев OutOfMemoryErrorРазбор сложных случаев OutOfMemoryError
Разбор сложных случаев OutOfMemoryError
 
Alexander manuhin selenium_php_v2.0
Alexander manuhin selenium_php_v2.0Alexander manuhin selenium_php_v2.0
Alexander manuhin selenium_php_v2.0
 
Continuous Delivery with Jenkins: Lessons Learned
Continuous Delivery with Jenkins: Lessons LearnedContinuous Delivery with Jenkins: Lessons Learned
Continuous Delivery with Jenkins: Lessons Learned
 
Артём Ерошенко «Рецепт приготовления облачных тестингов»
Артём Ерошенко «Рецепт приготовления облачных тестингов»Артём Ерошенко «Рецепт приготовления облачных тестингов»
Артём Ерошенко «Рецепт приготовления облачных тестингов»
 
Selenium, а давай подождем?
Selenium, а давай подождем?Selenium, а давай подождем?
Selenium, а давай подождем?
 

Similar to Реактивный двигатель для вашего Android-приложения — Матвей Мальков, 2ГИС

Формальная верификация кода на языке Си
Формальная верификация кода на языке СиФормальная верификация кода на языке Си
Формальная верификация кода на языке СиPositive Development User Group
 
Formal verification of C code
Formal verification of C codeFormal verification of C code
Formal verification of C codeDenis Efremov
 
Формальная верификация кода на языке Си
Формальная верификация кода на языке СиФормальная верификация кода на языке Си
Формальная верификация кода на языке СиPositive Hack Days
 
Как приручить реактивное программирование в XAML приложениях
Как приручить реактивное программирование в XAML приложенияхКак приручить реактивное программирование в XAML приложениях
Как приручить реактивное программирование в XAML приложенияхDenis Tsvettsih
 
Переход с Objective-C на Swift — все ли так просто? / Олег Алексеенко (SuperJob)
Переход с Objective-C на Swift — все ли так просто? / Олег Алексеенко (SuperJob)Переход с Objective-C на Swift — все ли так просто? / Олег Алексеенко (SuperJob)
Переход с Objective-C на Swift — все ли так просто? / Олег Алексеенко (SuperJob)Ontico
 
Java 9: what is there beyond modularization
Java 9: what is there beyond modularizationJava 9: what is there beyond modularization
Java 9: what is there beyond modularizationIvan Krylov
 
Rambler.iOS #9: Анализируй это!
Rambler.iOS #9: Анализируй это!Rambler.iOS #9: Анализируй это!
Rambler.iOS #9: Анализируй это!RAMBLER&Co
 
RESTful API: Best practices, versioning, design documentation
RESTful API: Best practices, versioning, design documentationRESTful API: Best practices, versioning, design documentation
RESTful API: Best practices, versioning, design documentationMikhail Shcherbakov
 
Multithreading in java past and actual
Multithreading in java past and actualMultithreading in java past and actual
Multithreading in java past and actualYevgen Levik
 
Система обработки бизнес-логики server-side приложения на Groovy
Система обработки бизнес-логики server-side приложения на GroovyСистема обработки бизнес-логики server-side приложения на Groovy
Система обработки бизнес-логики server-side приложения на GroovyRegn
 
Длинная транзакция или когда размер имеет значение / Михаил Балаян (Odin — In...
Длинная транзакция или когда размер имеет значение / Михаил Балаян (Odin — In...Длинная транзакция или когда размер имеет значение / Михаил Балаян (Odin — In...
Длинная транзакция или когда размер имеет значение / Михаил Балаян (Odin — In...Ontico
 
Построение аналитического хранилища на 100 петабайт
Построение аналитического хранилища на 100 петабайтПостроение аналитического хранилища на 100 петабайт
Построение аналитического хранилища на 100 петабайтAlexander Mazurov
 
Как приручить реактивное программирование
Как приручить реактивное программированиеКак приручить реактивное программирование
Как приручить реактивное программированиеDenis Tsvettsih
 
Референсная архитектура приложения на ASP.NET MVC
Референсная архитектура приложения на ASP.NET MVCРеференсная архитектура приложения на ASP.NET MVC
Референсная архитектура приложения на ASP.NET MVCAndrew Mayorov
 
Прокачиваем WebDriverAgent или как тестировать iOS-приложения после ядерного ...
Прокачиваем WebDriverAgent или как тестировать iOS-приложения после ядерного ...Прокачиваем WebDriverAgent или как тестировать iOS-приложения после ядерного ...
Прокачиваем WebDriverAgent или как тестировать iOS-приложения после ядерного ...Alexey Makhov
 
2017-02-04 03 Алексей Букуров, Игорь Циглер. DSL для правил валидации
2017-02-04 03 Алексей Букуров, Игорь Циглер. DSL для правил валидации2017-02-04 03 Алексей Букуров, Игорь Циглер. DSL для правил валидации
2017-02-04 03 Алексей Букуров, Игорь Циглер. DSL для правил валидацииОмские ИТ-субботники
 
Cache2012 administrationbasics
Cache2012 administrationbasicsCache2012 administrationbasics
Cache2012 administrationbasicsDenis Pavlov
 
Евгений Ртищев "Мобильная платформа на ReactNative"
Евгений Ртищев "Мобильная платформа на ReactNative"Евгений Ртищев "Мобильная платформа на ReactNative"
Евгений Ртищев "Мобильная платформа на ReactNative"IT Event
 
Что могут статические анализаторы, чего не могут программисты и тестировщики
Что могут статические анализаторы, чего не могут программисты и тестировщикиЧто могут статические анализаторы, чего не могут программисты и тестировщики
Что могут статические анализаторы, чего не могут программисты и тестировщикиAndrey Karpov
 
JPoint 2017 - Where is my service, dude?
JPoint 2017 - Where is my service, dude?JPoint 2017 - Where is my service, dude?
JPoint 2017 - Where is my service, dude?Viet Nguyen
 

Similar to Реактивный двигатель для вашего Android-приложения — Матвей Мальков, 2ГИС (20)

Формальная верификация кода на языке Си
Формальная верификация кода на языке СиФормальная верификация кода на языке Си
Формальная верификация кода на языке Си
 
Formal verification of C code
Formal verification of C codeFormal verification of C code
Formal verification of C code
 
Формальная верификация кода на языке Си
Формальная верификация кода на языке СиФормальная верификация кода на языке Си
Формальная верификация кода на языке Си
 
Как приручить реактивное программирование в XAML приложениях
Как приручить реактивное программирование в XAML приложенияхКак приручить реактивное программирование в XAML приложениях
Как приручить реактивное программирование в XAML приложениях
 
Переход с Objective-C на Swift — все ли так просто? / Олег Алексеенко (SuperJob)
Переход с Objective-C на Swift — все ли так просто? / Олег Алексеенко (SuperJob)Переход с Objective-C на Swift — все ли так просто? / Олег Алексеенко (SuperJob)
Переход с Objective-C на Swift — все ли так просто? / Олег Алексеенко (SuperJob)
 
Java 9: what is there beyond modularization
Java 9: what is there beyond modularizationJava 9: what is there beyond modularization
Java 9: what is there beyond modularization
 
Rambler.iOS #9: Анализируй это!
Rambler.iOS #9: Анализируй это!Rambler.iOS #9: Анализируй это!
Rambler.iOS #9: Анализируй это!
 
RESTful API: Best practices, versioning, design documentation
RESTful API: Best practices, versioning, design documentationRESTful API: Best practices, versioning, design documentation
RESTful API: Best practices, versioning, design documentation
 
Multithreading in java past and actual
Multithreading in java past and actualMultithreading in java past and actual
Multithreading in java past and actual
 
Система обработки бизнес-логики server-side приложения на Groovy
Система обработки бизнес-логики server-side приложения на GroovyСистема обработки бизнес-логики server-side приложения на Groovy
Система обработки бизнес-логики server-side приложения на Groovy
 
Длинная транзакция или когда размер имеет значение / Михаил Балаян (Odin — In...
Длинная транзакция или когда размер имеет значение / Михаил Балаян (Odin — In...Длинная транзакция или когда размер имеет значение / Михаил Балаян (Odin — In...
Длинная транзакция или когда размер имеет значение / Михаил Балаян (Odin — In...
 
Построение аналитического хранилища на 100 петабайт
Построение аналитического хранилища на 100 петабайтПостроение аналитического хранилища на 100 петабайт
Построение аналитического хранилища на 100 петабайт
 
Как приручить реактивное программирование
Как приручить реактивное программированиеКак приручить реактивное программирование
Как приручить реактивное программирование
 
Референсная архитектура приложения на ASP.NET MVC
Референсная архитектура приложения на ASP.NET MVCРеференсная архитектура приложения на ASP.NET MVC
Референсная архитектура приложения на ASP.NET MVC
 
Прокачиваем WebDriverAgent или как тестировать iOS-приложения после ядерного ...
Прокачиваем WebDriverAgent или как тестировать iOS-приложения после ядерного ...Прокачиваем WebDriverAgent или как тестировать iOS-приложения после ядерного ...
Прокачиваем WebDriverAgent или как тестировать iOS-приложения после ядерного ...
 
2017-02-04 03 Алексей Букуров, Игорь Циглер. DSL для правил валидации
2017-02-04 03 Алексей Букуров, Игорь Циглер. DSL для правил валидации2017-02-04 03 Алексей Букуров, Игорь Циглер. DSL для правил валидации
2017-02-04 03 Алексей Букуров, Игорь Циглер. DSL для правил валидации
 
Cache2012 administrationbasics
Cache2012 administrationbasicsCache2012 administrationbasics
Cache2012 administrationbasics
 
Евгений Ртищев "Мобильная платформа на ReactNative"
Евгений Ртищев "Мобильная платформа на ReactNative"Евгений Ртищев "Мобильная платформа на ReactNative"
Евгений Ртищев "Мобильная платформа на ReactNative"
 
Что могут статические анализаторы, чего не могут программисты и тестировщики
Что могут статические анализаторы, чего не могут программисты и тестировщикиЧто могут статические анализаторы, чего не могут программисты и тестировщики
Что могут статические анализаторы, чего не могут программисты и тестировщики
 
JPoint 2017 - Where is my service, dude?
JPoint 2017 - Where is my service, dude?JPoint 2017 - Where is my service, dude?
JPoint 2017 - Where is my service, dude?
 

Реактивный двигатель для вашего Android-приложения — Матвей Мальков, 2ГИС