Реактивный двигатель вашего Android приложения

193
Реактивный двигатель вашего Android приложения Матвей Мальков

Transcript of Реактивный двигатель вашего Android приложения

Page 1: Реактивный двигатель вашего Android приложения

Реактивный двигатель вашего Android приложения

Матвей Мальков

Page 2: Реактивный двигатель вашего Android приложения

Обо мне

Page 3: Реактивный двигатель вашего Android приложения

3Обо мне

Page 4: Реактивный двигатель вашего Android приложения

О чем доклад

Page 5: Реактивный двигатель вашего Android приложения

5

Page 6: Реактивный двигатель вашего Android приложения

• практика

6О чем доклад

Page 7: Реактивный двигатель вашего Android приложения

• практика

• проблемы

7О чем доклад

Page 8: Реактивный двигатель вашего Android приложения

• практика

• проблемы

• решения

8О чем доклад

Page 9: Реактивный двигатель вашего Android приложения

• практика

• проблемы

• решения

• android + RxJava

9О чем доклад

Page 10: Реактивный двигатель вашего Android приложения

Сейчас

Page 11: Реактивный двигатель вашего Android приложения

11

User Interface

Page 12: Реактивный двигатель вашего Android приложения

12

User Interface

TextView

EditText

EditText

Button Button

Page 13: Реактивный двигатель вашего Android приложения

13

User Interface

TextView

EditText

EditText

Button Button

State

Page 14: Реактивный двигатель вашего Android приложения

14

Data

Page 15: Реактивный двигатель вашего Android приложения

15

Data

API

CacheDevice

DB

Page 16: Реактивный двигатель вашего Android приложения

16

Data

State

API

CacheDevice

DB

Page 17: Реактивный двигатель вашего Android приложения

17

Состояние системы

Page 18: Реактивный двигатель вашего Android приложения

• мутабельно

18Состояние системы

Page 19: Реактивный двигатель вашего Android приложения

• мутабельно

• обновляется через callback

19Состояние системы

Page 20: Реактивный двигатель вашего Android приложения

• мутабельно

• обновляется через callback

• плохо композируется

20Состояние системы

Page 21: Реактивный двигатель вашего Android приложения

• мутабельно

• обновляется через callback

• плохо композируется

• явное

21Состояние системы

Page 22: Реактивный двигатель вашего Android приложения

Мутабельность

Page 23: Реактивный двигатель вашего Android приложения

23

User user = new User("Jake Mobius"); /** * 100 качественных строчек кода */final String name = user.getName(); //этот assert легко может упастьassert("Jake Mobius".equals(name));

Page 24: Реактивный двигатель вашего Android приложения

24// какой-то тред User user = new User("Jake Mobius"); fetchInfo(user); final String name = user.getName(); //этот assert легко может упастьassert("Jake Mobius".equals(name));

Page 25: Реактивный двигатель вашего Android приложения

25// какой-то тред User user = new User("Jake Mobius"); fetchInfo(user); final String name = user.getName(); //этот assert легко может упастьassert("Jake Mobius".equals(name));

// в это же время// другой какой-то тредuser.setName("Jake Popik");

Page 26: Реактивный двигатель вашего Android приложения

Обновляемость через callback

Page 27: Реактивный двигатель вашего Android приложения

27

Page 28: Реактивный двигатель вашего Android приложения

28

Page 29: Реактивный двигатель вашего Android приложения

29nameEditText.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)); } }); } }); } });

Page 30: Реактивный двигатель вашего Android приложения

30nameEditText.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)); } }); } }); } });

Page 31: Реактивный двигатель вашего Android приложения

31nameEditText.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)); } }); } }); } });

Page 32: Реактивный двигатель вашего Android приложения

32nameEditText.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)); } }); } }); } });

Page 33: Реактивный двигатель вашего Android приложения

Плохая композируемость

Page 34: Реактивный двигатель вашего Android приложения

34

Page 35: Реактивный двигатель вашего Android приложения

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(); } });

Page 36: Реактивный двигатель вашего Android приложения

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(); } });

Page 37: Реактивный двигатель вашего Android приложения

37

Page 38: Реактивный двигатель вашего Android приложения

38nameEditText.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(); } }); } }); } });

Page 39: Реактивный двигатель вашего Android приложения

39nameEditText.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(); } }); } }); } });

Page 40: Реактивный двигатель вашего Android приложения

40nameEditText.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(); } }); } }); } });

Page 41: Реактивный двигатель вашего Android приложения

41nameEditText.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(); } }); } }); } });

Page 42: Реактивный двигатель вашего Android приложения

Явное состояние

