欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android之webview详解

程序员文章站 2023-02-15 16:52:40
文章大纲 一、webview基本介绍1.什么是webview2.为什么要使用webview3.webview基本操作 二、webview高级使用1.WebView状态2.资源加载3.WebView加载优化4.数据缓存5.Android 和 JavaScript 交互6.网页前进与后退7.内存管理8. ......

文章大纲

一、webview基本介绍
1.什么是webview
2.为什么要使用webview
3.webview基本操作

二、webview高级使用
1.webview状态
2.资源加载
3.webview加载优化
4.数据缓存
5.android 和 javascript 交互
6.网页前进与后退
7.内存管理
8.cookie操作
9.页面监听与拦截
10.定位设置
11.常见问题处理

三、参考文章

 
Android之webview详解

webview基本介绍

1.什么是webview

  webview是android中的原生ui控件,主要用于在app应用中方便地访问远程网页或本地html资源。同时,webview也在android中充当java代码和js代码之间交互的桥梁。实际上,也可以将webview看做一个功能最小化的浏览器。

2.为什么要使用webview

  目前很多公司的 app 使用一个 webview 作为网页加载, app 中的所有网页内容使用 html5 进行展示,这样只需要写一次 html5 代码,就可以在 android 和 ios 平台上运行,这就是所谓的跨平台 。随着 html5 的普及,很多 app 都会内嵌 webview 来加载 html5 页面,即 原生和html5 共存,这就是当下最流行的「 混合开发 」。html5 最大的优势是迭代方便, 只需要修改服务端的 html5 页面,app 会同步更新,无论是做活动推广 app 还是及时修复 bug 都带来的极大的便利。不过 html5 劣势也很明显,当网速不尽如人意时候,加载速度会很慢(不知道5g出现后结果会带来什么变革),也就是html5 加载受限于网络,没有原生控件流畅,用户体验相对较差, 所以目前完全使用 html5 开发 app 并没有成为主流。

3.webview基本操作

添加网络权限
在androidmanifest.xml中添加以下内容

<uses-permission android:name="android.permission.internet" />

新建webview_simple.xml布局

<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <webview
        android:id="@+id/webview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</linearlayout>

在androidmanifest.xml中注册webviewactivity

<activity android:name=".webviewactivity"></activity>

webviewactivity中代码如下:

import android.app.activity;
import android.os.bundle;
import android.support.v7.app.appcompatactivity;
import android.webkit.webview;

public class webviewactivity extends appcompatactivity {

    webview webview;

    @override
    protected void oncreate(bundle savedinstancestate) {
        super.oncreate(savedinstancestate);
        setcontentview(r.layout.webview_simple);

        webview = (webview) findviewbyid(r.id.webview);

        //加载网页链接
        webview.loadurl("https://www.baidu.com");
    }
}

主页面跳转代码如下:

import android.content.intent;
import android.os.bundle;
import android.support.v7.app.appcompatactivity;
import android.view.view;
import android.widget.button;

import butterknife.bindview;
import butterknife.butterknife;
import butterknife.onclick;

public class mainactivity extends appcompatactivity {

    @bindview(r.id.button)
    button button;

    @override
    protected void oncreate(bundle savedinstancestate) {
        super.oncreate(savedinstancestate);
        setcontentview(r.layout.activity_main);

        butterknife.bind(this);


    }

    @onclick({r.id.button, r.id.button2})
    public void onviewclicked(view view) {

        switch (view.getid()) {

            //简单webview加载
            case r.id.button:

                startactivity(new intent(mainactivity.this, webviewactivity.class));

                break;
        }
    }
}

运行截图如下所示:

 
Android之webview详解
 
Android之webview详解

网页弹窗

