Model-View-ViewModel
MVP — Model-View-Presenter
Для початку — трошки теорії. Все почалося з того, що багато хто думав, як адаптувати шаблон MVC (Model-View-Controller) для написання додатків з інтерфейсом користувача. І в 2006 році в роботі “GUI Architectures” Мартін Фаулер детально розглянув шаблон, який пізніше отримав назву “MVP” (“Model-View-Presenter”).
Отже, MVP — шаблон проектування, похідний від MVC, розроблений переважно для побудови користувацького інтерфейсу. MVP використовується для полегшення автоматичного модульного тестування та покращення розділення логіки і відображення.
В цьому шаблоні є три елементи:
- View.
- Presenter.
- Model (модель).

- Елемент View відповідає за показ користувацьких даних і перехоплення користувацьких дій. Все це він надсилає
Presenter'у. Presenterобробляє дії користувача в UI, враховує зміни даних уModelі надсилає цю інформаціюView.Presenter— це елемент, який містить всю бізнес-логіку роботи з користувацьким інтерфейсом.Modelмістить у собі моделі з предметної області, які відображають знання та дані предметної області вашого додатка.Modelнадсилає інформацію про зміну данихPresenterі приймає повідомлення відPresenter.
MVP — реалізація в Android
MVP дозволяє створювати абстракцію представлення. Для цього необхідно виокремити інтерфейс представлення з певним набором властивостей і методів.
Тепер подивимося, як це можна реалізувати в Android — для цього напишемо невеликий «велосипед».
Presenter взаємодіє з View за допомогою спеціального інтерфейсу, який описує абстракцію цього View.
Припустимо, у нас є ось така модель View:
public interface SomeScreenView {
void startLoading();
void stopLoading();
void mapDataItems(final Collection<DataItem> items);
}
Зверніть увагу: не слід плутати цю модель View з тим виглядом (View), який ми бачимо на екрані. View, яка використовується в MVP — це певна абстракція View. Іншими словами, це узагальнення поведінки нашого View. В MVP View не відповідає за те, як саме все буде відображатися на користувацькому інтерфейсі. Вона відповідає за те, як буде поводитися користувацький інтерфейс.
Presenter отримує посилання на реалізацію інтерфейсу, взаємодіє з моделлю нашого View, ініціалізує його, викликає всі його повідомлення, посилає йому якісь повідомлення і т.д. Все взаємодія відбувається напряму: у нас є реалізація View, ми викликаємо її методи і отримуємо певний результат.
Іншими словами, Presenter як би підписується на події View і за необхідності змінює дані в Model.
public class SomeScreenPresenter extends Presenter {
private SomeScreenView mView;
public void setView(SomeScreenView view) {
mView = view;
}
@Override
public void initialize() {
mView.startLoading();
mView.mapDataItems(...);
mView.stopLoading();
}
}
Як приклад View у нашому випадку виступатиме Activity, що відповідає за реалізацію поведінки SomeScreenView. Роль View може відігравати не тільки Activity, але й Fragment, Dialog або просто Android View. Для цього йому також необхідно реалізувати поведінку SomeScreenView. У зазначеному Activity використовується об'єкт типу SomeScreenPresenter, який і виступає в ролі Presenter у нашому прикладі. Цьому об'єкту ми надаємо посилання на реалізацію вашого View, яке взаємодіє з Presenter шляхом прямого виклику в нього необхідних методів. Своєю чергою, Presenter викликає методи, реалізовані всередині вашої Activity, тому що вона є реалізацією вашого View.
@EActivity(R.layout.activity_some_screen)
public class SomeScreenActivity extends Activity implements SomeScreenView {
private SomeScreenPresenter mPresenter;
@ViewById(R.id.drawer_layout)
protected ProgressBar mProgressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenter = new SomeScreenPresenter(this);
mPresenter.gradletialize();
}
}
Цей простий приклад демонструє, як MVP дозволяє декомпозувати логіку, яка раніше повністю знаходилася в Activity та була пов'язана з обробкою даних і дій користувача. Ми винесли цю логіку в окремий модуль, і цей модуль, наприклад, можемо перевірити звичайним модульним тестуванням. На мою думку, це набагато простіше, ніж тестування нашої UI-функціональності за допомогою Robotium, запуску емуляторів і т. д. Іншими словами, ми взяли всю нашу логіку з Activity, яка раніше була Controller, винесли її в новий елемент Presenter, і тепер можемо цей елемент спокійно протестувати, не створюючи ніяких Controller і View. Крім того, цей код можна додатково покращити — наприклад, використовуючи впровадження залежностей (скажімо, за допомогою RoboGuice або Dagger).
Приклад
Опис бізнес-сценарію:
- Користувач може переглядати список товарів.
- Користувач може додавати товар у кошик.
- Користувач може оформити покупку.
- Ми використовуємо Retrofit для мережевих запитів, щоб отримати список товарів із серверу та виконати покупку.
Крок 1: Модель (Model)
1.1. Структура товару (Product)
public class Product {
private String id;
private String name;
private double price;
public Product(String id, String name, double price) {
this.id = id;
this.name = name;
this.price = price;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
}
1.2. Інтерфейс для отримання товарів із мережі
import retrofit2.Call;
import retrofit2.http.GET;
public interface ApiService {
@GET("products")
Call<List<Product>> getProducts();
}
1.3. Клас для обробки покупки
public class Purchase {
private String userId;
private List<Product> products;
public Purchase(String userId, List<Product> products) {
this.userId = userId;
this.products = products;
}
public String getUserId() {
return userId;
}
public List<Product> getProducts() {
return products;
}
}
Крок 2: Presenter
2.1. Презентер для роботи з продуктами та кошиком
import android.util.Log;
import java.util.List;
public class ProductPresenter {
private ProductView view;
private ApiService apiService;
private List<Product> products;
public ProductPresenter(ProductView view, ApiService apiService) {
this.view = view;
this.apiService = apiService;
}
public void loadProducts() {
apiService.getProducts().enqueue(new retrofit2.Callback<List<Product>>() {
@Override
public void onResponse(Call<List<Product>> call, retrofit2.Response<List<Product>> response) {
if (response.isSuccessful()) {
products = response.body();
view.showProducts(products);
} else {
view.showError("Failed to load products");
}
}
@Override
public void onFailure(Call<List<Product>> call, Throwable t) {
view.showError("Network error");
}
});
}
public void addToCart(Product product) {
// Логіка додавання товару в кошик
view.showProductAddedToCart(product);
}
public void makePurchase(String userId) {
if (products == null || products.isEmpty()) {
view.showError("Your cart is empty");
return;
}
Purchase purchase = new Purchase(userId, products);
// Можна реалізувати мережевий запит для оформлення покупки
view.showPurchaseSuccess(purchase);
}
}
Крок 3: View
3.1. Інтерфейс для View
public interface ProductView {
void showProducts(List<Product> products);
void showError(String error);
void showProductAddedToCart(Product product);
void showPurchaseSuccess(Purchase purchase);
}
3.2. Реалізація View в Activity
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.List;
public class MainActivity extends AppCompatActivity implements ProductView {
private ProductPresenter presenter;
private ListView productsListView;
private Button buyButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
productsListView = findViewById(R.id.productsListView);
buyButton = findViewById(R.id.buyButton);
// Ініціалізація Retrofit
ApiService apiService = RetrofitClient.getRetrofitInstance().create(ApiService.class);
presenter = new ProductPresenter(this, apiService);
// Завантаження продуктів
presenter.loadProducts();
buyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Оформлення покупки (потрібно передати userId)
presenter.makePurchase("user123");
}
});
}
@Override
public void showProducts(List<Product> products) {
// Налаштовуємо адаптер для відображення товарів
ProductAdapter adapter = new ProductAdapter(this, products);
productsListView.setAdapter(adapter);
}
@Override
public void showError(String error) {
Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
}
@Override
public void showProductAddedToCart(Product product) {
Toast.makeText(this, "Product added to cart: " + product.getName(), Toast.LENGTH_SHORT).show();
}
@Override
public void showPurchaseSuccess(Purchase purchase) {
Toast.makeText(this, "Purchase successful! " + purchase.getProducts().size() + " items bought.", Toast.LENGTH_SHORT).show();
}
}
Крок 4: Адаптер для відображення списку продуктів
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.List;
public class ProductAdapter extends BaseAdapter {
private Context context;
private List<Product> products;
public ProductAdapter(Context context, List<Product> products) {
this.context = context;
this.products = products;
}
@Override
public int getCount() {
return products.size();
}
@Override
public Object getItem(int position) {
return products.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.product_item, parent, false);
}
Product product = products.get(position);
TextView nameTextView = convertView.findViewById(R.id.productName);
TextView priceTextView = convertView.findViewById(R.id.productPrice);
nameTextView.setText(product.getName());
priceTextView.setText("$" + product.getPrice());
return convertView;
}
}
Крок 5: Ретрофіт клієнт для мережевих запитів
public class RetrofitClient {
private static Retrofit retrofit;
private static final String BASE_URL = "https://api.example.com/";
public static Retrofit getRetrofitInstance() {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
Крок 6: XML для Activity
<!-- activity_main.xml -->
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ListView
android:id="@+id/productsListView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/buyButton" />
<Button
android:id="@+id/buyButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Buy"
app:layout_constraintTop_toBottomOf="@+id/productsListView"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
MVVM
Шаблон MVP непоганий, але Microsoft придумала шаблон ще кращий — MVVM (Model-View-ViewModel). Цей шаблон дуже полюбляють .NET-розробники, він використовується в Silverlight, WPF, WinUI 3, MAUI, його реалізація є в AngularJS. MVVM — дуже зручний шаблон.
Чим MVVM відрізняється від MVP?
MVVM дозволяє зв'язувати елементи View з властивостями та подіями ViewModel. При цьому ViewModel — абстракція представлення. У MVVM є:
- View — містить поля, що відповідають інтерфейсу користувача.
- ViewModel — містить такі ж поля, але в предметній області.
- Той же, Model.
Властивості View збігаються з властивостями ViewModel/Model. При цьому ViewModel не має посилання на інтерфейс представлення. Зміна стану ViewModel автоматично змінює View, і навпаки. Для цього використовується механізм зв'язування даних. Також характерною рисою MVVM є двостороння комунікація з View.

MVVM у розробці Android: Як використати шаблон із Java та Data Binding
Вступ
MVVM (Model-View-ViewModel) — це один із найпопулярніших архітектурних шаблонів для Android-додатків. Він забезпечує чіткий поділ відповідальності, що робить код більш підтримуваним, тестованим і зрозумілим. У цій статті ми розглянемо, як реалізувати MVVM у Android із використанням Java та Data Binding.
Що таке MVVM?
MVVM розділяє додаток на три основні компоненти:
- Model:
- Відповідає за управління даними (логіка бізнесу, доступ до API, бази даних тощо).
- View:
- Це інтерфейс користувача (наприклад, XML-макет).
- Відображає дані, які отримує від ViewModel.
- ViewModel:
- Зв'язує View і Model.
- Містить всю логіку відображення даних і викликає Model для отримання або збереження даних.
Чому MVVM краще?
Переваги:
- Чіткий поділ відповідальності: Легше підтримувати й розширювати додаток.
- Легке тестування: ViewModel легко тестується, оскільки не має прямої залежності від UI.
- Data Binding: Позбавляє необхідності оновлювати UI вручну.
Недоліки:
- Додаткова складність у малих проєктах.
- Потребує більшої кількості класів та налаштувань.
Data Binding: Що це?
Data Binding дозволяє зв'язати UI-елементи напряму з даними у ViewModel, що усуває потребу в пошуку View через findViewById і дозволяє автоматично оновлювати UI при зміні даних.
Реалізація MVVM із Data Binding
Створимо простий приклад програми, що показує привітання користувачу за введеним ім'ям.
1. Налаштування проєкту
Додайте Data Binding у build.gradle:
android {
...
buildFeatures {
dataBinding true
}
}
Залежності:
dependencies {
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.4.1'
implementation 'androidx.lifecycle:lifecycle-livedata:2.4.1'
}
2. Створіть ViewModel
ViewModel зберігає введені дані та генерує повідомлення.
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class GreetingViewModel extends ViewModel {
private MutableLiveData<String> name = new MutableLiveData<>("");
private MutableLiveData<String> greetingMessage = new MutableLiveData<>("");
public LiveData<String> getName() {
return name;
}
public void setName(String newName) {
name.setValue(newName);
updateGreetingMessage();
}
public LiveData<String> getGreetingMessage() {
return greetingMessage;
}
private void updateGreetingMessage() {
String currentName = name.getValue();
if (currentName == null || currentName.isEmpty()) {
greetingMessage.setValue("Привіт, незнайомцю!");
} else {
greetingMessage.setValue("Привіт, " + currentName + "!");
}
}
}
3. Налаштуйте XML (View)
У XML ми використовуємо Data Binding для зв’язування UI-елементів із ViewModel.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="viewModel"
type="com.example.mvvmexample.GreetingViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Введіть своє ім'я"
android:text="@={viewModel.name}" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{viewModel.greetingMessage}"
android:layout_marginTop="16dp"
android:textSize="20sp" />
</LinearLayout>
</layout>
4. Створіть Activity (View)
У MainActivity ми ініціалізуємо ViewModel і зв’язуємо його з XML.
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.lifecycle.ViewModelProvider;
import com.example.mvvmexample.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Використовуємо Data Binding
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
// Ініціалізуємо ViewModel
GreetingViewModel viewModel = new ViewModelProvider(this).get(GreetingViewModel.class);
// Прив'язуємо ViewModel до Binding
binding.setViewModel(viewModel);
// Дозволяємо LiveData автоматично оновлювати UI
binding.setLifecycleOwner(this);
}
}
Що таке LiveData?
LiveData — це об'єкт із бібліотеки Android Architecture Components, який спостерігає за даними і забезпечує автоматичне оновлення UI при зміні даних.
Переваги LiveData:
- Автоматичне керування життєвим циклом.
- Безпечне оновлення UI з фонових потоків.
- Мінімізація витоків пам'яті.
Приклад із LiveData:
Створимо об'єкт LiveData для зберігання списку елементів:
private MutableLiveData<List<String>> items = new MutableLiveData<>(new ArrayList<>());
public LiveData<List<String>> getItems() {
return items;
}
public void addItem(String item) {
List<String> currentItems = items.getValue();
if (currentItems != null) {
currentItems.add(item);
items.setValue(currentItems);
}
}
Висновок
Шаблон MVVM у поєднанні з Data Binding і LiveData — це потужний інструмент для створення модульних і підтримуваних Android-додатків. У цьому прикладі ми створили простий додаток із привітанням, використовуючи найкращі практики. Цей підхід легко адаптується до складніших задач, таких як робота з API, базами даних або іншими джерелами даних.
ObservableArrayList в Android
Що таке ObservableArrayList?
ObservableArrayList — це клас із бібліотеки Android Data Binding, який дозволяє створювати списки, зміни в яких автоматично відслідковуються та повідомляються підписникам. Це робить його ідеальним для використання у патерні MVVM разом із Data Binding.
Клас ObservableArrayList особливо корисний, коли потрібно інтегрувати оновлення UI з бізнес-логікою, оскільки будь-яка зміна в списку автоматично тригерить оновлення прив’язаного представлення (View).
Як використовувати ObservableArrayList?
import androidx.databinding.ObservableArrayList;
public class CalculatorViewModel extends ViewModel {
// Список операцій у калькуляторі
public ObservableArrayList<String> operations = new ObservableArrayList<>();
// Додати операцію
public void addOperation(String operation) {
operations.add(operation);
}
// Видалити операцію
public void removeOperation(String operation) {
operations.remove(operation);
}
}
У цьому прикладі список operations автоматично повідомляє прив’язаний UI, якщо змінюється його вміст.
Інтеграція з Data Binding
XML-макет
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="viewModel"
type="com.example.calculator.CalculatorViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- Список операцій -->
<ListView
android:id="@+id/operationsListView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:entries="@{viewModel.operations}" />
<!-- Додати операцію -->
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Додати операцію"
android:onClick="@{() -> viewModel.addOperation(`Нова операція`)}" />
</LinearLayout>
</layout>
Що відбувається?
- Прив’язка (Binding): Список
operationsіз ViewModel прив’язаний доListView. - Автоматичне оновлення: Будь-яка зміна в
ObservableArrayListавтоматично оновлюєListView.
Особливості ObservableArrayList
- Автоматичні повідомлення: Усі зміни в списку автоматично тригерять оновлення прив’язаного представлення.
- Простота використання: Не потрібно вручну сповіщати підписників про зміни.
- Інтеграція з Data Binding: Клас створений спеціально для роботи з Data Binding.
- Немає підтримки складних змін: ObservableArrayList не підтримує подій на рівні окремих елементів (наприклад, оновлення властивості об’єкта в списку).
Обмеження ObservableArrayList
- Масштабованість: Для великих списків або складних змін краще використовувати інші підходи, наприклад,
LiveDataчиPagedList.
Прив’язка даних (Data Binding) в XML
Прив’язка даних у XML — це ключова особливість Android Data Binding Library, яка дозволяє напряму з'єднати дані з інтерфейсом користувача. Цей підхід спрощує зв’язок між логікою (ViewModel) і представленням (View), що є особливо зручним у патерні MVVM.
Основний синтаксис прив’язки
1. Декларація прив’язки в макеті
Щоб використовувати прив’язку даних у XML, макет файлу повинен починатися з <layout>.
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<!-- Оголошення змінних -->
<variable
name="viewModel"
type="com.example.app.MyViewModel" />
</data>
<!-- Основний макет -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Елементи UI -->
</LinearLayout>
</layout>
2. Оголошення змінних у <data>
Вкладений тег <data> використовується для визначення змінних, які будуть доступні для прив’язки в XML. Змінна визначається за допомогою тега <variable>.
name— ім’я змінної, яка буде доступна в XML.type— клас об’єкта, який буде прив’язаний.
<data>
<variable
name="viewModel"
type="com.example.app.MyViewModel" />
</data>
Типи прив’язки
1. Прив’язка до властивостей
Використовуйте синтаксис @{} для прив’язки до властивостей об’єкта.
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewModel.userName}" />
У цьому прикладі userName — це властивість у класі MyViewModel.
2. Прив’язка подій
Для подій (наприклад, натискань кнопок) використовується синтаксис @{} із лямбда-виразами.
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click Me"
android:onClick="@{() -> viewModel.onButtonClick()}" />
3. Прив’язка зі значеннями за замовчуванням
Ви можете вказати значення за замовчуванням, якщо значення прив’язки порожнє.
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewModel.age != null ? viewModel.age : `Немає даних`}" />
4. Прив’язка до методів
Можна викликати методи класу ViewModel напряму.
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@{viewModel.getProfileImageUrl()}" />
Умовна прив’язка
Можна використовувати умовні вирази для динамічної зміни атрибутів.
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{viewModel.isVisible ? View.VISIBLE : View.GONE}" />
Прив’язка з форматуванням
Використовуйте String.format для форматування тексту.
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text='@{String.format("Привіт, %s!", viewModel.userName)}' />
Двостороння прив’язка
Двостороння прив’язка дозволяє автоматично оновлювати дані у ViewModel при зміні UI. Для цього використовується атрибут @=.
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@={viewModel.userInput}" />
- Якщо користувач вводить текст у
EditText, значенняuserInputу ViewModel автоматично оновлюється. - Зміни в
userInputтакож автоматично відображаються вEditText.
Робота з LiveData
LiveData — це об'єкт, який використовується для спостереження за даними, які змінюються з часом. У Data Binding LiveData підтримується автоматично.
Прив’язка LiveData в XML
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewModel.liveUserName}" />
ViewModel з LiveData
public class MyViewModel extends ViewModel {
public MutableLiveData<String> liveUserName = new MutableLiveData<>();
public void updateName(String name) {
liveUserName.setValue(name);
}
}
У цьому прикладі:
- Значення
liveUserNameавтоматично відображається уTextView. - Зміни у
liveUserNameвикликають оновлення UI.
Додаткові приклади з LiveData
Прив’язка списків
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:entries="@{viewModel.liveItems}" />
У ViewModel:
public class MyViewModel extends ViewModel {
public MutableLiveData<List<String>> liveItems = new MutableLiveData<>();
public void addItem(String item) {
List<String> currentItems = liveItems.getValue();
if (currentItems == null) {
currentItems = new ArrayList<>();
}
currentItems.add(item);
liveItems.setValue(currentItems);
}
}
Висновок
Прив’язка даних у XML за допомогою Data Binding Library — це потужний інструмент для створення сучасних Android-додатків. Використовуючи Observable об’єкти, LiveData і двосторонню прив’язку, можна значно спростити код та покращити його підтримку, особливо у великих проектах.
- MVP — Model-View-Presenter
- MVP — реалізація в Android
- Приклад
- Крок 1: Модель (Model)
- Крок 2: Presenter
- Крок 3: View
- Крок 4: Адаптер для відображення списку продуктів
- Крок 5: Ретрофіт клієнт для мережевих запитів
- Крок 6: XML для Activity
- MVVM
- MVVM у розробці Android: Як використати шаблон із Java та Data Binding
- Вступ
- Що таке MVVM?
- Чому MVVM краще?
- Data Binding: Що це?
- Реалізація MVVM із Data Binding
- Що таке LiveData?
- Висновок
- Що таке ObservableArrayList?
- Як використовувати ObservableArrayList?
- Інтеграція з Data Binding
- Особливості ObservableArrayList
- Обмеження ObservableArrayList
- Прив’язка даних (Data Binding) в XML
- Основний синтаксис прив’язки
- Типи прив’язки
- Умовна прив’язка
- Прив’язка з форматуванням
- Двостороння прив’язка
- Робота з LiveData
- Додаткові приклади з LiveData
- Висновок