我想使用Jetpack Compose来实现浮动窗口UI。但我得到了这个错误:
java.lang.IllegalStateException: ViewTreeLifecycleOwner not found from androidx.compose.ui.platform.ComposeView
这是我的浮窗服务代码:
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
}
}
我确认当您使用
contentView
初始化Button(this)
时它可以正常工作。更重要的是,我尝试在LifecycleService
中使用implementation("androidx.lifecycle:lifecycle-service:2.5.1")
并使用ViewTreeLifecycleOwner
来初始化ViewTreeLifecycleOwner.set(contentView, this)
,结果是我又得到了另一个错误:java.lang.IllegalStateException: Composed into the View which doesn't propagateViewTreeSavedStateRegistryOwner!
。
好的。这是我自己的解决方案
implementation("androidx.lifecycle:lifecycle-service:2.5.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
// 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
}
android.permission.SYSTEM_ALERT_WINDOW
许可。