Home » Android » android – Using the recyclerview with a database

android – Using the recyclerview with a database

Posted by: admin March 11, 2020 Leave a comment


Currently there is no default implementation of RecyclerView.Adapter available.

May be with the official release, Google will add it.

Since there is no support for CursorAdapter with the RecyclerView currently, how can we use a RecyclerView with a database ? Any suggestions ?

How to&Answers:

If you are running a query with a CursorLoader and you want RecyclerView instead of ListView.

You can try my CursorRecyclerViewAdapter: CursorAdapter in RecyclerView


My solution was to hold a CursorAdapter member in my recyclerView.Adapter implementation. Then passing all the handling of creating the new view & binding it to the cursor adapter, something like this:

public class MyRecyclerAdapter extends Adapter<MyRecyclerAdapter.ViewHolder> {

    // Because RecyclerView.Adapter in its current form doesn't natively 
    // support cursors, we wrap a CursorAdapter that will do all the job
    // for us.
    CursorAdapter mCursorAdapter;

    Context mContext;

    public MyRecyclerAdapter(Context context, Cursor c) {

        mContext = context;

        mCursorAdapter = new CursorAdapter(mContext, c, 0) {

            public View newView(Context context, Cursor cursor, ViewGroup parent) {
                // Inflate the view here

            public void bindView(View view, Context context, Cursor cursor) {
                // Binding operations

    public static class ViewHolder extends RecyclerView.ViewHolder {
        View v1;

        public ViewHolder(View itemView) {
            v1 = itemView.findViewById(R.id.v1);

    public int getItemCount() {
        return mCursorAdapter.getCount();

    public void onBindViewHolder(ViewHolder holder, int position) {
        // Passing the binding operation to cursor loader
        mCursorAdapter.getCursor().moveToPosition(position); //EDITED: added this line as suggested in the comments below, thanks :)
        mCursorAdapter.bindView(holder.itemView, mContext, mCursorAdapter.getCursor());


    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // Passing the inflater job to the cursor-adapter
        View v = mCursorAdapter.newView(mContext, mCursorAdapter.getCursor(), parent);
        return new ViewHolder(v);


Since your question says “How to use RecyclerView with a database” and you are not being specific whether you want SQLite or anything else with the RecyclerView, I’ll give you a solution that is highly optimal. I’ll be using Realm as database and let you display all the data inside your RecyclerView. It has asynchronous query support as well without using Loaders or AsyncTask.

Why realm?
realm.io performance Android

Step 1

Add the gradle dependency for Realm , the dependency for the latest version is found here

Step 2

Create your model class, for example, lets say something simple like Data which has 2 fields, a string to be displayed inside the RecyclerView row and a timestamp which will be used as itemId for allowing the RecyclerView to animate items. Notice that I extend RealmObject below because of which your Data class will be stored as a table and all your properties will stored as columns of that table Data. I have marked the data text as primary key in my case since I don’t want a string to be added more than once. But if you prefer having duplicates, then make the timestamp as the @PrimaryKey. You can have a table without a primary key but it will cause problems if you try updating the row after creating it. A composite primary key at the time of writing this answer is not supported by Realm.

import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;

public class Data extends RealmObject {
private String data;

//The time when this item was added to the database
private long timestamp;

public String getData() {
    return data;

public void setData(String data) {
    this.data = data;

public long getTimestamp() {
    return timestamp;

public void setTimestamp(long timestamp) {
    this.timestamp = timestamp;

Step 3

Create your layout for how a single row should appear inside the RecyclerView.
The layout for a single row item inside our Adapter is as follows

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:visibility="visible" />


Notice that I have kept a FrameLayout as root even though I have a TextView inside. I plan to add more items in this layout and hence made it flexible for now 🙂

For the curious people out there, this is how a single item looks currently.
single item row layout inside RecyclerView

Step 4

Create your RecyclerView.Adapter implementation. In this case, the data source object is a special object called RealmResults which is basically a LIVE ArrayList, in other words, as items are added or removed from your table, this RealmResults object auto updates.

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import io.realm.Realm;
import io.realm.RealmResults;
import slidenerd.vivz.realmrecycler.R;
import slidenerd.vivz.realmrecycler.model.Data;

public class DataAdapter extends RecyclerView.Adapter<DataAdapter.DataHolder> {
private LayoutInflater mInflater;
private Realm mRealm;
private RealmResults<Data> mResults;

public DataAdapter(Context context, Realm realm, RealmResults<Data> results) {
    mRealm = realm;
    mInflater = LayoutInflater.from(context);

public Data getItem(int position) {
    return mResults.get(position);

public DataHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = mInflater.inflate(R.layout.row_data, parent, false);
    DataHolder dataHolder = new DataHolder(view);
    return dataHolder;

public void onBindViewHolder(DataHolder holder, int position) {
    Data data = mResults.get(position);

public void setResults(RealmResults<Data> results) {
    mResults = results;

public long getItemId(int position) {
    return mResults.get(position).getTimestamp();

public int getItemCount() {
    return mResults.size();

public void add(String text) {

    //Create a new object that contains the data we want to add
    Data data = new Data();

    //Set the timestamp of creation of this object as the current time

    //Start a transaction

    //Copy or update the object if it already exists, update is possible only if your table has a primary key

    //Commit the transaction

    //Tell the Adapter to update what it shows.

public void remove(int position) {

    //Start a transaction

    //Remove the item from the desired position

    //Commit the transaction

    //Tell the Adapter to update what it shows

public static class DataHolder extends RecyclerView.ViewHolder {
    TextView area;

    public DataHolder(View itemView) {
        area = (TextView) itemView.findViewById(R.id.area);

    public void setData(String text) {

Notice that I am calling notifyItemRemoved with the position at which the removal happened but I DON’T call notifyItemInserted or notifyItemRangeChanged because there is no direct way to know which position the item was inserted into the database since Realm entries are not stored in an ordered fashion. The RealmResults object auto updates whenever a new item is added, modified or removed from the database so we call notifyDataSetChanged while adding and inserting bulk entries. At this point, you are probably concerned about the animations that won’t be triggered because you are calling notifyDataSetChanged in place of notifyXXX methods. That is exactly why I have the getItemId method return the timestamp for each row from the results object. Animation is achieved in 2 steps with notifyDataSetChanged if you call setHasStableIds(true) and then override getItemId to provide something other than just the position.

Step 5

Lets add the RecyclerView to our Activity or Fragment. In my case, I am using an Activity. The layout file containing the RecyclerView is pretty trivial and would look something like this.

<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />

I have added an app:layout_behavior since my RecyclerView goes inside a CoordinatorLayout which I have not posted in this answer for brevity.

Step 6

Construct the RecyclerView in code and supply the data it needs. Create and initialise a Realm object inside onCreate and close it inside onDestroy pretty much like closing an SQLiteOpenHelper instance. At the simplest your onCreate inside the Activity will look like this. The initUi method is where all the magic happens. I open an instance of Realm inside onCreate.

protected void onCreate(Bundle savedInstanceState) {
    mRealm = Realm.getInstance(this);

private void initUi() {

    //Asynchronous query
    RealmResults<Data> mResults = mRealm.where(Data.class).findAllSortedAsync("data");

    //Tell me when the results are loaded so that I can tell my Adapter to update what it shows
    mResults.addChangeListener(new RealmChangeListener() {
        public void onChange() {
            Toast.makeText(ActivityMain.this, "onChange triggered", Toast.LENGTH_SHORT).show();
    mRecycler = (RecyclerView) findViewById(R.id.recycler);
    mRecycler.setLayoutManager(new LinearLayoutManager(this));
    mAdapter = new DataAdapter(this, mRealm, mResults);

    //Set the Adapter to use timestamp as the item id for each row from our database

Notice that in the first step, I query Realm to give me all objects from the Data class sorted by their variable name called data in an asynchronous manner. This gives me a RealmResults object with 0 items on the main thread which I am setting on the Adapter. I added a RealmChangeListener to be notified when the data has finished loading from the background thread where I call notifyDataSetChanged with my Adapter. I have also called setHasStableIds to true to let the RecyclerView.Adapter implementation keep track of items that are added, removed or modified. The onDestroy for my Activity closes the Realm instance

protected void onDestroy() {

This method initUi can be called inside onCreate of your Activity or onCreateView or onViewCreated of your Fragment. Notice the following things.

Step 7

BAM! There is data from database inside your RecyclerView asynchonously loaded without CursorLoader, CursorAdapter, SQLiteOpenHelper with animations. The GIF image shown here is kinda laggy but the animations are happening when you add items or remove them.

data from database inside RecyclerView


You can implement all the required methods yourself. I recently made my own implementation by just copy pasting code from CursorAdapter.


I made a RecyclerViewCursorAdapter using a SortedList as backend, extending RecyclerView.Adapter

Can be used with SQLiteCursor and Loaders


Just another answer, since I did not like the accepted one (which imo has not an intuitive usage).

The following is my own implementation, which is very similar to (and partially inspired by) SimpleCursorAdapter:

You may modify it for other particular usages, but having a cursor it works just as SimpleCursorAdapter does, only with a RecyclerView.


After retrieving data from DB and store in a list, maybe it should be something like this:

add data to recyclerview


Below is my implementation of cursoradapter for a recyclerview.
It supports OnItemClickListener, OnLongItemClickListener, OnfooterClickListener, Sections, and footer. Does not support, Header, onHeaderClickListner, fast scroller, sticky header or sticky sections.

Just extend this adapter and create your own adapter. Override the methods provided. and pass the cursor from OnCursorLoadFinished method.if the adapter is already created then swapCursor()

package com.tracker.paisa; import android.database.Cursor; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.util.SparseBooleanArray; import android.view.ViewGroup; import java.util.ArrayList; import java.util.List; /** * @author Rahul Upadhyay (https://github.com/devDroidRaul) * Supports footer * Onitemclicklistener, OnItemLongClickListener, OnFooterClickListener * Supports Sections. * * Does Not support,Header, OnHeaderClickListener, FastScroller, StickySection (this can b done with item decor) * Pull requests are welcome for improvements. * * Override this to give logic to place subheaders between items. * public abstract boolean onPlaceSubheaderBetweenItems(int position); * * create seperate viewHolders for item, subheaders and footer. and return required views. * * @Override below methods for individual item type. * public abstract VH onCreateItemViewHolder(ViewGroup parent, int viewType); * public abstract SH onCreateSubheaderViewHolder(ViewGroup parent, int viewType); * public abstract FH onCreateFooterViewHolder(ViewGroup parent, int viewType); * * Bind your views with data here. * @Override below methods to bind data to individual item types. * public abstract void onBindSubHeaderViewHolder(SH holder, Cursor cursor); * public abstract void onBindItemViewHolder(VH holder, Cursor cursor); * public abstract void onBindFooterViewHolder(FH holder, int itemPosition); * * Item type -1,-2,-3 are reserved, kindly do not pass them in getItemViewType. */ public abstract class RecyclerViewCursorAdapter<SH extends RecyclerView.ViewHolder, VH extends RecyclerView.ViewHolder, FH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<RecyclerView.ViewHolder> { public static final String TAG = RecyclerViewCursorAdapter.class.getSimpleName(); private static final int TYPE_SECTION_HEADER = -1; private static final int TYPE_MAIN_HEADER = -2; private static final int TYPE_FOOTER = -3; // private int headerLayout=0,viewLayout=0; boolean createHeader; private List<Integer> subheaderPositions = new ArrayList<>(); private Cursor mCursor; private boolean mDataValid,footerRequired=false; private int mRowIDColumn; private SparseBooleanArray mSelectedItemsIds; // public RecyclerViewCursorAdapter() { } //constructor public RecyclerViewCursorAdapter(Cursor c,boolean footerRequired) { setHasStableIds(true); swapCursor(c); this.footerRequired = footerRequired; this.mSelectedItemsIds = new SparseBooleanArray(); } // interface for listning click on recycler view; public interface OnItemClickedListener{ void OnItemClick(int id, Object data); void onItemLongClick(int id); } OnItemClickedListener onItemClickedListener; public void setOnItemClickedListener(OnItemClickedListener onItemClickedListener) { this.onItemClickedListener = onItemClickedListener; } public interface OnFooterClickedListener{ void onFooterClick(Object data); } OnFooterClickedListener onFooterClickedListener; public void setOnFooterClickedListener( OnFooterClickedListener onFooterClickedListener){ this.onFooterClickedListener = onFooterClickedListener; } public interface OnHeaderClickedListener{ void onHeaderClick(Object data); } OnHeaderClickedListener onHeaderClickedListener; public void setOnHeaderClickedListener( OnHeaderClickedListener onHeaderClickedListener){ this.onHeaderClickedListener = onHeaderClickedListener; } private void initSubheaderPositions() { subheaderPositions.clear(); if(getItemSize() != 0) { //TODO:Handle This please. //subheaderPositions.add(0); } else { return; } for(int i = 1; i < getItemSize(); i++) { if(onPlaceSubheaderBetweenItems(i - 1)) { subheaderPositions.add(i + subheaderPositions.size()); } } } @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { initSubheaderPositions(); } /** * Called when adapter needs to know whether to place subheader between two neighboring * items. * * @return true if you want to place subheader between two neighboring * items. */ public abstract boolean onPlaceSubheaderBetweenItems(int position); public abstract VH onCreateItemViewHolder(ViewGroup parent, int viewType); public abstract SH onCreateSubheaderViewHolder(ViewGroup parent, int viewType); public abstract FH onCreateFooterViewHolder(ViewGroup parent, int viewType); public abstract void onBindSubHeaderViewHolder(SH holder, Cursor cursor); public abstract void onBindItemViewHolder(VH holder, Cursor cursor); public abstract void onBindFooterViewHolder(FH holder, int itemPosition); public abstract int getItemSize(); /** * Return the view type of the item at position for the purposes * of view recycling. * Don't return -1. It's reserved for subheader view type. */ public int getViewType(int position) { return 0; } @Override public final int getItemViewType(int position) { if(isSubheaderOnPosition(position)) { return TYPE_SECTION_HEADER; } if(footerRequired && getCursor().getPosition()==(getCursor().getCount()-1)){ return TYPE_FOOTER; }else { return getViewType(position); } } public boolean isFooterAdded(){ return footerRequired; } @Override public final RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { Log.d("RVCA-OCVH","create viewholder"); if(viewType == TYPE_SECTION_HEADER) { return onCreateSubheaderViewHolder(parent, viewType); } if(footerRequired&&viewType == TYPE_FOOTER){ return onCreateFooterViewHolder(parent, viewType); }else { return onCreateItemViewHolder(parent, viewType); } } @SuppressWarnings("unchecked") @Override public final void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { Log.d("RVCA-OBVH","bind viewholder"); Log.d("RVCA-OBVH","subheader position:"+isSubheaderOnPosition(position)); if(isSubheaderOnPosition(position)) { if (!mDataValid) { throw new IllegalStateException("Cannot bind viewholder when cursor is in invalid state."); } if (!mCursor.moveToPosition(getItemPositionForViewHolder(position))) { throw new IllegalStateException("Could not move cursor to position " + getItemPositionForViewHolder(position) + " when trying to bind viewholder"); } onBindSubHeaderViewHolder((SH)holder, mCursor); }if(footerRequired && position==getItemCount()-1){ Log.d("RVCA-OBVH","bind footerHolder"); onBindFooterViewHolder((FH) holder,position); } else { if (!mDataValid) { throw new IllegalStateException("Cannot bind viewholder when cursor is in invalid state."); } if (!mCursor.moveToPosition(getItemPositionForViewHolder(position))) { throw new IllegalStateException("Could not move cursor to position " + getItemPositionForViewHolder(position) + " when trying to bind viewholder"); } // if(!mCursor.isAfterLast()) { // mCursor.moveToPosition(position); onBindItemViewHolder((VH)holder, mCursor); } } @Override public final int getItemCount() { return getItemSize() + subheaderPositions.size()+(footerRequired?1:0); } public void notifyDataChanged() { initSubheaderPositions(); notifyDataSetChanged(); } public void notifyItemInsertedAtPosition(int itemPosition) { if (itemPosition == 0) { if (getItemCount() == 1 || onPlaceSubheaderBetweenItems(itemPosition)) { subheaderPositions.add(0, 0); increaseSubheaderPositions(1, 2); notifyItemRangeInserted(0, 2); } else { increaseSubheaderPositions(1, 1); notifyItemInserted(1); } } else if (itemPosition == getItemSize() - 1) { if (onPlaceSubheaderBetweenItems(itemPosition - 1)) { subheaderPositions.add(getItemCount() - 1); notifyItemRangeInserted(getItemCount() - 1, 2); } else { notifyItemInserted(getItemPositionInRecyclerView(itemPosition)); } } else { if (onPlaceSubheaderBetweenItems(itemPosition - 1) && onPlaceSubheaderBetweenItems(itemPosition)) { final int itemPositionInRv = getItemPositionInRecyclerView(itemPosition - 1); final int countOfSubheadersBeforePosition = getCountOfSubheadersBeforePosition(itemPositionInRv); subheaderPositions.add(countOfSubheadersBeforePosition, itemPositionInRv + 1); increaseSubheaderPositions(countOfSubheadersBeforePosition + 1, 2); notifyItemRangeInserted(itemPositionInRv + 1, 2); } else if (onPlaceSubheaderBetweenItems(itemPosition)){ final int itemPositionInRv = getItemPositionInRecyclerView(itemPosition - 1); increaseSubheaderPositions(getCountOfSubheadersBeforePosition(itemPositionInRv), 1); notifyItemInserted(itemPositionInRv + 1); } else if (onPlaceSubheaderBetweenItems(itemPosition - 1)) { final int itemPositionInRv = getItemPositionInRecyclerView(itemPosition); increaseSubheaderPositions(getCountOfSubheadersBeforePosition(itemPositionInRv), 1); notifyItemInserted(itemPositionInRv); } else { final int itemPositionInRv = getItemPositionInRecyclerView(itemPosition); increaseSubheaderPositions(getCountOfSubheadersBeforePosition(itemPositionInRv), 1); notifyItemInserted(itemPositionInRv); } } } public void notifyItemChangedAtPosition(int itemPosition) { final int itemPositionInRv = getItemPositionInRecyclerView(itemPosition); notifyItemChanged(itemPositionInRv); } public void notifyItemRemovedAtPosition(int itemPosition) { final int itemPositionInRv = getItemPositionInRecyclerView(itemPosition); for (int i = 1; i < subheaderPositions.size(); i++) { final int subheaderPosition = subheaderPositions.get(i); if (subheaderPosition > itemPositionInRv) { final int previousSubheaderPosition = subheaderPositions.get(i - 1); if (subheaderPosition - previousSubheaderPosition == 2) { subheaderPositions.remove(subheaderPositions.indexOf(previousSubheaderPosition)); decreaseSubheaderPositions(subheaderPositions.indexOf(subheaderPosition), 2); notifyItemRangeRemoved(itemPositionInRv - 1, 2); } else { decreaseSubheaderPositions(subheaderPositions.indexOf(subheaderPosition), 1); notifyItemRemoved(itemPositionInRv); } return; } } final int lastSubheaderPosition = subheaderPositions.get(subheaderPositions.size() - 1); if (itemPositionInRv - lastSubheaderPosition == 1 && getItemCount() == itemPosition + subheaderPositions.size()) { subheaderPositions.remove(subheaderPositions.size() - 1); notifyItemRangeRemoved(itemPositionInRv - 1, 2); } else { notifyItemRemoved(itemPositionInRv); } } public void setGridLayoutManager(final GridLayoutManager gridLayoutManager) { gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { if(subheaderPositions.contains(position)) { return gridLayoutManager.getSpanCount(); } else { return 1; } } }); } public boolean isSubheaderOnPosition(int position) { return subheaderPositions.contains(position); } public int getCountOfSubheadersBeforePosition(int position) { int count = 0; for(int subheaderPosition : subheaderPositions) { if(subheaderPosition < position) { count++; } } return count; } public int getItemPositionInRecyclerView(int position) { int countOfItems = 0; for (int i = 1; i < subheaderPositions.size(); i++) { final int previousSubheaderPosition = subheaderPositions.get(i - 1); final int nextSubheaderPosition = subheaderPositions.get(i); countOfItems += nextSubheaderPosition - previousSubheaderPosition - 1; if (countOfItems > position) { return position + i; } } return position + subheaderPositions.size(); } public int getItemPositionForViewHolder(int viewHolderPosition) { return viewHolderPosition - getCountOfSubheadersBeforePosition(viewHolderPosition); } private void decreaseSubheaderPositions(int startSubheaderPosition, int decreaseNum) { for (int i = startSubheaderPosition; i < subheaderPositions.size(); i++) { final int subheaderPosition = subheaderPositions.get(i); subheaderPositions.set(i, subheaderPosition - decreaseNum); } } private void increaseSubheaderPositions(int startSubheaderPosition, int increaseNum) { for (int i = startSubheaderPosition; i < subheaderPositions.size(); i++) { final int subheaderPosition = subheaderPositions.get(i); subheaderPositions.set(i, subheaderPosition + increaseNum); } } private List<Integer> getSubheaderPositions() { return subheaderPositions; } public int getSubheaderCount() { return subheaderPositions.size(); } public void swapCursor(Cursor newCursor) { Log.d("RVCA-SC","swap cursor"); if (newCursor == mCursor) { Log.d("RVCA-SC","same cursor doing nothing"); return; } if (newCursor != null) { Log.d("RVCA-SC","swap cursor not null"); mCursor = newCursor; mRowIDColumn = mCursor.getColumnIndexOrThrow("_id"); mDataValid = true; // notify the observers about the new cursor notifyDataChanged(); } else { Log.d("RVCA-SC","swap cursor null"); notifyItemRangeRemoved(0, getItemCount()); mCursor = null; mRowIDColumn = -1; mDataValid = false; } } public Cursor getCursor(){ return mCursor ; } @Override public long getItemId(int position) { if (isSubheaderOnPosition(position)) return position; else { int cursorPosition = getItemPositionForViewHolder(position); Cursor cursor = getCursor(); if (hasOpenCursor() && cursor.moveToPosition(cursorPosition)) { return cursor.getLong(cursor.getColumnIndex("_id")); } return NO_CURSOR_POSITION; } } public static final int NO_CURSOR_POSITION = -99; protected boolean hasOpenCursor() { Cursor cursor = getCursor(); if (cursor == null || cursor.isClosed()) { swapCursor(null); return false; } return true; } //Methods to do Selection public void toggleSelection(int position) { selectView(position, !mSelectedItemsIds.get(position)); } //Remove selected selections public void removeSelection() { mSelectedItemsIds = new SparseBooleanArray(); notifyDataSetChanged(); } //Put or delete selected position into SparseBooleanArray public void selectView(int position, boolean value) { if (value) mSelectedItemsIds.put(position, value); else mSelectedItemsIds.delete(position); // notifyItemChangedAtPosition(position); notifyDataSetChanged(); } //Get total selected count public int getSelectedCount() { return mSelectedItemsIds.size(); } //Return all selected ids public SparseBooleanArray getSelectedIds() { return mSelectedItemsIds; } public void setSelectedItemIds(SparseBooleanArray selectedItemIds){ this.mSelectedItemsIds=selectedItemIds; } } 


Simplest implementation is to use cursor object in the adapter and pass cursor to viewholder constructor for modifying views and change the cursor position in onBindViewholder.

If you are using cursor Loader call the setCursor method in onLoadfinished() and passing null in onLoadReset()

public class PetCursorRecyclerViewAdapter extends RecyclerView.Adapter<PetCursorRecyclerViewAdapter.ViewHolder> { Cursor cursor = null; Context context; public PetCursorRecyclerViewAdapter(Context context) { this.context = context; } public void setCursor(Cursor cursor) { this.cursor = cursor; notifyDataSetChanged(); } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(context).inflate(R.layout.catalog_item, parent, false); return new ViewHolder(v); } @Override public void onBindViewHolder(ViewHolder holder, int position) { this.cursor.moveToPosition(position); holder.bindModel(this.cursor); } /* getItemCount() returns the count of videos from the Cursor, or 0 if the Cursor is null (mimicking the behavior of CursorAdapter, which also treats a null Cursor as merely being one that has no rows)*/ @Override public int getItemCount() { if (cursor == null) { return 0; } else { return cursor.getCount(); } } public static class ViewHolder extends RecyclerView.ViewHolder { private TextView name_tv, breed_tv; public ViewHolder(View itemView) { super(itemView); name_tv = (TextView) itemView.findViewById(R.id.name_tv); breed_tv = (TextView) itemView.findViewById(R.id.breed_tv); } public void bindModel(Cursor cursor) { int name_index = cursor.getColumnIndexOrThrow(PetsContract.PetEntry.COLUMN_PET_NAME); int breed_index = cursor.getColumnIndexOrThrow(PetsContract.PetEntry.COLUMN_PET_BREED); name_tv.setText(cursor.getString(name_index)); String breed = cursor.getString(breed_index); if (TextUtils.isEmpty(breed)) { breed = "Unknown Breed"; } breed_tv.setText(breed); } } 



Finally we have an implementation of RecyclerView.Adapter for database/network.

It realised with an Android Architecture Components:

Room database: Database layer on top of SQLite database that takes care of mundane tasks that you used to handle with an SQLiteOpenHelper. Database holder that serves as an access point to the underlying SQLite database. The Room database uses the DAO to issue queries to the SQLite database.

ViewModel: Provides data to the UI. Acts as a communication center between the Repository and the UI. Hides where the data originates from the UI. ViewModel instances survive Activity/Fragment recreation.

LiveData: A data holder class that can be observed. Always holds/caches latest version of data. Notifies its observers when the data has changed. LiveData is lifecycle aware. UI components just observe relevant data and don’t stop or resume observation. LiveData automatically manages all of this since it’s aware of the relevant lifecycle status changes while observing.


You can use SQLite database to store the details. It is easy to access the data.
You can check my code on github. https://github.com/thiru-wta/ToDo

 database = new Database(this); getSupportActionBar().setTitle("To Do List"); etAddItems = (EditText) findViewById(R.id.etAddItem); btnAdd = (Button) findViewById(R.id.btnAdd); mRecyclerView = (RecyclerView) findViewById(R.id.listView); mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); adapter = new RecyclerAdapter(this, listData); mRecyclerView.setAdapter(adapter); btnAdd.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { event_name = etAddItems.getText().toString(); String getname=""; database.storeEventDetails(event_name); getname = database.getEventDetails(event_name); if (getname.length() != 0) { listData.add(getname); etAddItems.setText(""); adapter.notifyData(listData); } 

Database methods:

 public void storeEventDetails(String event_name, long timerStart) { SQLiteDatabase db1 = getWritableDatabase(); db1.execSQL("insert into '"+event_details_tbl+"' values('" + event_name + "')"); db1.close(); } 

get method:

 public String getEventDetails(String event_name) { SQLiteDatabase db1 = getReadableDatabase(); Cursor cur = db1.rawQuery("select * from '"+event_details_tbl+"' where event_name ='" + event_name + "'", null); cur.moveToFirst(); String evName = null; if (cur != null) { do { int eventName = cur.getColumnIndex("event_name"); String ev_name = cur.getString(eventName); evName = ev_name; } while (cur.moveToNext()); } cur.close(); db1.close(); return evName; } 


You have simply to follow these steps:

  • In the recycler view.adapter, create an ArrayList or an Iterator initialized with a null value.
  • Create a method like the ex swapcursor, for example swapdata(Arraylist<T> data). Inside you give a new values to the array list, iterator or any structure that system can iterate using the integer position int the bindview. The values of this method are passed in the onloaderfinished(). Then call in just after assignement notifydatachange(); these will ask the RecyclerView to redraw all the list with new data of the ArrayList.

In the activity or fragment where you are using the loadercalback, create a method that transforms the cursor to an arraylist, or iterator, depending on the data structure chosen in the adapter.

This way you can always use the loadercalback with out blocking the main thread.