首页 > 其他分享 >如何在 WindowManager.addView 中使用 Jetpack Compose

如何在 WindowManager.addView 中使用 Jetpack Compose

时间:2023-12-25 22:45:00浏览次数:25  
标签:Compose androidx Jetpack ComposeView import android Lifecycle WindowManager

如何在 WindowManager.addView 中使用 Jetpack Compose

一、引出问题

Android 开发中,很常见的一个场景,通过 WindowManager.addView() 添加一个 View 到屏幕上。Android 最新的视图框架 Jetpack Compose,如何应用进来。这个被添加的 View 如何使用 Compose 编写视图呢?

二、探究问题

有的朋友肯定会马上想到使用 ComposeView 作为桥梁。没错,WindowManager.addView 方法,就接收一个 View 类型的参数。那肯定是要借助 ComposeView 了。但是,经过试验,直接使用 ComposeView 是行不通的。
看代码:

val params = WindowManager.LayoutParams(
    WindowManager.LayoutParams.WRAP_CONTENT,
    WindowManager.LayoutParams.WRAP_CONTENT,
    WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
    PixelFormat.TRANSLUCENT
)

val composeView: ComposeView = ComposeView(this).apply {
    setContent {
        Text(text = "I'm be added")
    }
}

windowManager.addView(composeView, params)

上面代码,编译没有问题,运行时会报错:

FATAL EXCEPTION: main
Process: xxxxxxxx
java.lang.IllegalStateException: ViewTreeLifecycleOwner not found from androidx.compose.ui.platform.ComposeView{8285855 V.E...... ......I. 0,0-0,0}
    at androidx.compose.ui.platform.WindowRecomposer_androidKt.createLifecycleAwareWindowRecomposer(WindowRecomposer.android.kt:352)
    at androidx.compose.ui.platform.WindowRecomposer_androidKt.createLifecycleAwareWindowRecomposer$default(WindowRecomposer.android.kt:325)
    at androidx.compose.ui.platform.WindowRecomposerFactory$Companion$LifecycleAware$1.createRecomposer(WindowRecomposer.android.kt:168)
    at androidx.compose.ui.platform.WindowRecomposerPolicy.createAndInstallWindowRecomposer$ui_release(WindowRecomposer.android.kt:224)
    at androidx.compose.ui.platform.WindowRecomposer_androidKt.getWindowRecomposer(WindowRecomposer.android.kt:300)
    at androidx.compose.ui.platform.AbstractComposeView.resolveParentCompositionContext(ComposeView.android.kt:244)
    at androidx.compose.ui.platform.AbstractComposeView.ensureCompositionCreated(ComposeView.android.kt:251)
    at androidx.compose.ui.platform.AbstractComposeView.onAttachedToWindow(ComposeView.android.kt:283)
    at android.view.View.dispatchAttachedToWindow(View.java:22065)
    at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3553)
    ...

看这个错误信息:
应该是从 ComposeView 中没有找到 ViewTreeLifecycleOwner, 其实很好理解。 View 的生命周期依赖于 ViewTreeLifecycleOwner, ComposeView 依赖于一个 ViewCompositonStrategy。核心问题是,ComposeView 需要一个 Lifecycle。

三、解决问题

有了思路自然就尝试解决问题。
首先定义一个 LifecycleOwner ,

import android.view.View
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import androidx.lifecycle.ViewModelStore
import androidx.lifecycle.ViewModelStoreOwner
import androidx.lifecycle.setViewTreeLifecycleOwner
import androidx.lifecycle.setViewTreeViewModelStoreOwner
import androidx.savedstate.SavedStateRegistry
import androidx.savedstate.SavedStateRegistryController
import androidx.savedstate.SavedStateRegistryOwner
import androidx.savedstate.setViewTreeSavedStateRegistryOwner

class MyComposeViewLifecycleOwner:
    LifecycleOwner, ViewModelStoreOwner, SavedStateRegistryOwner {

    private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(this)
    private val savedStateRegistryController = SavedStateRegistryController.create(this)
    private val store = ViewModelStore()

    override val lifecycle: Lifecycle
        get() = lifecycleRegistry
    override val savedStateRegistry: SavedStateRegistry
        get() = savedStateRegistryController.savedStateRegistry
    override val viewModelStore: ViewModelStore
        get() = store


    fun onCreate() {
        savedStateRegistryController.performRestore(null)
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
    }

    fun onStart() {
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
    }

    fun onResume() {
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
    }

    fun onPause() {
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    }

    fun onStop() {
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
    }

    fun onDestroy() {
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
        store.clear()
    }

    /**
     * Compose uses the Window's decor view to locate the
     * Lifecycle/ViewModel/SavedStateRegistry owners.
     * Therefore, we need to set this class as the "owner" for the decor view.
     */
    fun attachToDecorView(decorView: View?) {
        decorView?.let {
            it.setViewTreeViewModelStoreOwner(this)
            it.setViewTreeLifecycleOwner(this)
            it.setViewTreeSavedStateRegistryOwner(this)
        } ?: return
    }
}

再看看使用:

private var lifecycleOwner: MyComposeViewLifecycleOwner? = null

val params = WindowManager.LayoutParams(
    WindowManager.LayoutParams.WRAP_CONTENT,
    WindowManager.LayoutParams.WRAP_CONTENT,
    WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
    PixelFormat.TRANSLUCENT
)

val composeView: ComposeView = ComposeView(this).apply {
    setContent {
        Text(text = "I'm be added")
    }
}


// 注意,在 调用 addView 之前:
lifecycleOwner = MyComposeViewLifecycleOwner().also {
                        it.onCreate() // 注意
                        it.attachToDecorView(composeView)
                    }
windowManager.addView(composeView, params)




windowManager.removeViewImmediate(composeView)
lifecycleOwner?.onDestroy()
lifecycleOwner = null

OK,再次运行。成功~

标签:Compose,androidx,Jetpack,ComposeView,import,android,Lifecycle,WindowManager
From: https://www.cnblogs.com/joy99/p/17927135.html

相关文章

  • CATIA Composer R2023:创新设计的3D魔力盒
    DSCATIAComposerR2023是一款全球领先的3D辅助设计软件,它为设计师提供了强大的设计和建模工具,帮助他们在虚拟环境中创建、修改和优化产品设计。点击获取DSCATIAComposerR2023该软件采用了先进的3D建模技术,可以轻松处理复杂的产品设计任务,并提供了丰富的建模工具和功能,包括......
  • -bash: docker-compose: 未找到命令
    -bash:docker-compose:未找到命令我在使用Docker搭建Nacos容器时遇到了这个问题:是没有安装docker-compose工具。docker-compose的用处主要体现在以下几个方面:快速搭建开发环境:使用docker-compose可以快速搭建起开发环境,例如,在一个项目中可能需要多个服务,如Web应用、数据库等,使......
  • docker-compose gitlab
    version:'3'services:gitlab:image:'yrzr/gitlab-ce-arm64v8:latest'restart:unless-stoppedhostname:'test.gitlab.com'environment:TZ:'Asia/Shanghai'GITLAB_OMNIBUS_CONFIG:|......
  • Debian和Ubuntu国内安装docker和docker-compose
    01-安装docker0、如果你过去安装过docker,先删掉sudoapt-getremovedockerdocker-enginedocker.iocontainerdruncsudoapt-getpurgedocker-cedocker-ce-clicontainerd.iosudorm-rf/var/lib/dockersudorm-rf/etc/dockersudorm-rf/var/run/docker.socksudo......
  • docker-compose 部署 harbor 镜像仓库
    1、安装docker(这个就不写了,可以看)略......2、安装docker-compose[root@master2~]#curl-L"https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname-s)-$(uname-m)"-o/usr/local/bin/docker-compose[root@master2~]#chmod+x/usr/loc......
  • Docker Compose 快速搭建 Redis 单机版
    Redis是非常流行的缓存中间件,其具有功能强大和部署简单的优势,我们在CentOS上使用yum就能够在线安装Redis。之所以要介绍使用Docker进行容器化部署Redis,主要原因是当前容器化部署是主流,而且能够保障服务器文件系统的整洁。本篇博客主要介绍如何使用docker-compose快速......
  • Docker Compose: depends_on
    depends_ondepends_on expressesstartupandshutdowndependenciesbetweenservices.ShortsyntaxTheshortsyntaxvariantonlyspecifiesservicenamesofthedependencies.Servicedependenciescausethefollowingbehaviors:Composecreatesservicesind......
  • docker-compose 一键部署
    3.3.DockerCompose大家可以看到,我们部署一个简单的java项目,其中包含3个容器:MySQLNginxJava项目而稍微复杂的项目,其中还会有各种各样的其它中间件,需要部署的东西远不止3个。如果还像之前那样手动的逐一部署,就太麻烦了。 而DockerCompose就可以帮助我们实现多个相......
  • Docker Compose 使用
    DockerCompose使用Compose简介Compose是用于定义和运行多容器Docker应用程序的工具。通过Compose,您可以使用YML文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从YML文件配置中创建并启动所有服务。使用#yaml配置version:'3'services:web:......
  • docker和docker-compose生产的容器,不在同一个网段,解决方式
    在实际项目中,使用dockerrunxxXx 和docker-composeup-d不在同一个网段,一个是默认是172.17.x.x, 另一个是172.19.x.x。为解决这个问题需要自定义一个网络,我命名为“my-bridge”首先熟悉几条命令:dockernetworkls或者dockernetworklist查看当前的docker网络的内容、容器的......