Android Data Binding. Основи

У build.gradle файл модуля в секції android необхідно включити Data Binding:

android {
    ....
    dataBinding {
        enabled = true
    }
}

Data Binding допоможе організувати роботу з View так, щоб нам не довелося писати купу методів findViewById, setText, setOnClickListener тощо. Давайте розглянемо простий приклад.

Є клас Employee, який містить у собі дані про працівника

public class Employee {
 
   public Employee(long id, String name, String address) {
       this.id = id;
       this.name = name;
       this.address = address;
   }
 
   public long id;
 
   public String name;
 
   public String address;
}

Ми хочемо вивести ім'я та адресу працівника на екран main_activity.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:orientation="vertical">
 
   <TextView
       android:id="@+id/name"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
 
   <TextView
       android:id="@+id/address"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
 
</LinearLayout>

Нескладне завдання. Для цього ми зазвичай пишемо методи findViewById і setText. Тут усе зрозуміло.

Давайте розглянемо, як це ж можна зробити за допомогою Data Binding.

Вносимо зміни в main_activity.xml:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
 
   <data>
 
       <variable
           name="employee"
           type="ru.startandroid.application.data.Employee" />
 
   </data>
 
<LinearLayout
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:orientation="vertical">
 
       <TextView
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{employee.name}" />
 
       <TextView
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{employee.address}" />
 
   </LinearLayout>
 
</layout>

Кореневим елементом тепер є <layout>, а LinearLayout змістився всередину нього.

У секції data ми оголошуємо змінну з ім'ям employee. Її тип - раніше розглянутий клас Employee. Тепер ми можемо використовувати цю змінну в атрибутах в'юшок цього layout. У першому TextView, в атрибуті text ми використовуємо employee.name, а в другому TextView - employee.address.

Зверніть увагу, що ми не вказуємо id для View. У цьому немає необхідності.

Як ви розумієте, нам залишається лише передати об'єкт Employee у цей layout. І значення цього об'єкта будуть підставлені у відповідні TextView.

Це робиться таким чином.

public class MainActivity extends AppCompatActivity {
 
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
 
       Employee employee = new Employee(1, "John Smith", "London");
 
       MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity);
       binding.setEmployee(employee);
   }
}

Спочатку створюємо Employee об'єкт.

Потім використовуємо DataBindingUtil. Метод DataBindingUtil.setContentView всередині себе зробить звичний нам setContentView для Activity, а також налаштує і поверне об'єкт біндингу MainActivityBinding.

MainActivityBinding - це згенерований клас. Ім'я цього класу береться з імені layout файлу (тобто main_activity), плюс слово Binding. MainActivityBinding все знає про наш layout: які View там є, які змінні (variable) ми там вказували, і як все це пов'язати одне з одним, щоб дані зі змінних потрапляли в View.

Метод setEmployee був згенерований у класі біндингу, оскільки ми описали змінну employee у layout файлі. Цим методом ми передаємо біндингу об'єкт Employee. Біндінг візьме значення employee.name і employee.address і помістить їх (методом setText) у відповідні TextView. Усе, як ми й налаштовували в layout.

Запускаємо додаток

Дані з Employee поміщені в TextView.

Одразу хочу зауважити, що якщо ми тепер у коді будемо змінювати об'єкт Employee, то дані на екрані змінюватися не будуть. Вони рахувалися один раз і далі не відстежуються (за такої реалізації).

Щоб екран отримав нові дані, треба знову передати біндингу змінений об'єкт Employee:

binding.setEmployee(employee);

Або можна викликати метод invalidateAll:

binding.invalidateAll();

Біндинг рахує нові дані з раніше отриманого об'єкта Employee.

Поля в Employee у цьому прикладі я зробив public. Але ви можете зробити їх private і створити для них public get методи.

Можливо, використання біндингу для пари TextView здається безглуздим. Але коли таких TextView десятки, то біндинг може позбавити вас від написання купи коду.

Крім того, ми розглянули зовсім простий випадок використання біндингу. Але його можливості набагато ширші. Наприклад, можна зробити так, щоб під час передачі в атрибут ImageView посилання на картинку, біндінг запускав Picasso для завантаження цієї картинки і поміщав результат в ImageView. Або біндінг може сам відстежувати зміни в об'єкті з даними (у прикладі вище - це Employee) і оновлювати екран без будь-яких додаткових методів.

Ці можливості ми розглянемо в наступних уроках.