📅  最后修改于: 2023-12-03 15:12:53.399000             🧑  作者: Mango
在现代移动应用开发中,使用 WebView 来呈现网页内容是一种常见的做法。但是,当多个 WebView 同时存在于界面中,由于各种因素(例如网络状况、渲染进度等),可能会出现颤动现象,给用户带来不好的体验。
颤动的本质是由于多个 WebView 的渲染进程被同时刷新导致的。在 Android 中,每个 WebView 都会创建一个独立的渲染进程,这些进程会通过 IPC 机制进行通信。当多个 WebView 同时进行HTTP请求,获取DOM树并进行渲染时,多个渲染进程的刷新时刻存在偏差,导致界面出现非常明显的颤动。
我们可以针对多个 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));
}
}
}
});
}
}
另一种策略是让多个 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 进行网页渲染时,颤动是难以避免的。为了提供更好的用户体验,我们可以采用前文所述的两种策略,即设置优先级和并发请求。在实际应用中,需要根据具体情况选择一种或多种策略进行优化。