material-components / material-components/material-components-android

[BottomSheetDialog] `AbstractComposeView` can't be inserted a layout file used to a `BottomSheetDialog`.

Aperta
#4,207 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

bug
Lingua principale
Java
Stelle
17.4k
Fork
3.2k
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Descrizione

Description:

  • I have one BottomSheetDialog#setContentView(R.layout.earn_more_view).
  • Inside the layout file, I inserted ComposeEarnMoreView who extends from AbstractComposeView, and Of course, the @Composable override fun Content() was implemented by Composable functions.
  • My app just crashed when I tried to pop up the dialog.

And the main log looks like below:

FATAL EXCEPTION: main
Process: org.alias.staging, PID: 8224
java.lang.IllegalStateException: ViewTreeLifecycleOwner not found from android.widget.FrameLayout{b3ad65d V.E...... ......I. 0,0-0,0 #7f0902db app:id/container}
at androidx.compose.ui.platform.WindowRecomposer_androidKt.createLifecycleAwareWindowRecomposer(WindowRecomposer.android.kt:352)
at androidx.compose.ui.platform.WindowRecomposer_androidKt.createLifecycleAwareWindowRecomposer$default(WindowRecomposer.android.kt:325)
at androidx.compose.ui.platform.WindowRecomposerFactory$Companion.LifecycleAware$lambda$0(WindowRecomposer.android.kt:168)
at androidx.compose.ui.platform.WindowRecomposerFactory$Companion.$r8$lambda$PmWZXv-2LDhDmANvYhil4YZYJuQ(Unknown Source:0)
at androidx.compose.ui.platform.WindowRecomposerFactory$Companion$$ExternalSyntheticLambda0.createRecomposer(Unknown Source:0)
at androidx.compose.ui.platform.WindowRecomposerPolicy.createAndInstallWindowRecomposer$ui_release(WindowRecomposer.android.kt:224)
at androidx.compose.ui.platform.WindowRecomposer_androidKt.getWindowRecomposer(WindowRecomposer.android.kt:300)
at androidx.compose.ui.platform.AbstractComposeView.resolveParentCompositionContext(ComposeView.android.kt:244)
at androidx.compose.ui.platform.AbstractComposeView.ensureCompositionCreated(ComposeView.android.kt:251)
at androidx.compose.ui.platform.AbstractComposeView.onAttachedToWindow(ComposeView.android.kt:283)
at android.view.View.dispatchAttachedToWindow(View.java:21748)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3732)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3739)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3739)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3739)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3739)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3739)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3739)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3739)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3739)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3859)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:3146)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:11127)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1599)
at android.view.Choreographer.doCallbacks(Choreographer.java:1263)
at android.view.Choreographer.doFrame(Choreographer.java:1127)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1549)
at android.os.Handler.handleCallback(Handler.java:966)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:293)
at android.app.ActivityThread.loopProcess(ActivityThread.java:9986)
at android.app.ActivityThread.main(ActivityThread.java:9975)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:586)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1240)

Expected behavior: My app won't crash and the layout file should be shown in the BottomSheetDailog.

Source code: BottomSheetDialog or its parent AppCompatDialog or its delegate AppCompatDelegateImpl has no LifecycleOwner.

If we check the source code of androidx.activity.ComponentDialog, which implements LifecycleOwner and calledwindow!!.decorView.setViewTreeLifecycleOwner(this) when add/setContentView.

But BottomSheetDialog/AppCompatDialog/AppCompatDelegateImpl didn't.

Minimal sample app repro:

class CrashBottomSheetDialog(context: Context) : BottomSheetDialog(context) {
  init {
    setContentView(object : AbstractComposeView(context) {
      @Composable
      override fun Content() {
        Text(text = "Hello, World")
      }
    })
  }
}

Android API version: Android 10

Material Library version: com.google.android.material:material:1.9.0~1.12.0

Device: Huawei Mate 50

Solution:: I found this issue around May, 2023. I thought google team would fix this soon but actually they didn't. So I create an Issue for it to see if I could push google team to fix it inside the material library.

I had a solution like below, hoping it could inspire you guys somehow. Also I could create a PR like the solution below or create a PR inside AppCompatDelegateImpl. Tell me what you think.

class ComponentBottomSheetDialog @JvmOverloads constructor(
  context: Context,
  @StyleRes themeResId: Int = 0
) : BottomSheetDialog(context, themeResId),
  LifecycleOwner,
  SavedStateRegistryOwner {

  private var _lifecycleRegistry: LifecycleRegistry? = null
  private val lifecycleRegistry: LifecycleRegistry
    get() = _lifecycleRegistry ?: LifecycleRegistry(this).also {
      _lifecycleRegistry = it
    }

  private val savedStateRegistryController: SavedStateRegistryController =
    SavedStateRegistryController.create(this)
  override val savedStateRegistry: SavedStateRegistry
    get() = savedStateRegistryController.savedStateRegistry

  override val lifecycle: Lifecycle
    get() = lifecycleRegistry

  override fun onSaveInstanceState(): Bundle {
    val bundle = super.onSaveInstanceState()
    savedStateRegistryController.performSave(bundle)
    return bundle
  }

  @Suppress("ClassVerificationFailure") // needed for onBackInvokedDispatcher call
  @CallSuper
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    savedStateRegistryController.performRestore(savedInstanceState)
    lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
  }

  @CallSuper
  override fun onStart() {
    super.onStart()
    lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
  }

  @CallSuper
  override fun onStop() {
    // This is the closest thing to onDestroy that a Dialog has
    lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    _lifecycleRegistry = null
    super.onStop()
  }

  override fun setContentView(layoutResID: Int) {
    initViewTreeOwners()
    super.setContentView(layoutResID)
  }

  override fun setContentView(view: View) {
    initViewTreeOwners()
    super.setContentView(view)
  }

  override fun setContentView(view: View, params: ViewGroup.LayoutParams?) {
    initViewTreeOwners()
    super.setContentView(view, params)
  }

  override fun addContentView(view: View, params: ViewGroup.LayoutParams?) {
    initViewTreeOwners()
    super.addContentView(view, params)
  }

  private fun initViewTreeOwners() {
    window!!.decorView.setViewTreeLifecycleOwner(this)
    window!!.decorView.setViewTreeSavedStateRegistryOwner(this)
  }
}

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Inizia con BottomSheetDialog, AppCompatDialog e AppCompatDelegateImpl, quindi confronta la configurazione della loro vista di contenuto con androidx.activity.ComponentDialog e la gestione del proprietario dell’albero delle viste. Riproduci il problema con l’esempio CrashBottomSheetDialog fornito; il lavoro è completato quando un AbstractComposeView può essere mostrato in un BottomSheetDialog senza il crash di ViewTreeLifecycleOwner.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
kotlin
Ambito
mobile
Tipo di issue
Bug
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Ferma
Chiarezza
Abbastanza chiara
Idoneità per principianti
45/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.