You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android:如何在ViewModel中创建WebView的MutableStateFlow并管理状态

实现方案

核心思路

ViewModel的职责是管理数据与业务逻辑,直接持有WebView实例会引发内存泄漏(WebView关联Context),也不符合架构设计原则。正确的做法是:ViewModel管理WebView的状态数据,Compose侧通过rememberWebViewStateWithHTMLData创建WebView状态,两者联动实现需求。


1. ViewModel实现(管理状态与业务逻辑)

ViewModel仅存储WebView的加载内容、获取到的HTML结果,不持有任何View实例:

class WebViewModel : ViewModel() {
    // 待加载的HTML内容
    private val _webContent = MutableStateFlow("")
    val webContent: StateFlow<String> = _webContent

    // 存储获取到的页面HTML
    private val _pageHtml = MutableStateFlow<String?>(null)
    val pageHtml: StateFlow<String?> = _pageHtml

    // 更新要加载的HTML
    fun updateWebContent(html: String) {
        _webContent.value = html
    }

    // 处理WebView返回的HTML结果
    fun onPageHtmlReceived(html: String?) {
        _pageHtml.value = html
        println("页面HTML:$html")
    }
}

2. Compose侧实现(结合rememberWebViewStateWithHTMLData)

使用Jetpack提供的rememberWebViewStateWithHTMLData管理WebView加载状态,同时绑定ViewModel的逻辑:

@Composable
fun WebViewScreen(viewModel: WebViewModel = viewModel()) {
    val webContent by viewModel.webContent.collectAsStateWithLifecycle()
    val pageHtml by viewModel.pageHtml.collectAsStateWithLifecycle()

    // 创建WebView状态,传入要加载的HTML数据
    val webViewState = rememberWebViewStateWithHTMLData(
        htmlData = webContent,
        baseUrl = "https://your-base-url.com" // 根据实际场景配置baseUrl
    )

    // 渲染WebView
    AndroidView(
        factory = { context ->
            WebView(context).apply {
                settings.javaScriptEnabled = true // 必须启用JS才能调用evaluateJavascript
                webViewClient = object : WebViewClient() {
                    override fun onPageFinished(view: WebView?, url: String?) {
                        super.onPageFinished(view, url)
                        // 页面加载完成后,执行JS获取完整HTML
                        view?.evaluateJavascript("(function() { return document.documentElement.outerHTML; })()") { html ->
                            viewModel.onPageHtmlReceived(html)
                        }
                    }
                }
            }
        },
        update = { webView ->
            // 当ViewModel中的HTML内容更新时,重新加载页面
            val currentData = (webViewState.content as? WebContent.Data)?.data
            if (currentData != webContent) {
                webView.loadDataWithBaseURL(webViewState.baseUrl, webContent, "text/html", "UTF-8", null)
            }
        }
    )

    // 可选:展示获取到的HTML结果
    pageHtml?.let {
        Text(
            text = "获取到的页面HTML:$it",
            modifier = Modifier.padding(16.dp)
        )
    }
}

关键说明

  • 避免ViewModel持有WebView实例:WebView依赖Android Context,ViewModel的生命周期长于UI,直接持有会导致内存泄漏。
  • rememberWebViewStateWithHTMLData:Jetpack官方提供的Compose WebView状态管理API,能自动绑定Compose生命周期,避免状态丢失或异常。
  • JS调用时机:必须在onPageFinished回调中执行evaluateJavascript,确保页面已完全加载,能正确获取到完整HTML。

内容的提问来源于stack exchange,提问作者Slava

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 05:12:48