//message:alert弹出窗口中的提示信息(提示或警告信息对话框,仅一个确认按钮)
//result:向网页中的javascript代码反馈本次操作结果(result.confirm代表点击了确定按钮,result.cancel代表点击了取消按钮)
public boolean onjsalert(webview view, string url, string message,jsresult result)
///message:confirm弹出窗口中的提示信息(确认对话框,有确认、取消两个按钮)
//result:向网页中的javascript代码反馈本次操作结果(result.confirm代表点击了确定按钮,result.cancel代表点击了取消按钮)
public boolean onjsconfirm(webview view, string url, string message,jsresult result)
 
//message:prompt弹出窗口中的提示信息(输入信息对话框,有一个输入框,还有确认、取消两个按钮)
//defaultvalue:输入框中的默认信息
//result:向网页中的javascript代码反馈本次操作结果(result.confirm代表点击了确定按钮,result.cancel代表点击了取消按钮)
public boolean onjsprompt(webview view, string url, string message,string defaultvalue, jspromptresult result)

下面给出一个简单的处理方案,可以作为参考:

@override
public boolean onjsalert(webview view, string url, string message, final jsresult result) {
    new alertdialog.builder(mainactivity.this)
            .settitle("jsalert")
            .setmessage(message)
            .setpositivebutton("确定", new dialoginterface.onclicklistener() {
                @override
                public void onclick(dialoginterface dialog, int which) {
                    result.confirm();
                }
            })
            .setcancelable(false)
            .show();
    return true;
}
 
@override
public boolean onjsconfirm(webview view, string url, string message, final jsresult result) {
    new alertdialog.builder(mainactivity.this)
            .settitle("jsconfirm")
            .setmessage(message)
            .setpositivebutton("确定", new dialoginterface.onclicklistener() {
                @override
                public void onclick(dialoginterface dialog, int which) {
                    result.confirm();
                }
            })
            .setnegativebutton("取消", new dialoginterface.onclicklistener() {
                @override
                public void onclick(dialoginterface dialog, int which) {
                    result.cancel();
                }
            })
            .setcancelable(false)
            .show();
    return true;
}
 
@override
public boolean onjsprompt(webview view, string url, string message, string defaultvalue, final jspromptresult result) {
    final edittext edittext=new edittext(mainactivity.this);
    edittext.settext("默认数据");//设置默认数据
    new alertdialog.builder(mainactivity.this)
            .settitle("jspromt")
            .setview(edittext)//为弹出窗口设置输入框
            .setpositivebutton("确定", new dialoginterface.onclicklistener() {
                @override
                public void onclick(dialoginterface dialog, int which) {
                    result.confirm(edittext.gettext().tostring());//向javascript传递输入值
                }
            })
            .setnegativebutton("取消", new dialoginterface.onclicklistener() {
                @override
                public void onclick(dialoginterface dialog, int which) {
                    result.cancel();
                }
            })
            .setcancelable(false)
            .show();
    return true;
}

二、webview高级使用

1.webview状态

//激活webview为活跃状态,能正常执行网页的响应
webview.onresume() ;

//当页面被失去焦点被切换到后台不可见状态,需要执行onpause
//通过onpause动作通知内核暂停所有的动作,比如dom的解析、plugin的执行、javascript执行。
webview.onpause();

//当应用程序(存在webview)被切换到后台时,这个方法不仅仅针对当前的webview而是全局的全应用程序的webview
//它会暂停所有webview的layout,parsing,javascripttimer。降低cpu功耗。
webview.pausetimers()
//恢复pausetimers状态
webview.resumetimers();

//销毁webview
//在关闭了activity时,如果webview的音乐或视频,还在播放。就必须销毁webview
//但是注意:webview调用destory时,webview仍绑定在activity上
//这是由于自定义webview构建时传入了该activity的context对象
//因此需要先从父容器中移除webview,然后再销毁webview:
rootlayout.removeview(webview); 
webview.destroy();

2.资源加载

  webview可以加载多种资源,包括本地资源和远程资源,同时也有多种用于加载资源的方法。
加载assets中的资源

  新建assets文件夹,再新建.html文件

 
Android之webview详解

在activity中添加以下代码:

webview.loadurl("file:///android_asset/test.html");//加载本地assets文件夹下的资源

加载res中的资源

