Problems专题:RecyclerView

Problems专题:RecyclerView

0x01 Called attach on a child which is not detached

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
java.lang.IllegalArgumentException: Called attach on a child which is not detached: BaseViewHolder{2b241e1 position=12 id=-1, oldPos=-1, pLpos:-1} androidx.recyclerview.widget.RecyclerView{afecb06 VFED..... ......ID 0,0-1080,2055 #7f09236e app:id/recycler_view_xxx}, adapter:com.xxxx.adapter.XxxAdapter@cfc75c7, layout:androidx.recyclerview.widget.LinearLayoutManager@24af7f4, context:com.xxxx.XxxActivity@1ed75e2
at androidx.recyclerview.widget.RecyclerView$5.attachViewToParent(RecyclerView.java:917)
at androidx.recyclerview.widget.ChildHelper.attachViewToParent(ChildHelper.java:239)
at androidx.recyclerview.widget.RecyclerView.addAnimatingView(RecyclerView.java:1438)
at androidx.recyclerview.widget.RecyclerView.animateDisappearance(RecyclerView.java:4377)
at androidx.recyclerview.widget.RecyclerView$4.processDisappeared(RecyclerView.java:616)
at androidx.recyclerview.widget.ViewInfoStore.process(ViewInfoStore.java:242)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep3(RecyclerView.java:4210)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3864)
at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4410)
at android.view.View.layout(View.java:22213)
at android.view.ViewGroup.layout(ViewGroup.java:6340)
at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1131)
at android.view.View.layout(View.java:22213)
at android.view.ViewGroup.layout(ViewGroup.java:6340)
at androidx.viewpager.widget.ViewPager.onLayout(ViewPager.java:1775)
at android.view.View.layout(View.java:22213)
at android.view.ViewGroup.layout(ViewGroup.java:6340)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
at android.view.View.layout(View.java:22213)
at android.view.ViewGroup.layout(ViewGroup.java:6340)
at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1131)
at android.view.View.layout(View.java:22213)
at android.view.ViewGroup.layout(ViewGroup.java:6340)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at android.view.View.layout(View.java:22213)
at android.view.ViewGroup.layout(ViewGroup.java:6340)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
at android.view.View.layout(View.java:22213)
at android.view.ViewGroup.layout(ViewGroup.java:6340)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at android.view.View.layout(View.java:22213)
at android.view.ViewGroup.layout(ViewGroup.java:6340)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
at android.view.View.layout(View.java:22213)
at android.view.ViewGroup.layout(ViewGroup.java:6340)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at com.android.internal.policy.DecorView.onLayout(DecorView.java:905)
at android.view.View.layout(View.java:22213)
at android.view.ViewGroup.layout(ViewGroup.java:6340)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:3286)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2757)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1865)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7933)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1018)
at android.view.Choreographer.doCallbacks(Choreographer.java:837)
at android.view.Choreographer.doFrame(Choreographer.java:767)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1003)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:230)
at android.app.ActivityThread.main(ActivityThread.java:7951)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:526)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1034)

问题分析

对同一个 position 位置同时进行notifyItemRemoved(position)notifyItemInserted(position) 操作导致。

解决方案

避免同时对同一个位置先 notifyItemRemoved 再 notifyItemInserted,使用 notifyItemChanged。

1
adapter?.notifyItemChanged(position)

0x02 RecyclerView设置最大高度、宽度

当RecyclerView属性设置为wrap_content+maxHeight时,maxHeight没有效果。

问题分析

当RecyclerView的LayoutManager#isAutoMeasureEnabled()返回true时,RecyclerView高度取决于children view的布局高度,并非取决于RecyclerView自身的测量高度。

解决方案

因此,我们只需要重写LayoutManager的public void setMeasuredDimension(Rect childrenBounds, int wSpec, int hSpec)方法即可为RecyclerView设置最大宽高。

1
2
3
4
5
6
7
8
9
recyclerView.layoutManager = object : LinearLayoutManager(context, RecyclerView.VERTICAL, false) {
override fun setMeasuredDimension(childrenBounds: Rect?, wSpec: Int, hSpec: Int) {
val height = View.MeasureSpec.getSize(hSpec)
val maxHeight = getScreenHeight() * 4 / 5
val realHeight = height.coerceAtMost(maxHeight)
val realHeightSpec = View.MeasureSpec.makeMeasureSpec(realHeight, AT_MOST)
super.setMeasuredDimension(childrenBounds, wSpec, realHeightSpec)
}
}

作者:猫爸iYao
链接:https://www.jianshu.com/p/0dec79ff70df
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

作者

Dench

发布于

2021-06-19

更新于

2021-06-19

许可协议

CC BY-NC-SA 4.0

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×