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.

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

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

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

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

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

Ответы

Ответ 1

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

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

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

new WebView(this).pauseTimers();

и onResume():

new WebView(this).resumeTimers();

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

Ответ 2

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

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

Ответ 3

PZolee опубликовал эту тему и предлагаемое решение в своем блоге: https://pzoleeblogen.wordpress.com/2014/07/08/android-how-to-solve-adview-cpu-consuming/

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

  • Действительно, вызов просто adView.pause(); не останавливает компонент Google Ads от потребления ЦП, даже если приложение находится в фоновом режиме, а объявления не отображаются.
  • Поиск всех WebView внутри нашего adView и вызова методов onPause() и onResume() WevView на них не решает проблему ненужного потребления ЦП.
  • Только вызовы методов WebView pauseTimers() и resumeTimers(), как предлагает автор вышеприведенной публикации, останавливают ненужное потребление ЦП.
  • Поиск рекурсивно всех WebView и вызовов pauseTimers() и resumeTimers() для всех из них не требуется, поскольку один из таких вызовов "Приостанавливает (или возобновляет - g)) все макеты, синтаксический анализ и таймеры JavaScript для всех WebView. ( в процессе - g.)" - см. документы компонента WebView.
  • Если вы используете WebView где-нибудь еще в своем приложении - возможно, в других действиях, вы должны возобновитьTimers() для него, или он не будет работать правильно. Кроме того, имейте в виду, что WevView может быть временно создан и использован некоторыми библиотечными функциями, которые вы используете в своем проекте, не зная об этом. Это может быть, например, подсказка для входа на какой-либо веб-сайт, в социальную сеть и т.д. Такой WebView может снова не работать правильно, если pauseTimers() был вызван в вашем процессе где-то, и вы не возобновили их. ИСПОЛЬЗУЙТЕ ОСТОРОЖНО И ИСПЫТАТЬ все, что вы можете.

Поистине позор, что Google и AdMob обратили на нас такой неприятный сюрприз с их рекламным компонентом (постоянное потребление ЦП, даже если вы используете приложение, скрываете свой компонент, даже пауза() его своим API-вызовом...