3

This is related to this question

As described here I was able to create a keyboard with Jetpack Compose. Now after I upgrade the project from alpha-11 to alpha-12 the code broke (and is still broken in beta-01) and I get the following error whenever I try to open the keyboard:

 java.lang.IllegalStateException: ViewTreeLifecycleOwner not found from DecorView@aaf805f[InputMethod]
        at androidx.compose.ui.platform.WindowRecomposer_androidKt.createLifecycleAwareViewTreeRecomposer(WindowRecomposer.android.kt:214)
        at androidx.compose.ui.platform.WindowRecomposer_androidKt.access$createLifecycleAwareViewTreeRecomposer(WindowRecomposer.android.kt:1)
        at androidx.compose.ui.platform.WindowRecomposerFactory$Companion$LifecycleAware$1.createRecomposer(WindowRecomposer.android.kt:98)
        at androidx.compose.ui.platform.WindowRecomposerPolicy.createAndInstallWindowRecomposer$ui_release(WindowRecomposer.android.kt:151)
        at androidx.compose.ui.platform.WindowRecomposer_androidKt.getWindowRecomposer(WindowRecomposer.android.kt:199)
        at androidx.compose.ui.platform.AbstractComposeView.ensureCompositionCreated(ComposeView.android.kt:176)
        at androidx.compose.ui.platform.AbstractComposeView.onAttachedToWindow(ComposeView.android.kt:207)
        at android.view.View.dispatchAttachedToWindow(View.java:20105)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3430)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3437)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3437)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3437)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3437)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3437)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2052)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1745)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7768)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:967)
        at android.view.Choreographer.doCallbacks(Choreographer.java:791)
        at android.view.Choreographer.doFrame(Choreographer.java:726)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:952)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:491)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:940)

That's very weird because I have set the ViewTreeLifecycleOwner here and worked perfectly fine in previous versions of compose until alpha-12

The error gives me no idea of what's broken and what I should change. Maybe you can help me.

Here you can find all code for a reproducible example

Yannick
  • 4,833
  • 8
  • 38
  • 63
  • Does this answer your question? [ViewTreeLifecycleOwner not found from DecorView@2da7146\[MyActivity\]](https://stackoverflow.com/questions/66382502/viewtreelifecycleowner-not-found-from-decorview2da7146myactivity) – Mahozad Sep 18 '21 at 07:43

1 Answers1

7

The error message says:

ViewTreeLifecycleOwner not found from DecorView@aaf805f[InputMethod]

Compose looks for a ViewTreeLifecycleOwner set on the DecorView of your whole Window, not the one set on your View itself.

Therefore instead of setting the ViewTrees on the ComposeKeyboardView you return, instead use the InputMethodService API of getWindow() with getDecorView() to get the DecorView of your window.

override fun onCreateInputView(): View {
    val view = ComposeKeyboardView(this)
    window?.window?.decorView?.let { decorView ->
        ViewTreeLifecycleOwner.set(decorView, this)
        ViewTreeViewModelStoreOwner.set(decorView, this)
        ViewTreeSavedStateRegistryOwner.set(decorView, this)
    }
    return view
}
Yannick
  • 4,833
  • 8
  • 38
  • 63
ianhanniballake
  • 191,609
  • 30
  • 470
  • 443
  • Thank you very much. I don't understand why it worked before. You've forgot an `window?` in the chain. I suggested an edit – Yannick Mar 02 '21 at 21:49
  • 1
    The changes were deep in how recomposition happens, particularly in cases where you had nested composition scopes (i.e., a `ComposeView` that inflates an `AndroidView` that then inflates a `ComposeView` - nested, but separate scopes) that now requires a global idea of Lifecycle and the Window's `decorView` is that storage mechanism. – ianhanniballake Mar 02 '21 at 22:05
  • Now animations are broken. Is that related: https://stackoverflow.com/questions/66448080/animations-and-effects-broken-on-keyboard-written-in-jetpack-compos ? – Yannick Mar 02 '21 at 22:30
  • No idea about that one, sorry. – ianhanniballake Mar 02 '21 at 23:32
  • ViewTreeSavedStateRegistryOwner now no longer exists – dessalines Mar 07 '23 at 15:58
  • @thouliha - the APIs certainly still exist (in fact, if your code was in Java it would still look exactly the same), but if you [read the release notes](https://developer.android.com/jetpack/androidx/releases/savedstate#1.2.0), you'll see that they are now Kotlin extensions on View. – ianhanniballake Mar 07 '23 at 18:11