webview.loadurl(``"[file:///android_res/mipmap/ic_launcher.png](file:///android_res/mipmap/ic_launcher.png)"``);//加载本地res文件夹下的图片
webview.loadurl(``"[file:///android_res/raw/ic_launcher.png](file:///android_res/raw/ic_launcher.png)"``);//加载本地res文件夹下raw文件夹下的图片
webview.loadurl(``"[file:///android_res/raw/test.html](file:///android_res/raw/test.html)"``);//加载本地res文件夹下raw文件夹下的html文件

加载sdcard中的资源

webview.loadurl(``"file:/sdcard/test.html");//加载本地sdcard下的资源
webview.loadurl(``"[file:///sdcard/test.html](file:///sdcard/test.html)");//加载本地sdcard下的资源
webview.loadurl(``"[content://com.android.htmlfileprovider/sdcard/test.html

请求远程网页方式
loaddata(以字符串形式加载html片段)

//data:html片段
//mimetype:数据类型,如"text/html"
//encoding:数据编码,有两种可选值("base64"和其他任何值),分别代表base64编码和url编码
public void loaddata(string data, string mimetype, string encoding)

loadurlwithbaseurl(以字符串形式加载html片段)

//baseurl:基础url,传入null相当于传入了"about:blank"
//data:html片段
//mimetype:数据类型,如"text/html"
//encoding:数据编码,有两种可选值("base64"和其他任何值),分别代表base64编码和url编码
//historyurl:历史url
public void loaddatawithbaseurl(string baseurl, string data,string mimetype, string encoding, string historyurl)

posturl(以post请求的形式访问url)

//postdata:本次post请求携带的数据,必须是application/x-www-form-urlencoded编码
//如果传入的url不是一个远程网页地址,那么最终将通过loadurl方法加载这个url,同时postdata参数会被忽略。
public void posturl(string url, byte[] postdata)

3.webview加载优化

设置页面自适应屏幕

websettings.setusewideviewport(true);
websettings.setloadwithoverviewmode(true);

缩放功能

websettings.setsupportzoom(true);//启用缩放功能
websettings.setbuiltinzoomcontrols(true);//使用webview内置的缩放功能
websettings.setdisplayzoomcontrols(false);//隐藏屏幕中的虚拟缩放按钮

温馨提示:setdisplayzoomcontrols(true)在某些系统版本中可能会导致应用出现意外崩溃。

若加载的 html 里有js 在执行动画等操作,会造成资源浪费(cpu、电量)
在 onstop 和 onresume 里分别把 setjavascriptenabled() 给设置成 false 和 true 即可

页面加载过程优化
处理各种通知 & 请求事件

//步骤1. 定义webview组件
webview webview = (webview) findviewbyid(r.id.webview1);
//步骤2. 选择加载方式
  //方式1. 加载一个网页:
  webview.loadurl("http://www.google.com/");
//步骤3. 复写shouldoverrideurlloading()方法,使得打开网页时不调用系统浏览器, 而是在本webview中显示
    webview.setwebviewclient(new webviewclient(){
      @override
      public boolean shouldoverrideurlloading(webview view, string url) {
          view.loadurl(url);
      return true;
      }
  });

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

webview.setwebviewclient(new webviewclient(){
      @override
      public void  onpagestarted(webview view, string url, bitmap favicon) {
         //设定加载开始的操作
      }
  });

onpagefinished()
作用:在页面加载结束时调用。我们可以关闭loading 条,切换程序动作。

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;
          }  }
        });

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);    //可做其他处理
        }    
    });

4.数据缓存

当加载 html 页面时,webview会在/data/data/包名目录下生成 database 与 cache 两个文件夹
请求的 url记录保存在 webviewcache.db,而 url的内容是保存在 webviewcache 文件夹下,设置是否启动缓存方法如下:

 webview.getsettings().setcachemode(websettings.load_cache_else_network); 
      缓存模式如下:
       // load_cache_only: 不使用网络,只读取本地缓存数据
       // load_default: (默认)根据cache-control决定是否从网络上取数据。
       // load_no_cache: 不使用缓存,只从网络获取数据.
      // load_cache_else_network,只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。
