Repository
https://github.com/googlesamples/android-architecture-components/
What Will I Learn?
- How to create a ToDo Listing Application
- Implement Database operations on a separate thread Using Executors.
- Implement Swipe to delete functionality in the RecyclerView
Requirements
- Java knowledge
- IDE for developing android applications(Android Studio or IntelliJ)
- An Android Emulator or device for testing
- Must have read the Part 1 of this series
Other Resource Materials
- Executor Framework
- https://developer.android.com/reference/java/util/concurrent/Executor
- The Singleton Pattern
- RecyclerView Swipe
Difficulty
- Intermediate
Tutorial Duration 20- 25 Minutes
TUTORIAL CONTENTS
In the Part 1 of this tutorial series, we started off by creating a database with the Room library where To_do task are added based on their priority. In this Part Two of this series, we are going to implement the Room database operations on a separate thread using Executors and also include the swipe to delete feature on our Recyclerview. Lets get started...
Step 1 : Disable database operation on the main thread
In the AppDataBase class, where the singleton class is initialized,remove the . allowMainThreadQueries() . Runing the app now should crash, telling you database operations can not be accessed on the main thread. Let's proceed to fixing this error.
remove the rectangled line of code
This is the error
Step 2 : Create a new Singleton Executor Class and name it AppExecutor.
What is an Executor?
According to the class documentation, an Executor is an object that executes a submitted runnable tasks. It is normally used instead of explicitly creating threads for each of a set of tasks.
Using a singleton class ensures that we have only one instance of our executor object which is just beautiful, when you consider memory resources on android. This makes us a good citizen of android....
Here is the code of the Executor
public class AppExecutor {
//this is for singleton instantiation
private static final Object LOCK = new Object();
private static AppExecutor sInstance;
private final Executor diskIO;
private AppExecutor(Executor diskIO) {
this.diskIO = diskIO;
}
public static AppExecutor getInstance(){
if (sInstance == null) {
synchronized (LOCK){
sInstance = new AppExecutor(Executors.newSingleThreadExecutor()); }
}
return sInstance;
}
public Executor diskIO() {
return diskIO;
}
}
Code Explanation
As you can see from the code block above, we create a singleton class so as to have a single instance of the class. This class has a private constructor which will be initialized in the getInstance method. The Constructor has one Executor parameter called diskIO. The disk IO is a single thread executor. Only when the diskIO object is null will the AppExecutor object get created with the new key word.
Step 3 : Implement the Executor in the EditorActivity
I the editor activity where we have the button to add a new task, we replace with the following block of code
buttonAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// get text from user
String text = etTask.getText().toString().trim();
int priority = getPriorityFromViews();
Date date = new Date();
//create new task object
final Task task = new Task(text,priority,date);
AppExecutor.getInstance().diskIO().execute(new Runnable() {
@Override
public void run() {
mdb.taskDao().insertTask(task);
finish();
}
});
}
});
Code Explanation
- The onclickListener is where we add a new Task to the database. Firstly we create a new task object passing the user data as its parameters that is the text, priority and date.
- Now we implement the AppExecutor class with a new Runnable object.
- In the run method of Runnable object, we include our database code
Step 4 : Implement the Executor in the MainActivity
After adding a task, we need to see the UI refresh immediately so we do some database operations in the onResume method with our Executor class.
Also we need to add swipe to delete functionality to our RecyclerView and refresh the UI. This will require we do a database operation within the Runnable object executed by our AppExecutor class.
Since we have to call the AppExecutor.getIstance twice, we will create a method were all the code will go, so as to prevent writing long codes in two places.
Create a method and call it getTask
private void getTasks() {
AppExecutor.getInstance().diskIO().execute(new Runnable() {
@Override
public void run() {
final List<Task> tasks = appDataBase.taskDao().loadAllTask();
runOnUiThread(new Runnable() {
@Override
public void run() {
toDoListAdapter.setTasks(tasks);
}
});
}
});
}
Code Explanation
What the above block does basically is to get the list of task from the database which is then set to the adapter to display on the UI. Here we use the runOnUiThread to get acess to the UI thread in order to refresh the RecylerView.
Implement the Swipe to delete feature in the MainActivity
We want to make our recyclerView respond to both left and right swipe whereby we could then write our database code to delete that specific item from the database.To allow swipe, we use the ItemTouchHelper class of the android framework
here is the code
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false; // We return false because we are not going to use it
}
// Called when a user swipes left or right on a ViewHolder
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
// implement swipe to delete
//get item position
final int position = viewHolder.getAdapterPosition();
// get list of Task
final List<Task> tasks = toDoListAdapter.getTasks();
AppExecutor.getInstance().diskIO().execute(new Runnable() {
@Override
public void run() {
appDataBase.taskDao().deleteTask(tasks.get(position));
}
});
getTasks();
}
}).attachToRecyclerView(recyclerView);
Code Explanation
- Basically we allow the swipe on both directions of the recyclerView with the constants ItemTouchHelper.LEFT and ItemTouchHelper.RIGHT
- We get the task position in the adapter using viewHolder.getAdapterPosition();
- We get the List of task from the database
- We call the deleteTask method of our TaskDataAccessObject interface.
- getTask method is called to refresh our UI.
Step 5 : Test the App
After refactoring our codes to implement our database operations from a separate thread using Executors, and also adding the swipe to delete feature to our recyclerView, we can now proceeding to testing the app. Below is the app demo.
Curriculum
Creating a ToDoList Android Application with Android Achitecture Components - PART 1
Proof of Work Done
The complete source code can be found on github
https://github.com/enyason/TodoApp_Android_Architecture_Components