
Compose 本身独立于安卓经典的 View 系统,但并不是所有的 View 都可以用 Compose 替代,例如:WebView,MapView。
但如果你真的需要用这些 View 怎么办?
AndroidView 是一个可组合函数,可用于在 @Composable 函数内部添加安卓经典的 View。
AndroidView
我们先上一个示例:
Kotlin
AndroidView(factory = {
TextView(it).apply {
setText("Text 1")
}
})
AndroidView 需要一个创建 View 的 lambda 表达式------factory。当 Compose 需要显示这个 View 的时候,会调用该 factory 方法去创建 View。
效果如下:

效果如图,一个简单的 TextView 被成功显示。
当然了,你同样可以使用 Modifier 去修饰 AndroidView:
Kotlin
AndroidView(
modifier = Modifier
.size(100.dp)
.background(Color.LightGray), // 给定尺寸、背景
factory = {
TextView(it).apply {
setText("Text 1")
setTextColor(android.graphics.Color.RED)
}
}
)

更新状态
当然了,如果只是使用 AndroidView 去加载一个经典的 Android View,其优势尚未完全体现。
如果我们想更新 TextView 的状态怎么办?
Kotlin
var text by remember { mutableStateOf("Text 1") }
AndroidView(
modifier = Modifier
.size(100.dp)
.background(Color.LightGray),
factory = {
TextView(it).apply {
setText(text)
setTextColor(android.graphics.Color.RED)
}
}
)
Button(onClick = {
text = "Clicked" // 这里将 text 改成 Clicked
}) {
Text("Click")
}
很简单的一段使用 MutableState 去更新状态的代码,我们看下效果:

奇怪的事情发生了,界面并未更新,点击按钮后 TextView 的文本保持不变。无论你点击多少次,TextView 的 Text 1 都不会变成 Clicked。
AndroidView 使用 factory 来创建 View,并且保证在 View 整个生命周期期间,factory 都只会调用一次。如果想更新状态的话,需要通过另一个 lambda 表达式------update。
我们更改一下上面的代码,使之能够更新状态:
Kotlin
var text by remember { mutableStateOf("Text 1") }
AndroidView(
modifier = Modifier
.size(100.dp)
.background(Color.LightGray),
factory = {
TextView(it).apply {
// 这里去掉了原先的设置文字逻辑
setTextColor(android.graphics.Color.RED)
}
},
update = {
it.text = text // 通过 update 更新文字
}
)
Button(onClick = {
text = "Clicked"
}) {
Text("Click")
}
现在,我们在 update 中更新状态了:

