您的位置:首页 > 移动开发

[Android开发] WebView遇到的问题以及解决

2016-09-05 17:46 721 查看

一、内存泄漏

WebView内存不能回收导致内存溢出,可能很多朋友都试过,说说两种解决方法

1. 新开进程

另外单独开一个进程 去使用webview 并且当这个进程结束时,手动调用System.exit(0)

这是目前对于webview 内存泄露 最好的解决方案。使用此方法 所有因为webview引发的 资源无法释放等问题 全部可以解决。但是有一个小问题,就是打开时候会慢一点点。

例如一个文章浏览的activity ArticleActivity,在manifest里面添加属性:

<activity
android:name=".ArticleActivity"
android:process=":school.process.article"
android:launchMode="singleTop"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="school.process.articleactivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>


同一个应用程序的Activity组件都是运行在同一个进程中,但是,如果Activity配置了android:process这个属性,那么,它就会运行在自己的进程中。如果android:process属性的值以”:”开头,则表示这个进程是私有的;如果android:process属性的值以小写字母开头,则表示这是一个全局进程,允许其它应用程序组件也在这个进程中运行。

因此,这里我们以”:”开头,表示创建的是私有的进程。事实上,这里我们不要前面的”:”也是可以的,但是必须保证这个属性性字符串内至少有一个”.”字符。

在这个页面onDestory的时候,调用一下System.exit(0); 就是退出这个进程。

@Override
protected void onDestroy() {

if (null != webView) {
webView.removeAllViews();
webView.destroy();
}

super.onDestroy();
System.exit(0);
}


2.调用releaseWebViewCallback

在webview的 onDestroy方法里 调用下面这个方法,很大程度上可以避免内存泄漏

public void releaseWebViewCallback() {
if (android.os.Build.VERSION.SDK_INT < 16) {
try {
Field field = WebView.class.getDeclaredField("mWebViewCore");
field = field.getType().getDeclaredField("mBrowserFrame");
field = field.getType().getDeclaredField("sConfigCallback");
field.setAccessible(true);
field.set(null, null);
} catch (Exception e) {
e.printStackTrace();
}
} else {
try {
Field sConfigCallback = Class.forName("android.webkit.BrowserFrame").getDeclaredField("sConfigCallback");
if (sConfigCallback != null) {
sConfigCallback.setAccessible(true);
sConfigCallback.set(null, null);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}


二、js调用java的方法,这个方法再调用js 失效的问题

看代码,下面是html代码,在加载的时候调用java代码的showcontacts()这个方法,

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>电话演示</title>
<script type="text/javascript">
function showInfo(jsondata){
var jsonobjs = eval(jsondata);
var table = document.getElementById("personTable");
for(var y=0; y<jsonobjs.length; y++){
var tr = table.insertRow(table.rows.length);
var td1 = tr.insertCell(0);
var td2 = tr.insertCell(1);
td2.align = "center";
td1.innerHTML = jsonobjs[y].name;
td2.innerHTML = "<a href='javascript:Android.call(\""+ jsonobjs[y].phone+ "\")'>"+ jsonobjs[y].phone+ "</a>";
}
}
</script>
</head>
<body onload="javascript:Android.showcontacts()">

<table border="0" width="100%" id="personTable" cellspacing="0">
<tr>
<td width="30%">姓名</td>
<td align="center">电话</td>
</tr>
</table>

</body>
</html>


java代码,showcontacts这个方法里面调用js的代码:

package com.example.androidconnecthtml5;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.webkit.JavascriptInterface;
import android.webkit.WebChromeClient;
import android.webkit.WebView;

public class PhoneActivity extends AppCompatActivity {
private WebView wvVideo;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video);

wvVideo = (WebView) findViewById(R.id.wv_video);

wvVideo.getSettings().setJavaScriptEnabled(true);

wvVideo.setWebChromeClient(new WebChromeClient());

//添加js调用类
wvVideo.addJavascriptInterface(new JsInterface(), "Android");

wvVideo.loadUrl("file:///android_asset/JSCallJavaPhoneActivity.htm");

}

/**
* JavaScript调用Android的方法类
*/
class JsInterface {

/**
* 被js调用,用于加载联系人数据源
*/
@JavascriptInterface
public void showcontacts() {
String json = "[{\"name\":\"天平\", \"phone\":\"18600012345\"}]";
// 调用JS中的方法
wvVideo.loadUrl("javascript:showInfo('" + json + "')");
}

}

/**
* js调用,拨打电话
*
* @param phone 手机号码
*/
@JavascriptInterface
public void call(String phone) {
Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + phone));
if (ActivityCompat.checkSelfPermission(PhoneActivity.this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
return;
}
startActivity(intent);

}
}


