我有一个RecyclerView,我使用AsyncTask填充了数据。当我用clear()
和mAdapter.notifyDataSetChanged()
清除列表,然后尝试用AsyncTask再次填充它时,出现了以下异常:
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter position
在AsyncTask中将notifyItemInserted()
替换为notifyDataSetChanged()
可以解决问题,但是我认为这不是一个好的解决方案,我想了解为什么第一种方法不起作用。 / p>
我的AsyncTask doInBackground()
方法:
@Override
protected Void doInBackground(Void... voids) {
for (int i = 0; i < 100; i++) {
mDataContainer.addItem(i);
publishProgress(i);
}
return null;
}
和我的AsyncTask onProgressUpdate()
方法:
@Override
protected void onProgressUpdate(Integer... values) {
mAdapter.notifyItemInserted(values[0]);
super.onProgressUpdate(values);
}
我希望有人可以帮助我。预先感谢。
编辑: 这是适配器:
private class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private List<Item> mItems;
private int selectedPos = RecyclerView.NO_POSITION;
private class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private Item mItem;
private TextView mNameTextView;
private TextView mMembersTextView;
MyViewHolder(View view) {
super(view);
itemView.setOnClickListener(this);
mNameTextView = itemView.findViewById(R.id.item_name);
mMembersTextView = itemView.findViewById(R.id.item_members);
}
@Override
public void onClick(View view) {
notifyItemChanged(selectedPos);
selectedPos = getLayoutPosition();
notifyItemChanged(selectedPos);
mOnItemSelectedListener.onItemSelected(mItem);
}
}
MyAdapter(List<Item> items) {
mItems = items;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(getActivity())
.inflate(R.layout.list_item, parent, false);
return new MyViewHolder(view);
}
@Override
public void onBindViewHolder(MyViewHolder myViewHolder, int position) {
Item item = mItems.get(position);
myViewHolder.mItem = item;
myView.mNameTextView.setText(item.getName());
myView.mMembersTextView.setText(String.format(Locale.US,"%d/50", item.getMembers()));
if (!mIsInit) {
// select item that was selected before orientation change
if (selectedPos != RecyclerView.NO_POSITION) {
Item selectedItem = mItems.get(selectedPos);
mOnItemSelectedListener.onItemSelected(selectedItem);
// else select item 0 as default on landscape mode
} else if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){
selectedPos = 0;
mOnItemSelectedListener.onItemSelected(MyViewHolder.mItem);
}
mIsInit = true;
}
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
myViewHolder.itemView.setSelected(selectedPos == position);
}
}
@Override
public int getItemCount() {
return mItems.size();
}
}
答案 0 :(得分:1)
我认为最好在后台添加所有值并在插入所有数据后通知适配器”
@Override
protected Void doInBackground(Void... voids) {
for (int i = 0; i < 100; i++) {
mDataContainer.addItem(i);
}
return null;
}
@Override
protected void onPostExecute(Long result) {
mAdapter.notifyItemRangeInserted(0, 100);
}
我还建议您不要使用AsyncTask
,因为它是deprecated on Android 11
答案 1 :(得分:1)
您应该仅从UI线程向适配器添加项目(并进行通知)。从后台更改适配器的后备数据,然后稍后通过onProgressUpdate
在UI线程上进行通知很可能会导致争用情况。在这种情况下,应在通知适配器之前将mDataContainer.addItem(i);
移至onProgressUpdate
。
如果不查看mDataContainer
的定义,很难确认这是否是唯一的问题,但是在此处解决同步问题绝对是解决此问题的第一步。