Creating a simple todo app in Android Part II: LiveData & ViewModel
In the first part, we saw how to create the data model of our app, this time, we’re going to use LiveData & ViewModel to display our todos.
What’s a ViewModel ?
This is the definition you can find here:
The
ViewModel
class is designed to store and manage UI-related data in a lifecycle conscious way. TheViewModel
class allows data to survive configuration changes such as screen rotations.
So basically, ViewModel is here to save you lot of problems when dealing with the Android application lifecycle.
What’s a LiveData ?
This is what you can find on the Android Developer website:
LiveData
is an observable data holder class. Unlike a regular observable, LiveData is lifecycle-aware, meaning it respects the lifecycle of other app components, such as activities, fragments, or services. This awareness ensures LiveData only updates app component observers that are in an active lifecycle state.
When the LiveData is updated, observers are notified and we can, for example, update the view accordingly.
The ViewModel
This is the TodoViewModel class, it extends AndroidViewModel.
class TodoViewModel(application: Application) : AndroidViewModel(application){
private val todoRepository : TodoRepository
val todos : LiveData<List<Todo>> private var job = Job()
private val coroutineContext: CoroutineContext get() = job + Dispatchers.Main
private val scope = CoroutineScope(coroutineContext)
init {
val todoDao = TodoRoomDatabase.getDatabase(application).todoDao()
todoRepository = TodoRepository(todoDao)
todos = todoRepository.todos } fun insert(todo: Todo) = scope.launch(Dispatchers.IO) {
todoRepository.insert(todo)
}
fun toggleDone(todo : Todo, checked : Boolean) = scope.launch(Dispatchers.IO){
todo.done = checked
todoRepository.update(todo)
} override fun onCleared() {
super.onCleared()
job.cancel()
}
}
First, we create a LiveData
object “todos
”. It will contain the list of our todos.
Next, we have some objects for the use of coroutines. As in the first part, you can check here and here for more info.
The init
block, it contains the code we want to be executed when the ViewModel
is initialized. In our case we use it to get our todoDao and use it to initialize our repository. We also set the LiveData
.
Then, we have several methods calling the repository in order to insert or update the todos. We also override the onCleared()
method and call job.cancel()
to cancel still running jobs.
The Activity
I won’t paste the entire activity class here. But I’ll show you the relevant parts of it.
//in onCreate
todoViewModel = ViewModelProviders.of(this).get(TodoViewModel::class.java)
Here, we’re getting the TodoViewModel
from the ViewModelProvider
.
//also in onCreate
todoViewModel.todos.observe(this, Observer { todos ->
todos?.let{
adapter.setTodos(todos)
}
})
When we have the todoViewModel
we observe itstodos
object. In our case every time the object is modified, we update the adapter with the updated todos.
//onCreate again
fabAdd.setOnClickListener {
if(!TextUtils.isEmpty(editTodo.text)){
val todo = Todo(0, editTodo.text.toString(),"",false)
todoViewModel.insert(todo)
}
}
Lastly, we add a listener to a FloatingActionButton
and we call the insert()
method from todoViewModel
. The new todo will be inserted in the database using Room
and the liveData
observers will be notified with a list of todos containing the newly created todo.
That’s it for the second part of the app. I didn’t paste all the code (especially the Activity
or Layout
) I’ll share the entire app on Github after the publication of the last part.
In the third and last part, we’ll create the bubble notification allowing you to access all of your todos from everywhere on your phone.