
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
的复用,避免频繁创建和销毁,提升性能。
欢迎各位关注公众号,文章同步更新:
