web-dev-qa-db-fra.com

Les threads WebView ne s'arrêtent jamais (WebViewCoreThread, CookieSyncManager, http [0-3])

J'utilise une WebView pour afficher du contenu Internet sur l'une de nos activités De notre application.
Le problème, c’est que lorsque l’utilisateur quitte cette activité, les threads de WebView continuent de s’exécuter!
Les sujets problématiques sont:

Thread [<17> WebViewCoreThread] (Running)
Thread [<25> CookieSyncManager] (Running)
Thread [<19> http0] (Running)
Thread [<29> http1] (Running)
Thread [<31> http2] (Running)
Thread [<33> http3] (Running)

Mettre en pause chacun de ces threads et vérifier ce qu’il est en train de faire:

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

Je me demande comment puis-je dire à la Looper dans chacun de ces fils d'arrêter.

J'ai essayé d'appeler webView.destroy() dans la méthode onPause() de l'activité, Mais cela n'avait aucune influence.
Lorsque je désactive l’appel pour l’ouverture d’une page Web dans la WebView (webView.loadUrl(...)), ces threads ne sont naturellement pas lancés et, par conséquent, ne restent pas activés après avoir quitté l’activité.

Des idées sur la façon dont je peux faire en sorte que les fils de WebView cessent après avoir quitté Leur activité?

33
Amit Kotlovski

Vous devriez pouvoir arrêter/reprendre ces discussions en appelant onPause/onResume dans la vue Web.

Celles-ci sont cependant cachées, vous devrez donc le faire par réflexion. Le code suivant a fonctionné pour moi:

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

Où webView est l'instance de WebView.

Voir aussi: http://code.google.com/p/Android/issues/detail?id=10282

40
Skymt

Ma solution, dans la classe de visualisation Web étendue (testée sous Android 2.2, Android 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) {}
     }
 }
16
diyism

Une solution simple et propre qui fait le travail:

@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;
}
13
Bolling

Jetez un oeil à ce fil andev.org ( problème avec WebViewCoreThread ). 

Voir la réponse ... Objet: Problème WebViewCoreThread - Postby potatoho

2) Pour suspendre flash, vous devez appeler les méthodes cachées WebView.onPause ()/WebView.onResume ().

3) Pour suspendre WebViewCoreThread, utilisez WebView.pauseTimers ()/WebView.resumeTimers ().

J'ai ignoré le onPause/onResume, mais j'ai implémenté webView.pauseTimers() et webView.resumeTimers() et il arrête au moins la purge du processeur.

J'ai également ajouté CookieSyncManager.getInstance().stopSync()/startSync à mon onPause/onResume.

4
rquinn

Qu'en est-il de WebView.destroy ()? Cela semble être de nettoyer les choses ou moi sans faire des appels de réflexion géniaux.

2
Dan Carpenter

Merci pour ces informations, j'ai eu ce problème en suspendant les sons dans mon swf sur webView lorsque j'appuie sur le bouton de verrouillage du téléphone, onPause et onResume joue toujours mon swf lorsque j'appuie sur le bouton de déverrouillage mais l'activité n'est toujours pas visible placez-les sur onWindowFocusChanged si vous souhaitez suspendre et reprendre la lecture des sons swf dans 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);
}
2
Keiichi

En fait, utiliser webView.destroy(), onPause(), clear**() ne peut pas encore arrêter Webcore et ses threads associés.

Pratiquement, un moyen idéal consiste à définir l'activité où WebView réside dans un processus indépendant, de sorte que lorsque l'activité est terminée, tous les threads, y compris Webcore, soient détruits.

C'est la façon dont j'ai employé. Peut-être que cela vous est également utile.

1
Verdigrass

Les solutions ci-dessus ont échoué pour moi sur Samsung Galaxy S avec Android 2.3.3 .

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

Je force la webview à charger un fichier HTML non existant. Cela semble forcer la vue Web à nettoyer les choses.

0
dangel

J'ai dû appeler onDestroy de la WebView pour effacer la mémoire spécifiquement pour la vue Web. J'étais en train de charger le flash et cela tue mon application lorsque nous revenons à cette activité avec une vue Web. Flash vous dévorera si vous ne détruisez pas votre WebView CHAQUE FOIS que vous avez terminé.

0
Eric Novins

Définir une méthode: 

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

appelez ensuite hiddenWebViewMethod("onPause"); pour arrêter le chargement et hiddenWebViewMethod("onResume"); pour le reprendre.

0
Sa Qada