Reputation: 99
I am working on a project which include Recyclerview
and Cursorloader
and when user clicks on an item in recyclerview
it should get the data from item and start new Activity
.But instead it is giving me an exception
Attempt to invoke interface method 'boolean android.database.Cursor.moveToPosition(int)' on a null object reference
My Adapter :
public class Mainrow_Adapter extends CursorRecyclerViewAdapter<Mainrow_Adapter.ViewHolder>
{
Context context;
Cursor cursor;
public Mainrow_Adapter(Context context, Cursor cursor)
{
super(context, cursor);
this.cursor = cursor;
this.context = context;
}
@Override
public Mainrow_Adapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.mainrow_layout,parent,false);
ViewHolder viewHolder = new ViewHolder(view,context,cursor);
return viewHolder;
}
@Override
public void onBindViewHolder(Mainrow_Adapter.ViewHolder viewHolder, final Cursor cursor)
{
PersonDetails personDetails = PersonDetails.from(cursor);
AddLog addLog = new AddLog();
viewHolder.mName.setText(personDetails.getName());
NumberFormat currency = addLog.changeamount();
viewHolder.mAmount.setText(currency.format(personDetails.getAmount()));
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
TextView mName,mAmount;
Context context;
Cursor cursor;
public ViewHolder(View itemView,Context context,Cursor cursor) {
super(itemView);
this.context = context;
this.cursor = cursor;
itemView.setOnClickListener(this);
mName = (TextView)itemView.findViewById(R.id.mainrowname);
mAmount = (TextView)itemView.findViewById(R.id.mainrowAmount);
}
@Override
public void onClick(View view) {
int position = this.getAdapterPosition();
cursor.moveToPosition(position);
String name = cursor.getString(1);String mobile = cursor.getString(2);
String city = cursor.getString(3);String amount = cursor.getString(5);
Intent intent = new Intent(context,ViewLog.class);
intent.putExtra("Name",name);intent.putExtra("Mobile",mobile);
intent.putExtra("City",city);intent.putExtra("Amount",amount);
context.startActivity(intent);
Toast.makeText(context,String.valueOf(position), Toast.LENGTH_SHORT).show();
}
}
}
Cursor Adapter :
public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
private Context mContext;
private Cursor mCursor;
private boolean mDataValid;
private int mRowIdColumn;
private DataSetObserver mDataSetObserver;
public CursorRecyclerViewAdapter(Context context, Cursor cursor) {
mContext = context;
mCursor = cursor;
mDataValid = cursor != null;
mRowIdColumn = mDataValid ? mCursor.getColumnIndex("_id") : -1;
mDataSetObserver = new NotifyingDataSetObserver();
if (mCursor != null) {
mCursor.registerDataSetObserver(mDataSetObserver);
}
}
public Cursor getCursor() {
return mCursor;
}
@Override
public int getItemCount() {
if (mDataValid && mCursor != null) {
return mCursor.getCount();
}
return 0;
}
@Override
public long getItemId(int position) {
if (mDataValid && mCursor != null && mCursor.moveToPosition(position)) {
return mCursor.getLong(mRowIdColumn);
}
return 0;
}
@Override
public void setHasStableIds(boolean hasStableIds) {
super.setHasStableIds(true);
}
public abstract void onBindViewHolder(VH viewHolder, Cursor cursor);
@Override
public void onBindViewHolder(VH viewHolder, int position) {
if (!mDataValid) {
throw new IllegalStateException("this should only be called when the cursor is valid");
}
if (!mCursor.moveToPosition(position)) {
throw new IllegalStateException("couldn't move cursor to position " + position);
}
onBindViewHolder(viewHolder, mCursor);
}
/**
* Change the underlying cursor to a new cursor. If there is an existing cursor it will be
* closed.
*/
public void changeCursor(Cursor cursor) {
Cursor old = swapCursor(cursor);
if (old != null) {
old.close();
}
}
/**
* Swap in a new Cursor, returning the old Cursor. Unlike
* {@link #changeCursor(Cursor)}, the returned old Cursor is <em>not</em>
* closed.
*/
public Cursor swapCursor(Cursor newCursor) {
if (newCursor == mCursor) {
return null;
}
final Cursor oldCursor = mCursor;
if (oldCursor != null && mDataSetObserver != null) {
oldCursor.unregisterDataSetObserver(mDataSetObserver);
}
mCursor = newCursor;
if (mCursor != null) {
if (mDataSetObserver != null) {
mCursor.registerDataSetObserver(mDataSetObserver);
}
mRowIdColumn = newCursor.getColumnIndexOrThrow("_id");
mDataValid = true;
notifyDataSetChanged();
} else {
mRowIdColumn = -1;
mDataValid = false;
notifyDataSetChanged();
//There is no notifyDataSetInvalidated() method in RecyclerView.Adapter
}
return oldCursor;
}
private class NotifyingDataSetObserver extends DataSetObserver {
@Override
public void onChanged() {
super.onChanged();
mDataValid = true;
notifyDataSetChanged();
}
@Override
public void onInvalidated() {
super.onInvalidated();
mDataValid = false;
notifyDataSetChanged();
//There is no notifyDataSetInvalidated() method in RecyclerView.Adapter
}
}
}
i would really appreciate if any of you guys Know a better solution than this to initiate an onclicklistenter and get the Cursor at Items position.
Thank you
Upvotes: 2
Views: 634
Reputation: 226
You don't set the cursor to your viewHolder just set in on onBindViewHolder method
@Override
public void onBindViewHolder(Mainrow_Adapter.ViewHolder viewHolder, final Cursor cursor)
{
PersonDetails personDetails = PersonDetails.from(cursor);
AddLog addLog = new AddLog();
viewHolder.mName.setText(personDetails.getName());
viewHolder.cursor = cursor;
NumberFormat currency = addLog.changeamount();
viewHolder.mAmount.setText(currency.format(personDetails.getAmount()));
}
and don't call
cursor.moveToPosition(position);
in you OnClick method.
And I prefer to implement your OnClickListner method in onBindViewHolder method not in viewHolder class.
Upvotes: 1