开发者

WebView threads never stop (WebViewCoreThread, CookieSyncManager, http[0-3])

开发者 https://www.devze.com 2022-12-15 20:49 出处:网络
I use a WebView to display some internet content on one of our app\'s Activities. The problem is that when the user switches out of this activity,

I use a WebView to display some internet content on one of our app's Activities.

The problem is that when the user switches out of this activity, WebView's threads keep running!

The problematic threads are:

Thread [<17> WebViewCoreThread] (Running)
Thread [<25>开发者_如何学编程 CookieSyncManager] (Running)
Thread [<19> http0] (Running)
Thread [<29> http1] (Running)
Thread [<31> http2] (Running)
Thread [<33> http3] (Running)

Pausing each one of these threads, and checking what it is busy doing:

Thread [<17> WebViewCoreThread] (Suspended)
    Object.wait(long, int) line: not available [native method]
    MessageQueue(Object).wait() line: 288
    MessageQueue.next() line: 148
    Looper.loop() line: 110
    WebViewCore$WebCoreThread.run() line: 471
    Thread.run() line: 1060

Thread [<25> CookieSyncManager] (Suspended)
    Object.wait(long, int) line: not available [native method]
    MessageQueue(Object).wait(long) line: 326
    MessageQueue.next() line: 144
    Looper.loop() line: 110
    CookieSyncManager(WebSyncManager).run() line: 90
    Thread.run() line: 1060

Thread [<19> http0] (Suspended)
    Object.wait(long, int) line: not available [native method]
    RequestQueue(Object).wait() line: 288
    ConnectionThread.run() line: 93

I wonder how can I tell the Looper in each of those threads to quit.

I tried calling webView.destroy() in the activity's onPause() method, but it had no influence.

When I disable the call for opening a web page in the webView ( webView.loadUrl(...) ), those threads naturally are not started, and therefore don't stay on after leaving the activity.

Any ideas as to how I can make WebView's threads stop after leaving their activity?


You should be able to stop / resume these threads by calling the onPause / onResume on the webview.

Those are however hidden, so you will need to do it through reflection. The following code worked for me:

Class.forName("android.webkit.WebView").getMethod("onPause", (Class[]) null).invoke(webView, (Object[]) null);

Where webView is the instance of WebView.

Also see: http://code.google.com/p/android/issues/detail?id=10282


My solution, in extended webview class(tested in android 2.2, andriod 2.3, android 3.1):

 private boolean is_gone = false;
 public void onWindowVisibilityChanged(int visibility) {
     super.onWindowVisibilityChanged(visibility);
     if (visibility == View.GONE) {
         try {
             WebView.class.getMethod("onPause").invoke(this); //stop flash
         } catch (Exception e) {}
         this.pauseTimers();
         this.is_gone = true;
     } else if (visibility == View.VISIBLE) {
         try {
             WebView.class.getMethod("onResume").invoke(this); //resume flash
         } catch (Exception e) {}
         this.resumeTimers();
         this.is_gone = false;
     }
 }
 public void onDetachedFromWindow() { //this will be trigger when back key pressed, not when home key pressed
     if (this.is_gone) {
         try {
             this.destroy();
         } catch (Exception e) {}
     }
 }


A clean easy solution that does the job:

@Override
public void onPause() {
    super.onPause();
    webView.onPause();
    webView.pauseTimers(); //careful with this! Pauses all layout, parsing, and JavaScript timers for all WebViews.
}

@Override
public void onResume() {
    super.onResume();
    webView.onResume();
    webView.resumeTimers();
}

@Override
public void onDestroy() {
    super.onDestroy();
    parentViewGroup.removeAllViews(); //the viewgroup the webview is attached to
    webView.loadUrl("about:blank"); 
    webView.stopLoading();
    webView.setWebChromeClient(null);
    webView.setWebViewClient(null);
    webView.destroy();
    webView = null;
}


Take a look at this andev.org thread (WebViewCoreThread problem).

See the response... Re: WebViewCoreThread problem - Postby potatoho

2) To pause flash you have to call hidden methods WebView.onPause() / WebView.onResume().

3) To pause WebViewCoreThread you use WebView.pauseTimers() / WebView.resumeTimers().

I skipped the onPause/onResume, but I implemented webView.pauseTimers() and webView.resumeTimers() and it at least stops the CPU bleed.

I also added CookieSyncManager.getInstance().stopSync() / startSync to my onPause/onResume as well.


Thanks for these info, I had this problem pausing sounds in my swf on webView when I press the lock button on the phone, onPause and onResume still plays my swf when i press the unlock button but the activity is still not visible, I suggest you place these on onWindowFocusChanged if you want to pause and resume playing of swf sounds in webView

@Override
public void onWindowFocusChanged(boolean hasFocus) {
gameView = (WebView) findViewById(R.id.gameView);
    // TODO Auto-generated method stub
    if (hasFocus) {
        try {
            Class.forName("android.webkit.WebView")
                    .getMethod("onResume", (Class[]) null)
                    .invoke(gameView, (Object[]) null);
        } catch (Exception e) {

        }
        gameView.resumeTimers();
        gameView.loadUrl("javascript:setflashfocus()");
    } else {
        try {
            Class.forName("android.webkit.WebView")
                    .getMethod("onPause", (Class[]) null)
                    .invoke(gameView, (Object[]) null);
        } catch (Exception e) {

        }
        gameView.pauseTimers();
    }
    super.onWindowFocusChanged(hasFocus);
}


What about WebView.destroy()? That seems to be cleaning things up or me without doing any funky reflection calls.


Actually, using webView.destroy(), onPause(), clear**() cannot stop Webcore and its related threads yet.

Practically, an ideal way is to set the activity where WebView resides to be in an independent process, so that when the activity is finished, all the threads including Webcore will be destroyed.

That is the way I have employed. Maybe it is also useful to you.


I had to call onDestroy of the WebView to clear the memory specifically for the webview. I was loading flash in and it was killing my app when we go back to this activity with a webview. Flash will eat you alive if you don't destroy your WebView EVERY TIME you're done with it.


The above solutions failed for me on Samsung Galaxy S with Android 2.3.3. But I made success trying the below workaround:

    webview.loadUrl("file:///android_asset/nonexistent.html");

I am forcing the webview to load a non existent html file. This seems to be forcing the webview to clean things up.


Define a method:

    private void hiddenWebViewMethod(String state){
        if( webView != null ){
            try {
                Method method = WebView.class.getMethod(state);
                method.invoke(webView);
            } catch (Exception e) {
                Log.e("TAG", "Exception: " + e.toString());
                webView.loadData("", "text/html", "utf-8");
            }
        }
    }

then call hiddenWebViewMethod("onPause"); to stop loading, and hiddenWebViewMethod("onResume"); to resume.

0

精彩评论

暂无评论...
验证码 换一张
取 消