WebView 遇到的问题
总结一些在开发中遇到的问题, 上一篇中也有部分描述:
这篇文章主要记录一些WebView 出现的问题。
-
onPageStarted() 被调用多次问题:
因为网址的加载过程中存在重定向问题,所以会被调用多次。 这个是不可避免的,重定向后都是一个新的网址,肯定会重新再调用
onPageStarted()
.如果在这个方法里面涉及到一些逻辑,尽可能在这个逻辑里面加入一些判断,保证想要执行的逻辑只执行一次,这也是有益于程序的。
@Override public void onPageStarted(WebView view, String url, Bitmap favicon) { progressBar.setVisibility(VISIBLE); progressBar.setProgress(0); if(!isLoading) { //isLoading 默认为false isLoading = true; ... ... //执行只需要执行一次的逻辑 } } // 然后在`onPageFinished()` 里 isLoading = false;
-
在onPageStarted() 调用webView.canGoBack() 返回 false 问题
有时在加载网址的时候,需要对当前webview的状态进行判断,例如,自定义了一些前进、后退按钮,便需要实时的刷新按钮,需要在网址发生变化时监听webView;
在onPageStarted()里设置监听,去获取webView 的状态,但是有时会出现上述问题,明明webview是可以返回的,在onPageStarted()里获取的值为false。
解决方案: 经过测试onProgressChanged()方法的调用情况,发现,在网络的加载进度在30%左右以后,canGoBack() 才返回 true;所以可以在onProgressChanged() 里加入监听,或是在onPageFinished()里去监听 webView的状态。
-
在onPageFinished() 里去设置progressBar 不可见,仍然看到进度条显示出来:
问题出现的原因,有些不清楚为什么,但是在设置的时候更改为以下便可以:
progressBar.setVisibility(View.GONE);
所以在自行设置的时候,可以设置progressBar 为GONE 而不是INVISIBLE;
-
在一些低版本上,会出现webview 销毁时 程序发生crash的情况:
此类情况的出现,往往是webview销毁时出现了问题,可以仔细检查下自己代码的编写;
webView销毁代码示例:
if (webView != null) { // 要首先移除 removeView(webView); // 清理缓存 webView.stopLoading(); webView.onPause(); webView.clearHistory(); webView.clearCache(true); webView.clearFormData(); webView.clearSslPreferences(); WebStorage.getInstance().deleteAllData(); webView.destroyDrawingCache(); webView.removeAllViews(); // 最后再去webView.destroy(); webView.destroy(); }
若是 webView.destroy() 放在了前面,则就会出现错误,需要把 webView.destroy()放在最后面。
-
上面的销毁 webview时,在低版本4.4以下,这样会出现错误,包 空指针,
具体的原因还没有查明,有说是系统bug的,尚且原因不清楚,可做两种处理,第一种:
if (android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) { //4.4 以下 webView = null; } else { webView.destroy(); }
第二种:
webView.destroy(); webView = null;
第二种这样不需要判断一些版本,是否效果会更好些?
-
webview 快速销毁后, 可能会出现在onPageFinished() 等地方发生crash:
出现的情况可能是加载了很多网页,然后快速点击back键, 退出程序,这时,有可能在部分地方webview 的回调仍在进行,但是webView 可能已经是空了的, 就是发生空指针的crash, 解决方法:在webView的回调函数中 如果要对webview进行操作,先进行一次判空处理:
onPageFinished() { // ... if(webView != null) { ... //执行要做的有关webview操作的逻辑 boolean canGoForward = webView.canGoForward(); } }
-
webView 加载视频时出现的问题: 全屏问题
要想实现webview 全屏加载视频,需要在
webView.setWebChromeClient()
里重写onShowCustomView()
和onHideCustomView()
,这两个方法。可能出现的问题:在切换过程中,背景有白色的底色或是黑色的其他背景闪动一下;
原因: 可能是有根布局的背景色引起的,可自行检查。
-
webView 加载视频时出现的问题: 按back键 视频仍在播放:
应该是返回到:
if(webView.canGoBack()) { webView.goBack(); } else { ... }
webview可以canGoBack(), 成功goback()后 但是视频仍在播放
webview不知道对视频的处理调用了那些接口,解决方法:
在 webView.goBack() 前调用 webView.reload(); webView.stopLoading()
webView.reload(); webView.stopLoading(); webView.goBack();
这样可以让视频暂停。
注:很多地方都说应该调用webView 的onPause()和onResume() 方法去暂停和控制播放视频,这种方式下面介绍。
- webView 加载视频时出现的问题: 按home键和多任务键 视频仍在播放:
此时根据用户习惯应该暂停视频,但是webview本身没有处理这些事件,需要咱们自己去处理。
首先去通过一个广播监听用户点击home键和多任务键, 在监听中,点击后调用webView.onPause();
在用户重新进入到程序中时,在onresume() 中调用webView.onResume();
**注:**有些地方是利用反射的机制实现的:
```
webView.getClass().getMethod("onPause").invoke(webView, (Object[]) null);
```
其实这是为了兼容低版本3.0以下,所以现在基本上不需要再去兼容3.0,不需要利用反射的模式去写。
-
在加载视频的过程中,点击某个视频,会出现webview不去触发onPageStarted()的情况:
在某些视频网站,点击某个具体的视频,不会去调用webView 的onPageStarted(), onPageFinished();
原因是因为 onPageStarted(), onPageFinished()都是 "main frame loading" 即 整页加载时才会回调,在某些视频网站上,点击某个视频可能不属于整页加载,故而不会去调用 onPageStarted(), onPageFinished()。
这个问题可能会导致某些需求去刷新当前webview是否可前进和后退,可能导致后退的情况得不到及时的反馈(例如在onPageStarted()里去刷新状态,但是点击视频没有调用这个方法)。
解决方法:一定会回调的方法是webView.setWebChromeClient() 中的 onProgressChanged(), 可以尝试在这里解决。
-
关于webview 图片加载的问题:
在一般的设置里,都会设置图片的加载模式为:
//webSetting设置 if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { webSettings.setLoadsImagesAutomatically(false); } else { webSettings.setLoadsImagesAutomatically(true); }
然后在onPageFinished()里设置:
if(!webView.getSettings().getLoadsImagesAutomatically()) { webView.getSetting.setLoadsImagesAutomatically(true); }
如果不设置的话,会出现在android 4.4以下 图片加载不出来的问题,因为手动设置为false了。
上面的代码,其目的是对API 在19 以上的版本做了兼容,因为4.4以上系统在onPageFinished时再恢复图片加载时,如果存在多张图片引用的是相同的src时,会只有一个image标签得到加载,这样会造成界面不对的情况,所以4.4以上要在加载网页的时候就去主动加载图片,4.4以下可以等到onPageFinished()后再去加载图片(这样会首先去加载网页的界面,省去用户等待的时间)
-
关于 webView.clearCache(boolean includeDiskFiles) 清理的缓存问题:
在源码里面可以看到关于这个方法的陈述:
Clears the resource cache. Note that the cache is per-application, so this will clear the cache for all WebViews used.
即整个app 的缓存是一份的,里面不光是webView 的缓存,还有其他的一些缓存,所以当去调用这个方法时,实际清理的缓存要多余webview 占用的内存。
所以清理的时候要注意一下。 -
有关报错出现: 找不到 android.webkit.webViewClient 的错误
记得之前看到了这个问题,当时一脸懵,啊?这怎么可能,肯定是用户手机哪里出错了,不用解这个 bug……?近期忽然看到这样一个说法, 有关混淆文件
proguard-rules.pro
的说法,当你使用到一些复杂的 webView 操作时,应该把下面部分的代码加入到proguard-rules.pro
这个文件中:-keepclassmembers class * extends android.webkit.webViewClient { public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap); public boolean *(android.webkit.WebView, java.lang.String); } -keepclassmembers class * extends android.webkit.webViewClient { public void *(android.webkit.webView, java.lang.String); }
这个部分确实没想到,但没找到具体的依据,不知道是不是这个原因造成的。
- To be continued
以上是我在项目开发中遇到的问题,可能不全面,有错误与有疑问的,请留言。