问题
I'm using RecyclerView
as a list to show songs that can be downloaded. Each item has ProgressBar
in its View
. When the download starts, then I use a Handler
to notify each item to update the ProgressBar
to show the song download progress.
Q1. Is this is a correct way to do it or Is there any other way to do it more appropriately.
Q2. RecyclerView gets crashed when we use
adapter.notifyItemChanged(position);
to update the content of single item. It is called from aHandler
usingRunnable
. But, the log don't show any traces for my code. Why?
Below is the log for this issue:
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)
I searched to find the solution for this but couldn't find any appropriate answer.
回答1:
We also had this issue on our application, and after a really long debugging session we found out that it was caused by adapter.setHasStableIds(true)
We removed the offending line and the issue is finally gone.
Hope it helps.
回答2:
i had the same issue,i could handle it by disabling the animator of recyclerview:
recyclerView.itemAnimator = null
回答3:
adapter.notifyItemChanged(position);
must be called from the main thread
instead of your Handler use the Handler with mainLooper
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
//HERE
}
});
回答4:
I faced the same problem but turned out the reason was calling scrollToPosition
. The solution that worked for me after many attempts was to call notifyDataSetChanged
before scrolling (all from the UI thread of course). Maybe it will help someone.
回答5:
There are several workarounds to the problem:
Call to
notifyDataSetChanged()
insteadnotifyItemChanged()
. It is the less efficient way to solve it.As pointed by Henrique de Sousa, remove the line
adapter.setHasStableIds(true)
prevents the problem.
But the real solution (as commented by southerton), if the adapter is stable, is to implement and correctly getItemId()
, honouring the "hasStableIds" value set.
回答6:
Since this is the first post to come up I'll post another solution to the problem which helped in my specific case:
I was hiding the parentview
containing the recyclerview
using
parentView.setVisibility(View.GONE);
recyclerview does not like that, apparently if you want to hide a view which contains a recyclerview, you can only use View.INVISIBLE
.
回答7:
For me the issue was resolved after I removed animateLayoutChanges=“true”
from the parent ViewGroup of the recyclerview.
来源:https://stackoverflow.com/questions/30078834/recyclerview-gets-crashed-illegalargumentexception-when-use-notifyitemchanged