Android学习之WebView基础

来源:互联网 发布:三维全景图制作软件 编辑:程序博客网 时间:2024/06/02 04:20

最近做项目用到了用webView来展示H5页面,自己也是刚接触,来记录记录

1,简介

先看官网介绍:
A View that displays web pages. This class is the basis upon which you can roll your own web browser or simply display some online content within your Activity. It uses the WebKit rendering engine to display web pages and includes methods to navigate forward and backward through a history, zoom in and out, perform text searches and more.

它是一个View,可以用来展示网页。它可以调用自己的web浏览器或者在一个Activity中展示一些在线的内容。webView是使用WebKit引擎。它支持前进后退,方法缩小,文本搜索等

Android的WebVIew在低版本和高版本采用了不同的webkit版本内核,4.4后直接使用Chrome


2,作用

1,显示和渲染WebView页面
2,直接使用html文件(网络上或者文本assets中做布局)】
3,可和JavaScript交互


3,WebView常用的方法

 //激活WebView为活跃状态,能正常执行网页的响应        mWebView.onResume();        //当页面被失去焦点被失去焦点被切换到后台不可见状态,需要执行onPuase        //通过onPause动作通知内核暂停所有的动作,比如DOM的解析,plugin的执行,JavaScript执行        mWebView.onPause();        //当应用程序(存在webview)被切换到后台的时候,这个方法不仅仅        // 针对当前的webview而是全局的全应用程序的webview        //它会暂停所有webview的layout,parsing,javascripttimer,降低CPU功耗        mWebView.pauseTimers();        //恢复puaseTimer状态        mWebView.resumeTimers();        //销毁webView        //在关闭Activity的时候,如果WebView的音乐或者视频还在播放,就必须销毁webView        //但是注意,webView调用destroy时,webView仍绑定在activity上        //这是由于自定义webView构建时传入了该activity的context        //因此需要先从父容器中移除webView,然后再销毁        mRootLayout.removeView(mWebView);        mWebView.destroy();

前进/后退

//是否可以后退Webview.canGoBack() //后退网页Webview.goBack()//是否可以前进                     Webview.canGoForward()//前进网页Webview.goForward()//以当前的index为起始点前进或者后退到历史记录中指定的steps//如果steps为负数则为后退,正数则为前进Webview.goBackOrForward(intsteps) 

常见用法:Back键控制网页后退

问题:在不做任何处理前提下 ,浏览网页时点击系统的“Back”键,整个 Browser 会调用 finish()而结束自身
目标:点击返回后,是网页回退而不是推出浏览器
解决方案:在当前Activity中处理并消费掉该 Back 事件

public boolean onKeyDown(int keyCode, KeyEvent event) {    if ((keyCode == KEYCODE_BACK) && mWebView.canGoBack()) {         mWebView.goBack();        return true;    }    return super.onKeyDown(keyCode, event);}

清除缓存数据

//清除网页访问留下的缓存//由于内核缓存是全局的因此这个方法不仅仅针对webview而是针对整个应用程序.Webview.clearCache(true);//清除当前webview访问的历史记录//只会webview访问历史记录里的所有记录除了当前访问记录Webview.clearHistory();//这个api仅仅清除自动完成填充的表单数据,并不会清除WebView存储到本地的数据Webview.clearFormData();

webViewSetting

还是看官网介绍:
Manages settings state for a WebView. When a WebView is first created, it obtains a set of default settings. These default settings will be returned from any getter call. A WebSettings object obtained from WebView.getSettings() is tied to the life of the WebView

