如何在Service中使用Jetpack Compose。

huangapple go评论59阅读模式
英文:

how to use Jetpack Compose in Service

问题

I want to use Jetpack Compose to implement the floating 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 confirming it can work well when you initialize contentView by using Button(this). Furthermore, I have tried using LifecycleService which is in implementation("androidx.lifecycle:lifecycle-service:2.5.1") and initializing ViewTreeLifecycleOwner by using ViewTreeLifecycleOwner.set(contentView, this), but the result is that I got another error: java.lang.IllegalStateException: Composed into the View which doesn't propagate ViewTreeSavedStateRegistryOwner!.

英文:

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&lt;WindowManager&gt;()!!


        contentView = ComposeView(this).apply {
            setContent {
                Text(text = &quot;Hello World&quot;)
            }
        }

        layoutParams = WindowManager.LayoutParams().apply {
            type = if (Build.VERSION.SDK_INT &gt;= 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(&quot;androidx.lifecycle:lifecycle-service:2.5.1&quot;) 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&#39;t propagateViewTreeSavedStateRegistryOwner!.

答案1

得分: 1

以下是您提供的翻译:

  1. 添加此依赖项:
implementation("androidx.lifecycle:lifecycle-service:2.5.1")
  1. 根据我问题中的代码进行以下更改:
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

// 您需要扩展 LifecycleService 并实现 SavedStateRegistryOwner。
class YourService() : LifecycleService(), SavedStateRegistryOwner {

    // 创建 SavedStateRegistryController 以获取 SavedStateRegistry 对象。
    private val savedStateRegistryController = SavedStateRegistryController.create(this)

    private lateinit var contentView: View

    override fun onCreate() {
        super.onCreate()
        // 初始化您的 SavedStateRegistryController
        savedStateRegistryController.performAttach() // 您可以忽略此行,因为 performRestore 方法将自动调用 performAttach()。
        savedStateRegistryController.performRestore(null)

        // 配置您的 ComposeView
        contentView = ComposeView(this).apply {
            setViewTreeSavedStateRegistryOwner(this@YourService)
            setContent {
                Text(text = "Hello World")
            }
        }
        ViewTreeLifecycleOwner.set(contentView, this)

        // 初始化您的 WindowManager 和 LayoutParams
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        return super.onStartCommand(intent, flags, startId)
        // 将您的 contentView 添加到 WindowManager
    }

    override fun onDestroy() {
        super.onDestroy()
        // 从 WindowManager 中删除您的视图
    }

    // 从 SavedStateRegistryOwner 接口重写 savedStateRegistry 属性。
    override val savedStateRegistry: SavedStateRegistry
        get() = savedStateRegistryController.savedStateRegistry
}
  1. 注册您的服务并声明 android.permission.SYSTEM_ALERT_WINDOW 权限。
英文:

OK. Here is my own solution

  1. add this dependence:
implementation(&quot;androidx.lifecycle:lifecycle-service:2.5.1&quot;)
  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 = &quot;Hello World&quot;)
            }
        }
        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.

huangapple
  • 本文由 发表于 2023年6月19日 10:09:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/76503237.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定