Вид модели Архитектура ViewModel
- Вид - это пользовательский интерфейс, макет. В Android это обычно означает Activity, Fragment или ViewHolder и соответствующий ему файл разметки XML.
- Модель - это наш уровень бизнес-логики, который предоставляет методы для взаимодействия с данными.
- Модель представления выступает в качестве посредника между представлением и моделью, предоставляя данные из модели через свойства и содержащие состояние пользовательского интерфейса. Кроме того, он определяет команды, которые можно вызывать для таких событий, как щелчки. Модели представлений содержат логику представления вашего приложения.
В архитектурном шаблоне MVVM представление и модель представления в основном взаимодействуют друг с другом посредством привязки данных. В идеале модель представления и представления не должна знать друг о друге. Привязки должны быть связующим звеном между видом и моделью вида и обрабатывать большую часть материала в обоих направлениях. Однако в Android они не могут быть независимыми:
- Вы должны сохранить и восстановить состояние, но состояние теперь находится в модели представления.
- вам нужно сообщить модели представления о событиях жизненного цикла.
- Вы можете столкнуться с ситуациями, когда вам нужно напрямую вызывать методы представления.
В этих случаях и представление, и модель представления должны реализовывать интерфейсы, которые затем используются для связи через команды, если это необходимо. Однако почти во всех случаях требуется только интерфейс для модели представления, поскольку библиотека привязки данных обрабатывает взаимодействия с представлением, и могут использоваться пользовательские компоненты, например, когда нужен контекст.
Модель вида также обновляет модель, например, добавив новый элемент в базу данных или обновив существующий. Он также используется для извлечения данных из модели. В идеале модель также должна уведомлять модель представления об изменениях, но это зависит от реализации.
Теперь, вообще говоря, разделение представления и модели представления делает логику представления легко тестируемой, а также помогает в обслуживании в долгосрочной перспективе. Вместе с библиотекой привязки данных это означает меньше кода и более чистый код.
Пример:
<layout xmlns:android="...">
<data>
<variable name="vm" type="pkg.MyViewModel" />
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{vm.shouldShowText}"
android:text="@={vm.text}" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="@{vm::onButtonClick}"
android:text="@string/button"/>
</FrameLayout>
</layout>
Когда вы хотите использовать архитектуру MVVM, ваши макеты должны ссылаться только на одну переменную, конкретную модель представления для этого представления, в данном случае MyViewModel. В модели представления вы предоставляете свойства для макета. Это может быть так же просто, как вернуть String из объекта модели или более сложным, в зависимости от вашего варианта использования.
public class MyViewModel extends BaseObservable {
private Model model = new Model();
public void setModel(Model model) {
this.model = model;
notifyChange();
}
public boolean shouldShowText() {
return model.isTextRequired();
}
public void setText(String text) {
model.setText(text);
}
public String getText() {
return model.getText();
}
public void onButtonClick(View v) {
// Save data
}
}
Здесь у нас есть свойство text. Поскольку у нас есть EditText для пользовательского ввода, мы можем использовать двустороннюю привязку данных, чтобы библиотека привязки данных сохраняла входные данные обратно в модель представления. Для этого мы создаем как метод установки, так и метод получения и привязываем свойство к текстовому атрибуту нашего EditText, но на этот раз со знаком = перед скобкой, который сигнализирует библиотеке о том, что здесь требуется двустороннее связывание данных.
Кроме того, мы хотим показывать EditText только тогда, когда наша модель говорит, что требуется ввод текста. Для этого мы предоставляем логическое свойство в нашей модели представления и привязываем его к атрибуту видимости. Чтобы это работало, мы также должны создать адаптер привязки, который устанавливает видимость GONE, когда false, и VISIBLE, когда true.
@BindingAdapter("android:visibility")
public static void setVisibility(View view, boolean visible) {
view.setVisibility(visible ? View.VISIBLE : View.GONE);
}
Наконец, мы хотим сохранить информацию при нажатии кнопки. Для этого мы создаем команду onButtonClick () в нашей модели представления, которая обрабатывает взаимодействие с моделью. В макете мы привязываем команду к атрибуту onClick кнопки через ссылку на метод. Чтобы это работало напрямую, наш метод должен иметь один параметр типа View, как и OnClickListener. В качестве альтернативы - если вам не нужен параметр View - вы также можете использовать лямбда-выражения прямо в макете. Как видите, связывание данных с моделью представления довольно просто и понятно.
НетВажно помнить, что мы хотим включить логику представления в нашу модель представления для обеспечения возможности тестирования. Старайтесь не помещать логику непосредственно в привязки, даже если библиотека привязки данных позволяет это. Не забывайте, что у вас также могут быть настраиваемые адаптеры привязки, которые часто могут упростить вещи.