Skip to content

Commit 49106df

Browse files
committed
fix(android): resolve Scrapped or attached views may not be recycled crash
1 parent 5a4638a commit 49106df

2 files changed

Lines changed: 41 additions & 10 deletions

File tree

android/src/main/java/com/reactnativepagerview/PagerViewViewManager.kt

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.reactnativepagerview
22

33
import android.view.View
44
import android.view.ViewGroup
5+
import androidx.recyclerview.widget.RecyclerView
56
import androidx.viewpager2.widget.ViewPager2
67
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
78
import com.facebook.infer.annotation.Assertions
@@ -88,6 +89,21 @@ class PagerViewViewManager : ViewGroupManager<NestedScrollableHost>(), RNCViewPa
8889
return host
8990
}
9091

92+
private fun stopScrollIfNeeded(host: NestedScrollableHost) {
93+
val recyclerView = (host.getChildAt(0) as? ViewPager2)?.getChildAt(0) as? RecyclerView
94+
recyclerView?.stopScroll()
95+
}
96+
97+
override fun onDropViewInstance(view: NestedScrollableHost) {
98+
val viewPager = view.getChildAt(0) as? ViewPager2
99+
val recyclerView = viewPager?.getChildAt(0) as? RecyclerView
100+
recyclerView?.let {
101+
it.stopScroll()
102+
it.swapAdapter(null, false)
103+
}
104+
super.onDropViewInstance(view)
105+
}
106+
91107
override fun addView(host: NestedScrollableHost, child: View, index: Int) {
92108
PagerViewViewManagerImpl.addView(host, child, index)
93109
}
@@ -99,14 +115,17 @@ class PagerViewViewManager : ViewGroupManager<NestedScrollableHost>(), RNCViewPa
99115
}
100116

101117
override fun removeView(parent: NestedScrollableHost, view: View) {
118+
stopScrollIfNeeded(parent)
102119
PagerViewViewManagerImpl.removeView(parent, view)
103120
}
104121

105122
override fun removeAllViews(parent: NestedScrollableHost) {
123+
stopScrollIfNeeded(parent)
106124
PagerViewViewManagerImpl.removeAllViews(parent)
107125
}
108126

109127
override fun removeViewAt(parent: NestedScrollableHost, index: Int) {
128+
stopScrollIfNeeded(parent)
110129
PagerViewViewManagerImpl.removeViewAt(parent, index)
111130
}
112131

@@ -206,4 +225,4 @@ class PagerViewViewManager : ViewGroupManager<NestedScrollableHost>(), RNCViewPa
206225
PageScrollStateChangedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onPageScrollStateChanged"),
207226
PageSelectedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onPageSelected"))
208227
}
209-
}
228+
}

android/src/main/java/com/reactnativepagerview/ViewPagerAdapter.kt

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,28 @@ class ViewPagerAdapter() : Adapter<ViewPagerViewHolder>() {
1717
override fun onBindViewHolder(holder: ViewPagerViewHolder, index: Int) {
1818
val container: FrameLayout = holder.container
1919
val child = getChildAt(index)
20-
holder.setIsRecyclable(false)
2120

2221
if (container.childCount > 0) {
2322
container.removeAllViews()
2423
}
2524

2625
if (child.parent != null) {
27-
(child.parent as FrameLayout).removeView(child)
26+
(child.parent as ViewGroup).removeView(child)
2827
}
2928

3029
container.addView(child)
3130
}
3231

32+
override fun onViewRecycled(holder: ViewPagerViewHolder) {
33+
super.onViewRecycled(holder)
34+
holder.container.removeAllViews()
35+
}
36+
37+
override fun onFailedToRecycleView(holder: ViewPagerViewHolder): Boolean {
38+
holder.container.removeAllViews()
39+
return true
40+
}
41+
3342
override fun getItemCount(): Int {
3443
return childrenViews.size
3544
}
@@ -45,17 +54,16 @@ class ViewPagerAdapter() : Adapter<ViewPagerViewHolder>() {
4554

4655
fun removeChild(child: View) {
4756
val index = childrenViews.indexOf(child)
48-
49-
if(index > -1) {
57+
58+
if (index > -1) {
5059
removeChildAt(index)
5160
}
5261
}
5362

5463
fun removeAll() {
55-
for (index in 1..childrenViews.size) {
56-
val child = childrenViews[index-1]
57-
if (child.parent?.parent != null) {
58-
(child.parent.parent as ViewGroup).removeView(child.parent as View)
64+
for (child in childrenViews) {
65+
if (child.parent != null) {
66+
(child.parent as ViewGroup).removeView(child)
5967
}
6068
}
6169
val removedChildrenCount = childrenViews.size
@@ -64,7 +72,11 @@ class ViewPagerAdapter() : Adapter<ViewPagerViewHolder>() {
6472
}
6573

6674
fun removeChildAt(index: Int) {
67-
if (index >= 0 && index < childrenViews.size) {
75+
if (index >= 0 && index < childrenViews.size) {
76+
val child = childrenViews[index]
77+
if (child.parent != null) {
78+
(child.parent as ViewGroup).removeView(child)
79+
}
6880
childrenViews.removeAt(index)
6981
notifyItemRemoved(index)
7082
}

0 commit comments

Comments
 (0)