2013-08-22 140 views
0

我正在寫一個Android應用程序,它打開本地存儲的HTML文件check.html。這個html文件顯示了一些不錯的文本,然後http轉發到我真正想要的網頁。現在可能會發生,服務器關閉,甚至網絡拔掉,但我希望應用程序一直試圖達到它。Android Webview JNI錯誤與loadUrl

如果只是服務器停機,Android在返回onReceivedError()之前詢問網頁時會有一些延遲,所以我沒有問題,但是如果拔掉網絡,它會立即返回。

後用1〜2分鐘我的應用程序崩潰:

08-22 14:17:47.382:d/dalvikvm(8337):GC_CONCURRENT釋放178K,3%的遊離12530K/12807K,暫停0毫秒+ 7毫秒
08-22 14:17:57.572:d/dalvikvm(8337):GC_CONCURRENT釋放235K,3%的遊離14253K/14599K,暫停0毫秒+ 7毫秒
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/d alvikvm(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):本地參考表溢出(max = 512)
08-22 14:18:51.157:W/dalvikvm(8337):JNI本地參考表(0x1729e78)dump:
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 elements)
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個字節數組分配了32kB大小並且沒有被釋放。即使垃圾收集也沒有釋放它。我會盡力擺脫Web視圖每x次嘗試。也許這可以解決方法工作...

編輯:下,它們表明,有一個錯誤的link

似乎有外部/ WebKit的/來源/ WebKit的漏/安卓/ WebCoreSupport/UrlInterceptResponse.cpp。
if(!m_buffer){
m_buffer = env-> NewByteArray(out-> capacity());
m_buffer =(jbyteArray)env-> NewGlobalRef(m_buffer);
}

本地引用由NewByteArray創建,但不會被刪除。

我認爲這可能與我的問題有關。我正在運行Android 4.0.3,我無法更新,因爲它似乎解決了這個問題....好吧,我會盡力找到解決方法。

回答

1

據我瞭解,Android的WebView在加載頁面時存在內存泄漏(請參閱鏈接問題編輯)。有人可能會想到,解決方法是銷燬WebView。它可以工作,但由於某些原因,WebView無法銷燬(至少GC無法清理),因爲它與活動相關聯。 解決方法是在多次嘗試後銷燬活動。我決定每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秒。

+0

我與你有同樣的問題。但我不知道如何解決這個問題。我只是使用WebView來加載幾個(很多)html文件。不是NDK,不是jni。如何解決這個錯誤?你能給我一些幫助嗎? –

+0

在我的應用程序中,我只是加載本地html文件。不是來自互聯網。我也有同樣的問題。對於我的情況,onReceivedError永遠不會被調用。我不知道你的解決方法是不錯的選擇。 –

+0

我該如何解決這個問題?我的webview需要加載太多的本地html文件。 –

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); 
} 

我認爲你做了10000頁的URL負載在這些1-2分鐘,現在你會做每0.5秒一張支票,你的應用程序會喜歡好多了,不會再崩潰。

+0

所以你會說,我的問題是嘗試的速度(就像沒有網絡連接時的每次嘗試都是500毫秒),系統太慢,無法照顧我的垃圾?我可以等待10秒沒有問題,但我的恐懼是,我的問題只是推遲了4小時的工作與下面的崩潰工作... – Micky

+0

是的,嘗試的速度。放一個日誌語句並檢查:如果你在幾秒鐘內進入100次onReceivedError方法,那麼肯定會出現問題。隨着你的循環,你可能會堵塞整個系統。 – Frank

+0

我把一個計數器記錄下來,並顯示給我。就像我說的,每次嘗試都需要大約500毫秒,經過280次計數後崩潰。所以我敢打賭,即使我等了10秒鐘,我會在280 + - x次嘗試後得到問題。 – Micky