Афоризм
Алкоголь в малых дозах безвреден в любом количестве.
Михаил Жванецкий
Последние статьи

 • Активности Android
Многоэкранные Android приложения
 • Fragment dynamic
Динамическая загрузка фрагментов в Android
 • Fragment lifecycle
Жизненный цикл Fragment'ов в Android
 • Fragment example
Пример Fragment'ов в Android
 • Data Binding
Описание и пример Data Binding
 • Пример MVVM
Пример использования MVVM в Android
 • Компонент TreeTable
Описание компонента TreeTable для Swing
 • Пример TreeTable
Пример использования TreeTable
 • Хранилища Android
Внутренние и внешние хранилища данных
 • Пример SQLite
Пример использования SQLite в Android
 • WebSocket
Описание и пример реализации WebSocket
 • Визуальные компоненты
Улучшен компонент выбора даты из календаря
 • Анимация jQuery
Описание и примеры анимации элементов DOM
 • APK-файл Android
Создание apk-файла для android устройств, .dex файлы
 • платформа JaBricks
Платформа OSGi-приложения JaBricks
Поддержка проекта

Если Вам сайт понравился и помог, то будем признательны за Ваш «посильный» вклад в его поддержку и развитие
 • Yandex.Деньги
  410013796724260

 • Webmoney
  R335386147728
  Z369087728698

Пример использования Model-View-ViewModel

На странице рассмотрен пример использования Data Binding совместно с MVVM в приложении Android. Описание Data Binding и MVVM (Model-View-ViewModel) представлено на странице Data Binding Library в Android. Кратко отмечу, что использование Data Binding позволяет связать Java-объект с разметкой интерфейса layout (XML-файл). При этом некоторые свойства и методы Java-объекта можно непосредственно перенести в разметку XML-файла. MVVM — это шаблон определения архитектуры клиентских приложений, предложенный Джоном Госсманом (John Gossman) как альтернатива шаблонам MVC и MVP при использовании технологии связывания данных (Data Binding). Концепция MVVM связана с отделением логики представления данных от бизнес-логики путём вынесения её в отдельный класс для более четкого разграничения.

Интерфейс примера

Чтобы было легче связать отдельные фрагменты описания кода примера с его конечной целью начнем с интерфейса представления. На скриншоте представлен интерфейс примера после старта в Android Studio. В примере создается 2 компонента типа TextView для отображения имени пользователя и его возраста. Ниже располагается кнопка. Интерфейс примера ничем не отличается от своего прототипа, в котором рассмотрено использование Data Binding.

Бизнес-логика функционирования примера интуитивно понятна и примитивна. При старте в компонентах отображается имя и возраст одного пользователя. После нажатия на кнопку значение возраста age либо уменьшается на 3 единицы, если age > 18 , либо увеличивается на 2 единицы, если age < 18. Забегая вперед, отмечу, что значение изменяется в параметре user.age (Model), а ViewModel, отслеживая данное изменение, обновляет его в интерфейсе View.

Описание кода

Ниже представлен скриншот проекта/модуля databinding_mvvm в IDE Android Studio.

В проекте определены следующие программные объекты, используемые в разработке примера :

• strings.xml — ресурсный файл текстовых строк и шаблона представления возраста;
• activity_main.xml — файл определения интерфейса (разметка);
• User.java — класс описания пользователя;
• MainActivity.java — главный модуль активности.

Интерфейс примера на уровне среды разработки (IDE) определяет главный ресурсный файл activity_main.xml. В режиме исполнения примера главный модуль активности MainActivity.java формирует интерфейс и определяет бизнес-логику управления компонентами. Ресурсный файл strings.xml определяет текстовые значения интерфейсных компонентов. Класс User.java описывает объект пользователя.

Необходимо также добавить, что в файле Gradle Scripts/build.gradle (app.databinding_mvvm) в секцию android добавлено определение dataBinding, как это приведено в описании библиотеки. Это необходимо выполнить, чтобы получить доступ к библиотеке Data Binding.

На скриншоте раскрыта поддиректория модуля java (generated), в которой представлены генерируемые библиотекой Data Binding программные модули.

Листинг strings.xml

Ресурсный файл strings.xml создается автоматически средой Android Studio при формировании нового модуля/проекта. В модуле переопределен заголок (app_name) и добавлены строки определения текста.

<resources>
    <string name="app_name">Data Binding and MVVM</string>
    <string name="button">Button</string>
    <string name="age_format">Возраст: %d</string>
</resources>

Заметка : строка age_format включает выражение, которое используется для определения возраста пользователя в компоненте View, т.е. текстовое значение компонента формируется динамически.

activity_main.xml

Ниже представлен листинг файла разметки activity_main.xml. На что следует обратить внимание в файле разметки :

  • дополнительный внешний/корневой layout — это обязательная опция для использования Data Binding в приложении;
  • в файл разметки добавлена секция <data>, в которой
    • определяется переменная user с указанием класса com.example.dbmvvm.User в секции <variable>;
    • импортируется android.view.View, чтобы можно было использовать View.VISIBLE : View.INVISIBLE (см. android:visibility).
  • компоненты типа TextView и Button, которые используются в java-коде, имеют обязательные идентификаторы android:id;
  • текстовые значения интерфейсных компонентов android:text связаны со значениями определенных полей java-объекта user выражением в формате @{variable.field} (user.name, user.age);
  • текстовое значение компонента userAge определяется выражением @string/age_format (int) с использованием в качестве параметра user.age;
  • значение опции android:visibility компонента userAge определяется выражением : @{user.adult ? View.VISIBLE : View.INVISIBLE}, в котором user.adult — это «дополнительное поле», связанное со значением user.age.

