本文来自:http://www.jianshu.com/users/320f9e8f7fc9/latest_articles
感谢您的关注。

WebView在现在的项目中使用的频率应该还是非常高的。
我个人总觉得HTML5是一种趋势。找了一些东西,在此总结。
本篇最后有一个非常不错 的 Html5Activity 加载类,不想看的可以直接跳下载。

WebSettings

  1. WebSettings webSettings = mWebView .getSettings();
  2. //支持获取手势焦点,输入用户名、密码或其他
  3. webview.requestFocusFromTouch();
  4. setJavaScriptEnabled(true); //支持js
  5. setPluginsEnabled(true); //支持插件
  6. 设置自适应屏幕,两者合用
  7. setUseWideViewPort(true); //将图片调整到适合webview的大小
  8. setLoadWithOverviewMode(true); // 缩放至屏幕的大小
  9. setSupportZoom(true); //支持缩放,默认为true。是下面那个的前提。
  10. setBuiltInZoomControls(true); //设置内置的缩放控件。
  11. 若上面是false,则该WebView不可缩放,这个不管设置什么都不能缩放。
  12. setDisplayZoomControls(false); //隐藏原生的缩放控件
  13. setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); //支持内容重新布局
  14. supportMultipleWindows(); //多窗口
  15. setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //关闭webview中缓存
  16. setAllowFileAccess(true); //设置可以访问文件
  17. setNeedInitialFocus(true); //当webview调用requestFocus时为webview设置节点
  18. setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口
  19. setLoadsImagesAutomatically(true); //支持自动加载图片
  20. setDefaultTextEncodingName("utf-8");//设置编码格式

加载方式

加载一个网页:
webView.loadUrl("http://www.google.com/");
加载apk包中的一个html页面
webView.loadUrl("file:///android_asset/test.html");
加载手机本地的一个html页面的方法:
webView.loadUrl("content://com.android.htmlfileprovider/sdcard/test.html");


WebViewClient

WebViewClient就是帮助WebView处理各种通知、请求事件的。
打开网页时不调用系统浏览器, 而是在本WebView中显示:

  1. mWebView.setWebViewClient(new WebViewClient(){
  2. @Override
  3. public boolean shouldOverrideUrlLoading(WebView view, String url) {
  4. view.loadUrl(url);
  5. return true;
  6. }
  7. });

WebViewClient方法

  1. WebViewClient mWebViewClient = new WebViewClient()
  2. {
  3. shouldOverrideUrlLoading(WebView view, String url) 最常用的,比如上面的。
  4. //在网页上的所有加载都经过这个方法,这个函数我们可以做很多操作。
  5. //比如获取url,查看url.contains(“add”),进行添加操作
  6. shouldOverrideKeyEvent(WebView view, KeyEvent event)
  7. //重写此方法才能够处理在浏览器中的按键事件。
  8. onPageStarted(WebView view, String url, Bitmap favicon)
  9. //这个事件就是开始载入页面调用的,我们可以设定一个loading的页面,告诉用户程序在等待网络响应。
  10. onPageFinished(WebView view, String url)
  11. //在页面加载结束时调用。同样道理,我们可以关闭loading 条,切换程序动作。
  12. onLoadResource(WebView view, String url)
  13. // 在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次。
  14. onReceivedError(WebView view, int errorCode, String description, String failingUrl)
  15. // (报告错误信息)
  16. doUpdateVisitedHistory(WebView view, String url, boolean isReload)
  17. //(更新历史记录)
  18. onFormResubmission(WebView view, Message dontResend, Message resend)
  19. //(应用程序重新请求网页数据)
  20. onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host,String realm)
  21. //(获取返回信息授权请求)
  22. onReceivedSslError(WebView view, SslErrorHandler handler, SslError error)
  23. //重写此方法可以让webview处理https请求。
  24. onScaleChanged(WebView view, float oldScale, float newScale)
  25. // (WebView发生改变时调用)
  26. onUnhandledKeyEvent(WebView view, KeyEvent event)
  27. //(Key事件未被加载时调用)
  28. }

将上面定义的WebViewClient设置给WebView:

  1. webView.setWebViewClient(mWebViewClient);

WebChromeClient

