📜  颤动中的多个webview (1)

📅  最后修改于: 2023-12-03 15:12:53.399000             🧑  作者: Mango

颤动中的多个 WebView

在现代移动应用开发中,使用 WebView 来呈现网页内容是一种常见的做法。但是,当多个 WebView 同时存在于界面中,由于各种因素(例如网络状况、渲染进度等),可能会出现颤动现象,给用户带来不好的体验。

颤动原理

颤动的本质是由于多个 WebView 的渲染进程被同时刷新导致的。在 Android 中,每个 WebView 都会创建一个独立的渲染进程,这些进程会通过 IPC 机制进行通信。当多个 WebView 同时进行HTTP请求,获取DOM树并进行渲染时,多个渲染进程的刷新时刻存在偏差,导致界面出现非常明显的颤动。

解决方案
策略1 - 设置优先级

我们可以针对多个 WebView 设置不同的网络类型优先级和视图优先级,保证不会同时发起请求。例如,我们可以将一些 WebView 所需的资源全部下载完毕再启动其他的 WebView 渲染。

private void startWebViewRendering() {

    // 禁止所有 webview 自动加载图片
    for (WebView webView : mWebViews) {
        webView.getSettings().setLoadsImagesAutomatically(false);
    }

    // 先让最上层的 WebView 开始加载
    mWebViews.get(0).loadUrl(mUrls.get(0));

    // 依次往下加载
    for (int i = 1; i < mWebViews.size(); i++) {
        final WebView webView = mWebViews.get(i);
        webView.setLayerType(View.LAYER_TYPE_NONE, null);
        webView.getSettings().setLoadsImagesAutomatically(false);
        webView.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageFinished(WebView view, String url) {
                if (mCurrentIndex == mWebViews.indexOf(webView) - 1) {
                    mCurrentIndex = mWebViews.indexOf(webView);
                    if (mCurrentIndex == mWebViews.size() - 1) {
                        for (WebView webView : mWebViews) {
                            webView.getSettings().setLoadsImagesAutomatically(true);
                        }
                    } else {
                        mWebViews.get(mCurrentIndex + 1).loadUrl(mUrls.get(mCurrentIndex + 1));
                    }
                }
            }
        });
    }
}
策略2 - 并发请求

另一种策略是让多个 WebView 同时进行请求。这样可以减少整个渲染流程的时间,从而避免颤动。但是,需要注意的是在同一线程中请求过多资源可能会导致线程卡死,因此我们需要在各 WebView 之间切换线程进行请求。

private void startWebViewRendering() {
    // 请求线程池
    ExecutorService executorService = Executors.newFixedThreadPool(4);

    for (int i = 0; i < mWebViews.size(); i++) {
        final int index = i;
        WebView webView = mWebViews.get(index);
        webView.setLayerType(View.LAYER_TYPE_NONE, null);

        executorService.submit(new Runnable() {
            @Override
            public void run() {
                mWebViews.get(index).loadUrl(mUrls.get(index));
            }
        });
    }
    executorService.shutdown();
}
总结

当我们同时使用多个 WebView 进行网页渲染时,颤动是难以避免的。为了提供更好的用户体验,我们可以采用前文所述的两种策略,即设置优先级和并发请求。在实际应用中,需要根据具体情况选择一种或多种策略进行优化。