Jetpack Compose: сбой при добавлении представления в оконный менеджер

#android #android-jetpack-compose

#Android #android-jetpack-compose

Вопрос:

Я попытался добавить представление jetpack compose в диспетчер окон для представления наложения приложения. Но приложение сбой. Я использовал следующий код для добавления представления jetpack compose. Он работает правильно, когда я попробовал макет XML. Кто-нибудь еще сталкивался с этой проблемой? Заранее спасибо.

 private val overlayWindowManager by lazy {
    getSystemService(Context.WINDOW_SERVICE)
            as WindowManager
}

 private fun initWindowManager() {
    val params = WindowManager.LayoutParams(
        WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
        WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
        PixelFormat.TRANSLUCENT
    )
    params.gravity = Gravity.RIGHT or Gravity.TOP
    overlayWindowManager.addView(ComposeView(this).apply {
        setContent {  Text("WINDOW") }
    }, params)
}
  

Журнал ошибок

  java.lang.IllegalStateException: ViewTreeLifecycleOwner is not present in this window. Use ComponentActivity, FragmentActivity or AppCompatActivity to configure ViewTreeLifecycleOwner automatically, or call ViewTreeLifecycleOwner.set() for this View or an ancestor in the same window.
    at androidx.compose.ui.platform.AbstractComposeView.onAttachedToWindow(ComposeView.kt:176)
    at android.view.View.dispatchAttachedToWindow(View.java:20479)
    at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3489)
    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2417)
    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1952)
    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8171)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:972)
    at android.view.Choreographer.doCallbacks(Choreographer.java:796)
    at android.view.Choreographer.doFrame(Choreographer.java:731)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:223)
    at android.app.ActivityThread.main(ActivityThread.java:7656)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
  

Ответ №1:

Для ComposeView требуется LifecycleOwner , но у нас его здесь нет, поэтому мы должны его создать.

 internal class MyLifecycleOwner : SavedStateRegistryOwner {

    private var mLifecycleRegistry: LifecycleRegistry = LifecycleRegistry(this)
    private var mSavedStateRegistryController: SavedStateRegistryController = SavedStateRegistryController.create(this)

    val isInitialized: Boolean
        get() = true

    override fun getLifecycle(): Lifecycle {
        return mLifecycleRegistry
    }

    fun setCurrentState(state: Lifecycle.State) {
        mLifecycleRegistry.currentState = state
    }

    fun handleLifecycleEvent(event: Lifecycle.Event) {
        mLifecycleRegistry.handleLifecycleEvent(event)
    }

    override fun getSavedStateRegistry(): SavedStateRegistry {
        return mSavedStateRegistryController.savedStateRegistry
    }

    fun performRestore(savedState: Bundle?) {
        mSavedStateRegistryController.performRestore(savedState)
    }

    fun performSave(outBundle: Bundle) {
        mSavedStateRegistryController.performSave(outBundle)
    }
}
  

А затем используйте MyLifecycleOwner в качестве ViewTreeLifecycleOwner composeView.

 private fun initWindowManager() {
    val params = ...
    val composeView = ComposeView(context = context)
    composeView.setContent { . . . }

    val lifecycleOwner = MyLifecycleOwner()
    lifecycleOwner.performRestore(null)
    lifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
    ViewTreeLifecycleOwner.set(composeView, lifecycleOwner)
    ViewTreeSavedStateRegistryOwner.set(composeView, lifecycleOwner)

    val viewModelStore = ViewModelStore()
    ViewTreeViewModelStoreOwner.set(composeView) { viewModelStore }

    overlayWindowManager.addView(composeView, params) 
}
  

Вы можете проверить это с более подробной информацией здесь https://gist.github.com/handstandsam/6ecff2f39da72c0b38c07aa80bbb5a2f

Ответ №2:

Используйте ViewTreeLifecycleOwner.set() :

 windowManager.addView(ComposeView(this).apply {
    ViewTreeLifecycleOwner.set(this, activity)
    setContent {  Text("WINDOW") }
}, params)
  

Ответ №3:

На какой класс распространяется ваша основная деятельность? похоже, ваш ответ находится в первой строке трассировки стека Use ComponentActivity, FragmentActivity or AppCompatActivity to configure ViewTreeLifecycleOwner automatically

или

call ViewTreeLifecycleOwner.set() for this View or an ancestor in the same window