[Android] Утечка памяти Admob - избегая пустых действий


Answers

Я использую «play-services-ads: 7.5.0», и не было необходимости создавать AdMobActivity. Он работал:

  • Создание adView динамически

    mAdView = новый AdView (getApplicationContext (), AdSize.BANNER, banner_ad_unit_id); mAdsContainer.addView (mAdView);

  • Удаление всех представлений от linearLayout для уничтожения и уничтожения adView

                mAdView.setAdListener(null);
                mAdsContainer.removeAllViews();
                mAdView.destroy();

К сожалению, Interstitial все еще течет

Question

Наше приложение сильно пострадало от утечки памяти. Я обнаружил, что основной причиной является AdMob AdView, ссылаясь на старые действия. Проблема довольно хорошо документирована в вопросе Android AdMob вызывает утечку памяти? и сублинкции в комментариях / ответах. Я заметил, что проблема не проявляется в ICS, поскольку GC в конечном итоге очищает WebViews от ссылок на действия. Тем не менее, мой HTC EVO 3D работает с пряничными пряниками, никогда не собирает активности и учитывая количество отчетов о закрытии силы из-за ошибок OOM, проблема очень распространена для нашего приложения.

Я хотел бы следовать решению, предоставленному TacB0sS, https://.com/a/8364820/684893 . Он предложил создать пустую деятельность и использовать ту же самую активность для каждого AdView AdMob. Утечка будет содержаться, поскольку AdView будет поддерживать только ту пустую активность. Он предоставил код для самой деятельности и как ссылаться на нее, но я не понимаю, как ее можно интегрировать в наше приложение. Насколько мне известно, его код никогда не вызывает ничего из SDK AdMob.

В настоящее время мы используем AdView в XML-макетах, поэтому мы не динамически ничего не делаем с объявлениями в коде, такими как call loadAd (). Все наши макеты с рекламой полагаются на объявление, находящееся в XML, поскольку они расположены относительно него. Таким образом, мои два вопроса: как я могу реализовать код TacB0sS и как сохранить отношения XML-макета, если нам нужно переключиться на создание макетов XML в коде?

Обновление 3/6:

Спасибо Адаму (TacB0sS) за ответ! У меня нет проблем с переходом на создание кода Ad, но у меня все еще есть трудности с использованием вашей фиктивной активности при создании объявлений. В настоящее время мой код:

AdMobActivity adActivity = new AdMobActivity();
adActivity.startAdMobActivity(this);

// Create an ad with the activity reference pointing to dummy activity
AdView adView = new AdView(adActivity.AdMobMemoryLeakWorkAroundActivity, AdSize.IAB_BANNER, "myAdUnitID");

// Create an ad request.
AdRequest adRequest = new AdRequest();

// add the ad to the layout and request it to be filled
RelativeLayout root_main = (RelativeLayout) findViewById(R.id.root_main);
root_main.addView(adView);
adView.loadAd(adRequest);

Я поместил этот код в метод onCreate моей начальной активности. Я набираю силу в строке, где я создаю AdView, «AdView adView = новый AdView (...)». Фрагмент Stacktrace:

03-06 00:34:28.098 E/AndroidRuntime(16602): java.lang.RuntimeException: Unable to start activity ComponentInfo{org.udroid.wordgame/org.udroid.wordgame.MainMenu}: java.lang.NullPointerException
03-06 00:34:28.098 E/AndroidRuntime(16602):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1830)
(...)
03-06 00:34:28.098 E/AndroidRuntime(16602): Caused by: java.lang.NullPointerException
03-06 00:34:28.098 E/AndroidRuntime(16602):     at android.content.ContextWrapper.getApplicationContext(ContextWrapper.java:100)
03-06 00:34:28.098 E/AndroidRuntime(16602):     at com.google.ads.AdView.<init>(SourceFile:78)
03-06 00:34:28.098 E/AndroidRuntime(16602):     at org.udroid.wordgame.MainMenu.onCreate**(MainMenu.java:71)**  <- Line that creates the new AdView

