Получение ArrayIndexOutOfBoundsException в адаптере - PullRequest
0 голосов
/ 06 сентября 2018

Я отображаю данные в окне просмотра. Я использую 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)

В документации под getAdapterPosition () есть примечание:

Note that if you've called notifyDataSetChanged(), until the next layout pass, the return value of this method will be NO_POSITION.  

Так что теперь, когда я не хочу аварийно завершить работу моего приложения, я должен обновить свой OnClick во ViewHolder следующим образом:

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

Этот код работает, и приложение больше не падает. Но когда ошибка обычно появляется, я не могу больше щелкать по пунктам. Я думаю, что это логично, когда вы смотрите на код, потому что позиция даптера возвращает -1 или NO_POSITION. Итак, теперь мой Queston, как исправить всю ошибку? Что я должен сделать, чтобы приложение не вызывало сбоев и , чтобы я мог щелкнуть по элементам?

1 Ответ

0 голосов
/ 06 сентября 2018

Я не уверен, почему позиция адаптера признана недействительной (и это следует выяснить позже), но вы можете «исправить» эту проблему, улучшив свой код:

  1. Переместить NoteViewHolder в отдельный класс
  2. Добавить метод bind(Note note, String id) к NoteViewHolder и сохранить эти значения как изменяемые поля
  3. Измените анонимный внутренний класс на setOnClickListener(this) и реализуйте прослушиватель щелчков в NoteViewHolder
  4. Слушатель щелчка показан ниже
  5. В onBindViewHolder, позвоните 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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...