在适配器中获取 ArrayIndexOutOfBoundsException
Getting ArrayIndexOutOfBoundsException in Adapter
我正在回收站视图中显示数据。我正在使用 Firebase Firestore。以下是我在 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);
}
这是我的适配器:
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;
}
});
}
}}
所以我的应用程序崩溃了,这是由以下行引起的:
DocumentSnapshot snapshot = getSnapshots().getSnapshot(getAdapterPosition());
这是错误:
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.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)
在getAdapterPosition()下的documentation中有一个注解:
Note that if you've called notifyDataSetChanged(), until the next layout pass, the return value of this method will be NO_POSITION.
所以现在当我不想让我的应用程序崩溃时,我必须像这样更新 ViewHolder 中的 OnClick:
@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;
}
此代码有效,应用程序不再崩溃。但是当错误通常出现时,我不能再点击项目了。当您查看代码时,我认为这是合乎逻辑的,因为比 dapter 位置 returns -1
或 NO_POSITION
。那么现在我的 Queston 如何修复整个错误?我应该怎么做才能使应用程序不会崩溃和 我可以单击项目?
我不确定为什么适配器位置无效(稍后应该调查),但是您可以通过改进代码来"fix"解决这个问题:
- 将
NoteViewHolder
移至单独的 class
- 向
NoteViewHolder
添加 bind(Note note, String id)
方法并将这些值存储为可变字段
- 将匿名内部class更改为
setOnClickListener(this)
并在NoteViewHolder
中实现点击监听
- 点击监听如下图
- 在
onBindViewHolder
中,调用bind
并附上备注和id
NoteViewHolder
:
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);
}
}
我正在回收站视图中显示数据。我正在使用 Firebase Firestore。以下是我在 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);
}
这是我的适配器:
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;
}
});
}
}}
所以我的应用程序崩溃了,这是由以下行引起的:
DocumentSnapshot snapshot = getSnapshots().getSnapshot(getAdapterPosition());
这是错误:
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.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)
在getAdapterPosition()下的documentation中有一个注解:
Note that if you've called notifyDataSetChanged(), until the next layout pass, the return value of this method will be NO_POSITION.
所以现在当我不想让我的应用程序崩溃时,我必须像这样更新 ViewHolder 中的 OnClick:
@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;
}
此代码有效,应用程序不再崩溃。但是当错误通常出现时,我不能再点击项目了。当您查看代码时,我认为这是合乎逻辑的,因为比 dapter 位置 returns -1
或 NO_POSITION
。那么现在我的 Queston 如何修复整个错误?我应该怎么做才能使应用程序不会崩溃和 我可以单击项目?
我不确定为什么适配器位置无效(稍后应该调查),但是您可以通过改进代码来"fix"解决这个问题:
- 将
NoteViewHolder
移至单独的 class - 向
NoteViewHolder
添加bind(Note note, String id)
方法并将这些值存储为可变字段 - 将匿名内部class更改为
setOnClickListener(this)
并在NoteViewHolder
中实现点击监听
- 点击监听如下图
- 在
onBindViewHolder
中,调用bind
并附上备注和id
NoteViewHolder
:
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);
}
}