Каков правильный способ инициализации AdMobActivity и ссылки на него при создании AdView? Еще раз спасибо!

Обновление 2 3/6:

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

Создайте новое действие под названием AdMobActivity:

public final class AdMobActivity extends Activity {

    public static AdMobActivity AdMobMemoryLeakWorkAroundActivity;

    public AdMobActivity() {
        super();
        if (AdMobMemoryLeakWorkAroundActivity != null) {
            throw new IllegalStateException("This activity should be created only once during the entire application life");
        }
        AdMobMemoryLeakWorkAroundActivity = this;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i("CHAT", "in onCreate - AdMobActivity");
        finish();
    }

    public static final void startAdMobActivity(Activity activity) {
        Log.i("CHAT", "in startAdMobActivity");
        Intent i = new Intent();
        i.setComponent(new ComponentName(activity.getApplicationContext(), AdMobActivity.class));
        activity.startActivity(i);
    }
}

Добавьте в свой AndroidManifest.xml следующее.

<activity android:name="org.udroid.wordgame.AdMobActivity"
    android:launchMode="singleInstance" />

Перед загрузкой любых объявлений необходимо инициализировать манекен AdMobActivity. Эта деятельность не будет содержать ничего. Он будет отображаться в течение секунды секунды, а затем закрывается, возвращаясь к действию, в котором вы его вызывали. Вы не можете создать его в том же активном действии, которое хотите загрузить Объявления, поскольку оно должно быть полностью инициализировано вовремя перед использованием. Я инициализирую его в действии экрана экрана всплеска на CreateCreate до того, как основное действие, которое содержит объявление, начнется:

// Start the dummy admob activity.  Don't try to start it twice or an exception will be thrown
if (AdMobActivity.AdMobMemoryLeakWorkAroundActivity == null) {
    Log.i("CHAT", "starting the AdMobActivity");
    AdMobActivity.startAdMobActivity(this);
}

Теперь вы готовы создавать рекламу в коде. Добавьте следующий LinearLayout к вашему макету действий XML. Выровняйте все остальные виды, необходимые вокруг этого макета. Созданный в коде AdView будет размещен внутри этого представления.

<LinearLayout
android:id="@+id/adviewLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true" />

В действии, которое вы хотите загрузить, создайте глобальную переменную для AdView:

AdView adView;

В нашем приложении мы загружаем разные макеты, когда телефон вращается. Поэтому я призываю следующий код для каждого поворота. При необходимости он создает adView и добавляет его в adviewLayout.

    // DYNAMICALLY CREATE AD START
    LinearLayout adviewLayout = (LinearLayout) findViewById(R.id.adviewLayout);
    // Create an ad.
    if (adView == null) {
        adView = new AdView(AdMobActivity.AdMobMemoryLeakWorkAroundActivity, AdSize.BANNER, "<ADUNITID>");
        // Create an ad request.
        AdRequest adRequest = new AdRequest();
        // Start loading the ad in the background.
        adView.loadAd(adRequest);
        // Add the AdView to the view hierarchy. The view will have no size until the ad is loaded.
        adviewLayout.addView(adView);
    }
    else {
        ((LinearLayout) adView.getParent()).removeAllViews();
        adviewLayout.addView(adView);
        // Reload Ad if necessary.  Loaded ads are lost when the activity is paused.
        if (!adView.isReady() || !adView.isRefreshing()) {
            AdRequest adRequest = new AdRequest();
            // Start loading the ad in the background.
            adView.loadAd(adRequest);
        }
    }
    // DYNAMICALLY CREATE AD END

Наконец, убедитесь, что вы вызываете adView.destroy () в методах onDestroy ():

@Override
protected void onDestroy() {
    adView.destroy();
super.onDestroy();
}

Любой, кто читает это, помните, что это решение Адама (TacB0sS), а не мое. Я просто хотел предоставить полную информацию о реализации, чтобы сделать ее проще для других. Эта ошибка AdMob представляет собой огромную проблему для приложений, работающих с pre-honeycomb, и решение Адама - лучшее, что я могу найти, чтобы обойти его. И это работает!




Links