Android 当使用Runnable从处理程序更改use NotifyItem时,RecyclerView崩溃[IllegalArgumentException]
我正在使用Android 当使用Runnable从处理程序更改use NotifyItem时,RecyclerView崩溃[IllegalArgumentException],android,android-recyclerview,Android,Android Recyclerview,我正在使用RecyclerView作为列表来显示可下载的歌曲。每个项目在其视图中都有ProgressBar。下载开始时,我使用处理程序通知每个项目更新进度条,以显示歌曲下载进度 Q1。这是正确的方法还是有其他更合适的方法。 Q2。当我们使用adapter.notifyItemChanged(位置)时,RecyclerView崩溃更新单个项目的内容。使用Runnable从处理程序调用它。但是,日志没有显示我的代码的任何跟踪。为什么? 以下是此问题的日志: 05-06 19:09:45.804: E
RecyclerView
作为列表来显示可下载的歌曲。每个项目在其视图中都有ProgressBar
。下载开始时,我使用处理程序
通知每个项目更新进度条
,以显示歌曲下载进度
Q1。这是正确的方法还是有其他更合适的方法。
Q2。当我们使用adapter.notifyItemChanged(位置)时,RecyclerView崩溃
更新单个项目的内容。使用Runnable
从处理程序调用它。但是,日志没有显示我的代码的任何跟踪。为什么?
以下是此问题的日志:
05-06 19:09:45.804: E/AndroidRuntime(32115): FATAL EXCEPTION: main
05-06 19:09:45.804: E/AndroidRuntime(32115): java.lang.IllegalArgumentException: Tmp detached view should be removed from RecyclerView before it can be recycled: ViewHolder{41b7bec0 position=6 id=-1, oldPos=-1, pLpos:-1 update changed tmpDetachedundefined adapter position no parent}
05-06 19:09:45.804: E/AndroidRuntime(32115): at android.support.v7.widget.RecyclerView$Recycler.recycleViewHolderInternal(RecyclerView.java:3861)
05-06 19:09:45.804: E/AndroidRuntime(32115): at android.support.v7.widget.RecyclerView.removeAnimatingView(RecyclerView.java:779)
05-06 19:09:45.804: E/AndroidRuntime(32115): at android.support.v7.widget.RecyclerView.access$5300(RecyclerView.java:127)
05-06 19:09:45.804: E/AndroidRuntime(32115): at android.support.v7.widget.RecyclerView$ItemAnimatorRestoreListener.onAddFinished(RecyclerView.java:8228)
05-06 19:09:45.804: E/AndroidRuntime(32115): at android.support.v7.widget.RecyclerView$ItemAnimator.dispatchAddFinished(RecyclerView.java:8573)
05-06 19:09:45.804: E/AndroidRuntime(32115): at android.support.v7.widget.DefaultItemAnimator$5.onAnimationEnd(DefaultItemAnimator.java:239)
05-06 19:09:45.804: E/AndroidRuntime(32115): at android.support.v4.view.ViewPropertyAnimatorCompatJB$1.onAnimationEnd(ViewPropertyAnimatorCompatJB.java:47)
05-06 19:09:45.804: E/AndroidRuntime(32115): at android.view.ViewPropertyAnimator$AnimatorEventListener.onAnimationEnd(ViewPropertyAnimator.java:973)
05-06 19:09:45.804: E/AndroidRuntime(32115): at android.animation.ValueAnimator.endAnimation(ValueAnimator.java:1012)
05-06 19:09:45.804: E/AndroidRuntime(32115): at android.animation.ValueAnimator.access$400(ValueAnimator.java:51)
05-06 19:09:45.804: E/AndroidRuntime(32115): at android.animation.ValueAnimator$AnimationHandler.doAnimationFrame(ValueAnimator.java:623)
05-06 19:09:45.804: E/AndroidRuntime(32115): at android.animation.ValueAnimator$AnimationHandler.run(ValueAnimator.java:639)
05-06 19:09:45.804: E/AndroidRuntime(32115): at android.view.Choreographer$CallbackRecord.run(Choreographer.java:776)
05-06 19:09:45.804: E/AndroidRuntime(32115): at android.view.Choreographer.doCallbacks(Choreographer.java:579)
05-06 19:09:45.804: E/AndroidRuntime(32115): at android.view.Choreographer.doFrame(Choreographer.java:547)
05-06 19:09:45.804: E/AndroidRuntime(32115): at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:762)
05-06 19:09:45.804: E/AndroidRuntime(32115): at android.os.Handler.handleCallback(Handler.java:725)
05-06 19:09:45.804: E/AndroidRuntime(32115): at android.os.Handler.dispatchMessage(Handler.java:92)
05-06 19:09:45.804: E/AndroidRuntime(32115): at android.os.Looper.loop(Looper.java:153)
05-06 19:09:45.804: E/AndroidRuntime(32115): at android.app.ActivityThread.main(ActivityThread.java:5297)
05-06 19:09:45.804: E/AndroidRuntime(32115): at java.lang.reflect.Method.invokeNative(Native Method)
05-06 19:09:45.804: E/AndroidRuntime(32115): at java.lang.reflect.Method.invoke(Method.java:511)
05-06 19:09:45.804: E/AndroidRuntime(32115): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:833)
05-06 19:09:45.804: E/AndroidRuntime(32115): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
05-06 19:09:45.804: E/AndroidRuntime(32115): at dalvik.system.NativeStart.main(Native Method)
我搜索了此问题的解决方案,但找不到任何合适的答案。adapter.notifyItemChanged(位置)必须从主线程调用代码>
使用带有mainLooper的处理程序代替处理程序
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
//HERE
}
});
我们的应用程序上也有这个问题,经过很长时间的调试,我们发现它是由adapter.setHasStableIds(true)
我们去掉了冒犯的界线,问题终于解决了
希望能有所帮助。有几种解决方法:
调用notifyDataSetChanged()
而不是notifyItemChanged()
。这是解决这个问题效率较低的方法
正如Henrique de Sousa所指出的那样,删除线适配器。setHasStableIds(true)
可防止出现问题
但是,如果适配器是稳定的,那么真正的解决方案(正如southerton所评论的那样)是正确地实现getItemId()
,尊重“HassTableId”值集。我遇到了同样的问题,但结果证明原因是调用scrollToPosition
。在多次尝试之后,我的解决方案是在滚动之前调用notifydatasetchange
(当然,所有这些都是从UI线程中获得的)。也许它会对某人有所帮助。因为这是第一篇文章,所以我将发布另一个解决问题的方法,这对我的具体情况有所帮助:
我正在使用隐藏包含recyclerview
的parentview
parentView.setVisibility(View.GONE);
recyclerview不喜欢这样,显然,如果要隐藏包含recyclerview的视图,则只能使用view.INVISIBLE
我也遇到了同样的问题,我可以通过禁用recyclerview的animator来解决:
recyclerView.itemAnimator=null对我来说,在我从recyclerView的父视图组中删除了animateLayoutChanges=“true”
后,问题得到了解决。这里的一些人说“android:animateLayoutChanges”不应该设置为true,但我没有设置,设置为false也没有帮助
无论如何,出于某种原因,在我的例子中,将ConstraintLayout替换为LinearLayout作为RecyclerView的父级已经修复了它
另一种选择是,在我让RecyclerView的适配器对其进行任何更改或对RecyclerView的父级进行任何更改(在我的情况下,我在ViewAnimator中切换视图)之前,我添加了以下检查:
if (recyclerView.isAnimating)
Handler().post {
adapter.items = it.listItems
adapter.notifyDataSetChanged()
}
else {
adapter.items = it.listItems
adapter.notifyDataSetChanged()
}
由于某些原因,此替代方案在POC上不适用于我,因此我建议改用LinearLayout解决方案,或者在清除数据或切换到其他视图时使用此解决方案,就像我所做的那样:
val itemAnimator = recyclerView.itemAnimator
recyclerView.itemAnimator = null
clearItems()
recyclerView.itemAnimator = itemAnimator
我向谷歌报告了这个问题。POC和变通方法(对我来说是有效的)也可以在那里找到
POC显示,如果RecyclerView位于ConstraintLayout内部,则会发生这种情况,ConstraintLayout位于ViewAnimator内部。场景是,当RecyclerView正在为其某些视图设置动画(例如,删除单个项目)时,我会清除其所有项目并切换到ViewAnimator中的另一个视图。唯一对我有效的解决方案
fun RecyclerView.executeAfterAllAnimationsAreFinished(
callback: (RecyclerView) -> Unit
) = post(
object : Runnable {
override fun run() {
if (isAnimating) {
//if isAnimating() returned true itemAnimator will be non-null
itemAnimator!!.isRunning {
post(this)
}
} else {
callback(this@executeAfterAllAnimationsAreFinished)
}
}
}
)
说明:它会一直等到itemAnimator停止设置动画并提供recyclerview回调。如果recycler视图父对象是ConstraintLayout
内部ViewAnimator/ViewSwitcher
请尝试:
在回收器视图中设置水平约束
将回收器视图layout\u width
设置为0dp
或者,如果recycler视图是直接子视图,则对ViewAnimator/ViewSwitcher
执行相同的操作,如果您在ConstraintLayout中使用recycler视图。可以通过向回收器添加水平约束并将其宽度更改为0dp来解决此问题
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
我总是在UI线程中处理这些事情来调用它们。这不是我现在面临的问题。这是动画师的问题。有时会抛出,有时不会,我不知道如何修复:(Hi @ AMRUT BITRI,如果这个或任何答案已经解决了你的问题,请通过点击复选标记来考虑。这向更广泛的社区表明,你已经找到了解决方案并给回答者和你自己带来了一些声誉。没有义务这么做。解决了我的问题,尽管GETITEMID()为数据项返回了正确的唯一ID。我这样做:“在一个很长的调试会话之后”:d下载投票者是否可以解释?我认为如果这是一个原因不同的常见问题,那么在线程中评论其他解决方案是很常见的。很好地找到Ole。这是我的问题。我必须使回收器视图不可见(没有消失)-砰的一声,崩溃消失了。这也解决了我的问题,但如果你真的需要设置更改的动画,该怎么办?:/n你还需要恢复它,否?否则,当项目列表更改时,你会丢失漂亮的动画,否?在这个问题上停留了数小时。这为我停止了崩溃。你能为此添加一些上下文吗?我们何时调用此扩展N
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />