前言
说到优化是个老生常谈的话题了,如内存泄露这种,只要遵循一定的编码规则,大部分能避免。本文说下WebView
优化,如何大幅提高WebView加载网页速度。
WebView优化方法总结如下:
- WebView 动态加载和销毁
- 独立的web进程,与主进程隔开,解决任何webview内存泄漏之类的问题
- 实现WebView复用
- DNS解析优化(接口与网页主域名一致)
- 离线预推,下发离线包,并增量更新
- 网页按节点局部刷新
- 自定义实现图片资源缓存
- 加载本地网页
本文主要说明如何实现WebView复用(WebView
池),基于X5 WebView优化。X5与原生的WebView相比,本身已经做了很多加载优化,如果加上WebView
池,加载效果更加明显,给人丝滑般流畅。网上的WebView
池方案基本没有考虑视图缓存问题,即复用WebView时,加载新页面,存在历史浏览页面问题。
优化
国际规则,贴上核心代码:
WebViewPool:
package com.sjl.bookmark.util;
import android.view.ViewGroup;
import com.sjl.bookmark.app.MyApplication;
import com.sjl.bookmark.widget.X5WebView;
import java.util.ArrayList;
import java.util.List;
public class WebViewPool {
private static List<WebVieWrap> webViewPool = new ArrayList<>();
private static int maxSize = 2;
private WebViewPool() {
webViewPool = new ArrayList<>();
}
private static volatile WebViewPool instance = null;
public static WebViewPool getInstance() {
if (instance == null) {
synchronized (WebViewPool.class) {
if (instance == null) {
instance = new WebViewPool();
}
}
}
return instance;
}
/**
* webView 初始化
* 最好放在application onCreate里
*/
public static void init() {
for (int i = 0; i < maxSize; i++) {
X5WebView webView = new X5WebView(MyApplication.getContext());
WebVieWrap webVieWrap = new WebVieWrap();
webVieWrap.x5WebView = webView;
webViewPool.add(webVieWrap);
}
}
/**
* 获取webView
*/
public synchronized X5WebView getWebView() {
if (webViewPool.size() < maxSize) {
return buildWebView();
}
X5WebView x5WebView = checkWebView();
if (x5WebView != null) {
return x5WebView;
}
//再次判断
if (webViewPool.size() < maxSize) {
return buildWebView();
}
try {
wait(2 * 1000);
x5WebView = getWebView();
return x5WebView;
} catch (Exception e) {
}
throw new RuntimeException("webView池已满");
}
private X5WebView checkWebView() {
for (int i = webViewPool.size() - 1; i >= 0; i--) {
WebVieWrap webVieWrap = webViewPool.get(i);
if (webVieWrap.inUse) {
continue;
}
X5WebView x5WebView = webVieWrap.x5WebView;
webVieWrap.inUse = true;
return x5WebView;
}
return null;
}
/**
* 回收webView
* @param webView
*/
public synchronized void recycleWebView(X5WebView webView) {
for (int i = 0; i < webViewPool.size(); i++) {
WebVieWrap webVieWrap = webViewPool.get(i);
X5WebView temp = webVieWrap.x5WebView;
if (webView == temp) {
temp.stopLoading();
temp.setWebChromeClient(null);
temp.setWebViewClient(null);
temp.clearHistory();
// temp.clearCache(true);
temp.loadUrl("about:blank");
temp.pauseTimers();
webVieWrap.inUse = false;
break;
}
}
notifyAll();
}
/**
* 创建webView
* @return
*/
private X5WebView buildWebView() {
X5WebView webView = new X5WebView(MyApplication.getContext());
WebVieWrap webVieWrap = new WebVieWrap();
webVieWrap.x5WebView = webView;
webViewPool.add(webVieWrap);
return webView;
}
/**
* 销毁连接池
*/
public static void destroyPool() {
try {
if (webViewPool.size() == 0) {
return;
}
for (WebVieWrap webVieWrap : webViewPool) {
X5WebView webView = webVieWrap.x5WebView;
webView.destroy();
}
webViewPool.clear();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 回收webView ,解绑
*
* @param webView 需要被回收的webView
*/
public void recycleWebView(ViewGroup view, X5WebView webView) {
if (view != null && webView != null){
recycleWebView(webView);
view.removeView(webView);
}
}
/**
* 设置webView池个数
*
* @param size webView池个数
*/
public void setMaxPoolSize(int size) {
maxSize = size;
}
public static class WebVieWrap {
public X5WebView x5WebView;
public boolean inUse;
}
}
X5WebView:
public class X5WebView extends WebView {
public X5WebView(Context arg0) {
this(arg0,null);
}
public X5WebView(Context arg0, AttributeSet arg1) {
super(arg0, arg1);
setBackgroundColor(85621);
if (!isInEditMode()) {
initView(arg0);
}
initWebViewSettings();
this.getView().setClickable(true);
this.getView().setOverScrollMode(View.OVER_SCROLL_ALWAYS);
}
private void initView(Context context) {
LogUtils.i(getX5WebViewExtension() == null ? "Sys Core" : "X5 Core:" + QbSdk.getTbsVersion(getContext()));
}
private void initWebViewSettings() {
WebSettings webSettings = this.getSettings();
webSettings.setAllowFileAccess(true);
webSettings.setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS);
webSettings.setSupportZoom(true);
webSettings.setBuiltInZoomControls(true);
webSettings.setDisplayZoomControls(false); //隐藏原生的缩放控件
webSettings.setUseWideViewPort(true);
webSettings.setSupportMultipleWindows(false);
webSettings.setLoadWithOverviewMode(true);
webSettings.setAppCacheEnabled(true);
webSettings.setDatabaseEnabled(true);
webSettings.setDomStorageEnabled(true);
webSettings.setJavaScriptEnabled(true);
webSettings.setGeolocationEnabled(true);
webSettings.setAppCacheMaxSize(Long.MAX_VALUE);
webSettings.setAppCachePath(this.getContext().getDir("appcache", 0).getPath());
webSettings.setDatabasePath(this.getContext().getDir("databases", 0).getPath());
webSettings.setGeolocationDatabasePath(this.getContext().getDir("geolocation", 0)
.getPath());
webSettings.setPluginState(WebSettings.PluginState.ON_DEMAND);
//this.getSettingsExtension().setPageCacheCapacity(IX5WebSettings.DEFAULT_CACHE_CAPACITY);//extension// settings 的设计
}
}
Activity或Fragment使用伪代码:
private boolean clear;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//mViewParent 为 FrameLayout,动态添加WebView到FrameLayout中
mWebView = WebViewPool.getInstance().getWebView();
mViewParent.addView(mWebView, new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
mWebView.setWebViewClient(new WebViewClient() {
@Override
public void doUpdateVisitedHistory(WebView webView, String s, boolean b) {
//处理历史视图问题
if (clear){
webView.clearHistory();
clear = false;
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
WebViewPool.getInstance().recycleWebView(mViewParent,mWebView);
mWebView = null;
/* if (mWebView != null) {
mWebView.release();
}*/
}
关于X5 教程参考:https://x5.tencent.com/docs/access.html