WebChromeClient是辅助WebView处理Javascript的对话框,网站图标,网站title,加载进度等 :
方法中的代码都是由Android端自己处理。

  1. WebChromeClient mWebChromeClient = new WebChromeClient() {
  2. //获得网页的加载进度,显示在右上角的TextView控件中
  3. @Override
  4. public void onProgressChanged(WebView view, int newProgress) {
  5. if (newProgress < 100) {
  6. String progress = newProgress + "%";
  7. } else {
  8. }
  9. }
  10. //获取Web页中的title用来设置自己界面中的title
  11. //当加载出错的时候,比如无网络,这时onReceiveTitle中获取的标题为 找不到该网页,
  12. //因此建议当触发onReceiveError时,不要使用获取到的title
  13. @Override
  14. public void onReceivedTitle(WebView view, String title) {
  15. MainActivity.this.setTitle(title);
  16. }
  17. @Override
  18. public void onReceivedIcon(WebView view, Bitmap icon) {
  19. //
  20. }
  21. @Override
  22. public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
  23. //
  24. return true;
  25. }
  26. @Override
  27. public void onCloseWindow(WebView window) {
  28. }
  29. //处理alert弹出框,html 弹框的一种方式
  30. @Override
  31. public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
  32. //
  33. return true;
  34. }
  35. //处理confirm弹出框
  36. @Override
  37. public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult
  38. result) {
  39. //
  40. return true;
  41. }
  42. //处理prompt弹出框
  43. @Override
  44. public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
  45. //
  46. return true;
  47. }
  48. };

同样,将上面定义的WebChromeClient设置给WebView:

  1. webView.setWebChromeClient(mWebChromeClient);

调用JS代码

  1. WebSettings webSettings = mWebView .getSettings();
  2. webSettings.setJavaScriptEnabled(true);
  3. mWebView.addJavascriptInterface(new InsertObj(), "jsObj");

上面这是前提!!!
然后实现上面的类,这个类提供了四个方法,注释的非常清楚。

  1. class InsertObj extends Object {
  2. //给html提供的方法,js中可以通过:var str = window.jsObj.HtmlcallJava(); 获取到
  3. @JavascriptInterface
  4. public String HtmlcallJava() {
  5. return "Html call Java";
  6. }
  7. //给html提供的有参函数 : window.jsObj.HtmlcallJava2("IT-homer blog");
  8. @JavascriptInterface
  9. public String HtmlcallJava2(final String param) {
  10. return "Html call Java : " + param;
  11. }
  12. //Html给我们提供的函数
  13. @JavascriptInterface
  14. public void JavacallHtml() {
  15. runOnUiThread(new Runnable() {
  16. @Override
  17. public void run() {
  18. //这里是调用方法
  19. mWebView.loadUrl("javascript: showFromHtml()");
  20. Toast.makeText(Html5Activity.this, "clickBtn", Toast.LENGTH_SHORT).show();
  21. }
  22. });
  23. }
  24. //Html给我们提供的有参函数
  25. @JavascriptInterface
  26. public void JavacallHtml2(final String param) {
  27. runOnUiThread(new Runnable() {
  28. @Override
  29. public void run() {
  30. mWebView.loadUrl("javascript: showFromHtml2('IT-homer blog')");
  31. Toast.makeText(Html5Activity.this, "clickBtn2", Toast.LENGTH_SHORT).show();
  32. }
  33. });
  34. }
  35. }

Android 调用js有个漏洞:
http://blog.csdn.net/leehong2005/article/details/11808557


WebView的方法

前进、后退

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

清除缓存数据:

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

WebView的状态:

  1. onResume() //激活WebView为活跃状态,能正常执行网页的响应
  2. onPause()//当页面被失去焦点被切换到后台不可见状态,需要执行onPause动过, onPause动作通知内核暂停所有的动作,比如DOM的解析、plugin的执行、JavaScript执行。
  3. pauseTimers()//当应用程序被切换到后台我们使用了webview, 这个方法不仅仅针对当前的webview而是全局的全应用程序的webview,它会暂停所有webview的layout,parsing,javascripttimer。降低CPU功耗。
  4. resumeTimers()//恢复pauseTimers时的动作。
  5. destroy()//销毁,关闭了Activity时,音乐或视频,还在播放。就必须销毁。

但是注意:
webview调用destory时,webview仍绑定在Activity上.这是由于自定义webview构建时传入了该Activity的context对象,因此需要先从父容器中移除webview,然后再销毁webview:

  1. rootLayout.removeView(webView);
  2. webView.destroy();

判断WebView是否已经滚动到页面底端 或者 顶端:
getScrollY() //方法返回的是当前可见区域的顶端距整个页面顶端的距离,也就是当前内容滚动的距离.
getHeight()或者getBottom() //方法都返回当前WebView这个容器的高度
getContentHeight()返回的是整个html的高度,但并不等同于当前整个页面的高度,因为WebView有缩放功能,所以当前整个页面的高度实际上应该是原始html的高度再乘上缩放比例.因此,更正后的结果,准确的判断方法应该是:

  1. if (webView.getContentHeight() * webView.getScale() == (webView.getHeight() + webView.getScrollY())) {
  2. //已经处于底端
  3. }
  4. if(webView.getScrollY() == 0){
  5. //处于顶端
  6. }

