理解Android中WebView相关的几个概念

学知识就是要掌握一些概念的内涵和外延。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);
    

参考文档

  1. H5 缓存机制浅析 移动端 Web 加载性能优化

你可能感兴趣的