I have created one Activity in that I am implementing CursorLoader for load data from Database.
I have done that thing for all records of that Table but I want to load 30-30 records like Load More Functionality
I have tried to create query and its loading first 30 records but I cant able to understand how can I request for new records.
My Activity Code is Like:
public class ProductListActivity extends AppCompatActivity
        implements LoaderManager.LoaderCallbacks<Cursor> {
    /**
     * Records in list
     */
    int offset = 0;
    /**
     * For Current Activity *
     */
    Context mContext;
    /**
     * Activity Binding
     */
    ActivityProductListBinding activityProductListBinding;
    /**
     * Product Adapter
     */
    ProductListAdapter productListAdapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /**
         * DataBinding with XML
         */
        activityProductListBinding = DataBindingUtil.setContentView(this, R.layout.activity_product_list);
        /**
         * Getting Context
         */
        mContext = getApplicationContext();
        /***
         * TOOLBAR Settings...
         */
        setSupportActionBar(activityProductListBinding.toolbar);
        activityProductListBinding.toolbarTitleTextview.setText(R.string.string_title_products);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setDisplayShowTitleEnabled(false);
        final ActionBar ab = getSupportActionBar();
        if (ab != null)
            ab.setDisplayHomeAsUpEnabled(true);
        /**
         * RecyclerView Setup
         */
        GridLayoutManager manager = new GridLayoutManager(this, 2);
        activityProductListBinding.productListRecyclerView.setLayoutManager(manager);
        /**
         * First Time init Loader
         */
        getSupportLoaderManager().initLoader(1, null, this);
    }
    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        final Uri CONTENT_URI = KOOPSContentProvider.CONTENT_URI_PRODUCT.buildUpon()
                .appendQueryParameter(KOOPSContentProvider.QUERY_PARAMETER_OFFSET,
                        String.valueOf(offset))
                .build();
        return new CursorLoader(this, CONTENT_URI ,null, null, null, null);
    }
    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        //When the loader has loaded some data (either initially, or the
        //datasource has changed and a new cursor is being provided),
        //Then we'll swap out the cursor in our recyclerview's adapter
        // and we'll create the adapter if necessary
        Log.d(LogUtils.TAG, "Cursor : " + data.getCount());
        if (productListAdapter == null) {
            productListAdapter = new ProductListAdapter(this, data);
            activityProductListBinding.productListRecyclerView.setAdapter(productListAdapter);
        }
    }
    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        //If the loader is reset, we need to clear out the
        //current cursor from the adapter.
        productListAdapter.reQuery(null);
    }
}
UPDATE:
I have added EndlessRecyclerViewScrollListener
activityProductListBinding.productListRecyclerView.addOnScrollListener(new EndlessRecyclerViewScrollListener(manager) {
            @Override
            public void onLoadMore(int page, int totalItemsCount) {
                // Triggered only when new data needs to be appended to the list
                // Add whatever code is needed to append new items to the bottom of the list
                offset = limit * page;
                /**
                 * Adding Bundle in Loader and then Call
                 */
                getSupportLoaderManager().initLoader(LOADER_ID, productQueryData, ProductListActivity.this);
            }
        });
I have tried to MergeCursor in adapter but getting error:
FATAL EXCEPTION: main
Process: com.kevalam.koopsv3, PID: 25021
java.lang.IllegalStateException: Observer android.database.MergeCursor$1@570f82d is already registered.
    at android.database.Observable.registerObserver(Observable.java:49)
    at android.database.AbstractCursor.registerDataSetObserver(AbstractCursor.java:358)
    at android.database.CursorWrapper.registerDataSetObserver(CursorWrapper.java:222)
    at android.database.MergeCursor.<init>(MergeCursor.java:50)
    at com.kevalam.koops.adapter.ProductListAdapter.mergeCursor(ProductListAdapter.java:71)
    at com.kevalam.koops.ui.ProductListActivity.onLoadFinished(ProductListActivity.java:161)
    at com.kevalam.koops.ui.ProductListActivity.onLoadFinished(ProductListActivity.java:38)
Edited (ADAPTER Code):
public class ProductListAdapter extends RecyclerView.Adapter<ProductListAdapter.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;
    Activity mContext;
    Random rnd;
    public ProductListAdapter(AppCompatActivity context, Cursor c) {
        mContext = context;
        rnd = new Random();
        mCursorAdapter = new CursorAdapter(mContext, c, 0) {
            @Override
            public View newView(Context context, Cursor cursor, ViewGroup parent) {
                // Inflate the view here
                LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                return inflater.inflate(R.layout.row_product_layout_grid, parent, false);
            }
            @Override
            public void bindView(View view, Context context, Cursor cursor) {
                String productName = cursor.getString(cursor.getColumnIndex(PRODUCT_NAME));
                // Binding operations
                ((TextView) view.findViewById(R.id.sub_product_name_text_view)).setText(productName);
                int color = Color.argb(200, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
                String url = "http://dummyimage.com/300/" + color + "/ffffff&text=" + (cursor.getPosition() + 1);
                Picasso
                        .with(context)
                        .load(url)
                        .placeholder(R.mipmap.ic_launcher) // can also be a drawable
                        .into((ImageView) view.findViewById(R.id.sub_product_image_view));
            }
        };
    }
    public void mergeCursor(Cursor c) {
        if (mCursorAdapter != null) {
            Cursor[] cursorArray = {mCursorAdapter.getCursor(), c};
            MergeCursor mergeCursor = new MergeCursor(cursorArray);
            reQuery(mergeCursor);
        }
    }
    public void reQuery(Cursor c) {
        if (mCursorAdapter != null) {
            mCursorAdapter.changeCursor(c);
            mCursorAdapter.notifyDataSetChanged();
            notifyDataSetChanged();
        }
    }
    @Override
    public int getItemCount() {
        return mCursorAdapter.getCount();
    }
    @Override
    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.view, mContext, mCursorAdapter.getCursor());
    }
    @Override
    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);
    }
    public static class ViewHolder extends RecyclerView.ViewHolder {
        View view;
        public ViewHolder(View itemView) {
            super(itemView);
            view = itemView.findViewById(R.id.product_row_card_view);
        }
    }
}
Anybody can help please, Thanks in advance.
 
    
 
    