//webview.getsettings().setcachemode(websettings.load_no_cache);不使用缓存

结合使用(离线加载)

if (netstatusutil.isconnected(getapplicationcontext())) {
    websettings.setcachemode(websettings.load_default);//根据cache-control决定是否从网络上取数据。
} else {
    websettings.setcachemode(websettings.load_cache_else_network);//没网,则从本地获取,即离线加载
}
websettings.setdomstorageenabled(true); // 开启 dom storage api 功能
websettings.setdatabaseenabled(true);   //开启 database storage api 功能
websettings.setappcacheenabled(true);//开启 application caches 功能
string cachedirpath = getfilesdir().getabsolutepath() + app_cacahe_dirname;
websettings.setappcachepath(cachedirpath); //设置  application caches 缓存目录

//注意: 每个 application 只调用一次 websettings.setappcachepath(),websettings.setappcachemaxsize()

清理缓存

//清除网页访问留下的缓存
//由于内核缓存是全局的因此这个方法不仅仅针对webview而是针对整个应用程序.
webview.clearcache(true);

//清除当前webview访问的历史记录
//只会webview访问历史记录里的所有记录除了当前访问记录
webview.clearhistory();

//这个api仅仅清除自动完成填充的表单数据,并不会清除webview存储到本地的数据
webview.clearformdata();

另外一种方式:
//删除缓存文件夹
file file = cachemanager.getcachefilebasedir(); 

if (file != null && file.exists() && file.isdirectory()) { 
for (file item : file.listfiles()) { 
    item.delete(); 
     } 
    file.delete(); 
} 
        
//删除缓存数据库
context.deletedatabase("webview.db"); 
context.deletedatabase("webviewcache.db");

5.android 和 javascript 交互

安卓代码

 websettings settings = mwebview.getsettings();
  settings.setjavascriptenabled(true);//开启javascript 

  mwebview.loadurl("file:///android_asset/keithxiaoy.html");//加载本地网页
  mwebview.setwebchromeclient(new webchromeclient());//此行代码可以保证javascript的alert弹窗正常弹出

  //核心方法, 用于处理javascript被执行后的回调
  mwebview.addjavascriptinterface(new jscallback() {

      @javascriptinterface//注意:此处一定要加该注解,否则在4.1+系统上运行失败
      @override
      public void onjscallback() {
          system.out.println("javascript调用android啦");
      }
  }, "keithxiaoy");//参1是回调接口的实现;参2是javascript回调对象的名称

  //定义回调接口
  public interface jscallback {
      public void onjscallback();
  }

android 调用 javascript

  //直接使用webview加载js就可以了
  mwebview.loadurl("javascript:wave()");

html代码如下

<head>
     <meta http-equiv="content-type" content="text/html; charset=utf-8" />
     </head>
     <script language="javascript">
         /* this function is invoked by the activity */
         function wave() {
             alert("android调用javascript");
         }
     </script>
     <body>
         <!-- javascript调用android代码 -->
         <a onclick="window.demo.onjscallback()"><div style="width:80px;
             margin:0px auto;
             padding:10px;
             text-align:center;
             border:2px solid #202020;" >
                 ![](android_normal.png)<br>
                 click me!
         </div></a>
     </body>
 </html>

注意:
  javascript 回调的方法的书写格式: onclick="window.demo.onjscallback()格式是: windows.js 回调对象的名称(要和 java 代码中设置的一致)。回调方法名称(要和 java 代码中设置的一致)
  javascript 调用 android 的方式具有版本兼容问题。经测试,在 2.2、4.0+ 系统上运行稳定,可以正常调用,但是在 2.3 系统上运行时出现崩溃。原因是底层进行 jni 调用时,把一个 java 中的 string 对象当数组来访问了,最终导致虚拟机崩溃。基本算是一个比较严重的 bug,没办法解决。所以如果说用 webview 组件想在 javascript 和 java 互调就没办法适配所有机型。