Page 43: Реактивный двигатель вашего Android приложения

43

private String lastPassText; private String lastConfirmText; private boolean lastIsHasDuplicates; private boolean lastIsNameEmpty;

Page 44: Реактивный двигатель вашего Android приложения

44

lastPassText = editable.toString().trim();

Page 45: Реактивный двигатель вашего Android приложения

45

lastPassText = editable.toString().trim();

Page 46: Реактивный двигатель вашего Android приложения

46

lastPassText = editable.toString().trim();

Page 47: Реактивный двигатель вашего Android приложения

47

private String lastPassText; private String lastConfirmText; private boolean lastIsHasDuplicates; private boolean lastIsNameEmpty; private String lastPassTrimmedString;

Page 48: Реактивный двигатель вашего Android приложения

“Все может быть лучше”

Page 49: Реактивный двигатель вашего Android приложения

“Пора стать реактивней”

Page 50: Реактивный двигатель вашего Android приложения

50Потоки данных

t

Данные Ошибка Конец

Page 51: Реактивный двигатель вашего Android приложения

51

t

Page 52: Реактивный двигатель вашего Android приложения

52

M

Mt

Page 53: Реактивный двигатель вашего Android приложения

53

Mo

M Mot

Page 54: Реактивный двигатель вашего Android приложения

54

Mob

M Mo Mobt

Page 55: Реактивный двигатель вашего Android приложения

55

Mobi

M Mo Mob Mobit

Page 56: Реактивный двигатель вашего Android приложения

56

Mobiu

MobiuM Mo Mob Mobit

Page 57: Реактивный двигатель вашего Android приложения

57

Mobius

MobiuM Mo Mob Mobi Mobiust

Page 58: Реактивный двигатель вашего Android приложения

• изолируют состояние

58Потоки данных

Page 59: Реактивный двигатель вашего Android приложения

• изолируют состояние

• прошлое

59Потоки данных

Page 60: Реактивный двигатель вашего Android приложения

• изолируют состояние

• прошлое

• настоящее

60Потоки данных

Page 61: Реактивный двигатель вашего Android приложения

• изолируют состояние

• прошлое

• настоящее

• будущее

61Потоки данных

Page 62: Реактивный двигатель вашего Android приложения

• изолируют состояние

• прошлое

• настоящее

• будущее

• неизменяемые

62Потоки данных

Page 63: Реактивный двигатель вашего Android приложения

• изолируют состояние

• прошлое

• настоящее

• будущее

• неизменяемые

• строго типизированные

63Потоки данных

Page 64: Реактивный двигатель вашего Android приложения

• EditTextObservable

64Что может быть потоком?

Page 65: Реактивный двигатель вашего Android приложения

• EditTextObservable

• ApiDataObservable

65Что может быть потоком?

Page 66: Реактивный двигатель вашего Android приложения

• EditTextObservable

• ApiDataObservable

• TouchObservable

66Что может быть потоком?

Page 67: Реактивный двигатель вашего Android приложения

• EditTextObservable

• ApiDataObservable

• TouchObservable

• Все, что захотите

67Что может быть потоком?

Page 68: Реактивный двигатель вашего Android приложения

RxJava

Page 69: Реактивный двигатель вашего Android приложения

• reactive streams для java

69RxJava

Page 70: Реактивный двигатель вашего Android приложения

• reactive streams для java

• open source

• by Netflix

70RxJava

Page 71: Реактивный двигатель вашего Android приложения

• reactive streams для java

• open source

• by Netflix

• стабильная

71RxJava

Page 72: Реактивный двигатель вашего Android приложения

• reactive streams для java

• open source

• by Netflix

• стабильная

• почти

72RxJava

Page 73: Реактивный двигатель вашего Android приложения

Observable

Page 74: Реактивный двигатель вашего Android приложения

74Потоки данных

t

Данные Ошибка Конец

Page 75: Реактивный двигатель вашего Android приложения

• создать

75Observable можно

Page 76: Реактивный двигатель вашего Android приложения

• создать

• изменить

76Observable можно

Page 77: Реактивный двигатель вашего Android приложения

• создать

• изменить

• получить значения

77Observable можно

Page 78: Реактивный двигатель вашего Android приложения

78Создание

7

Observable<Integer> just = Observable.just(7);

t

Page 79: Реактивный двигатель вашего Android приложения

79Создание

6541 2 3 7

Observable<Integer> many = Observable .from(Arrays.asList(1, 2, 3, 4, 5, 6, 7));

t

Page 80: Реактивный двигатель вашего Android приложения

