使用Jetpack Compose的InputMethodService-ComposeView原因:组合到不传播ViewTreeLifecycleOwner的View中 [英] InputMethodService with Jetpack Compose - ComposeView causes: Composed into the View which doesn't propagate ViewTreeLifecycleOwner

查看:372
本文介绍了使用Jetpack Compose的InputMethodService-ComposeView原因:组合到不传播ViewTreeLifecycleOwner的View中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您可以在 Github 上找到一个示例项目来重现该问题.

You can find a sample project to reproduce the issue on Github

我一直在尝试将Jetpack Compose用于键盘UI.最终,当我尝试通过InputMethodService给键盘充气时

I've been trying to use Jetpack Compose for a Keyboard UI. Ultimately, When I try to inflate the Keyboard via the InputMethodService

class IMEService : InputMethodService() {

    override fun onCreateInputView(): View = KeyboardView(this)
}

使用此视图

class KeyboardView(context: Context) : FrameLayout(context)  {

    init {
        val view = ComposeView(context).apply {
            setContent {
                Keyboard() //<- This is the actual compose UI function
            }
        }
        addView(view)
    }

}

class KeyboardView2 constructor(
    context: Context,

    ) : AbstractComposeView(context) {

  
    @Composable
    override fun Content() {
        Keyboard()
    }
}

但是,当我尝试使用键盘时,出现以下错误

However, when I try to use the keyboard I get the following error

java.lang.IllegalStateException: Composed into the View which doesn't propagate ViewTreeLifecycleOwner!
        at androidx.compose.ui.platform.AndroidComposeView.onAttachedToWindow(AndroidComposeView.kt:599)
        at android.view.View.dispatchAttachedToWindow(View.java:19676)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3458)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3465)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3465)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3465)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3465)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3465)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3465)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3465)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2126)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1817)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7779)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1031)
        at android.view.Choreographer.doCallbacks(Choreographer.java:854)
        at android.view.Choreographer.doFrame(Choreographer.java:789)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1016)
        at android.os.Handler.handleCallback(Handler.java:914)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:227)
        at android.app.ActivityThread.main(ActivityThread.java:7582)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:953)

官方文档状态

您必须将ComposeView附加到ViewTreeLifecycleOwner.ViewTreeLifecycleOwner允许在保留构图的同时重复附加和分离视图.ComponentActivity,FragmentActivity和AppCompatActivity都是实现ViewTreeLifecycleOwner的类的所有示例

You must attach the ComposeView to a ViewTreeLifecycleOwner. The ViewTreeLifecycleOwner allows the view to be attached and detached repeatedly while preserving the composition. ComponentActivity, FragmentActivity and AppCompatActivity are all examples of classes that implement ViewTreeLifecycleOwner

但是,我不能使用 ComponentActivity FragmentActivity AppCompatActivity 来膨胀调用组合代码的View.我被困于实现 ViewTreeLifecycleOwner .我不知道该怎么办.

However, I cannot use ComponentActivity, FragmentActivity, or AppCompatActivity to inflate the View which calls the compose code. I became stuck with implementing ViewTreeLifecycleOwner. I don't know how to do it.

如何使用 @Composable 函数作为输入法视图?

How can I use @Composable functions as an Input Method View?

正如CommonsWare所建议的那样,我使用了 ViewTreeLifecycleOwner.set(...)方法,还必须实现 ViewModelStoreOwner SavedStateRegistryOwner :

As CommonsWare suggested I used the ViewTreeLifecycleOwner.set(...) method and I also had to implement ViewModelStoreOwner and SavedStateRegistryOwner as well:

class IMEService : InputMethodService(), LifecycleOwner, ViewModelStoreOwner,
    SavedStateRegistryOwner {

    override fun onCreateInputView(): View {
        val view = KeyboardView2(this)
        ViewTreeLifecycleOwner.set(view, this)
        ViewTreeViewModelStoreOwner.set(view, this)
        ViewTreeSavedStateRegistryOwner.set(view, this)
        return view
    }


    //Lifecycle Methods

    private var lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(this)

    override fun getLifecycle(): Lifecycle {
        return lifecycleRegistry
    }


    private fun handleLifecycleEvent(event: Lifecycle.Event) =
        lifecycleRegistry.handleLifecycleEvent(event)


    override fun onCreate() {
        super.onCreate()
        handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
    }

    override fun onDestroy() {
        super.onDestroy()
        handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    }


    //ViewModelStore Methods
    private val store = ViewModelStore()

    override fun getViewModelStore(): ViewModelStore = store

    //SaveStateRegestry Methods

    private val savedStateRegistry = SavedStateRegistryController.create(this)

    override fun getSavedStateRegistry(): SavedStateRegistry = savedStateRegistry.savedStateRegistry
}

现在我收到一个新错误

  java.lang.IllegalStateException: You can consumeRestoredStateForKey only after super.onCreate of corresponding component
        at androidx.savedstate.SavedStateRegistry.consumeRestoredStateForKey(SavedStateRegistry.java:77)
        at androidx.compose.ui.platform.DisposableUiSavedStateRegistryKt.DisposableUiSavedStateRegistry(DisposableUiSavedStateRegistry.kt:69)
        at androidx.compose.ui.platform.DisposableUiSavedStateRegistryKt.DisposableUiSavedStateRegistry(DisposableUiSavedStateRegistry.kt:44)
        at androidx.compose.ui.platform.AndroidAmbientsKt.ProvideAndroidAmbients(AndroidAmbients.kt:162)
        at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$3.invoke(Wrapper.kt:261)
[...]

这在某种程度上与生命周期事件传播有关,因为当我注释掉 onCreate onDestroy 方法时,键盘可以正常打开,而不可见

This is somehow related to the lifecycle event propagation because when I comment out the onCreate and onDestroy methods the keyboard works opens without crashes, but the keyboard is not visible

推荐答案

ComponentActivity 中寻找类似的实现之后我终于想出了一个可行的解决方案:

After looking for similar implementations in ComponentActivity I finally came up with a working solution:

class IMEService : InputMethodService(), LifecycleOwner, ViewModelStoreOwner,
    SavedStateRegistryOwner {

    override fun onCreateInputView(): View {
        val view = ComposeKeyboardView(this)
        ViewTreeLifecycleOwner.set(view, this)
        ViewTreeViewModelStoreOwner.set(view, this)
        ViewTreeSavedStateRegistryOwner.set(view, this)
        return view
    }


    //Lifecylce Methods

    private var lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(this)

    override fun getLifecycle(): Lifecycle {
        return lifecycleRegistry
    }


    private fun handleLifecycleEvent(event: Lifecycle.Event) =
        lifecycleRegistry.handleLifecycleEvent(event)

    override fun onCreate() {
        super.onCreate()
        savedStateRegistry.performRestore(null)
        handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
    }



    override fun onDestroy() {
        super.onDestroy()
        handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    }


    //ViewModelStore Methods
    private val store = ViewModelStore()

    override fun getViewModelStore(): ViewModelStore = store

    //SaveStateRegestry Methods

    private val savedStateRegistry = SavedStateRegistryController.create(this)

    override fun getSavedStateRegistry(): SavedStateRegistry = savedStateRegistry.savedStateRegistry
}

我不知道它是否是性能上最好的实现,但即使在较旧的设备上也能正常工作.赞赏改进想法

I don't know if it's the best implementation in terms of performance but it works fine even on older devices. Improvement ideas are appreciated

这篇关于使用Jetpack Compose的InputMethodService-ComposeView原因:组合到不传播ViewTreeLifecycleOwner的View中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