6.网页前进与后退

在安卓手机中,back 键控制网页后退,会关闭整个webview,解决方法是在当前 activity 中处理获取back键,改造成网络的返回上一步

webview.goback();//跳到上个页面
webview.goforward();//跳到下个页面
webview.cangoback();//是否可以跳到上一页(如果返回false,说明已经是第一页)
webview.cangoforward();//是否可以跳到下一页(如果返回false,说明已经是最后一页)

7.内存管理

  直接 new webview 并传入 application context 代替在 xml 里面声明以防止 activity 引用被滥用,能解决90+%的 webview 内存泄漏。

vweb =  new webview(getcontext().getapplicationcontext());
container.addview(vweb);

销毁 webview

if (vweb != null) {
    vweb.setwebviewclient(null);
    vweb.setwebchromeclient(null);
    vweb.loaddatawithbaseurl(null, "", "text/html", "utf-8", null);
    vweb.clearhistory();

    ((viewgroup) vweb.getparent()).removeview(vweb);
    vweb.destroy();
    vweb = null;
}

8.cookie操作
cookie 设置

 cookiesyncmanager.createinstance(this);
  cookiemanager cookiemanager = cookiemanager.getinstance();
  cookiemanager.setacceptcookie(true);

  string cookie = "name=xxx;age=18";
  cookiemanager.setcookie(url, cookie);
  cookiesyncmanager.getinstance().sync();

获取 cookie

  cookiemanager cookiemanager = cookiemanager.getinstance();
  string cookie = cookiemanager.getcookie(url);

清除 cookie

cookiesyncmanager.createinstance(context);  
cookiemanager cookiemanager = cookiemanager.getinstance(); 
cookiemanager.removeallcookie();
cookiesyncmanager.getinstance().sync();

9.页面监听与拦截

监听网页加载进度

public void onprogresschanged(webview view, int newprogress)

  onprogresschanged会在网页加载过程中多次触发。当newprogress的值为100时,可以认为当前网页已经加载完毕。因此,通过这个方法判断页面是否加载完成比使用上文提到的onpagefinished方法更准确。同时,由于这个方法在回调中会不断获得最新的加载进度,因此我们可以借助这个方法实现自定义的加载进度条。
  这里给出一个简单的思路:在webview的上方添加一个progressbar控件,并默认隐藏。在onpagestarted方法中显示progressbar,并在onprogresschanged方法回调时更新progressbar的进度值。当onprogresschanged方法中的newprogress达到100时,就隐藏这个progressbar。需要注意,为了在页面加载出错时也能正确隐藏进度条,也应该在onreceivederror方法中隐藏progressbar。

10.定位设置

websettings.setgeolocationenabled(true);//允许网页执行定位操作

如果要禁用网页的定位功能,传入false作为参数即可。需要注意,这个方法只是允许网页执行定位操作,但是最终定位操作的实现还是会委托给android应用处理。因此,为了保证定位功能正常执行,需要满足以下两点:
android应用需要获取定位权限。需要在androidmanifest文件中声明android.manifest.permission.access_coarse_location和android.manifest.permission.access_fine_location两个权限。 需要为webview设置webchromeclient,并重写webchromeclient的ongeolocationpermissionsshowprompt方法。这个方法会在网页中的javascript代码执行定位操作时触发。需要注意,android6.0及以上引入了运行时权限的概念。定位属于危险权限,需要在使用时手动获取。因此我们可以在这个回调方法中弹出一个请求定位的提示对话框(alertdialog),在用户选择确定后获得相应权限。

11.常见问题处理

loaddata加载中文数据出现乱码
  问题描述:使用loaddata方法加载含有中文的数据时,中文显示为乱码。
  解决方案:使用loaddatawithbaseurl方法代替loaddata加载数据,不会出现乱码问题。 为loaddata的mimetype参数传入“text/html;charset=utf-8”,也可以解决乱码问题。