避免WebView内存泄露的一些方式

1.可以将 Webview 的 Activity 新起一个进程,结束的时候直接System.exit(0);退出当前进程;
启动新进程,主要代码: AndroidManifest.xml 配置文件代码如下

  1. <activity
  2. android:name=".ui.activity.Html5Activity"
  3. android:process=":lyl.boon.process.web">
  4. <intent-filter>
  5. <action android:name="com.lyl.boon.ui.activity.htmlactivity"/>
  6. <category android:name="android.intent.category.DEFAULT"/>
  7. </intent-filter>
  8. </activity>

在新进程中启动 Activity ,里面传了 一个 Url:

  1. Intent intent = new Intent("com.lyl.boon.ui.activity.htmlactivity");
  2. Bundle bundle = new Bundle();
  3. bundle.putString("url", gankDataEntity.getUrl());
  4. intent.putExtra("bundle",bundle);
  5. startActivity(intent);

然后在 Html5Activity 的onDestory() 最后加上 System.exit(0); 杀死当前进程。

2.不能在xml中定义 Webview ,而是在需要的时候创建,并且Context使用 getApplicationgContext(),如下代码:

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

3.在 Activity 销毁的时候,可以先让 WebView 加载null内容,然后移除 WebView,再销毁 WebView,最后置空。
代码如下:

  1. @Override
  2. protected void onDestroy() {
  3. if (mWebView != null) {
  4. mWebView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
  5. mWebView.clearHistory();
  6. ((ViewGroup) mWebView.getParent()).removeView(mWebView);
  7. mWebView.destroy();
  8. mWebView = null;
  9. }
  10. super.onDestroy();
  11. }

返回键

返回上一次浏览的页面

  1. public boolean onKeyDown(int keyCode, KeyEvent event) {
  2. if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
  3. mWebView.goBack();
  4. return true;
  5. }
  6. return super.onKeyDown(keyCode, event);
  7. }

