MVVM e DataBinding¶
Introduzione¶
Il patten MVVM si può considerare come un evoluzione dell’ MVC in quanto il concetto di Model e di View è pressochè identico, la differenza tra i due pattern risiede tra Controller e ViewModel.
Model¶
Il Model rappresenta la parte che contiene i dati, i vari possibili stati del dato e della logica relativa a quel dato.
View¶
La View fondamentalmente è la UI ed è collegata al ViewModel con il DataBinding, è possibile collegare a molte View un singolo ViewModel.
ViewModel¶
Il ViewModel è la parte che si occupa di preparare il dato per essere mostrato nella View, in pratica prepara tutti gli observable necessari ad un corretto funzionamento della View e mette a disposizione degli eventi che poi potranno essere riusati dalla View. Ovviamente un ViewModel può essere riutilizzato in più View.
DataBinding¶
Il DataBinding è la cosa che rende unico e particolare questo pattern, in pratica consente di collegare la View con il ViewModel attraverso dei tag e degli attributi presenti nei vari file di layout. Grazie a queto meccanismo è possibile esporre alla View degli Observable, gli Observable sono un tipo di dato che quando subiscono un cambiamento notificano alla view che qualcosa è successo, la view a quel punto sa che deve aggiornarsi con il nuovo valore presente nell observable.
Come si usa il DataBinding¶
Per prima cosa va abilitato il DataBinding nel gradle
Configurazione¶
android {
dataBinding {
enabled true
}
}
Il secondo passo fondamentale è che la root di ogni layout di cui si vuol fare DataBinding sia <layout>
<layout 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">
<data>
</data>
</layout>
il tag <data> serve a contenere le variabili che verranno usata nel layout, vediamo come funziona con le variabili statiche:
<data>
<variable name="nome" type="String"/>
<variable name="cognome" type="String"/>
<variable name="user" type="it.monk.User"/>
</data>
<TextView android:text="@{user.stato}" ... />
<TextView android:text="@{nome}" ... />
<TextView android:text="@{cognome}" ... />
facendo così qualsiasi cosa ci sarà nella variabile nome si vedrà all’interno della prima TextView, mentre il cognome comparirà nella seconda ecc. Per valorizzare le variabili nell’ onCreate dell’activity è necessario richiamare i vari set:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
User user = new User();
user.setStato("Stato");
binding.setUser(user);
binding.setNome("Nome");
binding.setCognome("Cognome");
}
Così facendo però il DataBinding è poco utile e pratico, ed è qui che si inizia ad usare in aggiunta al ViewModel, come prima cosa modifichiamo il layout per far si che venga usato il ViewModel invece della variabili statiche
<data>
<variable name="viewModel" type="it.monk.viewmodels.TextViewModel"/>
</data>
<TextView android:text="@{viewModel.user.stato}" ... />
<TextView android:text="@{viewModel.nome}" ... />
<TextView android:text="@{viewModel.cognome}" ... />
Come seconda cosa dobbiamo cambiare il codice per poter usare il ViewModel invece che le singole variabili:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.viewmodel = new TextViewModel("Nome", "Cognome", "Stato");
}
da questo momento è possibile collegare i vari eventi a dei metodi presenti nel ViewModel, ad esempio se vogliamo prendere il tap su un bottone ci basterà inserire questo pezzo di codice nell’xml del pulsante
android:onClick="@{() -> viewmodel.onClickPressed()}"
un’altra cosa molto utile è la possibilità di creare dei parametri custom per le View, questo ci permette di poter fare binding di una url all’interno di un’ImageView e gestire tutta la logica di download e visualizzazione da codice
<ImageView app:imageUrl="@{viewModel.imageUrl}" />
nel ViewModel invece avremmo il seguente metodo:
@BindingAdapter({"imageUrl"})
public static void loadImage(ImageView view, String url) {
//codice per download immagine
}
inoltre è anche possibile passare più parametri alla funzione, per esempio si potrebbe aggiungere un immagine di placeholder modificando il codice nel seguente modo:
<ImageView app:imageUrl="@{viewModel.imageUrl}" app:error="@{@drawable/placeholder}"/>
@BindingAdapter({"imageUrl", "error"})
public static void loadImage(ImageView view, String url, Drawable error) {
//codice per download immagine
}
è inoltre possibile fare molte cose con il databinding come ad esempio dei controlli direttamente nell’ xml tipo:
<data>
<import type="android.view.View"/>
<variable name="viewModel" type="it.monk.viewmodels.TextViewModel"/>
</data>
<TextView android:visibility="@{viewModel.user.isActive ? View.Visible : View.Gone}"/>
per tutti gli altri comandi e le altre magie vi rimando alla documentazione di google ;)