【问题标题】:IndexOutOfBoundsException: Inconsistency detected error while scrollingIndexOutOfBoundsException:滚动时检测到不一致错误
【发布时间】:2020-07-03 03:07:56
【问题描述】:

我有一个来自我存储在数据库中的 API 的列表。现在我从 db 中获取列表并在 recyclerview 中显示它。然后从 recyclerview 列表中一一删除所有数据。此过程使用 JobScheduler 每 10 秒重复一次。当我滚动时,我收到了这个错误。我已经尝试过各种 SO 帖子中给出的许多解决方案,例如 this,但没有奏效。

java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionMessageViewHolder{c2276c4 position=31 id=-1, oldPos=-1, pLpos:-1 no parent} androidx.recyclerview.widget.RecyclerView{5223262 VFED..... .F...... 0,0-720,1120 #7f0900d4 app:id/recycler}, adapter:com.sam.testapp.MessageAdapter@4b57ff3, layout:androidx.recyclerview.widget.LinearLayoutManager@735b4b0, context:com.sam.testapp.MainActivity@e780e56
public class MessageAdapter extends RecyclerView.Adapter<MessageAdapter.MessageViewHolder> {

    private List<Message> messageList;

    public MessageAdapter(List<Message> messageList) {
        this.messageList = messageList;
    }

    protected static class MessageViewHolder extends RecyclerView.ViewHolder {
        private ConstraintLayout root;
        private TextView umfiTXT, msgTXT;

        MessageViewHolder(View view) {
            super(view);
            root = view.findViewById(R.id.root);
            umfiTXT = view.findViewById(R.id.umfiTXT);
            msgTXT = view.findViewById(R.id.msgTXT);
        }
    }

    @NonNull
    @Override
    public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new MessageViewHolder((LayoutInflater.from(parent.getContext())).inflate(R.layout.row_msg_list, parent, false));
    }

    @Override
    public void onBindViewHolder(@NonNull MessageViewHolder holder, int position) {
        try {
            holder.umfiTXT.setText("UMFI: " + messageList.get(position).getMessageUMFI());
            holder.msgTXT.setText("Message: " + messageList.get(position).getMessageTxt());
        }catch(Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public int getItemCount() {
        try {
            if(messageList.isEmpty())
                return 0;
            else
                return messageList.size();
        }catch(Exception e) {
            return 0;
        }
    }

    private void clearData() {
        this.messageList.clear();
        notifyDataSetChanged();
    }

    public void setData(List<Message> data) {
        clearData();
        this.messageList.addAll(data);
        notifyDataSetChanged();
    }
}
public class MainActivity extends AppCompatActivity {

    private ArrayList<Message> messageList;
    private RecyclerView recycler;
    private AppCompatTextView emptyTxt;
    private MessageAdapter messageAdapter;
    private SqliteDatabase database;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        messageList = new ArrayList<>();
        recycler = findViewById(R.id.recycler);
        emptyTxt = findViewById(R.id.emptyTxt);
        database = new SqliteDatabase(MainActivity.this);


        recycler.setLayoutManager(new LinearLayoutManager(this));
        messageAdapter = new MessageAdapter(messageList);
        recycler.setAdapter(messageAdapter);
        recycler.setItemAnimator(null);

        RxBus.subscribe((Consumer<Object>) o -> {
            if (o instanceof RxEvent) {
                RxEvent data = (RxEvent) o;
                System.out.println("SAM: status: " + data.getStatus());
                if (data.getStatus() == 1) {
                    fetchMessageList();
                }

            }
        });


    }

    private void fetchMessageList(){
        messageList.clear();
        AndroidNetworking.get(Util.url)
                .setPriority(Priority.IMMEDIATE)
                .build()
                .getAsJSONArray(new JSONArrayRequestListener() {
                    @Override
                    public void onResponse(JSONArray jsonArray) {
                        try{
                            System.out.println("SAM: fetchMessageList jsonArray: "+jsonArray);
                            ArrayList<Message> templist = new ArrayList<>();
                            for(int i=0; i<jsonArray.length(); i++){
                                JSONObject jsonObject = jsonArray.getJSONObject(i);
                                templist.add(new Message(jsonObject.getString("umfi"), jsonObject.getString("msg_to"), jsonObject.getString("msg_text")));
                            }

                            storeListinDB(templist);

                        }catch(Exception e){
                            e.printStackTrace();
                        }

                    }
                    @Override
                    public void onError(ANError error) {
                        System.out.println("SAM: fetchMessageList onError: "+error.getErrorBody());
                    }
                });
    }

    private void storeListinDB(ArrayList<Message> templist){
        database.insertArrayData(templist);
        showList();
    }

    private void showList(){
        try{
            //recycler.getRecycledViewPool().clear();


            if(messageList.size()>0){
                emptyTxt.setVisibility(View.GONE);
                messageAdapter.notifyDataSetChanged();
            }else{
                emptyTxt.setVisibility(View.VISIBLE);
                ArrayList<Message> templist = new ArrayList<>();
                templist = database.fetchMessageList();
                messageAdapter.setData(templist);
                System.out.println("SAM: templist size: "+templist.size());
            }
            System.out.println("SAM: messageList size: "+messageList.size());
            //removeAll();
        }catch(Exception e){
            e.printStackTrace();
        }
    }


}

【问题讨论】:

    标签: android-recyclerview androidx


    【解决方案1】:

    您将messageList 传递给适配器,因此适配器和活动中的messageList 是相同的对象引用。然后,据我了解,以某种方式调用了 fetchMessageList 方法,这就是问题出现的地方。您在列表上调用 .clear() 并启动异步操作以获取新列表,然后将其同步发布到您的适配器。

    问题是,在您清除列表后,您的适配器现在会保留对空列表的引用,而不会收到有关更改的通知。适配器仍然“认为”您的列表大小与以前相同,因此当您滚动 RecyclerView 时,它会尝试至少调用 onBindViewHolder 以获取新出现的项目。但是,由于列表为空,它会抛出 IndexOutOfBoundsException

    您可以尝试在调用messageList.clear() 后立即将更改通知适配器,但在我看来,只需删除此清除即可解决问题。

    private void fetchMessageList(){
            //messageList.clear(); <- delete this
            AndroidNetworking.get(Util.url)
                ...
    }
    

    【讨论】:

    • 非常感谢。删除该 clear() 方法解决了错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-30
    • 1970-01-01
    • 1970-01-01
    • 2013-12-11
    • 2015-01-05
    相关资源
    最近更新 更多