Skip to main content

Architecture Components: Paging Library With Room Database

Paging Library is one of the main parts of the complete set of the Architecture Components Library for MVC app development.  Architecture Components Library includes ViewModel, LiveData, RoomDatabase and Paging Library. In this article, we will create a TODO app that loads the paged data from Database.

Architecture Components Paging Library



Paging Library includes the DataSource, PagedList, PageListBuilder and PagedListAdapter. We will go through each component one by one. But first of all, What is paging Library?

Paging Library is a set of the component which helps app developer to load the data from backed gradually as it required. For example, an app loads thousands of line from the database or network but that all data can’t be display at once to the user. Just a small portion of all those data will be displayed to the user at a time. But if the app goes to load all these data at once then it creates the huge burden on the network and slows down the app as well. If we load the data on load more button click than user have to wait till data is not loaded from the database or network.

Currently, a developer has to use lots of terminologies to efficiently handle all these performance issues and bad user experience. But using the Google Architecture Components Paging Library we can do this work very efficiently without quickly.

What is DataSource in Paging Library?



DataSource is the main component which loads the chunk of pages into the PagedList.  Data loaded by the PagedList can’t be updated but it can grow as required. In case loaded data need to be updated than a new PagedList and DataSource pair is required. But you don’t have to worry about to provide each and every time new set of PagedList and DataSource pair, as its all are auto-managed by architecture components Library.

@Query("SELECT * FROM Todo ORDER BY todo COLLATE NOCASE ASC")
public abstract DataSource.Factory<Integer, Todo> allTodoByName();


PagedList



PagedList is responsible for query the DataSource and loads the data from DataSource. When we create the PagedList it immediately loads the data from DataSource. Later on when loadAruond() method is called then its load the data from DataSource.

The behaviour of the data loading is controlled by PagedList.Config, using this we can set the page size and prefetch distance.

PagedList.Config pagedListConfig=(new PagedList.Config.Builder()).setEnablePlaceholders(true)
.setPrefetchDistance(10)
.setPageSize(20).build();


PagedListAdapter



PagedListAdapter is a RecyclerView.Adapter which is capable of showing the paged data into RecyclerView. It accepts LiveData Paged List as input. For setting the data to this PagedListAdapter we can also user setList(PagedList) method.

public class TodoAdapter extends PagedListAdapter<Todo,TodoViewHolder> {


LivePagedListBuilder



This LivePagedLIstBuilder is used to create the PagedList. We have to provide a config to the constructor of the LivedPagedListBuilder, using this config we can change or customize the behaviour data loading from DataSource.

LiveData<PagedList<Todo>>  todoList = new LivePagedListBuilder<>(
todoDao.allTodoByName(), pagedListConfig).build();
}


In above sample, we have provided the list of all TODO item by DAO and PagedList Config.

Description  of the TODO app using Paging Library



We will use the almost all components of the Architecture Components in this TODO app.In this demo app, we will add the todo item and save into the SQLite database and use the sweep to delete option to delete the item. Our ViewModel, LiveData, RoomDatabase and Paging will work together and update the UI automatically in real time.

Paging Library Architecture

 

Create Layout for Todo App



We required two layouts for this demo app. First is the main layout file of the App and second is the item view to show the Todo Item into the RecyclerView.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.nplix.pagingdemo.MainActivity">

<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<EditText
android:id="@+id/inputText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="@string/add_todo"
android:imeOptions="actionDone"
android:inputType="text"
android:maxLines="1" />

<Button
android:id="@+id/addButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:text="@string/add" />
</LinearLayout>

<android.support.v7.widget.RecyclerView
android:id="@+id/todoList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:visibility="visible"
app:layoutManager="LinearLayoutManager"
app:layout_constraintTop_toBottomOf="@+id/linearLayout" />

</android.support.constraint.ConstraintLayout>


todo_item.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:cardUseCompatPadding="true">
<TextView android:id="@+id/name"
style="@style/TextAppearance.AppCompat.Medium"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.v7.widget.CardView>


Required  Library for Todo App



Below Library is required to create this ToDo app demo. So, add these libraries to your project level build.gradle file.

compile 'com.android.support:cardview-v7:26.1.0'
compile 'com.android.support:recyclerview-v7:26.1.0'
// ViewModel and LiveData
implementation "android.arch.lifecycle:extensions:1.1.0"
annotationProcessor "android.arch.lifecycle:compiler:1.1.0"

