0

I want to use Jetpack Compose to implement the floting window UI. But I got this error:java.lang.IllegalStateException: ViewTreeLifecycleOwner not found from androidx.compose.ui.platform.ComposeView Here are my floating window service code:

class FloatingService : Service() {
    private lateinit var windowManager: WindowManager

    private lateinit var contentView: View

    private lateinit var layoutParams: WindowManager.LayoutParams

    // init windowManager, contentView, layoutParams
    override fun onCreate() {
        super.onCreate()

        windowManager = getSystemService<WindowManager>()!!


        contentView = ComposeView(this).apply {
            setContent {
                Text(text = "Hello World")
            }
        }

        layoutParams = WindowManager.LayoutParams().apply {
            type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
            else
                WindowManager.LayoutParams.TYPE_PHONE

            width = WindowManager.LayoutParams.WRAP_CONTENT
            height = WindowManager.LayoutParams.WRAP_CONTENT
            flags =
                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
            x = 0
            y = 200

            format = PixelFormat.RGBA_8888 // give window transparent background

            gravity = Gravity.TOP or Gravity.END // layout right
        }
    }

    // add contentView to windowManager
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        windowManager.addView(
            contentView,
            layoutParams
        )
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onDestroy() {
        super.onDestroy()
        windowManager.removeView(contentView)
    }

    override fun onBind(intent: Intent?): IBinder? {
        return null
    }
}

I am confirm it can work good when you init contentView by using Button(this). What's more, I have tried using LifecycleService which in implementation("androidx.lifecycle:lifecycle-service:2.5.1") and init ViewTreeLifecycleOwner by using ViewTreeLifecycleOwner.set(contentView, this), the result is that I got another error: java.lang.IllegalStateException: Composed into the View which doesn't propagateViewTreeSavedStateRegistryOwner!.

Ting
  • 21
  • 3
  • Does this answer your question? [Using a ComposeView inside layout or a BottomSheetDialog throws exception](https://stackoverflow.com/questions/72395779/using-a-composeview-inside-layout-or-a-bottomsheetdialog-throws-exception) – Ricky Mo Jun 19 '23 at 02:34
  • @RickyMo I don't think it's the same as this problem. The core of this problem is how to load ComposeView inside Service, that problem not include this point. But thanks all the same. – Ting Jun 19 '23 at 03:22
  • This post might also help: [InputMethodService with Jetpack Compose - ComposeView causes: Composed into the View which doesn't propagate ViewTreeLifecycleOwner](https://stackoverflow.com/questions/65755763/inputmethodservice-with-jetpack-compose-composeview-causes-composed-into-the) – Ricky Mo Jun 19 '23 at 03:24
  • @RickyMo [InputMethodService with Jetpack Compose - ComposeView causes: Composed into the View which doesn't propagate ViewTreeLifecycleOwner](https://stackoverflow.com/questions/65755763/inputmethodservice-with-jetpack-compose-composeview-causes-composed-into-the). It is somewhat similar to my question, I have already solved it, thank you! – Ting Jun 19 '23 at 06:52

1 Answers1

1

OK. Here is my own solution

  1. add this dependence:
implementation("androidx.lifecycle:lifecycle-service:2.5.1")
  1. make the following changes based on the code in my question
import android.content.Intent
import android.view.View
import androidx.compose.material3.Text
import androidx.compose.ui.platform.ComposeView
import androidx.lifecycle.LifecycleService
import androidx.savedstate.SavedStateRegistry
import androidx.savedstate.SavedStateRegistryController
import androidx.savedstate.SavedStateRegistryOwner

// you need extends LifecycleService and implement SavedStateRegistryOwner.
class YourService() : LifecycleService(), SavedStateRegistryOwner {

    // create a SavedStateRegistryController to get SavedStateRegistry object.
    private val savedStateRegistryController = SavedStateRegistryController.create(this)

    private lateinit var contentView: View

    override fun onCreate() {
        super.onCreate()
        // init your SavedStateRegistryController
        savedStateRegistryController.performAttach() // you can ignore this line, becase performRestore method will auto call performAttach() first.
        savedStateRegistryController.performRestore(null)

        // configure your ComposeView
        contentView = ComposeView(this).apply {
            setViewTreeSavedStateRegistryOwner(this@YourService)
            setContent {
                Text(text = "Hello World")
            }
        }
        ViewTreeLifecycleOwner.set(contentView, this)

        // init your WindowManager and LayoutParams
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        return super.onStartCommand(intent, flags, startId)
        // add your contentView to windowManager
    }

    override fun onDestroy() {
        super.onDestroy()
        // remove your view from your windowManager
    }

    // override savedStateRegistry property from SavedStateRegistryOwner interface.
    override val savedStateRegistry: SavedStateRegistry
        get() = savedStateRegistryController.savedStateRegistry
}
  1. register you service and declare android.permission.SYSTEM_ALERT_WINDOW permission.
Ting
  • 21
  • 3