android webview常见问题以及性能优化

1.webview导致内存泄露问题
使用 WebView 的时候,不在 XML 里面声明,而是在代码中直接 new 出来,传入 application context 来防止 activity 引用被滥用

WebView webView = new WebView(getContext().getApplicationContext());
webFrameLayout.addView(webView,0);

在activity的ondestory的时候需要做一下操作

if (mWebView != null) {
        mWebView.stopLoading();//再次打开页面时,若界面没有消亡,会导致进度条不显示并且界面崩溃
            mWebView.onPause();
            mWebView.clearCache(true)
            mWebView.clearHistory();
           mWebView.removeAllViews();
           mWebView.destroyDrawingCache();
           ViewGroup parent = (ViewGroup) mWebView.getParent();
           if (parent != null) {
               parent.removeView(mWebView);
           }
           mWebView.removeAllViews();
           mWebView.destroy();//这句由于有些在其他线程还没有结束,会导致空指针异常导致没办法使用
           mWebView = null;
     }

这里面有个需要特别注意的地方就是如果你在调用webview.destory();的时候,如果webview里面还有别的线程在操作,就会导致当前这个webview为空。这时候我们需要结束相应线程。例如我们项目中有一个广告拦截是通过在
public void onPageFinished(final WebView view, String url)
里面启用一个runnable去执行一串的js脚本,如果用户在你脚本没执行完成的时候就关闭了当前界面,系统就会抛出空指针异常。这时候就需要通过去onPageFinished获取webview对象,封装成以下方法

public void stopJsLoad(){    
if (mWebView != null) {       
 mWebView.removeCallbacks(runnable);        
runnable = null;   
 }
}

然后在activity的onDestory()方法里面调用

if (mWebViewClient != null) {    
    mWebViewClient.stopJsLoad();    
    mWebViewClient = null;
}

2.WebView页面中播放了音频,退出Activity后音频仍然在播放,需要在Activity的onDestory()中调用

ViewGroup parent = (ViewGroup) mWebView.getParent();
           if (parent != null) {
               parent.removeView(mWebView);
           }
           mWebView.removeAllViews();

           mWebView.destroy();
           mWebView = null;

3.webview加载一些别人的url时候,有时候会发生证书认证错误的情况,这时候我们希望能够正常的呈现页面给用户,我们需要忽略证书错误,需要调用WebViewClient类的onReceivedSslError方法,调用handler.proceed()来忽略该证书错误。

4.webview支持H5通过浏览器远程调试配置

if (BuildConfig.DEBUG){ 
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
                      webview.setWebContentsDebuggingEnabled(true);  
  }
}

5.webview先加载样式之后再加载图片配置

        /*         
* 默认情况html代码下载到WebView后,webkit开始解析网页各个节点,        
 * 发现有外部样式文件或者外部脚本文件时,会异步发起网络请求下载文件         
* ,但如果在这之前也有解析到image节点,那势必也会发起网络请求下载相应的图片        
 * 。在网络情况较差的情况下,过多的网络请求就会造成带宽紧张,影响到css或js文件加载完成的时间        
 * ,造成页面空白loading过久。解决的方法就是告诉WebView先不要自动加载图片,等页面finish后再发起图片加载。        
 * 在系统API在19以上的版本作了兼容        
 * 因为4.4以上系统在onPageFinished时再恢复图片加载时,如果存在多张图片引用的是相同的src时,        
 * 会只有一个image标签得到加载,因而对于这样的系统我们就先直接加载。         */       
 if (Build.VERSION.SDK_INT >= 19) {
//            settings.setLoadsImagesAutomatically(true);            // 图片下载阻塞           
 settings.setBlockNetworkImage(true);      
  } else {            
settings.setLoadsImagesAutomatically(false);      
  }

6.H5页面有混合http和https的链接,5.0以上系统不支持混合模式,需要通过配置来开启

//5.0及以上webview不支持http和https混合模式 需要通过配置来开启混合模式if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {    

settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);

}

7.webview 拦截网页请求方法
public WebResourceResponse shouldInterceptRequest(WebView webView, String url) 从 API 11 引入,API 21 废弃
public WebResourceResponse shouldInterceptRequest (WebView view, WebResourceRequest request) 从 API 21 开始引入

@Override
            public WebResourceResponse shouldInterceptRequest(WebView webView, final String url) {
                WebResourceResponse response = null;
                boolean resDown = JSHelper.isURLDownValid(url);
                if (resDown) {
                    jsStr = JsjjJSHelper.getResInputStream(url);
                    if (url.endsWith(".png")) {
                        response = getWebResourceResponse(url, "image/png", ".png");
                    } else if (url.endsWith(".gif")) {
                        response = getWebResourceResponse(url, "image/gif", ".gif");
                    } else if (url.endsWith(".jpg")) {
                        response = getWebResourceResponse(url, "image/jepg", ".jpg");
                    } else if (url.endsWith(".jepg")) {
                        response = getWebResourceResponse(url, "image/jepg", ".jepg");
                    } else if (url.endsWith(".js") && jsStr != null) {
                        response = getWebResourceResponse("text/javascript", "UTF-8", ".js");
                    } else if (url.endsWith(".css") && jsStr != null) {
                        response = getWebResourceResponse("text/css", "UTF-8", ".css");
                    } else if (url.endsWith(".html") && jsStr != null) {
                        response = getWebResourceResponse("text/html", "UTF-8", ".html");
                    }
                }
                return response;
            }
        });
        private WebResourceResponse getWebResourceResponse(String url, String mime, String style) {
        WebResourceResponse response = null;
        try {
            response = new WebResourceResponse(mime, "UTF-8", new FileInputStream(new File(getJSPath() + TPMD5.md5String(url) + style)));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return response;
    }
    public String getJsjjJSPath() {
        String splashTargetPath = JarEnv.sApplicationContext.getFilesDir().getPath() + "/JS";
        if (!TPFileSysUtil.isDirFileExist(splashTargetPath)) {
            TPFileSysUtil.createDir(splashTargetPath);
        }
        return splashTargetPath + "/";
    }

8.通过获取Web页中的title用来设置自己界面中的title及相关问题

WebChromeClient webChromeClient = new WebChromeClient() {
            @Override
            public void onReceivedTitle(WebView view, String title) {
                super.onReceivedTitle(view, title);

                txtTitle.setText(title);
            }

        };

在有些手机上当通过webview.goBack()回退的时候,并没有触发onReceiveTitle(),这样会导致标题仍然是之前子页面的标题,没有切换回来.
(1) 可以确定webview中子页面只有二级页面,没有更深的层次,这里只需要判断当前页面是否为初始的主页面,可以goBack的话,只要将标题设置回来即可.
(2)webview中可能有多级页面或者以后可能增加多级页面,这种情况处理起来要复杂一些:
因为正常顺序加载的情况onReceiveTitle是一定会触发的,所以就需要自己来维护webview loading的一个url栈及url与title的映射关系
那么就需要一个ArrayList来保持加载过的url,一个HashMap保存url及对应的title.
正常顺序加载时,将url和对应的title保存起来,webview回退时,移除当前url并取出将要回退到的web 页的url,找到对应的title进行设置即可.
(3)当加载出错的时候,比如无网络,这时onReceiveTitle中获取的标题为 找不到该网页,因此建议当触发onReceiveError时,不要使用获取到的title.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容