我正在编写一个Android应用程序,它打开一个本地存储的html文件check.html
。这个html文件显示了一些不错的文本,然后http转发到我真正想要的网页。现在它可能发生,服务器已关闭,甚至网络已拔下,但我希望应用程序始终尝试联系它。
如果只是服务器关闭,Android在返回onReceivedError()
之前要求网页时有一些延迟,所以我没有问题,但如果网络被拔掉,它会立即返回。
1到2分钟后,我的应用程序崩溃了:
08-22 14:17:47.382:D / dalvikvm(8337):GC_CONCURRENT释放178K,3%免费12530K / 12807K,暂停0ms + 7ms
08-22 14:17:57.572:D / dalvikvm(8337):GC_CONCURRENT释放235K,3%免费14253K / 14599K,暂停0ms + 7ms
08-22 14:18:07.882:D / dalvikvm(8337):GC_CONCURRENT释放241K,3%免费15969K / 16327K,暂停0ms + 10ms
08-22 14:18:17.717:D / dalvikvm(8337):GC_CONCURRENT释放237K,2%释放17717K / 18055K,暂停0ms + 13ms
08-22 14:18:28.757:D / dalvikvm(8337):GC_CONCURRENT释放249K,2%免费19468K / 19783K,暂停3ms + 3ms
08-22 14:18:39.105:D / dalvikvm(8337):GC_CONCURRENT释放241K,2%免费21185K / 21511K,暂停4ms + 10ms
08-22 14:18:49.008:D / dalvikvm(8337):GC_CONCURRENT释放238K,2%免费22900K / 23239K,暂停0ms + 10ms
08-22 14:18:51.157:E / dalvikvm(8337):JNI ERROR(app bug):本地参考表溢出(最大= 512)
08-22 14:18:51.157:W / dalvikvm(8337):JNI本地参考表(0x1729e78)转储:
08-22 14:18:51.157:W / dalvikvm(8337):最后10个条目(512个):
08-22 14:18:51.157:W / dalvikvm(8337):511:0x410dec88 android.content.res.AssetManager
08-22 14:18:51.157:W / dalvikvm(8337):510:0x4215db30 byte [](32768个元素)
08-22 14:18:51.157:W / dalvikvm(8337):509:0x42155b18 byte [](32768个元素)
08-22 14:18:51.158:E / dalvikvm(8337):无法添加到JNI本地参考表(有512个条目)
以下是代码:
mWebView = (WebView) findViewById(R.id.webView);
mWebView.setWebChromeClient(new KB_WebChromeClient(this));
mWebView.setWebViewClient(new KB_WebViewClient());
mWebView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
mWebView.clearCache(true);
mWebView.clearHistory();
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
mWebView.addJavascriptInterface(new WebAppInterface(this, this), "Android");
mWebView.loadUrl("file:///android_asset/check.html");
WebViewClient具有以下代码:
public class KB_WebViewClient extends WebViewClient {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
view.clearCache(true);
}
@Override
public void onReceivedError (WebView view, int errorCode, String description, String failingUrl)
{
view.loadUrl("file:///android_asset/check.html");
}
}
基本上,check.html
页面被加载,onPageFinished
被调用,然后html转发到另一个页面,这不起作用,因此调用onReceivedError
,这将开始加载check.html
再次aso。
在我的研究中,我找到SO: Android Expand JNI Local Reference Table,答案是
您需要删除对类和对象的本地引用。
这意味着什么,我的问题在哪里? webview.loadUrl是否创建了任何复杂的内容并且垃圾收集器的速度不够快?我不是一直都在创建WebView,所以什么是搞乱?
提前感谢您的帮助!
编辑:我实现了一个计数器,用于计算调用webview.loadUrl的频率。应用程序崩溃之前它的数量为280到290。我尝试删除check.html
并在网络中加载我想要的网页,然后在崩溃之前尝试的数量达到570。它接缝,即使从HTML页面完成,也会计算每个网页的负载。我正在查看系统的堆,我看到的是每次完成一个循环时,还有1到3个byte []数组,分配32kB大小并且没有释放。即使垃圾收集也没有释放它。我将尝试每x次尝试摆脱Webview。也许这种解决方法可行......
编辑:在link下,他们表示存在错误:
外部/ webkit / Source / WebKit / android / WebCoreSupport / UrlInterceptResponse.cpp似乎存在泄漏。
if(!m_buffer){
m_buffer = env-> NewByteArray(out-> capacity());
m_buffer =(jbyteArray)env-> NewGlobalRef(m_buffer);
}
NewByteArray创建了一个本地引用,但它没有被删除。
我认为这可能与我的问题有关。我正在运行Android 4.0.3并且我无法更新,因为它似乎解决了这个问题....好吧,我会尝试找到解决方法。
答案 0 :(得分:1)
据我所知,Android的WebView在加载页面时会出现内存泄漏(请参阅链接的问题编辑)。人们可以想到,解决方法是破坏WebView。它可以工作,但由于某种原因,WebView无法被销毁(至少GC无法清除它),因为它链接到Activity。 解决方案是在几次尝试后销毁Activity。每150次尝试后我决定这样做。
WebViewClient:
@Override
public void onReceivedError (WebView view, int errorCode, String description, String failingUrl)
{
counter++;
if(150 == counter){
mainActivity.KillThisThenStartNewOne();
}
view.loadUrl("file:///android_asset/check.html");
}
的活动:
public void KillThisThenStartNewOne(){
Intent intent = new Intent(this.getApplicationContext(), MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.getApplicationContext().startActivity(intent);
//for restarting the Activity
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
}
在Android 4.0.3上测试并且有效。重新启动活动大约需要0.5到1秒。
答案 1 :(得分:0)
public void onReceivedError (WebView view, int errorCode, String description, String failingUrl)
{
view.loadUrl("file:///android_asset/check.html");
}
我猜这是一个非常快的事情。创建一个处理程序并在(一个)处理程序上延迟发布它可能会解决这个问题。类似的东西:
private Handler handler = new Handler();
@Override
public void onReceivedError (final WebView view, int errorCode, String description, String failingUrl) {
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (view != null && view.isActivated()) {
view.loadUrl("file:///android_asset/check.html");
}
}
}, 500);
}
我认为你在1-2分钟内完成了10000次网址加载,现在你将每0.5秒做一次检查,你的应用程序会更好,并且不会再崩溃。