这个时候就会发现showcontacts调用的js代码不起作用了。解决方法,把showcontacts里面的代码改成这样:

wvVideo.post(new Runnable() {
@Override
public void run() {
String json = "[{\"name\":\"天平\", \"phone\":\"18600012345\"}]";
// 调用JS中的方法
wvVideo.loadUrl("javascript:showInfo('" + json + "')");
}
});


三、setBuiltInZoomControls(true) 引发的奔溃

这个方法调用以后 如果你触摸屏幕 弹出提示框还没消失的时候 你如果activity结束了 就会报错了。3.0以上 4.4以下很多手机会出现这种情况

解决方法:

在activity的onDestroy方法里手动的将webiew设置成 setVisibility(View.GONE);

四、onPageFinished 没调用

这个函数并没有什么卵用,在不同的内核里调用的时机都不一样,有的时候是提前结束,有的时候就迟迟无法结束。如果一定要实现这种功能的话,建议不要这样做,否则卡在那用户迟迟动不了 这种体验不好。或者可以使用onProgressChanged

五、后台无法释放js 导致发热耗电

在有些手机你如果webview加载的html里,有一些js一直在执行比如动画之类的东西,如果此刻webview 挂在了后台这些资源是不会被释放用户也无法感知。导致一直占有cpu 耗电特别快,所以如果遇到这种情况请在onStop把setJavaScriptEnabled(false); 在onResume里面设置setJavaScriptEnabled(true)。

六、webview 自带的cookie机制

很多人 不知道webview实际上有自己一套完整的cookie机制的,利用好这个可以大大增加对客户端的访问速度。

很多人都想要一个效果:网页更新cookie设置完cookie以后不刷新页面即可生效。这个在2.3以下和2.3以上要实现的方法不太一样,所以要做一次兼容

public void updateCookies(String url, String value) {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) { // 2.3及以下
CookieSyncManager.createInstance(getContext().getApplicationContext());
}
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
cookieManager.setCookie(url, value);
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
CookieSyncManager.getInstance().sync();
}
}


七、webView直接执行js会输出到Webview

我之前研究出来的问题:

http://blog.csdn.net/niubitianping/article/details/51201553

八、加载网页空白

1.重写了shouldOverrideUrlLoading,但是里面没有重新loadUrl

public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}


2. 证书错误

重写WebViewClient的onReceivedSslError方法,忽略ssl证书错误

private class WebViewListener extends WebViewClient {

@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
handler.proceed();//忽略ssl证书错误,继续加载网页
}
}


3. 缓存问题

解决方法清除app数据,获取重新安装app。

代码改进, 重写loadUrl,在每个链接后面添加一个参数

@Override
public void loadUrl(String url) {

//获取当前时间戳
String random = String.valueOf(System.currentTimeMillis());

if (url.contains("?")) {
random = "&random=" + random;
} else {
random = "?random=" + random;
}

//添加一个参数,防止缓存
url += random;

super.loadUrl(url);
}


九、禁止调用系统浏览器打开网页

重写shouldOverrideUrlLoading返回真

    //在当前Activity打开
private class WebViewListener extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; }

}


十、vue的前端,WebView跳转不了网页

这个坑还是有点大,QQ里面的浏览器可以跳转,UC浏览器可以跳转,就自己的WebView跳转不了,研究了半天,终于还是发现了,需要WebView开启缓存:

wvContent.getSettings().setDomStorageEnabled(true);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息