Листинг activity_main.xml

<?xml version="1.0" encoding="utf-8"?>

<layout xmlns:tools="http://schemas.android.com/tools"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:android="http://schemas.android.com/apk/res/android">
  
  <data>
      <variable
          name = "user"
          type = "com.example.dbmvvm.User" />
      <import type="android.view.View" />
  </data>

  <androidx.constraintlayout.widget.ConstraintLayout
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/userName"
        android:layout_width="160dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:text="@{user.name}"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <TextView
        android:id="@+id/userAge"
        android:layout_width="160dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:text="@{@string/age_format(user.age)}"
        android:visibility="@{user.adult ? View.VISIBLE :
                                         View.INVISIBLE}"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf=
                                  "@+id/userName" />
    <Button
        android:id="@+id/button"
        android:layout_width="160dp"
        android:layout_height="48dp"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:text="@string/button"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/userAge"/>

  </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

Класс User.java

Класс User.java — это простой Java-объект, не унаследованный от какого-то специфического объекта. Класс содержит 2 поля, конструктор и методы Get/Set для обоих полей. Дополнительная логическая функция isAdult, имитирующая поля adult, возвращает значение true, если возраст меньше 18. Необходимо отметить, что весь объект/класс находится в зоне наблюдения (BaseObservable). О том, как можно наблюдать за отдельным полем класса/объекта описано здесь.

Листинг User.java

package com.example.dbmvvm;

import androidx.annotation.NonNull;
import androidx.databinding.BaseObservable;
import androidx.databinding.Bindable;

public class User extends BaseObservable
{
    private  int     age;
    private  String  name;

    //---------------------------------
    public User(int age, String name) {
        this.age = age;
        this.name = name;
    }
    //---------------------------------
    @Bindable
    public int getAge() {
        return age;
    }
    //---------------------------------
    public void setAge(int age) {
        this.age = age;
        notifyPropertyChanged(BR.age);
        notifyPropertyChanged(BR.adult);
    }
    //---------------------------------
    @Bindable
    @NonNull
    public String getName() {
        return name;
    }
    //---------------------------------
    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(BR.name);
    }
    //---------------------------------
    @Bindable
    public boolean isAdult()
    {
        return age >= 18;
    }
}
 

Класс BR.java

В разделе модуля/проекта появился один интересный класс BR.java, в котором содержатся идентификаторы полей, чьи методы Get помечены @Bindable. Класс BR подобен ресурсному R-классу и его можно использовать в java-коде (например, BR.age), вызывая метод notifyPropertyChanged.

package androidx.databinding.library.baseAdapters;

public class BR
{
  public static final int _all  = 0;
  public static final int adult = 1;
  public static final int age   = 2;
  public static final int name  = 3;
  public static final int user  = 4;
}

MainActivity.java

Файл MainActivity.java наследует свойства активности AppCompatActivity, формирует интерфейс примера и определяет бизнес-логику кнопки подключением к ней слушателя события onClick.

Особенности использования Data Binding в Java-коде :

  • наименование класса ActivityMainBinding определяется наименованием файла разметки activity_main.xml, CamelCase+Binding;
  • объект binding типа ActivityMainBinding создается с использованием статического метода inflate;
  • с альтернативным способом создания объекта связи binding, связанного с утилитой DataBindingUtil, можно познакомиться здесь;
  • текстовые значения нтерфейсных компонентов View определяются методом setUser(user) объекта связи binding;
  • подключение обработчика события к кнопке Button выполняется с использованием метода setOnClickListener объекта связи binding;
  • изменение возраста age пользователя user в интерфейсе выполняется с использованием метода объекта setAge(int), не связанного прямым способом с интерфейсным компонентом View.

Таким образом, используя объект связи binding типа ActivityMainBinding можно определить значения интерфейсных компонентов View и подключить к ним обработчики событий, а использование в приложении шаблона архитектуры MVVM позволяет связать данные (Model) и их представление в интерфейсе (View) через ViewModel.


package com.example.dbmvvm;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;

import androidx.appcompat.app.AppCompatActivity;

import com.example.dbmvvm.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity
{
    ActivityMainBinding binding;
    User                user   ;
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        LayoutInflater inflater = getLayoutInflater();

        binding = ActivityMainBinding.inflate(inflater);
        setContentView(binding.getRoot());

        user = new User(25, "Alex");
        binding.setUser(user);

        binding.button.setOnClickListener(
            new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    int age;
                    // Определение возраста
                    if (user.getAge() < 18)
                        age = user.getAge() + 2;
                    else
                        age = user.getAge() - 3;
                    // Изменение возраста в объекте
                    user.setAge(age);
                }
            }
        );
    }
}
  Рейтинг@Mail.ru