密码明文存储问题
  问题描述:在android 4.3(api 18)以前,用户在webview加载的网页中输入密码后,系统会弹出对话框询问用户是否需要保存密码。如果用户选择保存,那么密码将会以明文的形式保存在本地,显然这是一个巨大的安全隐患。
  解决方案:webview是否保存密码是由websettings的setsavepassword方法决定的。因此,我们只要调用这个方法并传入false,就可以避免明文储存的安全问题了。在android 4.3及以上的版本,setsavepassword方法已经被弃用,webview也不会默认保存密码,因此不再需要进行修复。

weview出现oom影响主进程
  问题描述:由于webview默认运行在应用进程中,如果webview加载的数据过大(例如加载大图片),就可能导致oom问题,从而影响应用主进程。
  解决方案:为了避免webview影响主进程,可以尝试将webview所在的activity运行在独立进程中。这样即使webview出现了oom问题,应用主进程也不会受到影响。具体做法也很简单,只要在androidmanifest文件中为相应的activity设置process属性即可。

webview后台耗电问题
  问题描述:在某些情况下,即使activity已经退出,webview依旧占据着内存空间,这会导致设备耗电量增加。
  解决方案:在上文提到过将webview运行在独立进程中,然后只要在activity的ondestroy方法中调用system.exit(0)退出虚拟机,就可以避免webview继续占据内存空间.

视频或音频在退出activity后继续播放的问题
  问题描述:在webview加载的网页中播放音乐或视频,然而当前应用进入后台后音乐或视频还在继续播放。
  解决方案:在activity的onpause方法中暂停webview,然后在onresume方法中恢复webview。

protected void onpause() {
    if(webview!=null){//暂停webview
        webview.onpause();
        webview.pausetimers();
    }
    super.onpause();
}
 
@override
protected void onresume() {
    if(webview!=null){//恢复webview
        webview.onresume();
        webview.resumetimers();
    }
    super.onresume();
}
&emsp;&emsp;

开启硬件加速导致的闪烁问题
  问题描述:在应用开启硬件加速后,webview可能在加载过程出现闪烁现象。
  解决方案:为webview关闭硬件加速功能。

webview.setlayertype(view.layer_type_software,null);

https请求失败的解决方案
  问题描述:在使用webview加载https协议的网页或资源时,如果该网站的安全证书不被android认可,就会出现无法成功加载的问题。
  解决方案:重写webviewclient的onreceivedsslerror方法,设置其接受所有网站的安全证书。

public void onreceivedsslerror(webview view, sslerrorhandler handler, sslerror error) {
    handler.proceed();//接受所有网站证书
}

webview中http和https混合使用的问题
  问题描述:在android 5.0及以上,webview可能在加载混合使用http和https的网页时出现异常。比如在一个https的安全网页中加载使用http协议的资源将会失败。
  解决方案:在android 5.0后利用websettings设置webview支持http和https混合内容模式。

//方式1
websettings.setmixedcontentmode(websettings.mixed_content_compatibility_mode);
//方式2
websettings.setmixedcontentmode(websettings.mixed_content_always_allow);

  需要注意,mixed_content_always_allow这个模式是不安全的,建议先使用mixed_content_compatibility_mode模式。这个模式会尝试以安全的方式加载部分http资源,另一部分http资源则不会被加载。资源是否能被加载的判断依据可能会随着版本的不同而改变,因此需要根据实际情况决定是否采用这一模式。

setdisplayzoomcontrols引起的崩溃问题
  问题描述:我们知道,setdisplayzoomcontrols(true)方法会允许显示系统缩放按钮,这个缩放按钮会在每次出现后的几秒内逐渐消失。但是在部分系统版本中,如果在缩放按钮消失前退出了activity,就可能引起应用崩溃。
  解决方案:调用setdisplayzoomcontrols(false)方法不显示系统缩放按钮,反正使用手势捏合动作就可以实现网页的缩放功能了。如果确实需要使用缩放按钮,就需要在activity的ondestroy方法中隐藏webview。

webview.setvisibility(view.gone);

三、参考文章