WebViewCoreThread, используемый admob AdView, использует высокую загрузку ЦП, даже когда родительская активность приостановлена ​​

Я использую Google Admob SDK v6.1.0 (https://developers.google.com/mobile-ads-sdk/download), создаю экземпляр com.google.ads.AdView программно (не в XML) и добавляю его в LinearLayout, динамически в моей деятельности.

Один из моих пользователей сообщил, что когда они нажимают кнопку «Домой» во время моей активности (чтобы сделать ее фоновой), они начинают видеть высокую загрузку ЦП, связанную с моим приложением. Я смог воспроизвести это на платформе Jellybean и заметил, что источником высокой загрузки ЦП был WebViewCoreThread.

Моя активность вообще не использует никаких веб-представлений, но я смог выполнить инициализацию своей активности и заметил, что этот WebViewCoreThread запускается, когда я создаю экземпляр объекта AdMob AdView. Как указано в ссылках AdMob, я вызываю destroy() для этого AdView в методе onDestroy() моей Activity. И я также изменил свой код, чтобы вызвать AdView.onDestroy() в моем методе onPause(). Но, похоже, ничто не приводит к остановке WebViewCoreThread. Я думаю, я в порядке, если эта нить останется. Но если я запускаю свою активность несколько раз снова и снова, этот поток начинает использовать где-то от 8 до 25% моего ЦП, даже моя активность не находится на переднем плане.

Я заметил, что несколько других пользователей говорят, что вы должны вызвать WebView.onPause() в качестве корректирующего действия. (http://stackoverflow.com/questions/2040963/webview-threads-never-stop-webviewcorethread-cookiesyncmanager-http0-3) Но это невозможно для меня напрямую, поскольку мое веб-представление создается AdView AdMob. Я также изменил свой код, чтобы вызвать .removeAllViews() для объекта LinearLayout контейнера Admob AdView mt, а затем вызвать System.gc() для принудительной сборки мусора, но, похоже, ничто не убивает мой WebViewCoreThread, и в конце концов он начинает потреблять ЦП, пока я не принудительно -убить процесс моего приложения.

Любые подсказки, почему AdMob делает это, и как я могу принудительно убить этот поток?

Я прикрепляю созданный мной класс для инкапсуляции создания и уничтожения AdView. Я вызываю метод getNewAd() этого класса при инициализации моей активности. И я вызываю метод removeAd() этого класса в методах onPause() и onDestroy() моей Activity:

package com.shiprack.client;

import com.google.ads.AdRequest;
import com.google.ads.AdSize;
import com.google.ads.AdView;
import com.mobclix.android.sdk.Mobclix;
import com.mobclix.android.sdk.MobclixMMABannerXLAdView;

import android.app.Activity;
import android.view.Gravity;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;

public class AdManager {
    public AdManager(EventLog logger, LinearLayout container, Activity activity) {
        _container = container;
        _activity = activity;
        _eventLogger = logger;
    }

    public void setNetwork(int network) {
        _network = network;
    }

    public void getNewAd() {
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT);
        params.gravity = Gravity.CENTER;
        switch (_network) {
            case TrackDatabase.AD_NETWORK_ADMOB: {
                _admobBanner = new AdView(_activity, AdSize.BANNER, "a14dc419375634c");
                _container.addView(_admobBanner, params);
                _admobBanner.loadAd(new AdRequest());
                break;
            }
            case TrackDatabase.AD_NETWORK_MOBCLIX: {
                Mobclix.onCreate(_activity);
                _mobclixBanner = new MobclixMMABannerXLAdView(_activity);
                _container.addView(_mobclixBanner, params);
                _mobclixBanner.getAd();
                break;
            }
        }
    }

    public void removeAd() {
        switch (_network) {
            case TrackDatabase.AD_NETWORK_ADMOB: {
                _admobBanner.destroy();
                break;
            }
            case TrackDatabase.AD_NETWORK_MOBCLIX: {
                _mobclixBanner.cancelAd();
                break;
            }
        }
        _container.removeAllViews();
    }

    private EventLog _eventLogger;
    private LinearLayout _container;
    private Activity _activity;
    private AdView _admobBanner;
    private MobclixMMABannerXLAdView _mobclixBanner;
    private int _network;
}

person Shiprack    schedule 14.10.2012    source источник
comment
Я думаю, что у меня это работает, но я не добавляю это в качестве ответа, потому что я еще не полностью убежден. После вызова destroy() для объекта AdMob AdView я теперь устанавливаю ссылку на null, что удаляет все ссылки на AdView, возможно, вызывая сборку мусора и, таким образом, избегая бесконечного запуска любых WebViewCoreThreads. В целом, мне не нравится такой подход — такая работа по очистке должна выполняться в рамках удаления AdMob. Или, на самом деле, мне даже не нужно было бы вызывать destroy() - это замедляет мою активность в паузе.   -  person Shiprack    schedule 18.10.2012


Ответы (3)


Не уверен, что эта информация еще кому-то нужна, но я сам искал решение этой проблемы. Очевидно, AdMob все еще имеет недостатки.

Единственная проблема в том, что это остановит работу всех WebView в фоновом режиме. Только проблема, если ваше приложение зависит от этого для работы.

Добавить к onPause() :

new WebView(this).pauseTimers();

и onResume() :

new WebView(this).resumeTimers();

Это сообщение поступило от сотрудника Google, который утверждает, что изучает его: https://groups.google.com/d/msg/google-admob-ads-sdk/Qu4G19NFAuI/wcNkoV0AeDUJ

person Bryan C    schedule 08.03.2014
comment
Спасибо! Я попробую это. - person Shiprack; 13.03.2014
comment
Надеюсь, поможет. Это сотворило со мной чудеса, но было бы лучше, если бы AdView.pause() работал как надо. - person Bryan C; 15.03.2014
comment
Это правильное решение (и единственное, которое сработало для меня) для новой версии AdMob (содержащейся в сервисах Google Play). - person Szymon; 05.04.2014
comment
Это также решило мою проблему, хотя проблема, казалось, существовала только для анимированных объявлений. Жаль, что я использую Cordova, он также приостанавливает мой веб-просмотр Cordova, а это не то, что мне нужно :(. Вернуться к чертежной доске - person Hless; 16.10.2014
comment
Долго искал решение!! Лучший ответ! Вы сделали мой день/неделю/месяц ;) - person Wicked161089; 21.01.2015
comment
К сожалению, не работает на Galaxy S5/Android 4.4. - person mdicosimo; 01.03.2015
comment
Помогите мне немного. Основная активность по-прежнему занимает много ресурсов ЦП, но теперь не в фоновом режиме. Спасибо. - person Eliasz Kubala; 03.07.2015

После вызова destroy() для объекта AdMob AdView я теперь устанавливаю ссылку на null, что удаляет все ссылки на AdView, возможно, вызывая сборку мусора и, таким образом, избегая бесконечного запуска любых WebViewCoreThreads. В целом, мне не нравится такой подход — такая работа по очистке должна выполняться в рамках удаления AdMob. Или, на самом деле, мне даже не нужно было бы вызывать destroy() - это замедляет мою активность в паузе.

Однако большой недостаток: многие мои пользователи жалуются на медлительность при нажатии кнопок «Назад» или «Домой» в моем приложении. Очевидно, это связано с затратами времени на метод onPause() при вызове admob destroy(). Долгосрочное решение состоит в том, чтобы использовать Fragments и ActionBar и не создавать несколько копий баннера Admob (по одной в каждом действии).

person Shiprack    schedule 23.10.2012
comment
Может с адмоба сгорит деструкт в ветке? - person stu; 04.07.2014

PZolee разместил сообщение на эту тему и предложил решение в своем блоге: ="nofollow">https://pzoleeblogen.wordpress.com/2014/07/08/android-how-to-solve-adview-cpu-using/

Я исследовал это дальше (в комментариях к сообщению в блоге задокументированы мои трудности) и пришел к следующему выводу:

  1. Действительно, вызов просто adView.pause(); не мешает компоненту Google Ads потреблять ресурсы ЦП, даже если приложение находится в фоновом режиме и реклама не отображается.
  2. Поиск всех WebView внутри нашего adView и вызов для них методов onPause() и onResume() WevView не решает проблему ненужного потребления процессора.
  3. Только вызов методов WebView pauseTimers() и возобновитьTimers(), как предлагает автор сообщения выше, останавливает ненужное потребление ЦП.
  4. В рекурсивном поиске всех WebView и вызове pauseTimers() и restoreTimers() для всех них нет необходимости, так как один такой вызов «приостанавливает (или возобновляет – g.) все таймеры компоновки, синтаксического анализа и JavaScript для всех WebView. (внутри процесса — ж.)» — см. документацию компонента WebView.
  5. Если вы используете WebView где-либо еще в своем приложении — может быть, в других действиях, — вы должны использовать для него метод restoreTimers(), иначе он не будет работать правильно. Кроме того, имейте в виду, что WevView может быть создан временно и использоваться некоторыми библиотечными функциями, которые вы используете в своем проекте, без вашего явного уведомления об этом. Это может быть, например. приглашение войти на какой-либо веб-сайт, в социальную сеть и т. д. Такой WebView может снова работать некорректно, если в вашем процессе где-то вызывалась pauseTimers() и вы не возобновили их. БУДЬТЕ ОСТОРОЖНЫ И ПРОВЕРЬТЕ все, что можете.

Очень жаль, что Google и AdMob преподнесли нам такой неприятный сюрприз со своим рекламным компонентом (постоянное потребление процессора, даже если вы запускаете приложение в фоновом режиме, скрываете их компонент, даже приостанавливаете () его с помощью собственного вызова API…

person gregko    schedule 29.01.2015