[Из песочницы] Быстрый старт Data Binding в Android
Введение Профессионально андроид-разработкой занимаюсь чуть больше года, до этого разрабатывал по Windows Phone и мне понравилась возможность связывать данные из вью модели с самим View при помощи механизма Bindings. А после изучения RX, многие задачи стали решаться более чисто, вью-модель полностью отделилась от View. Она стала оперировать только моделью, совсем не заботясь о том, как она будет отображаться.В Android такой строгости я не заметил, Activity или Fragment как простейшие представители контроллера чаще всего имеют полный доступ как ко View, так и к модели, зачастуя решая, какой View будет видим, решая таким образом чисто вьюшные задачи. Поэтому я довольно радостно воспринял новость о появлении Data Binding в Android на прошедшем Google IO.
[embedded content]
Пока что это только бета релиз, но уже можно протестировать функционал и увидеть направление, в котором двигаются разработчики из Google.
Начало Я использую Android Studio 1.3.Для сборки используется новый android плагин для Gradle (нужна версия 1.3.0-beta1 и старше). Так как связи отрабатываются во время компиляции, нам понадобиться ещё один плагин к Gradle 'com.android.databinding: dataBinder:1.0-rc0'. В отличие от того же Windows Phone где механизм привязок реализован глубоко по средством DependencyProperty и в RealTime, в Android эта функция реализуется как бы поверх обычных свойств, во время компиляции и дополнительной кодогенерации, поэтому в случае ошибок будьте готовы разбирать ответ от компилятора.
Итак, заходим в файл build.gradle, который лежит в корневом каталоге проекта (в нём идут настройки Gradle для всего проекта). В блоке dependencies вставляем:
dependencies {
classpath 'com.android.tools.build: gradle:1.3.0-beta2'
classpath 'com.android.databinding: dataBinder:1.0-rc0'
}
Теперь подключим плагин к конкретному модулю, откроем build.gradle файл, который лежит внутри модуля. По умолчанию app/build.gradle и добавим строчку:
apply plugin: 'com.android.databinding'
Настройка Layout
Мы должны обернуть наш внешний View в тег
@Override protected void onCreate (Bundle savedInstanceState) { super.onCreate (savedInstanceState); binding = DataBindingUtil.setContentView (this, R.layout.activity_main); binding.bindTv.setText («Some text»); } Название поля берётся из Id View, без Id в биндере поле не появиться, если изменить Id View, то поле в биндере сразу же переметнуться. Если с зажатым CTRL нажать на название поля View, то сразу перейдешь к нему в файле разметки. Как по мне так уже одного такого функционала достаточно для того чтобы начать использовать биндинги.Мои предвкушения Но это лишь начало и идёт как бонус, главная особенность это конечно же использование самого Layout файла для разметки того какие данные куда размещать и как следствие возможность реализации паттерна MVVM как это происходит в С# в Windows приложениях. А если ещё и приложить мощь Java RX, но не будем отвлекаться.
Привязка данных Например у нас есть карточка пользователя имя и возраст. public class User { public String name; public int age;
public User (String name, int age) {
this.nam = name;
this.age = age;
}
}
Изменим Layout, заменим содержимое LinearLayout на:
И в onCreate заменим последнюю строку на: binding.setUser (new User («Some name», 27)); Запускаем. Всё работает.Наверное у всех проектах в активити или в фрагментах встречается такие строчки: someView.setVisibility (isVisible: View.VISIBLE: View.GONE); Тут то мы и начинаем использовать непосредственно привязки данных. Перепишем модель: public class User { public String name; public int age;
public User (String name, int age, boolean isAdult) {
this.name = name;
this.age = age;
this.isAdult = isAdult;
}
public boolean isAdult;
}
И добавим в Layout:
Импортируем его в разметку:
Обратная связь и Binding
Попробуем сменить имя пользователя.Добавим в Layout:
binding.setUser (new User («New model», 668714400L, false)); Или вытащить старую, заменить данные и вставить опять: User user1 = binding.getUser (); user1.name = «old model»; binding.setUser (user1); Но тогда обновятся все View, связанные с этой моделью. Лучшим вариантом будет связать модель с binder, чтобы она могла его оповестить о своём изменении. Для этого перепишем класс модели, добавив геттеры и сеттеры, Что в Android Studio дело пары кликов Alt-Insert → Getter and Setter → Ctrl-A → Enter
помечая геттеры атрибутом @Bindable, и добавив в сеттеры вызов notifyPropertyChanged (BR.lastName);
public class User extends BaseObservable {
private String name;
private long birthday;
private boolean adult;
public User (String name, long birthday, boolean isAdult) {
this.name = name;
this.birthday = birthday;
this.adult = isAdult;
}
@Bindable
public String getName () {
return name;
}
public void setName (String name) {
this.name = name;
notifyPropertyChanged (com.georgeci.bindingssample.BR.name);
}
@Bindable
public long getBirthday () {
return birthday;
}
public void setBirthday (long birthday) {
this.birthday = birthday;
notifyPropertyChanged (com.georgeci.bindingssample.BR.birthday);
}
@Bindable
public boolean isAdult () {
return adult;
}
public void setAdult (boolean adult) {
this.adult = adult;
notifyPropertyChanged (com.georgeci.bindingssample.BR.adult);
}
}
Видим новый класс BR, в котором содержатся идентификаторы полей, чьи геттеры помечены атрибутом @Bindable. В Layout оставляем android: text=»@{user.name}», меняем только isAdult на adult, c 'is' в названии поля возникли проблемы. Запускаем всё работает.ObservableFields
В пакете android.databinding есть классы, которые могут упростить нотификацию binder об изменении модели: Обёртки над элементарными типами
ObservableField
public User (String name, long birthday, boolean isAdult) { this.name.set (name); this.birthday.set (birthday); this.adult.set (isAdult); } } Публичное поле? Не в мою смену. Так как поле помечено как final, и по существу является просто умной обёрткой над типом, то не вижу проблем в этом; для остальных есть первый вариант.
По коллекциям аналогично, единственное приведу пример обращения ко ключу к Map:
User user; ActivityMainBinding binding; Vm vm = new Vm ();
@Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
binding = DataBindingUtil.setContentView (this, R.layout.activity_main);
user = new User («Some name», 668714400L, false);
binding.setUser (user);
binding.setVm (vm);
binding.setClicker (new View.OnClickListener () {
@Override
public void onClick (View v) {
Toast.makeText (getApplicationContext (), vm.edit.get ().toString (), Toast.LENGTH_SHORT).show ();
}
});
}
}
А в разметку добавлю:
Итог Очень любопытно было увидеть библиотеку для поддержки Data Binding в Android от Google. В документации тоже нет информации про обратную связь данных, но я надеюсь на скорую её реализацию. После официального выхода стабильной версии можно будет посмотреть на интеграцию с JavaRX.[ Оффициальная документация ][ Ссылка на мой простенький пример ]