In this tutorial, you’ll get started with Android paging library with Room Database, we will create simple emoji app that show emojis throw paging library and recyclerview
what is paging library ?
Android paging library is a component of android jetpack, Paging Library helps you load and display small chunks of data at a time. Loading partial data on demand reduces usage of network bandwidth and system resources.
Benefits of using Paging
- You will only load a small chunk from your large data set, it will consume less bandwidth.
- The app will use less resources resulting in a smooth app and nice user experience.
To configure your app to use paging library , add the
Room: Database for storing data .
ViewModel: Android architecture component for storing data.
Paging: The paging library.
RecyclerView: For building the List.
Emoji Compatibility: For showing the emoji.
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.materialuiux.androidpaginglibraryexample"
minSdkVersion 15
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
// Recycler View components
implementation 'androidx.recyclerview:recyclerview:1.0.0'
// Room components
implementation "android.arch.persistence.room:runtime:1.1.1"
annotationProcessor "android.arch.persistence.room:compiler:1.1.1"
//Architecture Components
implementation "android.arch.lifecycle:extensions:1.1.1"
annotationProcessor "android.arch.lifecycle:compiler:1.1.1"
//PagingtComponents
implementation 'androidx.paging:paging-runtime:2.1.0'
//emoji components
implementation "com.android.support:support-emoji-bundled:26.1.0"
}
We need to create an abstract class that extends the RoomDatabase to give access to the DAO interface(s) implementations.
AppDatabase.java
package com.materialuiux.androidpaginglibraryexample.database;
import android.content.Context;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
import com.materialuiux.androidpaginglibraryexample.dao.EmojiDao;
import com.materialuiux.androidpaginglibraryexample.model.Emoji;
@Database(entities = Emoji.class, version = 1)
public abstract class AppDatabase extends RoomDatabase {
private static final String DATABASE_NAME = "database.db";
private static AppDatabase INSTANCE;
private static final Object sLock = new Object();
public abstract EmojiDao postDao();
public static AppDatabase getInstance(Context context) {
synchronized (sLock) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, DATABASE_NAME)
.allowMainThreadQueries()
.build();
}
return INSTANCE;
}
}
}
EmojiDao.java
package com.materialuiux.androidpaginglibraryexample.dao;
import androidx.paging.DataSource;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.Query;
import com.materialuiux.androidpaginglibraryexample.model.Emoji;
import java.util.List;
@Dao
public interface EmojiDao {
@Query("SELECT * FROM Emoji")
DataSource.Factory<Integer, Emoji> getAllPaged();
@Insert
void insertAll(List<Emoji> persons);
}
now lets create the viewmodel and and add the live data to the paging library
EmojiViewModel.java
package com.materialuiux.androidpaginglibraryexample.viewmodel;
import android.app.Application;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import androidx.paging.DataSource;
import androidx.paging.LivePagedListBuilder;
import androidx.paging.PagedList;
import com.materialuiux.androidpaginglibraryexample.database.AppDatabase;
import com.materialuiux.androidpaginglibraryexample.model.Emoji;
public class EmojiViewModel extends AndroidViewModel {
//the size of a page that we want
private static final int PAGE_SIZE = 10;
private AppDatabase appDatabase;
//creating livedata for PagedList
private LiveData<PagedList<Emoji>> liveResults;
//constructor
public EmojiViewModel(@NonNull Application application) {
super(application);
appDatabase = AppDatabase.getInstance(this.getApplication());
// get all emojies from database and apply it to the paging library
DataSource.Factory factory = appDatabase.postDao().getAllEmoji();
//Building the paged list
LivePagedListBuilder pagedListBuilder = new LivePagedListBuilder(factory, PAGE_SIZE);
liveResults = pagedListBuilder.build();
}
public LiveData<PagedList<Emoji>> getLiveResults() {
return liveResults;
}
}
now let’s create the Main Activity and show the data inside the recyclerview and write the data from json file to the database
MainActivity.java
package com.materialuiux.androidpaginglibraryexample;
import androidx.appcompat.app.AppCompatActivity;
import androidx.emoji.bundled.BundledEmojiCompatConfig;
import androidx.emoji.text.EmojiCompat;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.paging.PagedList;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import com.materialuiux.androidpaginglibraryexample.adapter.Ad_Emoji;
import com.materialuiux.androidpaginglibraryexample.database.AppDatabase;
import com.materialuiux.androidpaginglibraryexample.model.Emoji;
import com.materialuiux.androidpaginglibraryexample.viewmodel.EmojiViewModel;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
EmojiViewModel viewModel;
Ad_Emoji adapter;
SharedPreferences prefs;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//initialize the EmojiCompat
EmojiCompat.Config config= new BundledEmojiCompatConfig(this);
EmojiCompat.init(config);
setContentView(R.layout.activity_main);
prefs = PreferenceManager.getDefaultSharedPreferences(this);
viewModel = ViewModelProviders.of(this).get(EmojiViewModel.class);
adapter = new Ad_Emoji(MainActivity.this);
RecyclerView recipeRecyclerView = findViewById(R.id.rv);
recipeRecyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
recipeRecyclerView.setAdapter(adapter);
// get the live data from the database and submit it to the adapter
viewModel.getLiveResults().observe(this, new Observer<PagedList<Emoji>>() {
@Override
public void onChanged(PagedList<Emoji> pagedList) {
if (pagedList != null) {
adapter.submitList(pagedList);
}
}
});
// check if the data was whiten in the database
boolean loaded = prefs.getBoolean("loaded", false);
if (!loaded){
// if its not loaded then write the data again
loadEmojiJSONFromAsset();
}
}
public void loadEmojiJSONFromAsset() {
String json = null;
ArrayList<Emoji> emojiArrayList = new ArrayList<>();
try {
InputStream is = getAssets().open("emoji.json");
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
json = new String(buffer, "UTF-8");
} catch (IOException ex) {
ex.printStackTrace();
}
try {
JSONObject obj = new JSONObject(json);
JSONArray array = obj.getJSONArray("Smileys");
for (int i = 0; i < array.length(); i++) {
JSONObject object = (JSONObject) array.get(i);
ArrayList<String> keywordsList = new ArrayList<>();
JSONArray jArray = object.getJSONArray("keywords");
final int numberOfItemsInResp = jArray.length();
for (int j = 0; j < numberOfItemsInResp; j++) {
keywordsList.add(jArray.getString(j));
}
emojiArrayList.add(new Emoji(0, object.getString("code"), fromArray(keywordsList)));
}
} catch (JSONException e) {
e.printStackTrace();
}
AppDatabase.getInstance(this).postDao().insertAll(emojiArrayList);
prefs.edit().putBoolean("loaded", true).apply();
}
public String fromArray(ArrayList<String> strings) {
StringBuilder string = new StringBuilder();
for (String s : strings) string.append(s).append(" ");
return string.toString();
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Ad_Emoji.java
package com.materialuiux.androidpaginglibraryexample.adapter; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.emoji.widget.EmojiTextView; import androidx.paging.PagedListAdapter; import androidx.recyclerview.widget.RecyclerView; import com.materialuiux.androidpaginglibraryexample.R; import com.materialuiux.androidpaginglibraryexample.model.Emoji; public class Ad_Emoji extends PagedListAdapter<Emoji, Ad_Emoji.viewHolder> { private final Context context; public Ad_Emoji(Context context) { super(Emoji.DIFF_CALLBACK); this.context = context; } @NonNull @Override public viewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(context).inflate(R.layout.item_emoji, parent, false); return new viewHolder(view); } @Override public void onBindViewHolder(@NonNull viewHolder holder, int position) { Emoji emoji = getItem(position); if (emoji != null) { holder.bindTo(emoji); } else { holder.clear(); } } public class viewHolder extends RecyclerView.ViewHolder { private TextView keywords; private EmojiTextView emoji; viewHolder(@NonNull View itemView) { super(itemView); emoji = itemView.findViewById(R.id.tv_emoji); keywords = itemView.findViewById(R.id.tv_keywords); } void bindTo(Emoji emojis) { this.itemView.setTag(emojis.getUid()); try { char[] chars = Character.toChars(Integer.parseInt(emojis.getCode().substring(2), 16)); this.emoji.setText(new String(chars)); this.emoji.setTextSize(22); } catch (NumberFormatException e) { e.printStackTrace(); } this.keywords.setText(emojis.getKeywords()); } void clear() { itemView.invalidate(); emoji.invalidate(); keywords.invalidate(); } } }
item_emoji.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.emoji.widget.EmojiTextView
android:id="@+id/tv_emoji"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginStart="8dp"
android:gravity="center"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp" />
<TextView
android:id="@+id/tv_keywords"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="8dp"
android:textSize="16sp" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#000000" />
</LinearLayout>
That’s it. Get the full example Github