Building a simple notes app with new Architecture Components(Room+ViewModel+LiveData+Dagger) Part 2

Its a two part article if you haven’t read the first part go here where I explain each component in brief and also lay down some of the benefits of using the new components.

Get started by adding these dependency to the build.gradle file :

//LIFE CYCLE EXTENSIONS
implementation "android.arch.lifecycle:extensions:1.0.0-beta2"

//LIFE CYCLE JAVA 8
implementation "android.arch.lifecycle:common-java8:1.0.0-beta2"

//LIVE DATA BACKGROUND TEST
testImplementation "android.arch.core:core-testing:1.0.0-beta2"

//LIVE DATA WITH REACTIVE STREAMS
implementation "android.arch.lifecycle:reactivestreams:1.0.0-beta2"

//ROOM
implementation "android.arch.persistence.room:runtime:1.0.0-beta2"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0-beta2"

//ROOM TEST MIGRATION
testImplementation "android.arch.persistence.room:testing:1.0.0-beta2"
Now lets dive straight into the code.

The Database

First the entity class.

@Entity(indices = {@Index(value = "id")})
public class NoteEntity {
@PrimaryKey(autoGenerate = true)
private int id;
private String note;
@TypeConverters(DateConverter.class)
private Date date;

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getNote() {
return note;
}

public void setNote(String note) {
this.note = note;
}

public Date getDate() {
return date;
}

public void setDate(Date date) {
this.date = date;
}
}

The class annotated with @Entity annotation is treated as a database component where each field represents a column in database unless annotated with @Ignore and the name of the fields maps to the name of column in database unless the field is annotated with @ColumnInfo(name = "name_you_want") .

You should have a constructor with all the fields initialized or you can have getter and setter for all the fields as i have done here for room to work.

You might have noticed the type converter, what it does is to allow storage of types which are not identifiable by sqlite by converting them to type understood by sqlite it can be achieved by writing this converter class.

class DateConverter {

@Contract("null -> null; !null -> !null")
@TypeConverter
public static Date longToDate(Long date){
return date == null ? null : new Date(date);
}

@Contract("null -> null")
@TypeConverter
public static Long dateToLong(Date date){
return date == null ? null : date.getTime();
}

}

Next the Dao :

@Dao
public interface NoteDao {

@Query("SELECT * FROM NoteEntity")
LiveData<List<NoteEntity>> getNoteList();

@Query("SELECT * FROM NoteEntity WHERE id = :id")
LiveData<NoteEntity> getNote(int id);

@Insert(onConflict = OnConflictStrategy.REPLACE)
long[] insertNote(NoteEntity... entities);

@Delete
void deleteNote(NoteEntity... entities);

@Update(onConflict = OnConflictStrategy.REPLACE)
int updateNote(NoteEntity... entities);

@Query("SELECT COUNT(*) FROM NoteEntity")
int getCount();
}

The Dao is an interface with abstract methods that correspond to sqlite crud operations.

The few advantage of using dao is :

  1. Compile time sql statement verification.
  2. Easier conversion of sql queries to java object
  3. Operations like update, delete and insert are very easy as they don’t require any sql statements.

You can wrap the entity in LiveData object which make it an observable so that you can auto-magically observe changes on the data.

And finally the database

@Database(entities = {NoteEntity.class}, version = 1)
public abstract class NoteDatabase extends RoomDatabase {
public abstract NoteDao getNoteDao();
}

The final piece of the puzzle is the database class that extends RoomDatabase and is annotated with @Database(“it takes all the entities and database version”).

It is an abstract class or it can be an interface usually it is the place where you will have a method to create a singleton instance of database but since i am using dagger i decided to not create it here.

It has public method to access the dao so that you can perform operations on database, it is the entry point for the database.


I have created an helper class called DbUtil which has a instance of NoteDatabase and methods that performs the database operations asynchronously.

@ApplicationScope
public class DbUtil {

private final NoteDatabase mNoteDatabase;

@Inject
public DbUtil(NoteDatabase noteDatabase) {
this.mNoteDatabase = noteDatabase;
}
....
....
....
}

The ViewModel

ViewModel is created by extending either the ViewModel or AndroidViewModel(provide application) class here you expose the method that the activity/fragment can perform on the database via the viewmodel the views never talk to data directly but rather through the viewmodel.

public class ListViewModel extends AndroidViewModel {

private LiveData<List<NoteEntity>> mNoteList;
private final DbUtil mDbUtil;

ListViewModel(Application application) {
super(application);
mDbUtil = ((MyApplication) application).getDbUtil();
mNoteList = mDbUtil.getNoteList();
}

public LiveData<List<NoteEntity>> getNoteList() {
return mNoteList;
}

public void insert(NoteEntity... entities) {
mDbUtil.insert(entities);
}

public void delete(NoteEntity... entities) {
mDbUtil.delete(entities);
}

public void update(NoteEntity... entities) {
mDbUtil.upadate(entities);
}

public LiveData<NoteEntity> getNote(int id) {
return mDbUtil.getNote(id);
}
}

And finally connecting everything together by creating an instance of viewmodel within the view and then start observing the livedata for data changes.

...
mListViewModel = ViewModelProviders.of(this).get(ListViewModel.class);
...
...
...
mListViewModel.getNoteList().observe(this, noteEntityList -> {
mNoteEntityList = noteEntityList;
mListAdapter.swapList(mNoteEntityList);
mListAdapter.notifyDataSetChanged();
});
...
..
That’s it this is all you require to build your own first app using room + livedata + viewmodel.

You can find the source code for the app here

Like what you read? Give Nikhil Soni a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.