No desenvolvimento de aplicações Android, a adição de views à tela via WindowManager.addView() é uma abordagem comum para interfaces sobrepostas. Integrar o Jetpack Compose nesse cenário requer atenção especial ao ciclo de vida, pois o ComposeView depende de proprietários de ciclo de vida e estado para funcionar corretamente.
Uma tentativa direta de usar ComposeView com o WindowManager pode resultar em erros. Por exemplo, ao adicionar uma ComposeView simplesmente:
val layoutParams = WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT
)
val composableElement = ComposeView(context).apply {
setContent {
Text(text = "Exemplo de Compose")
}
}
windowManager.addView(composableElement, layoutParams)
Isso pode causar uma exceção em tempo de execução indicando que o ViewTreeLifecycleOwner não foi encontrado. A raiz do problema é que o ComposeView precisa de um LifecycleOwner para gerenciar recomposições e estados.
Para resolver isso, é necessário criar um proprietário de ciclo de vida personalizado. A implementação envolve definir uma classe que implemente as interfaces necessárias:
class OverlayLifecycleProvider : LifecycleOwner, ViewModelStoreOwner, SavedStateRegistryOwner {
private val lifecycleRegistry = LifecycleRegistry(this)
private val savedStateController = SavedStateRegistryController.create(this)
private val modelStore = ViewModelStore()
override val lifecycle: Lifecycle get() = lifecycleRegistry
override val savedStateRegistry: SavedStateRegistry get() = savedStateController.savedStateRegistry
override val viewModelStore: ViewModelStore get() = modelStore
fun initialize() {
savedStateController.performRestore(null)
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
}
fun activate() {
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
}
fun deactivate() {
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
}
fun terminate() {
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
modelStore.clear()
}
fun attachToView(view: View) {
ViewTreeLifecycleOwner.set(view, this)
ViewTreeViewModelStoreOwner.set(view, this)
ViewTreeSavedStateRegistryOwner.set(view, this)
}
}
Após configurar o proprietário, associe-o à view antes de adicioná-la ao WindowManager. Além disso, é crucial configurar o recompositor para garantir que as atualizações de composição ocorrram:
val owner = OverlayLifecycleProvider().apply {
initialize()
attachToView(composableElement)
}
val recompositorContext = AndroidUiDispatcher.CurrentThread
val recompositor = Recomposer(recompositorContext)
composableElement.compositionContext = recompositor
CoroutineScope(recompositorContext).launch {
recompositor.runRecomposeAndApplyChanges()
}
windowManager.addView(composableElement, layoutParams)
Lembre-se de gerenciar o ciclo de vida ao remover a view. Por exemplo, ao desativar:
windowManager.removeView(composableElement)
owner.deactivate()
owner.terminate()
Essa abordagem garante que o Jetpack Compose funcione corretamente em views gerenciadas pelo WindowManager, permitindo a utilização de componentes composáveis em sobreposições.