Потоки WebView никогда не останавливаются (WebViewCoreThread, CookieSyncManager, http[0-3])

Я использую WebView для отображения интернет-контента в одном из действий нашего приложения.
Проблема в том, что когда пользователь отключается от этого действия, потоки WebView продолжают работать!
Проблемные потоки:

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

Приостановка каждого из этих потоков и проверка того, чем он занят:

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

Интересно, как я могу сказать Looper в каждом из этих потоков, чтобы они прекратили работу.

Я пытался вызвать webView.destroy() в методе onPause() активности, но это не повлияло.
Когда я отключаю вызов для открытия веб-страницы в webView ( webView.loadUrl(...) ), эти потоки, естественно, не запускаются и, следовательно, не остаются активными. после выхода из активности.

Любые идеи относительно того, как я могу остановить потоки WebView после выхода из их активности?


person Amit Kotlovski    schedule 11.01.2010    source источник
comment
Любые идеи относительно того, как я могу остановить потоки WebView после выхода из их активности? Почему тебе не все равно? Какой конкретно вред он причиняет?   -  person CommonsWare    schedule 11.01.2010
comment
Я пытался избежать запуска дополнительных потоков, хранения ресурсов в памяти и (возможно) добавления дополнительных слотов планирования процессора. Вы говорите, что это не повлияет ни на производительность, ни на ресурсы?   -  person Amit Kotlovski    schedule 13.01.2010
comment
то же самое. Потоки WebView слишком сильно разряжают батарею.   -  person xrath    schedule 13.06.2010


Ответы (10)


Вы должны иметь возможность останавливать/возобновлять эти потоки, вызывая onPause/onResume в веб-просмотре.

Однако они скрыты, поэтому вам нужно будет сделать это через отражение. У меня работал следующий код:

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

Где webView — это экземпляр WebView.

См. также: http://code.google.com/p/android/issues/detail?id=10282

person Skymt    schedule 20.08.2010
comment
Спасибо за ответ. Как говорится в отчете об ошибке в предоставленном вами URL-адресе, это может работать, но кажется немного грязным. Думаю, на данный момент это лучший ответ на этот вопрос. - person Amit Kotlovski; 25.08.2010
comment
Не могли бы вы более четко указать, где я должен добавить этот код. - person user1106888; 18.04.2013
comment
Что ж, принимая во внимание первоначальный вопрос, я бы переопределил основные методы активности onPause и onResume и вызвал их оттуда. - person Skymt; 24.04.2013
comment
Обратите внимание, что это не работает, если в WebView запущен какой-либо таймер Javascript. - person mkuech; 11.06.2013

Мое решение в расширенном классе веб-просмотра (проверено в 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) {}
     }
 }
person diyism    schedule 26.09.2011
comment
Работает отлично! это на самом деле сделало мое приложение намного быстрее. - person Rotemmiz; 25.04.2012
comment
Предостережение, которое следует иметь в виду. Я заметил, что если вы вызываете this.pauseTimers(), все WebView приостанавливаются, а не только тот экземпляр, для которого вы это вызываете. Это было на андроиде 4.0.4 - person Geert Weening; 23.07.2012
comment
Спасибо за тестирование Weenings в Android 4.0.4 - person diyism; 27.07.2012
comment
Это работает. Позвольте мне повторить: ЭТО, РАБОТАЕТ. Другой обходной путь был недостаточно хорош, потому что если у вас был веб-просмотр во фрагменте, если вы потеряли вложение, у вас больше не было доступа к потоку. Но это работает безупречно. Большое спасибо. - person Reinherd; 19.03.2014
comment
Лучшее решение на сегодняшний день :) - person JWqvist; 31.03.2014

Чистое простое решение, которое выполняет свою работу:

@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;
}
person Bolling    schedule 04.06.2014
comment
onPause и onResume веб-просмотра были недоступны до API 11. - person Ayyappa; 13.03.2015
comment
Это отлично сработало для моего приложения 4.4.2, хотя я еще не понял, что такое parentViewGroup.removeAllViews(); для, но javaScriptTester.removeAllViews(); казалось, было принято ide. так?? и, как сказал Айяппа, для этого требуется уровень API 11. - person Logic1; 23.06.2015
comment
@GmanO removeAllViews() очищает все связанные представления, такие как встроенные элементы управления масштабированием. Если они отображаются, когда вы отказываетесь от действия, вы получите утечку. См. stackoverflow.com/questions/27254570/ - person Scott D. Strader; 29.06.2015

Взгляните на эту ветку andev.org (проблема WebViewCoreThread< /а>).

См. ответ... Re: проблема WebViewCoreThread - Сообщение от pototho

2) Чтобы приостановить вспышку, вы должны вызвать скрытые методы WebView.onPause() / WebView.onResume().

3) Чтобы приостановить WebViewCoreThread, вы используете WebView.pauseTimers()/WebView.resumeTimers().

Я пропустил onPause/onResume, но реализовал webView.pauseTimers() и webView.resumeTimers(), и это, по крайней мере, остановило кровотечение ЦП.

Я также добавил CookieSyncManager.getInstance().stopSync() / startSync в мой onPause/onResume.

person rquinn    schedule 14.03.2011
comment
Спасибо, я нашел решение в блоге: в своей активности onPause вы должны вызывать WebView.onPause() и WebView.pauseTimers(). В вашей Activity onResume вы должны вызывать WebView.onResume() и WebView.resumeTimers(). Но поскольку в счетчике ссылок есть разовая ошибка, вам нужно вызвать WebView.resumeTimers() при первом создании WebView. WebView.class.getMethod(onPause).invoke(webview); - person diyism; 26.09.2011

Спасибо за эту информацию, у меня была эта проблема с приостановкой звуков в моем swf на webView, когда я нажимаю кнопку блокировки на телефоне, onPause и onResume по-прежнему воспроизводит мой swf, когда я нажимаю кнопку разблокировки, но активность все еще не видна, я предлагаю вам поместите их в onWindowFocusChanged, если вы хотите приостановить и возобновить воспроизведение звуков swf в 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);
}
person Keiichi    schedule 13.10.2011

А как насчет WebView.destroy()? Это, кажется, очищает вещи или меня, не делая никаких причудливых звонков для размышлений.

person Dan Carpenter    schedule 17.05.2013

На самом деле, использование webView.destroy(), onPause(), clear**() еще не может остановить Webcore и связанные с ним потоки.

На практике идеальным способом является установка действия, в котором находится WebView, в независимом процессе, так что, когда действие завершится, все потоки, включая Webcore, будут уничтожены.

Именно так я и работал. Возможно, это также полезно для вас.

person Verdigrass    schedule 31.05.2014

Мне пришлось вызвать onDestroy WebView, чтобы очистить память специально для веб-просмотра. Я загружал флэш-память, и это убивало мое приложение, когда мы возвращаемся к этому действию с веб-просмотром. Flash съест вас заживо, если вы не будете уничтожать свой WebView КАЖДЫЙ РАЗ, когда закончите с ним работать.

person Eric Novins    schedule 21.01.2011

Приведенные выше решения не помогли мне на Samsung Galaxy S с Android 2.3.3. Но я добился успеха, попробовав следующий обходной путь:

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

Я заставляю веб-просмотр загружать несуществующий файл html. Кажется, это заставляет веб-просмотр очищать вещи.

person dangel    schedule 09.05.2013

Определите метод:

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

затем вызовите hiddenWebViewMethod("onPause");, чтобы остановить загрузку, и hiddenWebViewMethod("onResume");, чтобы возобновить.

person Ayaz Alifov    schedule 11.02.2015