在适配器中获取ArrayIndexOutOfBoundsException

时间:2018-09-06 19:19:40

标签: android android-recyclerview google-cloud-firestore indexoutofboundsexception

我正在recyclerview中显示数据。我正在使用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$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)

documentation中的getAdapterPosition()下有一个注释:

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;
            }  

此代码有效,该应用程序不再崩溃。但是当错误通常消失时,我无法再单击“项目”。在查看代码时,我认为这是合乎逻辑的,因为修饰符位置返回的是-1NO_POSITION。那么现在是我的Queston如何解决整个错误?我应该怎么做才能使应用程序不会崩溃并且我可以单击项目?

1 个答案:

答案 0 :(得分:3)

我不确定为什么适配器位置无效(以后应进行调查),但是您可以通过改进代码来“解决”此问题:

  1. NoteViewHolder移到一个单独的类中
  2. bind(Note note, String id)添加NoteViewHolder方法并将这些值存储为可变字段
  3. 将匿名内部类更改为setOnClickListener(this),并在NoteViewHolder中实现点击侦听器
  4. 点击侦听器如下所示
  5. onBindViewHolder中,用笔记和ID呼叫bind

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);
    }
}