学知识就是要掌握一些概念的内涵和外延。So,让我们看看与WebView相关的几个概念吧。
概念 | 内涵 | 外延 |
---|---|---|
WebView | 一个绝对布局容器 | 用来展示或渲染Web页面 |
WebSettings | 一个抽象类,包含对WebView的设置方法。 | 用来对WebView进行设置,比如支持JS、缓存模式等 |
WebViewClient | 这个类的方法有一个特点,就是参数的第一项就是WebView,其他项是事件或数据信息。WebView通过该类对外通知页面加载相关的消息 | 用来在页面加载的各个阶段进行业务处理,处理加载错误情况,拦截页面内和页面外的请求 |
WebChromeClient | WebView通过该类,通知获取到站点图标、标题、加载进度,以及JS对话框等 | 用来更好地展示页面和交互 |
理解了上面几个概念后,我们就可以处理一般的业务需求了。比如
设置缓存
缓存模式
获取到WebSettings然后调用其中的设置方法就可以了。
WebSettings webSettings = webView.getSettings();
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
缓存模式有LOAD_DEFAULT(默认)、LOAD_CACHE_ELSE_NETWORK(先缓存后网络)、LOAD_NO_CACHE(不要缓存)、LOAD_CACHE_ONLY(只要缓存),可以根据业务要求选择。
缓存机制
(1)浏览器缓存机制
- 概念:通过 HTTP 协议头里的 Cache-Control(或 Expires)和 Last-Modified(或 Etag)等字段来控制文件缓存的机制。
- 适用:适用于 Web 的静态资源文件。
(2)Dom Storage(Web Storage)
- 概念:通过存储字符串的 Key/Value 对来提供,并提供 5MB (不同浏览器可能不同,分 HOST)的存储空间(Cookies 才 4KB)。分为 sessionStorage 和 localStorage。
- 适用:代替掉将一些不需要让服务器知道的信息存储到 cookies 里的这种传统方法。
webSettings.setDomStorageEnabled(true);
(3)Web SQL Database
- 概念:基于 SQL 的数据库存储机制,用于存储适合数据库的结构化数据。
- 适用:Web SQL Database 存储机制不再推荐使用,将来也不再维护,而是推荐使用 AppCache 和 IndexedDB。
webSettings.setDatabaseEnabled(true);
final String dbPath = getApplicationContext().getDir("db", Context.MODE_PRIVATE).getPath();
webSettings.setDatabasePath(dbPath);
(4)Application Cache(AppCache)
- 概念:为支持 Web App 离线使用而开发的缓存机制。以文件为单位进行缓存,且文件有一定更新机制。
- 适用:AppCache 是对浏览器缓存机制的补充,不是替代。不推荐使用了,标准也不会再支持。
webSettings.setAppCacheEnabled(true);
final String cachePath = getApplicationContext().getDir("cache", Context.MODE_PRIVATE).getPath();
webSettings.setAppCachePath(cachePath);
webSettings.setAppCacheMaxSize(5*1024*1024);
(5)Indexed Database
- 概念:NoSQL 数据库,类似于 Dom Storage 的 key-value 的存储方式,但功能更强大,且存储空间更大。
- 适用:用于存储大块或复杂结构的数据,提供更大的存储空间,使用起来也比较简单。可以作为 Web SQL Database 的替代。不太适合静态文件的缓存。
webSettings.setJavaScriptEnabled(true);
(6)File System API
- 概念:为 Web App 提供了一个虚拟的文件系统,运行在沙盒中
- 适用:任何需要通过文件来管理数据,或通过文件系统进行数据管理的场景都比较适合。到目前,Android 系统的 Webview 还不支持 File System API。
处理页面导航
方法一
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) {
myWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
方法二
@Override
public void onBackPressed() {
if (contentWeb.canGoBack()) {
contentWeb.goBack();
} else {
super.onBackPressed();
}
}
与Activity/Fragment生命周期相适应
参考WebViewFragment实现
/**
* A fragment that displays a WebView.
*
* The WebView is automically paused or resumed when the Fragment is paused or resumed.
*/
public class WebViewFragment extends Fragment {
private WebView mWebView;
private boolean mIsWebViewAvailable;
public WebViewFragment() {
}
/**
* Called to instantiate the view. Creates and returns the WebView.
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (mWebView != null) {
mWebView.destroy();
}
mWebView = new WebView(getActivity());
mIsWebViewAvailable = true;
return mWebView;
}
/**
* Called when the fragment is visible to the user and actively running. Resumes the WebView.
*/
@Override
public void onPause() {
super.onPause();
mWebView.onPause();
}
/**
* Called when the fragment is no longer resumed. Pauses the WebView.
*/
@Override
public void onResume() {
mWebView.onResume();
super.onResume();
}
/**
* Called when the WebView has been detached from the fragment.
* The WebView is no longer available after this time.
*/
@Override
public void onDestroyView() {
mIsWebViewAvailable = false;
super.onDestroyView();
}
/**
* Called when the fragment is no longer in use. Destroys the internal state of the WebView.
*/
@Override
public void onDestroy() {
if (mWebView != null) {
mWebView.destroy();
mWebView = null;
}
super.onDestroy();
}
/**
* Gets the WebView.
*/
public WebView getWebView() {
return mIsWebViewAvailable ? mWebView : null;
}
}
展示页面加载进度
旧有的实现
参考Android: The progress bar in the window's title does not display文中的一种实现,然而看了下发布时间是2010.06。注意:那时候用的是Android 2.3,BrowserActivity不是继承自AppCompactActivity,使用的主题也不是AppCompact主题。
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
requestWindowFeature(Window.FEATURE_PROGRESS);
currentURL = BrowserActivity.this.getIntent().getExtras().getString("currentURL");
setContentView(R.layout.browser);
setProgressBarIndeterminateVisibility(true);
setProgressBarVisibility(true);
try {
mWebView = (WebView) findViewById(R.id.webview);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebViewClient(new browserActivityClient());
mWebView.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress) {
setProgress(progress * 100);
if(progress == 100) {
setProgressBarIndeterminateVisibility(false);
setProgressBarVisibility(false);
}
}
});
mWebView.loadUrl(currentURL);
} catch (Exception e) {
Log.e(getClass().getSimpleName(), "Browser: " + e.getMessage());
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
}
}
自定义实现
- 思路:在webView内部或外部添加一个ProgressBar(水平样式),并通过WebChromeClient获知页面的加载进度,进而调整ProgressBar的进度。
-
实现:
WebChromeClient webChromeClient = new WebChromeClient() { @Override public void onProgressChanged(WebView view, int newProgress) { if (newProgress == 100) { progressBar.setVisibility(View.GONE); } else { progressBar.setVisibility(View.VISIBLE); progressBar.setProgress(newProgress); } } }; webView.setWebViewClient(webViewClient);
参考文档
- H5 缓存机制浅析 移动端 Web 加载性能优化