Пишем ObservableViewModel для биндинга в Android XML layout

Для чего нужно? В ViewModel получаем, подготавливаем к выводу нужные данные, а в xml просто используем/отображаем. Второй подход - создать много переменных ObservableField в ViewModel, но если их много то это не очень удобно.

Если заинтересовала тема DataBinding, то можно почитать это https://developer.android.com/topic/libraries/data-binding/index.html
C ним можно сильно упростить себе жизнь. Начиная от отказа от findViewById и заканчивая кастомными BindingAdapter для валидации текста, для загрузки картинок в ImageView без единой строчки java, обработка нажатий на кнопки с помощью переиспользуемых Action ( https://habrahabr.ru/post/305916/ ) и т.д., насколько хватит фантазии.

Базовый класс который реализует механизм уведомления разметки об изменениях данных:
  1. import android.content.Context;
  2. import android.databinding.Bindable;
  3. import android.databinding.Observable;
  4. import android.databinding.PropertyChangeRegistry;
  5.  
  6. public class ObservableViewModel implements Observable {
  7.  
  8.     private transient PropertyChangeRegistry mCallbacks;
  9.  
  10.     public ObservableViewModel() {
  11.         // ...
  12.     }
  13.  
  14.     @Override
  15.     public void addOnPropertyChangedCallback(OnPropertyChangedCallback callback) {
  16.         synchronized (this) {
  17.             if (mCallbacks == null) {
  18.                 mCallbacks = new PropertyChangeRegistry();
  19.             }
  20.         }
  21.         mCallbacks.add(callback);
  22.     }
  23.  
  24.     @Override
  25.     public void removeOnPropertyChangedCallback(OnPropertyChangedCallback callback) {
  26.         synchronized (this) {
  27.             if (mCallbacks == null) {
  28.                 return;
  29.             }
  30.         }
  31.         mCallbacks.remove(callback);
  32.     }
  33.  
  34.     public void notifyChange() {
  35.         synchronized (this) {
  36.             if (mCallbacks == null) {
  37.                 return;
  38.             }
  39.         }
  40.         mCallbacks.notifyCallbacks(this, 0, null);
  41.     }
  42.  
  43.     public void notifyPropertyChanged(int fieldId) {
  44.         synchronized (this) {
  45.             if (mCallbacks == null) {
  46.                 return;
  47.             }
  48.         }
  49.         mCallbacks.notifyCallbacks(this, fieldId, null);
  50.     }
  51. }
Пример имплементации
  1. public class ExampleViewModel extends ObservableViewModel {
  2.  
  3.      @Bindable
  4.      public List<ExampleObject> getExampleObjects() {
  5.           // Тут могут быть сложные вычисления, а не обычный геттер - результат кeшируется
  6.      }
  7.  
  8.     public void onSomeDataChanged() {
  9.         // Уведомляем что что-то изменилось, данные обновятся в xml
  10.         // Переменная BR.exampleObjects генерируется автоматом
  11.         notifyPropertyChanged(BR.exampleObjects);
  12.         // Если нужно оповестить что поменялось все в ViewModel, то просто вызывыаем notifyChange();
  13.     }
  14. }
Разметка
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <layout xmlns:android="http://schemas.android.com/apk/res/android"
  3.        xmlns:app="http://schemas.android.com/apk/res-auto"
  4.        xmlns:tools="http://schemas.android.com/tools">
  5.  
  6.     <data>
  7.  
  8.         <variable
  9.            name="viewModel"
  10.            type="com.example.ExampleViewModel"/>
  11.     </data>
  12.       <TextView
  13.            android:layout_width="wrap_content"
  14.            android:layout_height="wrap_content"
  15.            android:text="@{viewModel.exampleObjects == 1 ? viewModel.exampleObjects.get(0) : @plurals/example_plurals_objects_count(viewModel.exampleObjects.size(), viewModel.exampleObjects.size())}"/>
  16.  
  17. </layout>
Использовать в xml поле exampleObjects можно сколько угодно раз и как угодно, при биндинге это поле просчитывается и далее просто подставляется, а если обращаться как viewModel.getExampleObjects(), то будет просто вызываться метод.

Реклама

Мы в соцсетях

tw tg yt gt