RecyclerView异常BUG

来源:互联网 发布:php argc argv 编辑:程序博客网 时间:2024/05/21 11:31
                                                              05-05 11:47:52.021 4882-4882/com.daijintao.youjin E/AndroidRuntime: FATAL EXCEPTION: main                                                                    Process: com.daijintao.youjin, PID: 4882                                                                    java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{184736a1 position=1 id=-1, oldPos=1, pLpos:-1 scrap [attachedScrap] tmpDetached no parent}                                                                   at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:5297)        at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5479)        at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5440)        at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5436)        at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2224)        at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1551)        at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1511)        at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:595)        at android.support.v7.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.java:3534)        at android.support.v7.widget.RecyclerView.onMeasure(RecyclerView.java:3019)        at android.view.View.measure(View.java:17547)        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535)        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1436)        at android.widget.LinearLayout.measureVertical(LinearLayout.java:722)        at android.widget.LinearLayout.onMeasure(LinearLayout.java:613)        at android.view.View.measure(View.java:17547)        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535)        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1436)        at android.widget.LinearLayout.measureVertical(LinearLayout.java:722)        at android.widget.LinearLayout.onMeasure(LinearLayout.java:613)        at android.view.View.measure(View.java:17547)        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535)        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1436)        at android.widget.LinearLayout.measureVertical(LinearLayout.java:722)        at android.widget.LinearLayout.onMeasure(LinearLayout.java:613)        at android.view.View.measure(View.java:17547)        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535)        at android.widget.FrameLayout.onMeasure(FrameLayout.java:436)        at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:139)        at android.view.View.measure(View.java:17547)        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535)        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1436)        at android.widget.LinearLayout.measureVertical(LinearLayout.java:722)        at android.widget.LinearLayout.onMeasure(LinearLayout.java:613)        at android.view.View.measure(View.java:17547)        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535)        at android.widget.FrameLayout.onMeasure(FrameLayout.java:436)        at android.view.View.measure(View.java:17547)        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535)        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1436)        at android.widget.LinearLayout.measureVertical(LinearLayout.java:722)        at android.widget.LinearLayout.onMeasure(LinearLayout.java:613)        at android.view.View.measure(View.java:17547)        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535)        at android.widget.FrameLayout.onMeasure(FrameLayout.java:436)        at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2615)        at android.view.View.measure(View.java:17547)        at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2015)        at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1173)        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1379)        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1061)        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5885)        at android.view.Choreographer$Callb

这么晚了还在调试BUG实在伤不起,不过作为一个准程序员来说这点幸苦当然算不了什么。现在把今天碰到的一个比较令人不解的错误记录下来,以备日后随时翻查。
这么长一串异常信息实在很令人头疼,因为异常的地方根本没有跟自己的代码无关,所以在看了几个错误之后我放弃了,果断度娘。在几经搜索之后,终于在一篇博文中搜到了结果,这里我就引用下网上大神的原话:

文章中说到:在进行数据移除和数据增加时,务必要保证RVAdapter中的数据和移除的数据保持一致!什么意思呢?我自己琢磨认为是这样的,如果你更新你的集合后,调用RVAdapter的新出现的notifyxxxx方法时,adapter 的更新预期结果和实际集合更新结果不同,那么就会出现异常了。
举个例子吧: 比如你集合remove了两条数据,但是你RVAdapter只notifyItemRemoved(2)(这里表示移除第三条数据,只移除了一条),这种情况旧属于数据不一致了。还有一种是你增加数据,你集合增加10条数据,但是你RVAdapter的notify只增加了5条数据,这也是数据不一致。
好了,通过以上两种情况,大概就知道了,这个数据一致其实说的是要保证数量一致。就是说RVAdapter有个size,你的集合有个size。这两个size,在调用RvAdapter的notifyxxxx时候必须保持相同。

看到这里,似乎茅塞顿开,去翻看自己的代码,果然在一个不起眼的位置发现了异常。

editText.addTextChangedListener(new TextWatcher() {            @Override            public void beforeTextChanged(CharSequence s, int start, int count, int after) {            }            @Override            public void onTextChanged(CharSequence s, int start, int before, int count) {            }            @Override            public void afterTextChanged(Editable s) {                if (s.toString().equals("")) {                    ryHint.setVisibility(View.GONE);                    searchList.clear();                    hintAdapter.notifyItemChanged(0);                }else {                    //当内容清空的时候恢复初始值                    loadYoujinData(s.toString());                }            }     });

当我们清空输入内容的时候会执行if语句的第一个判断,这里的hintAdapter调用了notifyItemChanged(0)这个方法,然后是loadYoujiData这个方法的内容,这个方法是根据输入内容去请求网络数据,以下是这个方法里的关键部分,这里我使用了Bmob后端云作为我的云端服务器。

youjinBmobQuery.findObjects(new FindListener<Youjin>() {            @Override            public void done(List<Youjin> list, BmobException e) {                if (e == null) {                    if (list.size() == 0) {                        //返回数据大小为0                        Toast.makeText(MainActivity.this, "数据不存在", Toast.LENGTH_SHORT).show();                    } else {                        ryHint.setVisibility(View.VISIBLE);                        //设置RecyclerView                        searchList.clear();                        searchList.addAll(list);                        for(Youjin youjin:searchList){                            Log.i("TAG",youjin.getName());                        }                        hintAdapter.notifyDataSetChanged();                    }                } else {                    Toast.makeText(MainActivity.this, "加载错误", Toast.LENGTH_SHORT).show();                    Log.i("TAG", "加载错误:" + e.getMessage().toString());                }

可以看到这里的adapter使用了notifyDataSetChaned();
这样写导致的结果就是两次notifyXXX时所更新的数据和实际不一致,当我把两个调用notifyXXX的地方对调notifyXXX方法后发现错误仍然存在,而两处调用同一个notify方法,异常却没有了。

以上只是我个人的看法,欢迎大家多多指点,指出错误的地方,让小弟我及时查漏补缺。

0 0