80СозданиеObservable.create(subscriber -> { final List<Data> list = requestNewData(); for (final Data data : list) { subscriber.onNext(data); } subscriber.onCompleted(); });

Page 81: Реактивный двигатель вашего Android приложения

81СозданиеObservable.create(subscriber -> { final List<Data> list = requestNewData(); for (final Data data : list) { subscriber.onNext(data); } subscriber.onCompleted(); });

Page 82: Реактивный двигатель вашего Android приложения

82СозданиеObservable.create(subscriber -> { final List<Data> list = requestNewData(); for (final Data data : list) { subscriber.onNext(data); } subscriber.onCompleted(); });

Page 83: Реактивный двигатель вашего Android приложения

83СозданиеObservable.create(subscriber -> { final List<Data> list = requestNewData(); for (final Data data : list) { subscriber.onNext(data); } subscriber.onCompleted(); });

Page 84: Реактивный двигатель вашего Android приложения

84Подписка

t

Page 85: Реактивный двигатель вашего Android приложения

85Подписка

Кто-то №1

t

Page 86: Реактивный двигатель вашего Android приложения

86Подписка

Кто-то №1

Mt

M

Page 87: Реактивный двигатель вашего Android приложения

87Подписка

Кто-то №2

Mt

Кто-то №1

M

Page 88: Реактивный двигатель вашего Android приложения

88Подписка

Кто-то №2

M Mot

Mo

Кто-то №1

Page 89: Реактивный двигатель вашего Android приложения

89Подписка

Кто-то №2

M Mo Mobt

Mob

Кто-то №1

Page 90: Реактивный двигатель вашего Android приложения

90

Page 91: Реактивный двигатель вашего Android приложения

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); });

Page 92: Реактивный двигатель вашего Android приложения

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); });

Page 93: Реактивный двигатель вашего Android приложения

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); });

Page 94: Реактивный двигатель вашего Android приложения

94

// когда больше не надо слушать этот EditTextnameSubs.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); });

Page 95: Реактивный двигатель вашего Android приложения

95

Page 96: Реактивный двигатель вашего Android приложения

Операторы

Page 97: Реактивный двигатель вашего Android приложения

• возвращают новый Observable

97Операторы

Page 98: Реактивный двигатель вашего Android приложения

• возвращают новый Observable

• применяются ко всему потоку

98Операторы

Page 99: Реактивный двигатель вашего Android приложения

Основы : map и flatMap

Page 100: Реактивный двигатель вашего Android приложения

100

Page 101: Реактивный двигатель вашего Android приложения
Page 102: Реактивный двигатель вашего Android приложения

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));

Page 103: Реактивный двигатель вашего Android приложения

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));

Page 104: Реактивный двигатель вашего Android приложения

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));

Page 105: Реактивный двигатель вашего Android приложения

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));

Page 106: Реактивный двигатель вашего Android приложения

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));

Page 107: Реактивный двигатель вашего Android приложения

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));

Page 108: Реактивный двигатель вашего Android приложения

108

Page 109: Реактивный двигатель вашего Android приложения

109

Page 110: Реактивный двигатель вашего Android приложения

110DebounceObservable<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*/ });

Page 111: Реактивный двигатель вашего Android приложения

111DebounceObservable<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*/ });

Page 112: Реактивный двигатель вашего Android приложения

112DebounceObservable<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*/ });

Page 113: Реактивный двигатель вашего Android приложения

113DebounceObservable<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*/ });

Page 114: Реактивный двигатель вашего Android приложения

• выполняется когда надо

114Наше решение

Page 115: Реактивный двигатель вашего Android приложения

• выполняется когда надо

• экономит траффик

115Наше решение

Page 116: Реактивный двигатель вашего Android приложения

• выполняется когда надо

• экономит траффик

• не нагружает сервер

116Наше решение

Page 117: Реактивный двигатель вашего Android приложения

• выполняется когда надо

• экономит траффик

• не нагружает сервер

• без callback hell

117Наше решение

Page 118: Реактивный двигатель вашего Android приложения

• выполняется когда надо

• экономит траффик

• не нагружает сервер

• без callback hell

• легко обрабатывает ошибки

118Наше решение

Page 119: Реактивный двигатель вашего Android приложения

119

Page 120: Реактивный двигатель вашего Android приложения

Прочие полезности

Page 121: Реактивный двигатель вашего Android приложения

• debounce

121Полезности

Page 122: Реактивный двигатель вашего Android приложения

• debounce

• cache

122Полезности

Page 123: Реактивный двигатель вашего Android приложения

• debounce

• cache

• timeout

123Полезности

Page 124: Реактивный двигатель вашего Android приложения

• debounce

• cache

