Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ComposeView in flexbox crashes, because it is not attached when measured #613

Open
1 task done
Direwolfik opened this issue Nov 2, 2022 · 0 comments
Open
1 task done

Comments

@Direwolfik
Copy link

Direwolfik commented Nov 2, 2022

Issues and steps to reproduce

When I try to use ComposeView or AbstractComposeView with FlexboxLayoutManager, it crashes due to

 java.lang.IllegalStateException: Cannot locate windowRecomposer; View androidx.compose.ui.platform.ComposeView{7ae95e1 V.E...... ......I. 0,0-0,0} is not attached to a window
                                                                                                    	at androidx.compose.ui.platform.WindowRecomposer_androidKt.getWindowRecomposer(WindowRecomposer.android.kt:294)
                                                                                                    	at androidx.compose.ui.platform.AbstractComposeView.resolveParentCompositionContext(ComposeView.android.kt:242)
                                                                                                    	at androidx.compose.ui.platform.AbstractComposeView.ensureCompositionCreated(ComposeView.android.kt:249)
...
                                                                                                    	at android.view.View.measure(View.java:25466)
                                                                                                    	at com.google.android.flexbox.FlexboxHelper.calculateFlexLines(FlexboxHelper.java:477)
                                                                                                    	at com.google.android.flexbox.FlexboxHelper.calculateHorizontalFlexLines(FlexboxHelper.java:249)
                                                                                                    	at com.google.android.flexbox.FlexboxLayoutManager.updateLayoutState(FlexboxLayoutManager.java:2112)
                                                                                                    	at com.google.android.flexbox.FlexboxLayoutManager.handleScrollingMainOrientation(FlexboxLayoutManager.java:1993)
                                                                                                    	at com.google.android.flexbox.FlexboxLayoutManager.scrollVerticallyBy(FlexboxLayoutManager.java:1957)
                                                                                                    	at androidx.recyclerview.widget.RecyclerView.scrollStep(RecyclerView.java:2009)

This basically prevents usage of FlexboxLayoutManager with compose views.

Root cause is that FlexboxLayoutManager attempts to measure composable before it is attached to window, which crashes in ComposeView:

/**
 * Get or lazily create a [Recomposer] for this view's window. The view must be attached
 * to a window with a [ViewTreeLifecycleOwner] registered at the root to access this property.
 */
@OptIn(InternalComposeUiApi::class)
internal val View.windowRecomposer: Recomposer
    get() {
        check(isAttachedToWindow) {
            "Cannot locate windowRecomposer; View $this is not attached to a window"
        }
        val rootView = contentChild
        return when (val rootParentRef = rootView.compositionContext) {
            null -> WindowRecomposerPolicy.createAndInstallWindowRecomposer(rootView)
            is Recomposer -> rootParentRef
            else -> error("root viewTreeParentCompositionContext is not a Recomposer")
        }
    }

Expected behavior

It should not crash, as it does not crash with other managers (e.g. LinearLayourManager)

Version of the flexbox library

Flexbox: 3.0.0
Compose: 1.3.0
Recycler view: 1.3.0-rc1

Link to code

class ComposeAdapter : RecyclerView.Adapter<ComposeHolder>() {

    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int,
    ): MyComposeViewHolder {
        return ComposeHolder(ComposeView(parent.context))
    }

class MyComposeViewHolder(
    val composeView: ComposeView
) : RecyclerView.ViewHolder(composeView) {

    fun bind(input: String) {
        composeView.setContent {
            MdcTheme {
                Text(input)
            }
        }
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant