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.
SQLiteCursor
as it "paginates" by itself extendingAbstractWindowedCursor
– MotorbusinitLoader
twice: first to read some small number of rows (100 for example) which will load in 10ms or so (and you see them right now) and the second with no row limit – MotorbusinitLoader
again @Motorbus – FlaggingonLoadFinished
is called) – MotorbusonLoadMore
so wait for someone else, i already said it is pointless to use any "pagination" – Motorbus"first to read some small number of rows (100 for example) which will load in 10ms or so (and you see them right now) and the second with no row limit"
and yes, the second cursor will replace the first since the first will contain rows 0..99 and the second rows 0..max-1 – MotorbusproductQueryData
is a Cursor or what else? – Rodgers