Reputation: 2339
I am displaying data in a recyclerview. I am using Firebase Firestore. Here is how I am setting up my Adapter in MainActivity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setUpRecyclerView();
}
private void setUpRecyclerView() {
FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder().setPersistenceEnabled(true).build();
db.setFirestoreSettings(settings);
Query query = db.collection("users").document(firebase_user_uid).collection("notes");
FirestoreRecyclerOptions<Note> response = new FirestoreRecyclerOptions.Builder<Note>().setQuery(query, Note.class).build();
adapter = new NoteListAdapter(response, MainActivity.this);
recyclerViewLayoutManager = new LinearLayoutManager(MainActivity.this, LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(recyclerViewLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.addItemDecoration(new CustomRecyclerViewDivider(this, LinearLayoutManager.VERTICAL, 16));
recyclerView.setAdapter(adapter);
ItemTouchHelper.SimpleCallback itemTouchHelperCallback = new RecyclerItemTouchHelper(0, ItemTouchHelper.LEFT, MainActivity.this);
new ItemTouchHelper(itemTouchHelperCallback).attachToRecyclerView(recyclerView);
}
And here is my Adapter:
public class NoteListAdapter extends FirestoreRecyclerAdapter<Note, NoteListAdapter.NoteViewHolder>{
private Context context;
public NoteListAdapter(@NonNull FirestoreRecyclerOptions<Note> options, @NonNull Context context) {
super(options);
this.context = context;
}
@Override
protected void onBindViewHolder(@NonNull NoteViewHolder holder, int position, @NonNull Note note) {
holder.title.setText(note.getTitle());
holder.content.setText(note.getContent());
}
@NonNull
@Override
public NoteViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_note_view, parent, false);
return new NoteViewHolder(view);
}
public void removeItem(int position) {
getSnapshots().getSnapshot(position).getReference().delete();
notifyItemRemoved(position);
}
public class NoteViewHolder extends RecyclerView.ViewHolder {
public TextView title, content;
public ImageView bg_note_image;
public RelativeLayout viewBackground, viewForeground;
public NoteViewHolder(View view) {
super(view);
title = view.findViewById(R.id.tvTitle);
content = view.findViewById(R.id.tvContent);
bg_note_image = view.findViewById(R.id.note_image_view);
viewBackground = view.findViewById(R.id.view_background);
viewForeground = view.findViewById(R.id.view_foreground);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
DocumentSnapshot snapshot = getSnapshots().getSnapshot(getAdapterPosition());
Note note = snapshot.toObject(Note.class);
String id = getSnapshots().getSnapshot(getAdapterPosition()).getId();
MainActivity.updateNote(id, note);
return;
}
});
}
}}
So my App crashes and thats caused by this line:
DocumentSnapshot snapshot = getSnapshots().getSnapshot(getAdapterPosition());
Here's the Error:
09-06 21:09:11.976 19959-19959/com.test.test.test E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.test.test.test, PID: 19959
java.lang.ArrayIndexOutOfBoundsException: length=10; index=-1
at java.util.ArrayList.get(ArrayList.java:413)
at com.firebase.ui.common.BaseObservableSnapshotArray.getSnapshot(BaseObservableSnapshotArray.java:70)
at com.raycroud.notes.notes.adapter.NoteListAdapter$NoteViewHolder$1.onClick(NoteListAdapter.java:97)
at android.view.View.performClick(View.java:5685)
at android.view.View$PerformClick.run(View.java:22481)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:241)
at android.app.ActivityThread.main(ActivityThread.java:6274)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
In the documentation under getAdapterPosition() there is a Note:
Note that if you've called notifyDataSetChanged(), until the next layout pass, the return value of this method will be NO_POSITION.
So now when I don't want to crash my App I must update my OnClick in ViewHolder like this:
@Override
public void onClick(View view) {
if (getAdapterPosition() == RecyclerView.NO_POSITION) {
return;
}
DocumentSnapshot snapshot = getSnapshots().getSnapshot(getAdapterPosition());
Note note = snapshot.toObject(Note.class);
String id = getSnapshots().getSnapshot(getAdapterPosition()).getId();
MainActivity.updateNote(id, note);
return;
}
This code works and the App doesnt crash anymore. But when the error normally apears I can't click the Items anymore. I think that's logical right when you look at the code, because than the dapter position returns -1
or NO_POSITION
. So now is my Queston how to fix the whole Error? What I shuld do that the app won't crash and that I can click the Items?
Upvotes: 1
Views: 1283
Reputation: 4007
I'm not sure why the adapter position is being invalidated (and that should be investigated later), but you can "fix" this problem by improving your code:
NoteViewHolder
into a separate classbind(Note note, String id)
method to NoteViewHolder
and store those values as mutable fieldssetOnClickListener(this)
and implement the click listener in NoteViewHolder
onBindViewHolder
, call bind
with the note and idNoteViewHolder
:
public final class NoteViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
// ...
private Note note;
private String id;
public NoteViewHolder(View itemView) {
super(itemView);
// ...
itemView.setOnClickListener(this);
}
public void bind(Note note, String id) {
this.note = note;
this.id = id;
title.setText(note.getTitle());
content.setText(note.getContent());
}
@Override
public void onClick(View v) {
MainActivity activity = (MainActivity) itemView.getContext(); // You really shouldn't do this, but I don't know what you're building
activity.updateNote(id, note);
}
}
Upvotes: 3