0

我正在编写一个打开本地存储的 html 文件的 Android 应用程序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% free 14253K/14599K, paused 0ms+7ms
08-22 14:18:07.882: D/dalvikvm(8337): GC_CONCURRENT freed 241K, 3% free 15969K/16327K, paused 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/19 , 暂停 3ms+3ms
08-22 14:18:39.105: D/dalvikvm(8337): GC_CONCURRENT freed 241K, 2% free 21185K/21511K, paused 4ms+10ms
08-22 14:18:49.008: D/dalvikvm(8337 ): GC_CONCURRENT freed 238K, 2% free 22900K/23239K, paused 0ms+10ms
08-22 14:18:51.157:E/dalvikvm(8337):JNI 错误(应用程序错误):本地引用表溢出(最大值 = 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。

在我的研究中,我发现了:Android Expand JNI Local Reference Table,答案是

您需要删除对类和对象的本地引用。

这是什么意思,我的问题在哪里?webview.loadUrl 是否会创建任何复杂的东西并且垃圾收集器不够快而无法清理?我不是一直都在创建 WebView,那么到底有什么问题呢?

提前感谢您的帮助!

编辑:我实现了一个计数器,它计算 webview.loadUrl 被调用的频率。在应用程序崩溃之前,它计数 280 到 290。我试图删除check.html并在网络中加载我想要的网页,然后在崩溃之前尝试次数上升到 570。它接缝,每个网页加载都被计算在内,即使它是从 HTML 页面完成的。我正在查看系统的堆,我看到的是,每次完成一个循环时,都会分配 1 到 3 个 byte[] 数组,大小为 32kB,但未释放。即使是垃圾收集也没有释放它。我会尝试每 x 次尝试摆脱 Webview。也许这种解决方法可以工作......

编辑:在他们显示存在错误的链接下:

好像external/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 并且无法更新,因为他们似乎解决了这个问题....好吧,我会尝试找到解决方法。

4

2 回答 2

1

据我了解,Android的WebView在加载页面时会发生内存泄漏(请参阅Link的问题编辑)。人们可能会想到一种解决方法是销毁 WebView。它可以工作,但由于某种原因,WebView 不能被销毁(至少 GC 不能清理它),因为它链接到 Activity。解决方案是多次尝试后销毁 Activity。我决定在每 150 次尝试后进行一次。

网络视图客户端:

@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 上测试并且可以工作。Activity 的重启大约需要 0.5 到 1 秒。

于 2013-09-03T09:38:04.983 回答
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 次 url 加载,现在您将每 0.5 秒进行一次检查,您的应用会更喜欢这样,并且不会再崩溃。

于 2013-08-22T09:03:15.127 回答