// Room
implementation "android.arch.persistence.room:runtime:1.0.0"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0"
// Paging
implementation "android.arch.paging:runtime:1.0.0-alpha5"


Create RoomDatabase Classes for Paging Library Demo



For this demo app, we only required two fields,  Id and name of the todo. Below is the code of our Entity class.

Todo.java

@Entity
public class Todo {
@PrimaryKey(autoGenerate = true)
int id;

public String getTodo() {
return todo;
}

public void setTodo(String todo) {
this.todo = todo;
}

private String todo;
}


Data Access Object for Paging Library



This interface is used for the accessing the data stored in the SQLite database.

TodoDao.java

@Dao
public interface TodoDao {
@Query("SELECT * FROM Todo ORDER BY todo COLLATE NOCASE ASC")
public abstract DataSource.Factory<Integer, Todo> allTodoByName();

@Insert
public void insert(List<Todo> todos);

@Insert
public void insert(Todo todo);

@Delete
public void delete(Todo todo);
}


Next, we need our SQLite database class.

TodoDB.java

@Database(entities = Todo.class,version = 1)
public abstract class TodoDB extends RoomDatabase {
public abstract TodoDao TodoDao();
}


You may have to add the schema details in your compilation script and database migration functionality as well. If not familiar with room database and don't know how to do then check the RoomDatabase Tutorial.

Create ViewHolder and ViewModel



TodoViewHolder.java

class TodoViewHolder extends RecyclerView.ViewHolder{

private TextView todoName;
public Todo todo;

public TodoViewHolder(View itemView) {
super(itemView);
todoName= itemView.findViewById(R.id.name);
}

void bindTo(Todo todo){
this.todo=todo;
todoName.setText(todo.getTodo());
}
}


TodoViewModel.java

public class TodoViewModel extends ViewModel {

LiveData<PagedList<Todo>> todoList;
public TodoViewModel() {
}

public void init(TodoDao todoDao){
PagedList.Config pagedListConfig=(new PagedList.Config.Builder()).setEnablePlaceholders(true)
.setPrefetchDistance(10)
.setPageSize(20).build();

todoList = new LivePagedListBuilder<>(
todoDao.allTodoByName(), pagedListConfig).build();
}
}


PagedListAdapter to Load the PagedList.



This is the main component which is used to show the Livedata<PagedList> data into RecyclearView and trigger to load the data from DataSource using PagedList.

TodoAdapter.java

public class TodoAdapter extends PagedListAdapter<Todo,TodoViewHolder> {


protected TodoAdapter(@NonNull DiffCallback diffCallback) {
super(diffCallback);
}


@Override
public TodoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

return new TodoViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.todo_item, parent, false));
}

@Override
public void onBindViewHolder(TodoViewHolder holder, int position) {
holder.bindTo(getItem(position));
}

}


This  PagedListAdapter uses the constructor and takes the DiffUtil callbacks as input. This DiffUtil help RecyclerView to load the latest received PagedList data. Below is the code of the DiffUtil.

private DiffCallback diffCallback = new  DiffCallback<Todo>() {

@Override
public boolean areItemsTheSame(@NonNull Todo oldItem, @NonNull Todo newItem) {

return oldItem.id == newItem.id;
}

@Override
public boolean areContentsTheSame(@NonNull Todo oldItem, @NonNull Todo newItem) {
return oldItem == newItem;
}
};


All the above class and code is just helper class for our main class.  Now, we will create the MainActivity.java in which we will bind all these class together.

Create Instance of RoomDatabase



In our main activity class, we will create the instance of the RoomDatabase using Room Database Builder. This RoomDatabase Builder class takes three parameters as shown below.


  • Context is the first parameter

  • Class name of the RoomDatabase in our case its TodoDB.class

  • Third and last is the name of the Database, In our case its MyTodoDB



todoDB= Room.databaseBuilder(getApplicationContext(),TodoDB.class,"MyTodoDB")
.addCallback(new RoomDatabase.Callback() {
@Override
public void onCreate(@NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
}
}).build();


Get the DAO using database instance.

todoDao=todoDB.TodoDao();


Create the instance of the TodoViewModel using code below.

viewModel = ViewModelProviders.of(this).get(TodoViewModel.class);
viewModel.init(todoDao);


.To create the LivePagedList using the builder. We have to call viewModel.init(todoDao) method from our main activity.

Create the instance of the PagedListAdapter class using the code below.

TodoAdapter todoAdapter=new TodoAdapter(diffCallback);