有一个非常不错的 Html5Activity 加载类帖出来:

  1. package com.lyl.web;
  2. import android.graphics.Bitmap;
  3. import android.os.Bundle;
  4. import android.os.Message;
  5. import android.support.v7.app.AppCompatActivity;
  6. import android.util.Log;
  7. import android.view.KeyEvent;
  8. import android.webkit.GeolocationPermissions;
  9. import android.webkit.WebChromeClient;
  10. import android.webkit.WebSettings;
  11. import android.webkit.WebView;
  12. import android.webkit.WebViewClient;
  13. import com.lyl.test.R;
  14. public class Html5Activity extends AppCompatActivity {
  15. private String mUrl;
  16. private LinearLayout mLayout;
  17. private WebView mWebView;
  18. @Override
  19. protected void onCreate(Bundle savedInstanceState) {
  20. super.onCreate(savedInstanceState);
  21. setContentView(R.layout.activity_web);
  22. Bundle bundle = getIntent().getBundleExtra("bundle");
  23. mUrl = bundle.getString("url");
  24. Log.d("Url:", mUrl);
  25. mLayout = (LinearLayout) findViewById(R.id.web_layout);
  26. LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
  27. mWebView = new WebView(getApplicationContext());
  28. mWebView.setLayoutParams(params);
  29. mLayout.addView(mWebView);
  30. WebSettings mWebSettings = mWebView.getSettings();
  31. mWebSettings.setSupportZoom(true);
  32. mWebSettings.setLoadWithOverviewMode(true);
  33. mWebSettings.setUseWideViewPort(true);
  34. mWebSettings.setDefaultTextEncodingName("utf-8");
  35. mWebSettings.setLoadsImagesAutomatically(true);
  36. //调用JS方法.安卓版本大于17,加上注解 @JavascriptInterface
  37. mWebSettings.setJavaScriptEnabled(true);
  38. saveData(mWebSettings);
  39. newWin(mWebSettings);
  40. mWebView.setWebChromeClient(webChromeClient);
  41. mWebView.setWebViewClient(webViewClient);
  42. mWebView.loadUrl(mUrl);
  43. }
  44. /**
  45. * 多窗口的问题
  46. */
  47. private void newWin(WebSettings mWebSettings) {
  48. //html中的_bank标签就是新建窗口打开,有时会打不开,需要加以下
  49. //然后 复写 WebChromeClient的onCreateWindow方法
  50. mWebSettings.setSupportMultipleWindows(true);
  51. mWebSettings.setJavaScriptCanOpenWindowsAutomatically(true);
  52. }
  53. /**
  54. * HTML5数据存储
  55. */
  56. private void saveData(WebSettings mWebSettings) {
  57. //有时候网页需要自己保存一些关键数据,Android WebView 需要自己设置
  58. mWebSettings.setDomStorageEnabled(true);
  59. mWebSettings.setDatabaseEnabled(true);
  60. mWebSettings.setAppCacheEnabled(true);
  61. String appCachePath = getApplicationContext().getCacheDir().getAbsolutePath();
  62. mWebSettings.setAppCachePath(appCachePath);
  63. }
  64. WebViewClient webViewClient = new WebViewClient(){
  65. /**
  66. * 多页面在同一个WebView中打开,就是不新建activity或者调用系统浏览器打开
  67. */
  68. @Override
  69. public boolean shouldOverrideUrlLoading(WebView view, String url) {
  70. view.loadUrl(url);
  71. return true;
  72. }
  73. };
  74. WebChromeClient webChromeClient = new WebChromeClient() {
  75. //=========HTML5定位==========================================================
  76. //需要先加入权限
  77. //<uses-permission android:name="android.permission.INTERNET"/>
  78. //<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
  79. //<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
  80. @Override
  81. public void onReceivedIcon(WebView view, Bitmap icon) {
  82. super.onReceivedIcon(view, icon);
  83. }
  84. @Override
  85. public void onGeolocationPermissionsHidePrompt() {
  86. super.onGeolocationPermissionsHidePrompt();
  87. }
  88. @Override
  89. public void onGeolocationPermissionsShowPrompt(final String origin, final GeolocationPermissions.Callback callback) {
  90. callback.invoke(origin, true, false);//注意个函数,第二个参数就是是否同意定位权限,第三个是是否希望内核记住
  91. super.onGeolocationPermissionsShowPrompt(origin, callback);
  92. }
  93. //=========HTML5定位==========================================================
  94. //=========多窗口的问题==========================================================
  95. @Override
  96. public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
  97. WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
  98. transport.setWebView(mWebView);
  99. resultMsg.sendToTarget();
  100. return true;
  101. }
  102. //=========多窗口的问题==========================================================
  103. };
  104. @Override
  105. public boolean onKeyDown(int keyCode, KeyEvent event) {
  106. if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) {
  107. mWebView.goBack();
  108. return true;
  109. }
  110. return super.onKeyDown(keyCode, event);
  111. }
  112. @Override
  113. protected void onDestroy() {
  114. if (mWebView != null) {
  115. mWebView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
  116. mWebView.clearHistory();
  117. ((ViewGroup) mWebView.getParent()).removeView(mWebView);
  118. mWebView.destroy();
  119. mWebView = null;
  120. }
  121. super.onDestroy();
  122. }
  123. }

原谅我,忘了出自哪里,如果侵权请联系我,一定删除。
这是下载地址:http://yun.baidu.com/s/1eQWFDvG

觉得不错的点个喜欢呗,要是直接赞赏的话,那真是太荣幸了。

参考链接:
Android webview使用详解
Android WebView 开发详解(一)
还有一些零散的链接。

文/Wing_Li(简书作者)
原文链接:http://www.jianshu.com/p/3fcf8ba18d7f
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

