RecyclerView适配器的位置与其数据集的索引有何关系?

Huk*_*ABA 10 android android-recyclerview

我以为他们是一样的,但他们不是.当我尝试访问我的数据集的"position"索引时,下面的代码给出了indexOutOfBounds异常,在这种情况下,我创建了一个名为Task的模型列表:

public class TaskAdapter extends RecyclerView.Adapter<TaskAdapter.TaskViewHolder>   {

private List<Task> taskList;
private TaskAdapter thisAdapter = this;

// cache of views to reduce number of findViewById calls
public static class TaskViewHolder extends RecyclerView.ViewHolder {
    protected TextView taskTV;
    protected ImageView closeBtn;

    public TaskViewHolder(View v) {
        super(v);
        taskTV = (TextView)v.findViewById(R.id.taskDesc);
        closeBtn = (ImageView)v.findViewById(R.id.xImg);
    }
}


public TaskAdapter(List<Task> tasks) {
    if(tasks == null)
        throw new IllegalArgumentException("tasks cannot be null");
    taskList = tasks;
}


// onBindViewHolder binds a model to a viewholder
@Override
public void onBindViewHolder(TaskViewHolder taskViewHolder, int pos) {
    final int position = pos;
    Task currTask = taskList.get(pos);
    taskViewHolder.taskTV.setText(currTask.getDescription());

    **taskViewHolder.closeBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.d("TRACE", "Closing task at position " + position);
            // delete from SQLite DB
            Task taskToDel = taskList.get(position);
            taskToDel.delete();
            // updating UI
            taskList.remove(position);
            thisAdapter.notifyItemRemoved(position);
        }
    });**
}

@Override
public int getItemCount() {
    //Log.d("TRACE", taskList.size() + " tasks in DB");
    return taskList.size();
}


// inflates row to create a viewHolder
@Override
public TaskViewHolder onCreateViewHolder(ViewGroup parent, int pos) {
    View itemView = LayoutInflater.from(parent.getContext()).
                                   inflate(R.layout.list_item, parent, false);
    Task currTask = taskList.get(pos);

    //itemView.setBackgroundColor(Color.parseColor(currTask.getColor()));
    return new TaskViewHolder(itemView);
}
}
Run Code Online (Sandbox Code Playgroud)

从我的recyclerview删除有时会产生意外结果.有时会删除单击之前的元素,有时会在"taskList.get(position)"处发生indexOutOfBounds异常.

阅读https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.htmlhttps://developer.android.com/training/material/lists-cards.html没有给我更深入地了解为什么会发生这种情况以及如何解决这个问题.

它看起来像RecyclerView回收行,但我不希望indexoutofbounds异常使用较小的数字子集来索引我的列表.

yig*_*git 12

RecyclerView在其位置发生变化时不会重新绑定视图(出于明显的性能原因).例如,如果您的数据集如下所示:

A B C D
Run Code Online (Sandbox Code Playgroud)

并通过添加项目X.

mItems.add(1, X);
notifyItemInserted(1, 1);
Run Code Online (Sandbox Code Playgroud)

要得到

A X B C D
Run Code Online (Sandbox Code Playgroud)

RecyclerView只会绑定X并运行动画.

getPositionViewHolder中有一个方法,但如果在动画中间调用它,它可能与适配器位置不匹配.

如果您需要适配器位置,最安全的选择是从适配器获取位置.

更新您的评论

将任务字段添加到ViewHolder.

更改onCreateViewHolder如下以避免在每个重新绑定上创建侦听器对象.

// inflates row to create a viewHolder
@Override
public TaskViewHolder onCreateViewHolder(ViewGroup parent, int type) {
    View itemView = LayoutInflater.from(parent.getContext()).
                               inflate(R.layout.list_item, parent, false);

    final TaskViewHolder vh = new TaskViewHolder(itemView);
    taskViewHolder.closeBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // delete from SQLite DB
            Task taskToDel = vh.getTask();
            final int pos = taskList.indexOf(taskToDel);
            if (pos == -1) return;
            taskToDel.delete();
            // updating UI
            taskList.remove(pos);
            thisAdapter.notifyItemRemoved(pos);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

所以在你的on bind方法中,你做到了

// onBindViewHolder binds a model to a viewholder
@Override
public void onBindViewHolder(TaskViewHolder taskViewHolder, int pos) {
    Task currTask = taskList.get(pos);
    taskViewHolder.setTask(currTask);
    taskViewHolder.taskTV.setText(currTask.getDescription());
}
Run Code Online (Sandbox Code Playgroud)

  • 我想点击它时删除适配器的一个元素,如我的适配器所示.pos不是要使用的变量,我应该使用哪个变量? (2认同)

Ely*_*tas 10

像yigit所说,RecyclerView的工作原理如下:

A B C D
Run Code Online (Sandbox Code Playgroud)

并通过添加项目X.

mItems.add(1, X);
notifyItemInserted(1, 1);
Run Code Online (Sandbox Code Playgroud)

你得到

A X B C D
Run Code Online (Sandbox Code Playgroud)

使用holder.getAdapterPosition()在onClickListener()会给你的数据集的权利要删除的项目,而不是"静态"的观点立场.这是关于它的文档onBindViewHolder