Put the observer on the ViewModel todoList to update the UI with latest PagedList.

viewModel.todoList.observe(this, todoAdapter::setList);


Create Method to Sweep to Delete



This method is used for deleting the item from the Database using Dao interface.

public void initSwipeToDelete(){
new ItemTouchHelper(new ItemTouchHelper.Callback() {

@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
return makeMovementFlags(0,ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT);
}

@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}

@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
remove(((TodoViewHolder) viewHolder).todo);
}
}).attachToRecyclerView(todoList );
}


Create the addTodo method as given below. This method does the following work.


  • Get the ToDo name from editText

  • Insert the todo item into the database using insert() method

  • Then, at last, clear the edit box for next user input



private void addTodo() {
String newTodo = inputText.getText().toString().trim();
if (newTodo!=null) {
insert(newTodo);
inputText.setText("");
}
}


RoomDatabase does not allow you to run DB query on the main thread. So below given insert and remove method is the respective method to delete and remove the ToDo item form SQLite database using a thread executor.

public void  insert(CharSequence text){
final Todo todo=new Todo();
todo.setTodo(text.toString());
IO_EXECUTOR.execute(()->{
todoDB.TodoDao().insert(todo);
});
}

public void remove(Todo todo){
IO_EXECUTOR.execute(()->{
todoDB.TodoDao().delete(todo);
});

}


Now, create a method to add the listener on our add Todo button to call the addTodo() method.

private void initAddButtonListener(){
addBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
addTodo();
}
});

inputText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if(actionId== EditorInfo.IME_ACTION_DONE){
addTodo();
}
return true;
}
});

inputText.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if(event.getAction()== KeyEvent.ACTION_DOWN && keyCode== KeyEvent.KEYCODE_ENTER){
addTodo();
}
return true;
}
});


}


Conclusion



This Article is very basic or we can say a model for implementing the ViewModel, LiveData, RoomDatabase and Paging Library Architectural components together. If you go step by step then its very easy to implement.

You can download the source code of this Tutorial form NPLIX Repository on GitHub.

Comments

  1. […] Google Architecture Component for using the pagination of the resource. It is helpful to create the pagination from Database using Room as well as with network resource. Here in this article, we will explore the how to use it for […]

    ReplyDelete

Post a Comment

Popular posts from this blog

Flutter Theme Creation, Programmatic Way

Flutter and Dart is an excellent combination for creating the mobile app with material design with nice GUI. Its lots of widget which help the developer for creating the app UI very fast with respect to the other language. You may face some problem in starting due to comm, curly brace and semicolon but after some time you will find the way how to work with these all stuff and it becomes very easy for you. But in this article, we are not going to discuss all these. In this article, we will handle a very interesting topic on how to create a custom theme or multiple themes and let's user decide which theme to use.



Create a flutter project



So let's create a flutter project by selecting the appropriate option from the File menu in android studio or Visual Code. If you are new to Flutter and Dart you can check out our recent post to get started Creating Cross-platform app using flutter.



Once your project is created you will get the default counter app and you try running the app in the…

Flutter How to Start Android Activity from Flutter View

Flutter and Dart is an excellent combination for creating the UI, but for accessing the platform-specific service we need to open platform-specific activity. So lets in this article we will explore how to start an android activity and access the service from Flutter View.

Create a Project for this Android Activity Flutter View Demo Create a Project From File menu select the New Flutter Project Enter the project name Select the AndroidX support and click on next After the above, we step click on Finish We will have the following project structure created. Create the Second Activity in Android
Just go to the android folder and open it in separate windows. We will have the following project structure.









Create the Activity Just right click on the Kotlin folder and create a blank activity from the menu. If you create the activity then you may be required to upgrade the Gradle and do some import. So Just click on update and wait for the project sync completed.
Update the project build config …

Flutter State Management With Provider and ChangeNotifier

Flutter state management with provider library and why it's so important? There are lots of topics in flutter which are very important but out of those state management of your flutter application is the most important and little bit complicated as well. So in this article, I will try to explain how to use the provider package for managing the state of flutter and dart application and how to access the data down the hierarchy of the widget tree without recreating the whole UI.



Basic knowledge of the state management and data flow in the Flutter



Before starting the coding I would like to explain some basics about the Flutter application so that you can understand, why it's important to manage the state of your application in the correct way.



In Flutter, everything is a widget and whenever the state of your application changes the UI is recreated the UI with the new data. Let's list out the topic or problem that we are going to explore about state management.



Challenge of St…