管理webView的状态,当webView第一次被创建的时候,它会获得一组默认的设置。这些默认的设置可以从任何getter方法返回。也可以从WebView.getSettings()得到WebViewSettings实例

       //得到WebViewSwttings实例        mSettings = mWebView.getSettings();        //如果访问的页面中要与JavaScript交互,则webview必须设置支持javasc        mSettings.setJavaScriptEnabled(true);        //设置自适应屏幕,两者合用        mSettings.setUseWideViewPort(true);//设置为true,如果页面包含viewport meta 这个标志,这个标志中定义的width将会被使用,如果页面不包含或者没有提供,一个默认宽的viewport将会被使用        mSettings.setLoadWithOverviewMode(true);//设置WebView是否在overview mode下加载页面,也就是说是否将内容放大到屏幕宽度。默认为false        //缩放操作        mSettings.setSupportZoom(true);//支持缩放,默认为ture,是下面的前提        mSettings.setBuiltInZoomControls(true);//设置内置的缩放控件。若为false,则该webView不可缩放        mSettings.setDisplayZoomControls(false);//隐藏原生的缩放控件        //其他细节操作        mSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);//关闭webView的缓存操作        mSettings.setAllowFileAccess(true);//设置可以访问文件        mSettings.setJavaScriptCanOpenWindowsAutomatically(true);//支持通过JS打开新的窗口        mSettings.setLoadsImagesAutomatically(true);//支持自动加载图片        mSettings.setDefaultTextEncodingName("utf-8");//设置编码格式

什么是viewport
手机浏览器是把页面放在一个虚拟的“窗口”(viewport)中,通常这个虚拟的窗口比屏幕宽,这样就不用把每个网页挤到很小的窗口中,但是会破坏没有针对手机浏览器优化的网页的布局,因此引进了viewport这个meta tag,让网页开发者来控制viewport的大小和缩放
<meta name=”viewport” content=”width=device-width, initial-scale=1, maximum-scale=1″>
width:控制 viewport 的大小,可以指定的一个值,如果 600,或者特殊的值,如 device-width 为设备的宽度(单位为缩放为 100% 时的 CSS 的像素)。
height:和 width 相对应,指定高度。
initial-scale:初始缩放比例,也即是当页面第一次 load 的时候缩放比例。
maximum-scale:允许用户缩放到的最大比例。
minimum-scale:允许用户缩放到的最小比例。
user-scalable:用户是否可以手动缩放

webView的cacheMode:

  • LOAD_CACHE_ELSE_NETWORK
    Use cached resources when they are available, even if they have expired.
    只要有缓存,就用缓存

  • LOAD_CACHE_ONLY
    Don’t use the network, load from the cache.
    只从缓存加载

  • LOAD_DEFAULT
    Default cache usage mode.
    默认模式
    根据cache-control决定是否从网络上取数据

  • LOAD_NORMAL
    This constant was deprecated in API level 17. This value is obsolete, as from API level HONEYCOMB and onwards it has the same effect as LOAD_DEFAULT.
    在api大于17后被废弃,效果和loade_default一样

  • LOAD_NO_CACHE
    Don’t use the cache, load from the network.
    不适用缓存,只从网络加载

设置webView缓存

  • 当加载html页面时,WebView会在data/data/包名目录下生成database与cache两个文件夹
  • 请求的URL记录保存在WebViewCache.db,而URL的内容是保存在WebViewCache文件夹下
  • 是否缓存
if (NetStatusUtil.isConnected(getApplicationContext())) {    webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);//根据cache-control决定是否从网络上取数据。} else {    webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);//没网,则从本地获取,即离线加载} //开启DOM storage API功能        mSettings.setDomStorageEnabled(true);        //开启database storage API 功能        mSettings.setDatabaseEnabled(true);        //开启Application Cache功能        mSettings.setAppCacheEnabled(true);        String cacheDirPath = getFilesDir().getAbsolutePath()+"cache";        //设置Application Caches缓存目录        mSettings.setAppCachePath(cacheDirPath);

DOM Storage 是H5引入的机制的,通过使用键值对在客户端保存数据,并且提供了更大容量的存储空间
注意:
每个Application只调用一次WebSettings.setAppCachePath(),WebSettings.setAppCacheMaxSize()

WebViewCilent

用于处理各种通知&请求事件

常见方法:
shouldOverrideUrlLoding()
作用:打开网页时不调用系统浏览器,而是在本WebView中显示;在网页上的所有加载都经过这个方法

