title: Android RecyclerView + CursorLoader + ContentProvider + "Load More"
body: <p>I have created one Activity in that I am implementing <strong>CursorLoader</strong> for load data from Database.</p>
  
  <p>I have done that thing for all records of that Table but I want to load 30-30 records like <strong>Load More Functionality</strong></p>
  
  <p>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.</p>
  
  <p>My Activity Code is Like:</p>
  
  <pre><code>public class ProductListActivity extends AppCompatActivity
          implements LoaderManager.LoaderCallbacks&lt;Cursor&gt; {
  
      /**
       * 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&lt;Cursor&gt; 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&lt;Cursor&gt; 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&lt;Cursor&gt; loader) {
          //If the loader is reset, we need to clear out the
          //current cursor from the adapter.
          productListAdapter.reQuery(null);
      }
  }
  </code></pre>
  
  <h1>UPDATE:</h1>
  
  <p>I have added <strong>EndlessRecyclerViewScrollListener</strong> </p>
  
  <pre><code>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);
              }
          });
  </code></pre>
  
  <p>I have tried to <strong>MergeCursor</strong> in adapter but getting error:</p>
  
  <pre><code>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.&lt;init&gt;(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)
  </code></pre>
  
  <h1>Edited (ADAPTER Code):</h1>
  
  <pre><code>public class ProductListAdapter extends RecyclerView.Adapter&lt;ProductListAdapter.ViewHolder&gt; {
  
      // 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&amp;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);
          }
      }
  }
  </code></pre>
  
  <p>Anybody can help please, Thanks in advance.</p>