是的,运行的很完美。
这里有两个事情值得注意:
update会在factory完成之后,执行一次。也就说,AndroidView确保View在创建完毕之后,执行一次更新操作。- 当状态发生变化时,便会执行
update。
我们添加部分日志来观测这些现象:
Kotlin
var text by remember { mutableStateOf("Text 1") }
AndroidView(
modifier = Modifier
.size(100.dp)
.background(Color.LightGray),
factory = {
Log.d("AnV","create view") // 创建
TextView(it).apply {
setTextColor(android.graphics.Color.RED)
}
},
update = {
Log.d("AnV","update view") // 更新
it.text = text
}
)
Button(onClick = {
text = "Clicked"
Log.d("AnV","click") // 点击
}) {
Text("Click")
}
按照上面的步骤操作,我们看下日志:
sql
2025-09-10 21:39:08.911 AnV D create view
2025-09-10 21:39:08.913 AnV D update view
2025-09-10 21:39:15.886 AnV D click
2025-09-10 21:39:15.890 AnV D update view
可以看到,当创建完成之后,立马执行了更新。当点击按钮之后,更新操作也执行了。
这也解释了为什么我们的代码没有在 factory 中设置文字,但是当我们看到该 View 的时候,文字确是对的的原因。
onRelease
如果当前页面离开,或者 AndroidView 离开了当前的重组,可以通过 onRelease 表达式执行对于 View 的清理工作。
如果你的 View 是一个 WebView,或者播放器的 PlayerView,这一点至关重要。
Kotlin
AndroidView(
modifier = Modifier
.size(100.dp)
.background(Color.LightGray),
factory = {
Log.d("AnVR","create view")
TextView(it).apply {
setText("Text 1")
setTextColor(android.graphics.Color.RED)
}
},
onRelease = {
Log.d("AnVR","release view")
}
)
这里我们执行一次进入和退出页面的操作:
sql
2025-09-10 21:46:00.682 AnVR D create view
2025-09-10 21:46:03.925 AnVR D release view
可以看到,在退出的时候执行了 onRelease。
onReset
AndroidView 还支持一种情况,View 的复用。
想象一下在一个列表中使用 AndroidView 的情况:
Kotlin
val items = remember { (0..20).toList().toMutableStateList() }
LazyColumn(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(20.dp),
contentPadding = PaddingValues(vertical = 20.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
items(items = items, key = { it }) { id ->
AndroidView(
modifier = Modifier
.fillMaxWidth()
.height(120.dp)
.background(Color.LightGray),
factory = {
Log.d("AnV","create $id")
TextView(it).apply {
setTextColor(android.graphics.Color.RED)
}
},
update = {
Log.d("AnV","update $id")
it.text = "@ $id"
},
onRelease = {
Log.d("AnV","release $id")
}
)
}
}
逻辑非常简单,我们在一个 LazyColumn 中,使用 AndroidView 加载普通的 TextView 去显示列表信息。
我们来回滚动一下列表,看下日志:
yaml
2025-09-10 21:56:57.815 AnV D create 0
2025-09-10 21:56:57.836 AnV D update 0
2025-09-10 21:56:57.848 AnV D create 1
2025-09-10 21:56:57.852 AnV D update 1
2025-09-10 21:56:57.865 AnV D create 2
2025-09-10 21:56:57.868 AnV D update 2
2025-09-10 21:56:57.881 AnV D create 3
2025-09-10 21:56:57.884 AnV D update 3
2025-09-10 21:56:57.896 AnV D create 4
2025-09-10 21:56:57.899 AnV D update 4
2025-09-10 21:56:57.912 AnV D create 5
2025-09-10 21:56:57.915 AnV D update 5
2025-09-10 21:56:57.928 AnV D create 6
2025-09-10 21:56:57.931 AnV D update 6
2025-09-10 21:57:01.840 AnV D create 7
2025-09-10 21:57:01.844 AnV D update 7
2025-09-10 21:57:03.193 AnV D create 8
2025-09-10 21:57:03.196 AnV D update 8
2025-09-10 21:57:03.197 AnV D release 0
2025-09-10 21:57:03.807 AnV D create 9
2025-09-10 21:57:03.809 AnV D update 9
2025-09-10 21:57:09.833 AnV D create 1
2025-09-10 21:57:09.838 AnV D update 1
2025-09-10 21:57:09.842 AnV D release 1
2025-09-10 21:57:09.893 AnV D create 0
2025-09-10 21:57:09.897 AnV D update 0
2025-09-10 21:57:09.899 AnV D release 9
注意末尾几行,我们发现,View 被 release 了。
release 0 和 release 1 表示 0 号 View 和 1 号 View 被释放了,而往回滚动列表的时候,create 0 表示 0 号 View 又被重新创建了。
默认情况下,AndroidView 不会自动缓存或重用 View。如果将其放置在可重复使用的容器中(包括在 LazyRow 或 LazyColumn 中),当包含 AndroidView 的组合发生变化时,即使布局结构未发生变化且 View 理论上可以被重复使用,View 实例也总会被丢弃并重新创建。
如果我们想重复使用 View,需要实现 onReset。
现在,我们修改一下代码:
Kotlin
AndroidView(
//...
onRelease = {
Log.d("AnV","release $id")
},
onReset = { // 省略了部分代码,这里设置了 onReset
Log.d("AnV","reset $id")
it.text = ""
},
)
指定 onReset 时,如果 LazyColumn 等容器决定回收一个 item 的视图时,Compose 会尝试保留该 View 实例,并在需要显示另一个 item 时,先调用 onReset 来重置其状态,然后将其插入新的 item 中,并立即调用 update 来设置新数据。
我们来看下效果:
yaml
2025-09-10 22:06:09.950 AnV D create 0
2025-09-10 22:06:09.974 AnV D update 0
2025-09-10 22:06:09.986 AnV D create 1
2025-09-10 22:06:09.991 AnV D update 1
2025-09-10 22:06:10.003 AnV D create 2
2025-09-10 22:06:10.007 AnV D update 2
2025-09-10 22:06:10.020 AnV D create 3
2025-09-10 22:06:10.024 AnV D update 3
2025-09-10 22:06:10.035 AnV D create 4
2025-09-10 22:06:10.039 AnV D update 4
2025-09-10 22:06:10.049 AnV D create 5
2025-09-10 22:06:10.051 AnV D update 5
2025-09-10 22:06:10.064 AnV D create 6
2025-09-10 22:06:10.067 AnV D update 6
2025-09-10 22:06:11.372 AnV D create 7
2025-09-10 22:06:11.375 AnV D update 7
2025-09-10 22:06:11.807 AnV D create 8
2025-09-10 22:06:11.810 AnV D update 8
2025-09-10 22:06:12.370 AnV D reset 0
2025-09-10 22:06:13.849 AnV D reset 1
2025-09-10 22:06:13.910 AnV D update 9
2025-09-10 22:06:15.080 AnV D reset 9
2025-09-10 22:06:15.101 AnV D update 1
2025-09-10 22:06:15.132 AnV D reset 8
2025-09-10 22:06:15.181 AnV D update 0
2025-09-10 22:06:15.212 AnV D reset 7
当列表来回滚动的时候,不再执行 release 了,取而代之的是 reset。上述 log 中,已经不会再销毁 View 了。
当我们退出页面的时候:
yaml
2025-09-10 22:08:17.364 AnV D release 3
2025-09-10 22:08:17.365 AnV D release 1
2025-09-10 22:08:17.366 AnV D release 7
2025-09-10 22:08:17.367 AnV D release 8
2025-09-10 22:08:17.368 AnV D release 5
2025-09-10 22:08:17.370 AnV D release 6
2025-09-10 22:08:17.372 AnV D release 2
2025-09-10 22:08:17.373 AnV D release 4
2025-09-10 22:08:17.374 AnV D release 0
每个 View 都会得到释放。
总结
本文介绍了 Compose 中 AndroidView 使用方法,用于在 Compose 中嵌入传统 Android View(如 WebView、MapView)
以下几点是精华:
AndroidView通过factory参数创建View。update响应状态变化,确保高效更新。onRelease用于资源释放,这对于类似播放器的View中尤为重要。onReset在可复用容器(如LazyColumn)中实现View的复用,避免频繁创建和销毁,提升性能。
欢迎各位关注公众号,文章同步更新:
