web-dev-qa-db-ja.com

Runnableを使用してハンドラーからnotifyItemChangedを使用すると、RecyclerViewがクラッシュする[IllegalArgumentException]

ダウンロードできる曲を表示するリストとしてRecyclerViewを使用しています。各アイテムのProgressBarにはViewが含まれています。ダウンロードが開始したら、Handlerを使用して各アイテムにProgressBarを更新し、曲のダウンロードの進行状況を表示するよう通知します。

Q1。これは正しい方法ですか、それとも他の方法で適切に行うことができますか?

Q2。adapter.notifyItemChanged(position);を使用して単一のアイテムのコンテンツを更新すると、RecyclerViewがクラッシュします。Handlerから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)

私はこれの解決策を見つけるために検索しましたが、適切な答えを見つけることができませんでした。

26
Amrut Bidri

アプリケーションにもこの問題があり、reallyの長いデバッグセッションの後、adapter.setHasStableIds(true)が原因であることがわかりました

問題のある行を削除し、問題はようやく解消しました。

それが役に立てば幸い。

11

同じ問題がありましたが、recyclerviewのアニメーターを無効にすることで処理できます。

recyclerView.itemAnimator = null

4
ali samawi

adapter.notifyItemChanged(position);メインスレッドから呼び出す必要があります

ハンドラの代わりに、mainLooperでハンドラを使用します

    new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            //HERE
        }
    });
2

私は同じ問題に直面しましたが、その理由はscrollToPositionを呼び出すことでした。何度も試してみましたが、解決策は、スクロールする前にnotifyDataSetChangedを呼び出すことでした(もちろんすべてUIスレッドから)。多分それは誰かを助けるでしょう。

2
Sir Codesalot

私にとっては、recyclerviewの親ViewGroupからanimateLayoutChanges=“true”を削除した後、問題は解決しました。

1
Levon Petrosyan

これは最初の投稿なので、特定の場合に役立つ問題の別の解決策を投稿します。parentviewを含むrecyclerviewを非表示にして

parentView.setVisibility(View.GONE);

recyclerviewはそれが好きではありません。明らかに、recyclerviewを含むビューを非表示にしたい場合は、View.INVISIBLE

1
Ole

この問題にはいくつかの回避策があります。

  1. 代わりにnotifyDataSetChanged()を呼び出すnotifyItemChanged()。それはそれを解決するためのより非効率的な方法です。

  2. Henrique de Sousaが指摘したように、adapter.setHasStableIds(true)の行を削除すると問題が回避されます。

しかし、サウザートンがコメントした本当の解決策は、アダプターが安定している場合、「hasStableIds」値セットを尊重して実装し、正しくgetItemId()を実行することです。

1
Gonmator