[安卓bug收录] IllegalArgumentException: Called attach on a child which is not detached

问题描述

Fabric上报的bug,一开始的时候不知道问题出在哪里,然后每个用到RecyclerView的地方都排查了一下终于找到了复现的步骤。

有一个列表支持左右滑动删除,Item的布局里面也有删除按钮,点击之后有删除的动画,然后在动画结束的监听里面调用了adapter.notifyItemRemoved()方法。复现步骤是:在执行删除Item动画的时候立即上下滑动RecyclerView,必崩。

Fabric上详细错误信息如下:

Fatal Exception: java.lang.IllegalArgumentException: Called attach on a child which is not detached: ViewHolder{4244ca70 position=0 id=-1, oldPos=-1, pLpos:-1 not recyclable(1)}
     at android.support.v7.widget.RecyclerView$5.attachViewToParent(RecyclerView.java:719)
     at android.support.v7.widget.ChildHelper.attachViewToParent(ChildHelper.java:239)
     at android.support.v7.widget.RecyclerView.addAnimatingView(RecyclerView.java:1222)
     at android.support.v7.widget.RecyclerView.animateDisappearance(RecyclerView.java:3594)
     at android.support.v7.widget.RecyclerView$4.processDisappeared(RecyclerView.java:485)
     at android.support.v7.widget.ViewInfoStore.process(ViewInfoStore.java:244)
     at android.support.v7.widget.RecyclerView.dispatchLayoutStep3(RecyclerView.java:3444)
     at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3194)
     at android.support.v7.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:1593)
     at android.support.v7.widget.RecyclerView$1.run(RecyclerView.java:323)
     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:788)
     at android.view.Choreographer.doCallbacks(Choreographer.java:591)
     at android.view.Choreographer.doFrame(Choreographer.java:559)
     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:774)
     at android.os.Handler.handleCallback(Handler.java:808)
     at android.os.Handler.dispatchMessage(Handler.java:103)
     at android.os.Looper.loop(Looper.java:193)
     at android.app.ActivityThread.main(ActivityThread.java:5292)
     at java.lang.reflect.Method.invokeNative(Method.java)
     at java.lang.reflect.Method.invoke(Method.java:515)
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824)
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640)
     at dalvik.system.NativeStart.main(NativeStart.java)

可能的原因

根据Google Issue Tracker #37045161 上面的解释,当Item发生改变的时候,改变的动画会创建两份ViewHolder,旧的ViewHolder 淡出,新的ViewHolder 淡入。当我们想要重用这个ViewHolder 的时候,如果动画刚结束,ViewHolder 还没来得及回收,传递给RecyclerView的就是一个已经存在的ViewHolder ,这就导致了以上的问题。

虽然看人家这么说是这个原因,但是没看过源码还是搞不明白,等有空把RecyclerView的源码研究研究再说吧。

My Solution

根据 samebug上推荐的答案,将notifyItemRemoved()方法替换成了notifyDataSetChanged(),bug解决。

参考资料

RecycleView报错Java.lang.IllegalArgumentException: Called attach on a child which is not detached
java.lang.IllegalArgumentException: Called attach on a child which is not detached: ViewHolder
Google Issue Tracker #37045161
Samebug上的解决办法
使用RecyclerView的两个非传统型崩溃

你可能感兴趣的:([安卓bug收录] IllegalArgumentException: Called attach on a child which is not detached)