• timeout

• first

124Полезности

Page 125: Реактивный двигатель вашего Android приложения

• debounce

• cache

• timeout

• first

• distinct

125Полезности

Page 126: Реактивный двигатель вашего Android приложения

• debounce

• cache

• timeout

• first

• distinct

• skipLast

126Полезности

Page 127: Реактивный двигатель вашего Android приложения

• debounce

• cache

• timeout

• first

• distinct

• skipLast

• reduce

127Полезности

Page 128: Реактивный двигатель вашего Android приложения

• debounce

• cache

• timeout

• first

• distinct

• skipLast

• reduce

• cast

128Полезности

Page 129: Реактивный двигатель вашего Android приложения

• debounce

• cache

• timeout

• first

• distinct

• skipLast

• reduce

• cast

• averageDouble

129Полезности

Page 130: Реактивный двигатель вашего Android приложения

• debounce

• cache

• timeout

• first

• distinct

• skipLast

• reduce

• cast

• averageDouble

• takeWhile

130Полезности

Page 131: Реактивный двигатель вашего Android приложения

Комбинирование

Page 132: Реактивный двигатель вашего Android приложения

132

Page 133: Реактивный двигатель вашего Android приложения

133

Page 134: Реактивный двигатель вашего Android приложения

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));

Page 135: Реактивный двигатель вашего Android приложения

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));

Page 136: Реактивный двигатель вашего Android приложения

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));

Page 137: Реактивный двигатель вашего Android приложения

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));

Page 138: Реактивный двигатель вашего Android приложения

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));

Page 139: Реактивный двигатель вашего Android приложения

139

Page 140: Реактивный двигатель вашего Android приложения

А сколько у нас явного состояния?

Page 141: Реактивный двигатель вашего Android приложения

141

// нисколько

Page 142: Реактивный двигатель вашего Android приложения

• полезно знать все

142Операции

Page 143: Реактивный двигатель вашего Android приложения

• полезно знать все

• применение есть всем. Ищите!

143Операции

Page 144: Реактивный двигатель вашего Android приложения

• полезно знать все

• применение есть всем. Ищите!

• смотрите исходники

144Операции

Page 145: Реактивный двигатель вашего Android приложения

• полезно знать все

• применение есть всем. Ищите!

• смотрите исходники

• думайте!

145Операции

Page 146: Реактивный двигатель вашего Android приложения

Когда тредов > 1

Page 147: Реактивный двигатель вашего Android приложения

Scheduler

Page 148: Реактивный двигатель вашего Android приложения

• имеет пул потоков

148Scheduler

Page 149: Реактивный двигатель вашего Android приложения

• имеет пул потоков

• создает Scheduler.Worker

149Scheduler

Page 150: Реактивный двигатель вашего Android приложения

• имеет пул потоков

• создает Scheduler.Worker

• Worker –– цепочка последовательных вычислений

150Scheduler

Page 151: Реактивный двигатель вашего Android приложения

subscribeOn observeOn

Page 152: Реактивный двигатель вашего Android приложения

1. observeOn для того, что ниже по коду

Page 153: Реактивный двигатель вашего Android приложения

2. subscribeOn для того, что выше по коду

Page 154: Реактивный двигатель вашего Android приложения

3. Каждый следующий observeOn заменяет предыдущий

Page 155: Реактивный двигатель вашего Android приложения

4. subscribeOn актуален только до первого observeOn

Page 156: Реактивный двигатель вашего Android приложения

Оба оператора все еще возвращают новый поток

Page 157: Реактивный двигатель вашего Android приложения

157

Observable<Boolean> duplicatesCheckObservable = nameObs .debounce(500, TimeUnit.MILLISECONDS) .map(name -> requestDuplicates(name)) .map(response -> checkResponseForDuplicates(response)) .map(checkedResp -> calcDuplicates(checkedResp)) .onErrorReturn(throwable -> false);

Page 158: Реактивный двигатель вашего Android приложения

158

Observable<Boolean> duplicatesCheckObservable = nameObs .debounce(500, TimeUnit.MILLISECONDS) .map(name -> requestDuplicates(name)) .map(response -> checkResponseForDuplicates(response)) .map(checkedResp -> calcDuplicates(checkedResp)) .onErrorReturn(throwable -> false);

Page 159: Реактивный двигатель вашего Android приложения

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);

Page 160: Реактивный двигатель вашего Android приложения

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);

Page 161: Реактивный двигатель вашего Android приложения

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);

Page 162: Реактивный двигатель вашего Android приложения

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);

Page 163: Реактивный двигатель вашего Android приложения

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);

