Description
Well-designed ViewModels should completely decouple Views from Model classes. In such way, by strictly adhering to the MVVM pattern, Models and Views can evolve independently and be tested with ease. Additionally, by applying the inversion of control principle and implementing ViewModels decoupled from the Android framework, it is possible to test ViewModels via unit tests. In contrast, if the binding between the MVVM components is too complex and intertwined, testing and debugging Android apps can become a cumbersome challenge.
Example
We created a simple MVVM example.
This is our current model:
@Entity(tableName = "note_table") | |
public class Note { | |
@PrimaryKey(autoGenerate = true) | |
private int id; | |
private String title; | |
private String description; | |
private int priority; | |
public int getId() { | |
return id; | |
} | |
public void setId(int id) { | |
this.id = id; | |
} | |
public Note(String title, String description, int priority) { | |
this.title = title; | |
this.description = description; | |
this.priority = priority; | |
} | |
public String getTitle() { | |
return title; | |
} | |
public String getDescription() { | |
return description; | |
} | |
public int getPriority() { | |
return priority; | |
} | |
} |
We evolve this model, by adding a new feature:
@Entity(tableName = "note_table") | |
@TypeConverters(DateConverter.class) | |
public class Note { | |
@PrimaryKey(autoGenerate = true) | |
private int id; | |
private String title; | |
private String description; | |
private int priority; | |
//Newly added | |
@ColumnInfo(name = "last_update") | |
private Date lastUpdate; | |
//Newly added | |
public Date getLastUpdate() { | |
return lastUpdate; | |
} | |
//Newly added | |
public void setLastUpdate(Date lUpdate) { | |
this.lastUpdate = lUpdate; | |
} | |
public int getId() { | |
return id; | |
} | |
public void setId(int id) { | |
this.id = id; | |
} | |
public Note(String title, String description, int priority) { | |
this.title = title; | |
this.description = description; | |
this.priority = priority; | |
//Newly added | |
lastUpdate = new Date(System.currentTimeMillis()); | |
} | |
public String getTitle() { | |
return title; | |
} | |
public String getDescription() { | |
return description; | |
} | |
public int getPriority() { | |
return priority; | |
} | |
} |
Since Room cannot convert Date value, we need to write our own converter.
public class DateConverter { | |
@TypeConverter | |
public static Date toDate(Long timestamp) { | |
return timestamp == null ? null : new Date(timestamp); | |
} | |
@TypeConverter | |
public static Long toTimestamp(Date date) { | |
return date == null ? null : date.getTime(); | |
} | |
} |
The @TypeConverters(DateConverter.class) has been added to the top of the Note model.
We change the version of our database from 1 to 2. And we need to write a migration.
We can now restart the app, and the database has been updated. Maybe this is a bad example, but when we create a new feature for our model. We can evolve our model and test it without creating a new view.
Check this page to view the complete repository.