//步骤1. 定义Webview组件Webview webview = (WebView) findViewById(R.id.webView1);//步骤2. 选择加载方式  //方式1. 加载一个网页:  webView.loadUrl("http://www.google.com/");  //方式2:加载apk包中的html页面  webView.loadUrl("file:///android_asset/test.html");  //方式3:加载手机本地的html页面   webView.loadUrl("content://com.android.htmlfileprovider/sdcard/test.html");//步骤3. 复写shouldOverrideUrlLoading()方法,使得打开网页时不调用系统浏览器, 而是在本WebView中显示    webView.setWebViewClient(new WebViewClient(){      @Override  @Override            public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {                return super.shouldOverrideUrlLoading(view, request);            }  });

onPageStarted()
开始载入页面的时候调用
我们可以设定一个loading页面,告诉用户程序在等待网络响应

webView.setWebViewClient(new WebViewClient(){      @Override      public void  onPageStarted(WebView view, String url, Bitmap favicon) {         //设定加载开始的操作      }  });

onPageFinish()

作用:在页面加载结束的时候调用

   webView.setWebViewClient(new WebViewClient(){      @Override      public void onPageFinished(WebView view, String url) {         //设定加载结束的操作      }  });

onLoadResource()
作用:在加载页面资源的时候会调用,每一个资源(如图片)的加载都会被调用一次

  webView.setWebViewClient(new WebViewClient(){      @Override      public boolean onLoadResource(WebView view, String url) {         //设定加载资源的操作      }  });

onReceivedError()
作用:加载页面的服务器出现错误的时候(如404)调用

App里面使用webview控件的时候遇到了诸如404这类的错误的时候,若也显示浏览器里面的那种错误提示页面就显得很丑陋了,那么这个时候我们的app就需要加载一个本地的错误提示页面,即webview如何加载一个本地的页面

//步骤1:写一个html文件(error_handle.html),用于出错时展示给用户看的提示页面//步骤2:将该html文件放置到代码根目录的assets文件夹下//步骤3:复写WebViewClient的onRecievedError方法//该方法传回了错误码,根据错误类型可以进行不同的错误分类处理    webView.setWebViewClient(new WebViewClient(){      @Override      public void onReceivedError(WebView view, int errorCode, String description, String failingUrl){switch(errorCode)                {                case HttpStatus.SC_NOT_FOUND:                    view.loadUrl("file:///android_assets/error_handle.html");                    break;                }            }        });

上面那个方法是api23之前的
文档是:

Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable). The errorCode parameter corresponds to one of the ERROR_* constants.

简单来说,只有在遇到不可用的错误下,才能被调用
不可用的包括有:

  • 没有网络连接
  • 连接超时
  • 找不到页面

而下面情况不会被报告:

  • 网页内引用其他资源加载错误,比如图片,css不可用
  • js执行错误

然后Api23后(Android6),有了新版的onReceviceError
签名为:

public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error);

文档为

Report web resource loading error to the host application. These errors usually indicate inability to connect to the server. Note that unlike the deprecated version of the callback,the new version will be called for any resource (iframe, image, etc), not just for the main page. Thus, it is recommended to perform minimum required work in this callback.

新版的onReceiveError能接受到的错误更多,不再局限于之前的“不可用”的情况

因此为了兼容版本
我们可以这样写:

  // 旧版本,会在新版本中也可能被调用,所以加上一个判断,防止重复显示    @Override    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {        super.onReceivedError(view, errorCode, description, failingUrl);        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){            return;        }           // 在这里显示自定义错误页    }    // 新版本,只会在Android6及以上调用    @TargetApi(Build.VERSION_CODES.M)    @Override    public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {         super.onReceivedError(view, request, error);        if (request.isForMainFrame()){ // 或者: if(request.getUrl().toString() .equals(getUrl()))            // 在这里显示自定义错误页        }    }

在新版本中,多了一个WebResourceRequset参数,而WebResourceRequest有一个方法叫做isForMainFrame,描述为:

Gets whether the request was made for the main frame
获取当前的网络请求是否是为main frame创建的.

onReceivedSslError()

作用:处理https请求
webView默认是不处理https请求的,页面显示空白,需要进行设置:

webView.setWebViewClient(new WebViewClient() {            @Override            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {                handler.proceed();    //表示等待证书响应        // handler.cancel();      //表示挂起连接,为默认方式        // handler.handleMessage(null);    //可做其他处理        }        });  

默认行为为取消加载。这个设置会被保留

WebViewChromeCilent

作用:获得网页的加载进度并显示

webview.setWebChromeClient(new WebChromeClient(){      @Override      public void onProgressChanged(WebView view, int newProgress) {          if (newProgress < 100) {              String progress = newProgress + "%";              progress.setText(progress);            } else {        }    });

常见方法:
onReceivedTitle()
作用:获取Web页中的标题

每个网页的页面都有一个标题,比如www.baidu.com这个页面的标题即“百度一下,你就知道”,那么如何知道当前webview正在加载的页面的title并进行设置呢?

webview.setWebChromeClient(new WebChromeClient(){    @Override    public void onReceivedTitle(WebView view, String title) {       titleview.setText(title);    }

注意事项:如何避免WebView内存泄漏

1,不在xml中定义WebView,而是在需要的时候在Activity中创建,并且Context使用getApplictionContext()

LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);        mWebView = new WebView(getApplicationContext());        mWebView.setLayoutParams(params);        mLayout.addView(mWebView);

2,在activity销毁的时候,先让vwebView加载null内容,然后移除wenView,再销毁WebView,最后置空

@Override    protected void onDestroy() {        if (mWebView != null) {            mWebView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);            mWebView.clearHistory();            ((ViewGroup) mWebView.getParent()).removeView(mWebView);            mWebView.destroy();            mWebView = null;        }        super.onDestroy();    }

实例:

 private void init(){        mTitle = (TextView)findViewById(R.id.tv_title);        mWebView = (WebView)findViewById(R.id.wv_webview);        mStartLoading = (TextView)findViewById(R.id.tv_startloading);        mLoading = (TextView)findViewById(R.id.tv_loading);        mWebSetting = mWebView.getSettings();        mWebSetting.setUseWideViewPort(true);        mWebSetting.setLoadWithOverviewMode(true);        mWebSetting.setSupportZoom(true);        mWebSetting.setBuiltInZoomControls(true);        mWebSetting.setDisplayZoomControls(false);        mWebView.loadUrl("https://www.baidu.com");        mWebView.setWebViewClient(new WebViewClient() {            @Override            public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {                view.loadUrl(request.getUrl().toString());                return true;            }            @Override            public void onPageStarted(WebView view, String url, Bitmap favicon) {                mStartLoading.setText("开始加载");            }            @Override            public void onPageFinished(WebView view, String url) {                mStartLoading.setText("加载结束");                mWebView.setVisibility(View.VISIBLE);            }            @Override            public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {                if(request.isForMainFrame()){                    mTitle.setText(String.valueOf(error.getErrorCode())+" 出错了");                    mWebView.setVisibility(View.GONE);                }            }            @Override            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {                if(Build.VERSION.SDK_INT > 23){                    Log.d("aaaaa","aaaaaaa");                    return;                }                mTitle.setText(String.valueOf(errorCode)+"   出错了");                Log.d("bbb","bbbb");                mWebView.setVisibility(View.GONE);            }            @Override            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {                handler.proceed();            }        });        mWebView.setWebChromeClient(new WebChromeClient(){            @Override            public void onReceivedTitle(WebView view, String title) {                mTitle.setText(title);                super.onReceivedTitle(view, title);            }            @Override            public void onProgressChanged(WebView view, int newProgress) {                if(newProgress<=100){                    mLoading.setText(" "+newProgress+"%");                }            }        });    }    @Override    public boolean onKeyDown(int keyCode, KeyEvent event) {        if(keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()){            mWebView.goBack();            return true;        }        return super.onKeyDown(keyCode, event);    }    @Override    protected void onDestroy() {        if(mWebView!=null){            mWebView.loadDataWithBaseURL(null,"","text/html","utf-8",null);            mWebView.clearHistory();            ((ViewGroup)mWebView.getParent()).removeView(mWebView);            mWebView.destroy();            mWebView=null;        }        super.onDestroy();    }

这里写图片描述

关于WebView和JS的交互,再另写

参考:http://blog.csdn.net/carson_ho/article/details/52693322

练习地址:
https://github.com/vivianluomin/PracticeEveryDay/tree/master/TestWebView