Page 164: Реактивный двигатель вашего Android приложения

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);

Page 165: Реактивный двигатель вашего Android приложения

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);

Page 166: Реактивный двигатель вашего Android приложения

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*/ });

Page 167: Реактивный двигатель вашего Android приложения

Ложечка дегтя

Page 168: Реактивный двигатель вашего Android приложения

• объектов аллоцируется больше

168Ложечка дегтя

Page 169: Реактивный двигатель вашего Android приложения

• объектов аллоцируется больше

• сложно дебажить

169Ложечка дегтя

Page 170: Реактивный двигатель вашего Android приложения

• объектов аллоцируется больше

• сложно дебажить

• логируйте много

170Ложечка дегтя

Page 171: Реактивный двигатель вашего Android приложения

• объектов аллоцируется больше

• сложно дебажить

• логируйте много

• пишите правильно сразу

171Ложечка дегтя

Page 172: Реактивный двигатель вашего Android приложения

• объектов аллоцируется больше

• сложно дебажить

• логируйте много

• пишите правильно сразу

• сложно объяснить

172Ложечка дегтя

Page 173: Реактивный двигатель вашего Android приложения

• объектов аллоцируется больше

• сложно дебажить

• логируйте много

• пишите правильно сразу

• сложно объяснить

• сложно найти крутую команду

173Ложечка дегтя

Page 174: Реактивный двигатель вашего Android приложения

Итоги

Page 175: Реактивный двигатель вашего Android приложения

• изолированное состояние

175Итоги

Page 176: Реактивный двигатель вашего Android приложения

• изолированное состояние

• легкая многопоточность

176Итоги

Page 177: Реактивный двигатель вашего Android приложения

• изолированное состояние

• легкая многопоточность

• легкое комбинирование

177Итоги

Page 178: Реактивный двигатель вашего Android приложения

• изолированное состояние

• легкая многопоточность

• легкое комбинирование

• понятность кода

178Итоги

Page 179: Реактивный двигатель вашего Android приложения

• изолированное состояние

• легкая многопоточность

• легкое комбинирование

• понятность кода

• стойкость к ошибкам

179Итоги

Page 180: Реактивный двигатель вашего Android приложения

Reactive Extension

Page 181: Реактивный двигатель вашего Android приложения

Reactive Extension

Page 182: Реактивный двигатель вашего Android приложения

Reactive Extension

Page 183: Реактивный двигатель вашего Android приложения

Это круто!

Page 184: Реактивный двигатель вашего Android приложения

Меняйтесь

Page 185: Реактивный двигатель вашего Android приложения

За этим будущее

Page 186: Реактивный двигатель вашего Android приложения

Спасибо

Матвей Мальков

[email protected]

matveyka_jj

Page 187: Реактивный двигатель вашего Android приложения

Правильная реализация подсветки кнопки

Page 188: Реактивный двигатель вашего Android приложения

Observable<String> nameObs = EditTextObservable .from(nameEditText);Observable<Boolean> duplicatesCheckObservable2 = nameObs .flatMap(name -> DebouncedDuplicatesObservable .from(name) .startWith(false)) .onErrorReturn(thr -> false); duplicatesCheckObservable2. subscribe(isDubl -> { /*process*/ });

Page 189: Реактивный двигатель вашего Android приложения

Observable<String> nameObs = EditTextObservable .from(nameEditText);Observable<Boolean> duplicatesCheckObservable2 = nameObs .flatMap(name -> DebouncedDuplicatesObservable .from(name) .startWith(false)) .onErrorReturn(thr -> false); duplicatesCheckObservable2. subscribe(isDubl -> { /*process*/ });

Page 190: Реактивный двигатель вашего Android приложения

Observable<String> nameObs = EditTextObservable .from(nameEditText);Observable<Boolean> duplicatesCheckObservable2 = nameObs .flatMap(name -> DebouncedDuplicatesObservable .from(name) .startWith(false)) .onErrorReturn(thr -> false); duplicatesCheckObservable2. subscribe(isDubl -> { /*process*/ });

Page 191: Реактивный двигатель вашего Android приложения

Observable<String> nameObs = EditTextObservable .from(nameEditText);Observable<Boolean> duplicatesCheckObservable2 = nameObs .flatMap(name -> DebouncedDuplicatesObservable .from(name) .startWith(false)) .onErrorReturn(thr -> false); duplicatesCheckObservable2. subscribe(isDubl -> { /*process*/ });

Page 193: Реактивный двигатель вашего Android приложения

• Reactive Extensions

• Reactive Extensions for JavaScript

• Reactive Cocoa

• Rx.py

• Rx.php

193Ссылки