史上最全WebView使用,附送Html5Activity一份的更多相关文章

  1. 史上最全webview详解

    本文来自:http://www.jianshu.com/users/320f9e8f7fc9/latest_articles WebView在现在的项目中使用的频率应该还是非常高的. 我个人总觉得HT ...

  2. 了解iOS消息推送一文就够:史上最全iOS Push技术详解

    本文作者:陈裕发, 腾讯系统测试工程师,由腾讯WeTest整理发表. 1.引言 开发iOS系统中的Push推送,通常有以下3种情况: 1)在线Push:比如QQ.微信等IM界面处于前台时,聊天消息和指 ...

  3. 史上最全面的SignalR系列教程-2、SignalR 实现推送功能-永久连接类实现方式

    1.概述 通过上篇史上最全面的SignalR系列教程-1.认识SignalR文章的介绍,我们对SignalR技术已经有了一个全面的了解.本篇开始就通过SignalR的典型应用的实现方式做介绍,例子虽然 ...

  4. 史上最全面的SignalR系列教程-3、SignalR 实现推送功能-集线器类实现方式

    1.概述 通过前两篇 史上最全面的SignalR系列教程-1.认识SignalR 史上最全面的SignalR系列教程-2.SignalR 实现推送功能-永久连接类实现方式 文章对SignalR的介绍, ...

  5. 史上最全面的SignalR系列教程-4、SignalR 自托管全解(使用Self-Host)-附各终端详细实例

    1.概述 通过前面几篇文章 史上最全面的SignalR系列教程-1.认识SignalR 史上最全面的SignalR系列教程-2.SignalR 实现推送功能-永久连接类实现方式 史上最全面的Signa ...

  6. 史上最全PMP备考考点全攻略(上篇-五大过程组,附赠资料)

    一.这可能是一篇史上最全的PMP备考考点全梳理文章 写在前面,这可能是史上最全的PMBOK考点全书考点梳理,由PMP备考自律营呕心沥血整理,内容较长,分为上下篇,绝对值得所有正在备考PMP的学员收藏! ...

  7. GitHub上史上最全的Android开源项目分类汇总 (转)

    GitHub上史上最全的Android开源项目分类汇总 标签: github android 开源 | 发表时间:2014-11-23 23:00 | 作者:u013149325 分享到: 出处:ht ...

  8. 史上最全面的SignalR系列教程-5、SignalR 实现一对一聊天

    1.概述 通过前面几篇文章 史上最全面的SignalR系列教程-1.认识SignalR 史上最全面的SignalR系列教程-2.SignalR 实现推送功能-永久连接类实现方式 史上最全面的Signa ...

  9. 史上最全面的SignalR系列教程-6、SignalR 实现聊天室

    1.概述 通过前面几篇文章对SignalR的详细介绍.我们知道Asp.net SignalR是微软为实现实时通信的一个类库.一般情况下,SignalR会使用JavaScript的长轮询(long po ...

随机推荐

  1. 简单学c——前言

      1.学C语言需要什么基础吗? 零基础. 2.什么是C语言? C语言是一种编程语言. 3.什么是编程语言? 编程语言是用来定义计算机程序的形式语言,是一种被标准化的交流技巧,用来向计算机发出指令. ...

  2. 苹果搜索广告后台大揭秘,最全最细致详解,手把手设置教程「后附官方视频」-b

    WWDC2016 搜索广告分会视频和 PPT 发布了,ASO100 带开发者第一时间了解 Search Ads 后台设置(文末有原声视频). 首先介绍一下搜索广告的模式和竞价规则 广告模式为 CPT( ...

  3. Entity Framework 实践系列 —— 搞好关系 - 两情相悦(双向一对一)【转载】

    Entity Framework 实践系列 —— 搞好关系 - 两情相悦(双向一对一) 自从搞好了单向一对一关系,装满代码的心中塞进了挥之不去的情丝 —— 单相思.谁都知道音乐世界离不开情感,可谁又知 ...

  4. BootStrap Progressbar 实现大文件上传的进度条

    1.首先实现大文件上传,如果是几兆或者几十兆的文件就用基本的上传方式就可以了,但是如果是大文件上传的话最好是用分片上传的方式.我这里主要是使用在客户端进行分片读取到服务器段,然后保存,到了服务器段读取 ...

  5. 移动App设计之分层架构+MVC

    http://www.cnblogs.com/Logen/archive/2012/11/08/2760638.html 场景分析:我们知道,一个移动设备的应用大多与网络有关,也就是说,我在移动设备上 ...

  6. [BZOJ 3196] 213平衡树 【线段树套set + 树状数组套线段树】

    题目链接:BZOJ - 3196 题目分析 区间Kth和区间Rank用树状数组套线段树实现,区间前驱后继用线段树套set实现. 为了节省空间,需要离线,先离散化,这样需要的数组大小可以小一些,可以卡过 ...

  7. SQLite 中的各种限制

    英文原文:Limits In SQLite       本文定义了 SQLite 的限制,如何针对这些限制定制特定的应用程序.默认的限制设置通常是适当的,几乎适合于每一个应用.有一些应用程序可能需要在 ...

  8. poj1849

    不难发现每条边最多走两次,最少走一次也就是我们要在所有走两次的边中选两条从根出发没有公共边的路径使路径上的边少走一次显然我们找的是最长路径

  9. Linux Shell编程(17)——嵌套循环

    嵌套循环就是在一个循环中还有一个循环,内部循环在外部循环体中.在外部循环的每次执行过程中都会触发内部循环,直到内部循环执行结束.外部循环执行了多少次,内部循环就完成多少次.当然,不论是外部循环或内部循 ...

  10. 如何实现View上添加标签

    效果图: 利用 https://github.com/linger1216/labelview 类库来实现 具体代码 问度娘. {LabelView label = new LabelView(thi ...