Giphy / giphy-react-native-sdk

GIPHY React Native SDK
https://developers.giphy.com
Apache License 2.0
67 stars 25 forks source link

[Fatal Error] Scrapped or attached views may not be recycled. isScrap:false isAttached:true com.giphy.sdk.ui.universallist.SmartGridRecyclerView #172

Closed enterteg closed 4 months ago

enterteg commented 5 months ago

🐛 Bug Report

On Android When I open the new screen with GiphyGridView and I start scrolling the list + close the screen - it almost every time crashes the app with the following error:

FATAL EXCEPTION: main
Process: com.***.***, PID: 14891
java.lang.IllegalArgumentException: Scrapped or attached views may not be recycled. isScrap:false isAttached:true com.giphy.sdk.ui.universallist.SmartGridRecyclerView{29244f2 VFED..... ......ID 0,0-1080,1525 #7f09011f app:id/gifRecycler}, adapter:com.giphy.sdk.ui.universallist.SmartGridAdapter@e16c80d, layout:com.giphy.sdk.ui.universallist.WrapStaggeredGridLayoutManager@e754743, context:com.***.***.MainActivity@91b078e
    at androidx.recyclerview.widget.RecyclerView$Recycler.recycleViewHolderInternal(RecyclerView.java:7071)
    at androidx.recyclerview.widget.RecyclerView$Recycler.quickRecycleScrapView(RecyclerView.java:7194)
    at androidx.recyclerview.widget.RecyclerView$LayoutManager.removeAndRecycleScrapInt(RecyclerView.java:10076)
    at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep3(RecyclerView.java:4717)
    at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:4367)
    at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4919)
    at android.view.View.layout(View.java:23324)
    at android.view.ViewGroup.layout(ViewGroup.java:6505)
    at com.giphy.sdk.ui.universallist.SmartGridRecyclerView.requestLayout$lambda$9(SmartGridRecyclerView.kt:514)
    at com.giphy.sdk.ui.universallist.SmartGridRecyclerView.$r8$lambda$EKVNT-jtDPlC2JZgWtnoI0RbS_Y(Unknown Source:0)
    at com.giphy.sdk.ui.universallist.SmartGridRecyclerView$$ExternalSyntheticLambda1.run(Unknown Source:2)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:233)
    at android.os.Looper.loop(Looper.java:344)
    at android.app.ActivityThread.main(ActivityThread.java:8210)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:584)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1034)

To Reproduce

  1. Open the screen which renders the GiphyGridView
  2. Wait for Gifs to load
  3. Start scrolling and close the screen when list is still scrolling

This sometimes also happens when I select one of the gifs and as result just close the screen.

Expected behavior

App should not crash.

Actual Behavior

Fatal error.

Your Environment

"dependencies": {
    "@giphy/react-native-sdk": "^3.2.3",
    "expo": "~50.0.14",
    "expo-status-bar": "~1.11.1",
    "react": "18.2.0",
    "react-native": "0.73.6",
    "expo-dev-client": "~3.3.11",
    "typescript": "^5.3.0",
    "@types/react": "~18.2.45",
    "expo-router": "~3.4.8",
    "react-native-safe-area-context": "4.8.2",
    "react-native-screens": "~3.29.0",
    "expo-linking": "~6.2.2",
    "expo-constants": "~15.4.5"
  },

Reproducible Demo

Created a minimal reproduction example repo with expo and expo-router (you need to add .env file with proper giphy key to make it work): https://github.com/enterteg/TestGiphy

enterteg commented 5 months ago

Looks like this helps to prevent the crash:

  1. In RTNGiphyGridView.kt add:

    fun onDropViewInstance() {
    gridView.children.forEach {
      (it as? ViewGroup)?.let { vg ->
        vg.removeAllViews()
        vg.clearDisappearingChildren()
      }
    }
    gridView.removeAllViews()
    gridView.clearDisappearingChildren()
    removeAllViews()
    }
  2. In RTNGiphyGridViewManager.kt add:

    override fun onDropViewInstance(view: RTNGiphyGridView) {
    view.onDropViewInstance()
    }
ALexanderLonsky commented 4 months ago

Hey @enterteg, Thank you for flagging this and for the helpful response! Indeed, this issue occurs only in React Native, it doesn't happen in the Native Android SDK. The only solution seems to be overriding onDropViewInstance, since onDetachedFromWindow is triggered after the crash occurs. This issue might be related to how React Native handles views, as I've also encountered the crash when trying to use a standard Android recycler view for a list of static texts.

I plan to release a new version with the fix on Monday.