Creating a ToDoList Android Application with Android Architecture Components - PART 3
Repository
https://github.com/googlesamples/android-architecture-components/
What Will I Learn?
- How to Implement LiveData of the Android Architecture Component
- How to Implement the Update Task Functionality using the Update Query of Room Database
Requirements
- IDE for developing android applications(Android Studio or IntelliJ)
- An Android Emulator or device for testing
- Java Programming knowledge
- Must have read the Part 1 & 2 of this series
- Previous experience working with Room Database.
Other Resource Materials
- Observer Design Pattern in Java
- Lifecycle Aware Data Loading
- Android Architecture Components: LiveData
Difficulty
- Intermediate
Tutorial Duration 30- 35 Minutes
TUTORIAL CONTENT
In this Tutorial, we are going to continue learning the Android Architecture Components, specifically the LiveData component. But before we proceed to today's tutorial, below is a brief highlight of the former parts of this tutorial series.
PART 1 : In the part one of this tutorial series, we implemented the Room Database component of the Android Architecture Components in creating a simple todo application. Here we carried the following operations: Insert new Task Entry and load all task from database
PART 2 : In the second part of this series, we learned the singleton pattern and implemented it with the Executor. The Executor here, enabled us to make database queries on a separate thread other than the Main Thread.
So for this PART 3 of the the series, we will implement the following step by step:
- We will first implement the update functionality to our todo list application
- Thereafter we will re-factor our existing codes to implement the LiveData
STEP 1 : Implement the Update Task Functionality
We will be using the Editor Activity to do both saving a new task and update a task. Accessing the Editor Activity to insert a new task is achieved by clicking on the Floating Action Button (FAB) . We desire also to update a task in the EditorActivity. To achieve this, we do the following sub-steps :
- Add an Click Listener to the RecyclerView Item in the TodoListAdapter
- Create an intent with task id as its extra
- Start the Editor Activity
- Get the intent from the Editor Activity
- Change button text to Update
- Load task to UI
- Do the database update operation
Code Implementation of 1-3
add onClick Listener to item view
Task taskEntry = mTaskEntries.get(position);
final int id = taskEntry.getId(); // get item id
// set Onclick Listener
holder.view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(mContext.getApplicationContext(),EditorActivity.class);
intent.putExtra("id",id);
mContext.getApplicationContext().startActivity(intent);
}
});
Code Explanation
- The code block above is implemented in the onBindViewHolder method of our adapter class. This allows reference to each o f the tasks in the list. With this knowledge, we can get the id of a task using the getId method of taskEntry object.
- Now we set an onClick Listener to our item view declared as view in the viewholer class. In this Listener, we create a new intent where we pass the id as an extra and then start the editor activity.
Code Implementation of 4-6
change button text thereafter load task to UI
Intent intent = getIntent();
if (intent != null && intent.hasExtra("id")) {
buttonAdd.setText("Update");
AppExecutor.getInstance().diskIO().execute(new Runnable() {
@Override
public void run() {
final Task task = mdb.taskDao().getTaskById(intent.getIntExtra("id", 0));
runOnUiThread(new Runnable() {
@Override
public void run() {
etTask.setText(task.getDescription());
setPriority(priority);
} });
} });
}
Code Explanation
- In the code above, we get the intent and then check if the intent is not null and if it has an extra of name id
- If the condition is true, we change the text of the button in the Editor Activity to Update.
- To Load our UI with the details of the task that was clicked from the list, we use our AppExecutor to query the database in a separate thread
- After getting the task based on the id, we update our UI on the runOnUiThread method
Code Implementation of 7
Do database update operation
buttonAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String text = etTask.getText().toString().trim();
int priority = getPriorityFromViews();
Date date = new Date();
final Task task = new Task(text, priority, date);
AppExecutor.getInstance().diskIO().execute(new Runnable() {
@Override
public void run() {
if (intent != null && intent.hasExtra("id")) {
task.setId(intent.getIntExtra("id", 0));
mdb.taskDao().updateTask(task);
} else {
mdb.taskDao().insertTask(task);
}
finish();
}
});
}
});
Code Explanation
- Since our button add now has to perform two operations which are inserting a new task and updating a task, we have to decide when to do either of the two operations using the extra data gotten from the intent as a factor.
- We get the text description, the priority and the date, which we then pass into our Task object created
- All database queries must be done on a separate thread so we continue using AppExecutor class to implement them
- We now check if the intent is not null and if the intent contains id as an extra using an IF Statement
- If the above is true then we call setId method on the task object, passing the id we received from the intent. This is done to enable the Room database know which entity to update.
- If the conditions are false it means the EditorActivity was started by the FAB. Thus implement the else block that contains the insertTask method.
STEP 2 : Add LiveData Dependencies to Gradle
implementation "android.arch.persistence.room:runtime:1.0.0"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0"
STEP 3 : Implement the LiveData Component
In this step we are going add livedata to our app.
What is LiveData?
According to the documentation, LiveData is an observable data holder class. The LiveData acts as a middle man between our UI and the database. It is aware of data changes in the database and then notify the UI.
This kind of operation is achieveable with the help of a software engineering design pattern called The Observer Pattern. Basically classes called observers subscribe to what is called the subject. In our case, our subject is the LiveData. The Subject will in turn notify the subcribers of any data change in the database.
Why is LiveData?
Previously we implemented our todo list application without the live data and we had to query the database even when there is no change in the database. This is no where near efficient considering the fact that database operations could be very expensive to make. As a proof to what am saying, below is a video where the application is implemented without livedata. You will realize that every time onResume method of the main activity is triggered, the database is queried.
To avoid this pitfall lets do the following sub-steps
- First we re-factor our TaskDataObjectAccess interface to allow Livedata. We make loadAllTask and getTaskById method return a live data object
- Goto MainActivity class and Remove every implementation of the getTask method
- Refactor the codes in the getTask method to use LiveData
- Add getTask method to onCreate
- Implement the LiveData as well in the Editor Activity
Code Implementation of 1
@Dao
public interface TaskDataAccessObject {
@Query("SELECT * FROM task ORDER BY priority")
LiveData<List<Task>> loadAllTask(); // returns a list of task object
@Insert
void insertTask(Task task);
@Update(onConflict = OnConflictStrategy.REPLACE)
void updateTask(Task task);
@Delete
void deleteTask(Task task);
@Query("SELECT * FROM task WHERE id = :id")
LiveData<Task> getTaskById(int id);
}
Code Explanation
In this DOA interface, we wrap the return object of the loadAllTask() and getTaskById() with a LiveDataObject. Remember we previously said the LiveData serves as a middle man between the database and the UI that listens for data changes in order to update the UI. This implementation here should give you a clearer understanding of how LiveData works.
Code Implementation of 3
private void getTasks() {
final LiveData<List<Task>> tasks = appDataBase.taskDao().loadAllTask();
tasks.observe(MainActivity.this, new Observer<List<Task>>() {
@Override
public void onChanged(@Nullable List<Task> tasks) {
toDoListAdapter.setTasks(tasks);
}
});
}
Code Explanation
- In our previous tutorial, we implemeted the getTasks method with our AppExecutor class which does not have live data implementation.
- The AppExecutor Implementation is removed because the LiveData itself runs on a separate thread off the main thread
- We make a database query to loadAllTasks using our taskDoa interface.
- This query returns a LiveData List of task which is assigned to a list of task entries wrapped with LiveData
- Now we call the observe method on the tasks variable, which require two parammeters; a LifeCycle Owner and an Observer
- In the onChange method, we update out adapter and then refresh the UI
The LifeCycle owner is basically anything that has a LifeCycle like our MainActivity
The Observer is an interface that implements the onchange method which has access to the views. By this, we can refresh our UI without having to call the runOnUiThread method.
Code Implementation of 4
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_task);
...
getTasks();
}
Code Explanation
With the getTask in the onCreate, we only have to query the database once to get all task thereafter LiveData handles the Job of notifying the UI of data changes in the database (inserted data and deleted data). No more Unnecessary querying of the DataBase, Thanks to live data!!!
Code Implementation of 5
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_task);
...
final LiveData<Task> task = mdb.taskDao().getTaskById(intent.getIntExtra("id", 0));
Log.i("DetailActivity ", " Reading DataBAse");
task.observe(EditorActivity.this, new Observer<Task>() {
@Override
public void onChanged(@Nullable Task task) {
etTask.setText(task.getDescription());
setPriority(task.getPriority());
}
});
}
Code Explanation
- Just as we did in the MainActivity we will also refactor the codes implementing the database operations in the Editor Activity to use LiveData
- Here we get just a single task by id from the database
- We call the observe method of the task variable then pass the EditorActivity.this and new Observable as its parameters
- In the onChange method implemented by the Observable interface, we update our UI using the Task object provided by the method.
Step 3 : Test the Application
After refactoring our codes to use LiveData and also implementing the update feature of the todo application, we can now proceeding to testing the application. Watch carefully and you will realize that the database is not queried unnecessarily .Below is the application demo.
Curriculum
- Creating a ToDoList Android Application with Android Architecture Components - PART 1
- Creating a ToDoList Android Application with Android Architecture Components - PART 2
Proof of Work Done
The complete source code can be found on github
https://github.com/enyason/TodoApp_Android_Architecture_Components

Thanks for the contribution.
Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.
To view those questions and the relevant answers related to your post, click here.
Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]
thanks @deathwing for moderating my contribution and also for your advice. I'll improve on my subsequent contributions as regards what you have said.
Hey @ideba
Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!
Contributing on Utopian
Learn how to contribute on our website or by watching this tutorial on Youtube.
Want to chat? Join us on Discord https://discord.gg/h52nFrV.
Vote for Utopian Witness!
Congratulations @ideba! You have completed some achievement on Steemit and have been rewarded with new badge(s) :
Click on the badge to view your Board of Honor.
If you no longer want to receive notifications, reply to this comment with the word
STOP