- Android Data Binding Library — from Observable Fields to LiveData in two steps
- Step 1: Replace Observable Fields with LiveData
- Step 2 — Set the lifecycle owner for the LiveData
- Урок 21. Android Data Binding. Observable поля. Двусторонний биндинг.
- Observable поля
- BaseObservable
- Двусторонний биндинг
- Урок 9. Android Data Binding с событиями пользовательского интерфейса и наблюдаемыми данными
- User events
- Observing data
- Изучай observable, создавая observable
- Вступление
- Observables — просто функции
- Почему бы просто не использовать функции? Что «особенного» в observable?
- Обработка Partial Observers
- Уведомления об ошибке
- Источники данных и кейс для отмены подписки
- Это всё! Observables — это просто специализированные функции!
Android Data Binding Library — from Observable Fields to LiveData in two steps
One of the most important features of Data Binding is observability. It allows you to bind data and UI elements so that when the data changes, the pertinent elements are updated on screen.
Plain primitives and Strings are not observable by default so if you use them in your Data Binding layouts, their values will be used when the binding is created but subsequent changes to them will be ignored.
To make objects observable, we included in the Data Binding Library a series of observable classes: ObservableBoolean , ObservableInt , ObservableDouble … and the generic , ObservableField . We’ll call these Observable Fields from now on.
Some years later, as part of the first wave of Architecture Components, we released LiveData, which is another observable. It was an obvious candidate to be compatible with Data Binding, so we added this capability.
LiveData is lifecycle-aware but this is not a huge advantage with respect to Observable Fields because Data Binding already checks when the view is active. However, LiveData supports Transformations , and many Architecture Components, like Room and WorkManager , support LiveData.
For these reasons, it’s recommended to migrate to LiveData. You only need two simple steps to do so.
Step 1: Replace Observable Fields with LiveData
If you are using Observable Fields directly in your data binding layout, simply replace Observable Something (or ObservableField Something> ) with LiveData Something> .
Remember that %lt; is not a typo. You have to escape the character inside XML layouts.
Alternatively, if you’re exposing observables from a ViewModel (the preferred approach) or a presenter or controller, you don’t need to change your layout. Just replace those ObservableField s with LiveData in the ViewModel.
Step 2 — Set the lifecycle owner for the LiveData
Binding classes have a method called setLifecycleOwner that must be called when observing LiveData from a data binding layout.
Note: If you’re setting the content for a fragment, it is recommended to use fragment.viewLifecycleOwner (instead of the fragment’s lifecycle) to deal with potential detached fragments.
Now you can use your LiveData objects with Transformations and MediatorLiveData. If you’re not familiar with these features, check out this recording of “Fun with LiveData”, from the Android Dev Summit 2018.
Источник
Урок 21. Android Data Binding. Observable поля. Двусторонний биндинг.
В этом уроке разберем, как настроить автоматическую передачу данных в View и обратно.
Полный список уроков курса:
Когда мы используем биндинг для обычного Java объекта, то экран не будет автоматически меняться при изменении значений в этом объекте.
Т.е. вы передаете объект Employee в биндинг, а затем можете сколько угодно менять в нем поля и ничего на экране меняться не будет. Вам надо будет снова руками передать измененный объект в биндинг или вызвать у биндинга метод invalidateAll, тогда экран отобразит актуальные данные.
В первом уроке по Data Binding я упоминал, что есть возможность сделать так, чтобы биндинг сам мониторил значения полей и обновлял экран, как только произошли какие-то изменения. Для этого надо использовать механизмы Observable.
Observable поля
Сделаем несколько Observable полей в классе Employee:
Для Java примитивов есть готовые Observable поля: ObservableInt, ObservableFloat и т.п. Для остальных используем ObservableField с указанием типа. Чтобы присвоить такому полю значение, используем метод set.
Поля name и salary делаем Observable. Их мы будем использовать в биндинге.
layout файл выглядит как обычно, в нем ничего менять не надо:
Теперь, передав в биндинг объект Employee, вы сможете менять значения его полей:
А биндинг сам отследит эти изменения и обновит экран.
Для коллекций есть классы ObservableArrayMap и ObservableArrayList.
Биндинг будет работать, даже если передавать значения в Observable поля не в UI потоке.
Рассмотрим еще один возможный сценарий использования ObservableField. Его можно использовать не только с отдельными полями объекта, но и с целым объектом.
Есть класс Employee:
Вполне может быть ситуация, когда нам в ViewModel (или в презентер) периодически «прилетает» из репозитория новый объект Employee и его надо отобразить в View.
В этом случае в ViewModel создаем поле ObservableField :
В это поле методом employee.set() репозиторий будет помещать новый Employee.
В layout в качестве переменной используем ViewModel.
Достаем из model объект employee и используем его поля в биндинге.
Теперь при обновлении значения в ObservableField будут изменены и поля в View без каких-либо дополнительных действий с нашей стороны.
BaseObservable
Есть еще один способ включить автобиндинг для Java объекта.
Делается это наследованием BaseObservable:
Поле id я оставил обычным. А поля name и salary будут отслеживаться биндингом. Для этого надо пометить get-методы аннотацией @Bindable, а в set-методах вызывать notifyPropertyChanged метод, который и будет уведомлять биндинг об изменениях значения поля.
В layout все будет как обычно.
Двусторонний биндинг
Биндинг может работать в обе стороны. Т.е. он будет не только передавать данные в View, но и получать их оттуда.
Рассмотрим на примере пары полей в Employee:
Поле name и статус enabled. Настроим биндинг этих полей в EditText и CheckBox.
При этом сделаем так, чтобы биндинг работал в обе стороны. Для этого надо в строке биндинга добавить символ = между @ и
Теперь при изменении текста в EditText, биндинг будет передавать новое значение в employee.name. А при включении\выключении чекбокса, биндинг будет передавать текущее состояние этого чекбокса в поле employee.enabled.
Т.е. изменения содержимого View будут отражены в Employee объекте, который мы передавали в биндинг. Если необходимо, можно использовать и Observable поля. С ними это тоже будет работать.
Кстати, если после передачи в биндинг вы нигде не храните у себя объект employee, то вы всегда можете получить его обратно методом binding.getEmployee().
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Источник
Урок 9. Android Data Binding с событиями пользовательского интерфейса и наблюдаемыми данными
Продолжаем изучать Android Data Binding. На прошлом уроке мы просто отобразили статичные данные пользователю, но возможности библиотеки биндинга гораздо шире.
User events
В этом уроке рассмотрим обработку пользовательских событий ввода и работу с наблюдаемыми данными (observable data), при изменении которых будет меняться их представление.
Будем использовать проект из прошлого урока, скачать его можно здесь.
Изменим макет разметки главного экрана activity_main.xml. Во-первых, заменим переменные для ViewModel:
Таким образом, код представления и состояние будет содержаться в одном месте. Вместо прямого доступа к переменным мы будем вызывать свойства viewmodel.
Теперь измените выражения макета в обоих текстовых полях:
Также мы будем реагировать на нажатия на кнопку лайков. Найдите кнопку like_button и замените:
В предыдущем атрибуте onClick использовался небезопасный механизм, при котором метод onLike () в активити или фрагменте вызывается при щелчке по представлению. Если указать ошибочное имя метода, среда разработки не заметит ошибку, но приложение вылетит.
Новый способ намного безопаснее, поскольку он проверяется во время компиляции и использует лямбда-выражение для вызова метода onLike () модели представления.
Проверьте наличие ошибок привязки данных, нажав «Make Project» в меню «Build» в Android Studio. Вы увидите, что в процессе сборки проекта появятся ошибки, которые будут показаны в журнале сборки. Клик на ошибке приведет вас в MainActivity, где идет обращение к несуществующим переменным макета.
Давайте удалим из проекта то, что нам уже не нужно.
- Замените строки в MainActivity:
Если вы запустите приложение, вы увидите, что кнопка ничего не делает. Это потому, что мы больше не вызываем updateLikes (). Давайте реализуем это правильно.
Observing data
Мы создали статическую привязку на предыдущем шаге. Если вы откроете модель представления (класс SimpleViewModel), вы обнаружите, что val name и val lastName — это неизменяемые строковые переменные, поскольку их не нужно менять. Однако количество лайков var likes должно изменяться в ответ на действия пользователя. Вместо явного обновления пользовательского интерфейса при изменении этого значения мы сделаем его наблюдаемым — observable. Таким образом, при изменении наблюдаемого значения элементы пользовательского интерфейса будут обновляться автоматически.
Есть несколько способов реализации наблюдаемости. Вы можете использовать наблюдаемые классы, наблюдаемые поля или, предпочтительно, LiveData. Полная документация по этому вопросу здесь.
Более подробно на практике мы работаем с LiveData и Android Data Binding в новом продвинутом курсе
В этом уроке мы рассмотрим наблюдаемые поля (ObservableFields), поскольку они проще.
Источник
Изучай observable, создавая observable
Эта статья — перевод оригинальной статьи Ben Lesh “Learning Observable By Building Observable”. Также я веду телеграм канал “Frontend по-флотски”, где рассказываю про интересные вещи из мира разработки интерфейсов
Вступление
Это повторение старой статьи, написанной мною в 2016 году, и доклада, с которым я выступал несколько раз. Я хочу немного модернизировать контент и, надеюсь, упростить его. Цель — помочь людям понять, что такое observable. Не только observable из RxJS, но и любой observable (да, их больше одного) как тип.
Observables — просто функции
Чтобы понять это, я хочу разместить рядом два примера. Один является observable из RxJS, а другой — просто функцией. Оба этих примера имеют одинаковый результат:
RxJS Observable
Это пример простого observable, созданного с помощью RxJS, который выдает три числа и завершается. Если вы уже знакомы с RxJS, это эквивалент (1, 2, 3).
Функция “observable”
Вывод (обоих!)
Я хочу, чтобы вы обратили внимание на сходство. В обоих случаях вы передаете объект с помощью метода next и complete. В обоих случаях вы вызываете next и complete в теле функции. В обоих случаях тело функции не выполняется до тех пор, пока вы не вызовете source.subscribe() или просто вызовете функцию напрямую как source() в другом примере. Это потому, что observables — это просто специализированные функции.
Почему бы просто не использовать функции? Что «особенного» в observable?
Отлично подмечено. Если бы вы были очень осторожны, вы, вероятно, могли бы использовать обычные функции для некоторых из этих случаев. Но проблема в том, что версия с функциями не совсем «безопасна». На основе всего лишь одного примера, если семантика observable такова, что next никогда не должен вызываться после завершения, нам понадобятся некоторые гарантии для этого.
В примере выше будет написано «done», а затем сразу 4. Такого быть вообще не должно! Поэтому мы хотим предоставить способ гарантировать, что следующий метод нашего подписчика не будет вызван после завершения. Это можно сделать, заключив нашу функцию в класс.
Обработка Partial Observers
Другой возможный сценарий — «partial» observer. Другими словами, observable, у которого есть только метод next или complete (или, возможно, метод ошибки, но мы вернемся к этому позже). Теперь мы можем легко разобраться с этим сценарием имея наш тип observable, указанный выше, потому что мы можем реализовать это в нашем SafeSubscriber:
Уведомления об ошибке
Уведомить нашего подписчика об ошибке так же просто, как добавить дополнительный обработчик к нашим Observer и SafeSubscriber. Семантика очень похожа на complete выше. И ошибка, и complete считаются прекращением наблюдения.
Observer просто немного изменится, чтобы появился обработчик ошибок:
После этого мы можем добавить в наш SafeSubscriber error метод:
Источники данных и кейс для отмены подписки
Основной вариант использования observable — обертывание асинхронного источника данных, например WebSocket.
Чтобы сделать что-то подобное, вы можете использовать наш самодельный observable созданный выше, например:
Но теперь у нас появилась проблема. Пользователь, который подписывается на наш observable, не имеет возможности отменить его и закрыть сокет. Нам нужен способ прекратить работу. Если бы мы просто использовали функцию, мы могли бы вернуть функцию, содержащую нашу логику прекращения подписки.
Еще одна проблема, которая возникает не обязательно связанная с WebSocket, но и с другими ситуациями, — это ситуации, когда автор observable решает, что он столкнулся с ошибкой или состоянием завершения, и он хочет уведомить пользователя, а затем удалить его. Было бы неплохо иметь единое место для этого, чтобы при вызове subscriber.error или subscriber.complete удаление выполнялось как можно быстрее.
Мы можем добиться всего этого с помощью некоторых изменений SafeSubscriber и добавления типа Subscription.
Это всё! Observables — это просто специализированные функции!
Я знаю, что это было очень МНОГО кода, надеюсь, пошаговое руководство помогло вам понять, что входит в тип observable (например, тип из rxjs), и помогло немного прояснить его. Это уж точно не волшебство.
Тогда я бы посоветовал вам спросить себя: «Для чего нужны observables?» и, честно говоря, самый короткий ответ: вы можете использовать observables для всего, для чего вы можете использовать функцию. Самая большая разница — это небольшой набор гарантий в отношении обратных вызовов и то, что, возможно, наиболее важно, в отношении прекращения работы.
Важно отметить, что описанная выше реализация НЕ является чем-то, что вы должны воссоздавать или использовать в продакшене. Я бы рекомендовал использовать observable из RxJS, поскольку он охватывает гораздо больше ситуаций, чтобы помочь сохранить ваш код надежным и безопасным при составлении сложных потоков данных.
Источник