Right now I am trying to use recyclerview with a cursorloader. I included the cursorloader within my recyclerview adapter based on my research. I do not have the desire to put my SQLite database data into an arraylist. Right now it looks like my code is correct but when I load the app I get a blank screen. Can anyone help me see my mistake in my code?
Here is my adapter:
public class PrescriptionRecyclerAdapter extends RecyclerView.Adapter<PrescriptionRecyclerAdapter.ViewHolder> {
private CursorAdapter mCursorAdapter;
private Context mContext;
private ViewHolder holder;
Cursor prescriptionCursor;
public PrescriptionRecyclerAdapter(Context context, Cursor c) {
mContext = context;
prescriptionCursor = c;
mCursorAdapter = new CursorAdapter(mContext, c, 0) {
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// Inflate the view here
View v = LayoutInflater.from(context)
.inflate(R.layout.recycle_item, parent, false);
return v;
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
// Extract data from the current store row and column
int nameColumnIndex = cursor.getColumnIndex(PrescriptionContract.PrescriptionEntry.COLUMN_PRESCRIPTION_NAME);
int amountColumnIndex = cursor.getColumnIndex(PrescriptionContract.PrescriptionEntry.COLUMN_PRESCRIPTION_AMOUNT);
int durationColumnIndex = cursor.getColumnIndex(PrescriptionContract.PrescriptionEntry.COLUMN_PRESCRIPTION_FREQUENCY_DURATION);
final int columnIdIndex = cursor.getColumnIndex(PrescriptionContract.PrescriptionEntry._ID);
//Read the store attritubes from the Cursor for the current stores
String name = cursor.getString(nameColumnIndex);
String amount = cursor.getString(amountColumnIndex);
String duration = cursor.getString(durationColumnIndex);
String col = cursor.getString(columnIdIndex);
// Populate fields with extracted properties
holder.prescriptionName.setText(name);
holder.prescriptionAmount.setText(amount);
holder.prescriptionDays.setText(duration);
}
};
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView prescriptionName;
public TextView prescriptionAmount;
public TextView prescriptionDays;
final public Button prescriptionButton;
public ViewHolder(View itemView) {
super(itemView);
// Find fields to populate in inflated template
prescriptionName = (TextView) itemView.findViewById(R.id.name);
prescriptionAmount = (TextView) itemView.findViewById(R.id.amountlist);
prescriptionDays = (TextView) itemView.findViewById(R.id.daysList);
prescriptionButton = itemView.findViewById(R.id.scheduleButton);
}
}
@Override
public int getItemCount() {
return mCursorAdapter.getCount();
}
public Cursor swapCursor(Cursor cursor) {
if (prescriptionCursor == cursor) {
return null;
}
Cursor oldCursor = prescriptionCursor;
this.prescriptionCursor = cursor;
if (cursor != null) {
this.notifyDataSetChanged();
}
return oldCursor;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
// Passing the binding operation to cursor loader
mCursorAdapter.getCursor().moveToPosition(position);
mCursorAdapter.bindView(holder.itemView, 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);
holder = new ViewHolder(v);
return holder;
}
}
Here is my display activity.
public class DisplayActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>{
private static final int PRESCRIPTION_LOADER = 0;
PrescriptionRecyclerAdapter mCursorAdapter;
private RecyclerView.LayoutManager mLayoutManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(DisplayActivity.this, EditorActivity.class);
startActivity(intent);
}
});
RecyclerView prescriptionRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mLayoutManager = new LinearLayoutManager(getApplicationContext());
prescriptionRecyclerView.setLayoutManager(mLayoutManager);
mCursorAdapter = new PrescriptionRecyclerAdapter(this, null);
prescriptionRecyclerView.setAdapter(mCursorAdapter);
//Kick off the loader
getLoaderManager().initLoader(PRESCRIPTION_LOADER,null,this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_display, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// User clicked on a menu option in the app bar overflow menu
switch (item.getItemId()) {
// Respond to a click on the "Delete all entries" menu option
case R.id.action_delete_all_entries:
deleteAllPrescriptions();
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* Helper method to delete all items in the database.
*/
private void deleteAllPrescriptions() {
int rowsDeleted = getContentResolver().delete(PrescriptionEntry.CONTENT_URI, null, null);
Log.v("CatalogActivity", rowsDeleted + " rows deleted from prescription database");
}
@Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
// Since the editor shows all store attributes, define a projection that contains
// all columns from the store table
String[] projection = {
PrescriptionEntry._ID,
PrescriptionEntry.COLUMN_PRESCRIPTION_NAME,
PrescriptionEntry.COLUMN_PRESCRIPTION_AMOUNT,
PrescriptionEntry.COLUMN_PRESCRIPTION_FREQUENCY_HOURS,
PrescriptionEntry.COLUMN_PRESCRIPTION_FREQUENCY_TIMES,
PrescriptionEntry.COLUMN_PRESCRIPTION_FREQUENCY_DURATION,
PrescriptionEntry.COLUMN_PRESCRIPTION_REFILL,
PrescriptionEntry.COLUMN_PRESCRIPTION_EXPIRATION,
PrescriptionEntry.COLUMN_PRESCRIPTION_PHARMACIST_NAME,
PrescriptionEntry.COLUMN_PRESCRIPTION_PHARMACIST_NUMBER,
PrescriptionEntry.COLUMN_PRESCRIPTION_PHYSICIAN_NAME,
PrescriptionEntry.COLUMN_PRESCRIPTION_PHYSICIAN_NUMBER};
// This loader will execute the ContentProvider's query method on a background thread
return new CursorLoader(this, // Parent activity context
PrescriptionEntry.CONTENT_URI, // Query the content URI for the current store
projection, // Columns to include in the resulting Cursor
null, // No selection clause
null, // No selection arguments
null); // Default sort order
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mCursorAdapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
mCursorAdapter.swapCursor(null);
}
}
I think i got your problem. After getting new Cursor
in onLoadFinished
method you are calling PrescriptionRecyclerAdapter
's swapCursor()
method this method is updating prescriptionCursor
Cursor reference. Thats OK. But updating prescriptionCursor
will not effect your CursorAdapter
. You are actually dependent on CursorAdapter
. So you have to update theCursor
of your CursorAdapter
. Because your mCursorAdapter
still holding the old reference of the Cursor
you have provided in constructor.
So use this method to update Cursor reference mCursorAdapter.swapCursor(prescriptionCursor)
.
public Cursor swapCursor(Cursor cursor) {
if (prescriptionCursor == cursor) {
return null;
}
Cursor oldCursor = prescriptionCursor;
this.prescriptionCursor = cursor;
if (cursor != null) {
this.notifyDataSetChanged();
// update your Cursor for CursorAdapter
mCursorAdapter.swapCursor(prescriptionCursor);
}
return oldCursor;
}
I think you have made it complex by maintaining two Adapter. You can use RecyclerView.Adapter
with List
or Cursor
. There is not need to make it complex.
Hope it will help you. Let me know it solve your problem.