Passing data from React ViewGroupManager to Fragment

27 Views Asked by At

I have a view manager extending ViewGroupManager that when receives a command, it creates a fragment. Would be dangerous and lead to memory leaks to store a reference of the created fragment to pass data?


class MyViewManager(
    private val reactContext: ReactApplicationContext
) : ViewGroupManager<FrameLayout>() {
    private var propWidth: Int? = null
    private var propHeight: Int? = null
    private var callback: Callback? = null
    override fun getName() = REACT_CLASS

    override fun createViewInstance(reactContext: ThemedReactContext) =
        FrameLayout(reactContext)


    override fun getCommandsMap() = mapOf("create" to COMMAND_CREATE)

    override fun receiveCommand(
        root: FrameLayout,
        commandId: String,
        args: ReadableArray?
    ) {
        super.receiveCommand(root, commandId, args)
        val reactNativeViewId = requireNotNull(args).getInt(0)

        when (commandId.toInt()) {
            COMMAND_CREATE -> createFragment(root, reactNativeViewId)
        }
    }

    @ReactPropGroup(names = ["width", "height"], customType = "Style")
    fun setStyle(view: FrameLayout, index: Int, value: Int) {
        if (index == 0) propWidth = value
        if (index == 1) propHeight = value
    }


    fun createFragment(root: FrameLayout, reactNativeViewId: Int) {
        val parentView = root.findViewById<ViewGroup>(reactNativeViewId)
        setupLayout(parentView)

        val myFragment = MyFragment()
        callback = myFragment
        val activity = reactContext.currentActivity as FragmentActivity
        activity.supportFragmentManager
            .beginTransaction()
            .replace(reactNativeViewId, myFragment, "MyFragmentTag")
            .commit()
    }

    @ReactProp(name = "nativeData")
    fun setNativeData(view: FrameLayout, data: String?) {
        if (data != null) {
            callback?.passNativeData(data)
        }
    }

    fun setupLayout(view: View) {
        Choreographer.getInstance().postFrameCallback(object : Choreographer.FrameCallback {
            override fun doFrame(frameTimeNanos: Long) {
                manuallyLayoutChildren(view)
                view.viewTreeObserver.dispatchOnGlobalLayout()
                Choreographer.getInstance().postFrameCallback(this)
            }
        })
    }

    private fun manuallyLayoutChildren(view: View) {
        // propWidth and propHeight coming from react-native props
        val width = requireNotNull(propWidth)
        val height = requireNotNull(propHeight)

        view.measure(
            View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
            View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)
        )

        view.layout(0, 0, width, height)
    }

    companion object {
        private const val REACT_CLASS = "MyViewManager"
        private const val COMMAND_CREATE = 12345
    }
}

MyFragment implements the Callback interface. If this approach is not correct, how could I pass data to the fragment every time setNativeData is called?

0

There are 0 best solutions below