ダウンロードできる曲を表示するリストとして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)
私はこれの解決策を見つけるために検索しましたが、適切な答えを見つけることができませんでした。
アプリケーションにもこの問題があり、reallyの長いデバッグセッションの後、adapter.setHasStableIds(true)
が原因であることがわかりました
問題のある行を削除し、問題はようやく解消しました。
それが役に立てば幸い。
同じ問題がありましたが、recyclerviewのアニメーターを無効にすることで処理できます。
recyclerView.itemAnimator = null
adapter.notifyItemChanged(position);
メインスレッドから呼び出す必要があります
ハンドラの代わりに、mainLooperでハンドラを使用します
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
//HERE
}
});
私は同じ問題に直面しましたが、その理由はscrollToPosition
を呼び出すことでした。何度も試してみましたが、解決策は、スクロールする前にnotifyDataSetChanged
を呼び出すことでした(もちろんすべてUIスレッドから)。多分それは誰かを助けるでしょう。
私にとっては、recyclerviewの親ViewGroupからanimateLayoutChanges=“true”
を削除した後、問題は解決しました。
これは最初の投稿なので、特定の場合に役立つ問題の別の解決策を投稿します。parentview
を含むrecyclerview
を非表示にして
parentView.setVisibility(View.GONE);
recyclerviewはそれが好きではありません。明らかに、recyclerviewを含むビューを非表示にしたい場合は、View.INVISIBLE
。
この問題にはいくつかの回避策があります。
代わりにnotifyDataSetChanged()
を呼び出すnotifyItemChanged()
。それはそれを解決するためのより非効率的な方法です。
Henrique de Sousaが指摘したように、adapter.setHasStableIds(true)
の行を削除すると問題が回避されます。
しかし、サウザートンがコメントした本当の解決策は、アダプターが安定している場合、「hasStableIds」値セットを尊重して実装し、正しくgetItemId()
を実行することです。