Android AdMob вызывает утечку памяти? - PullRequest
21 голосов
/ 27 мая 2011

Я интегрировал AdMob v4.1.0 в свое приложение, и, похоже, это вызвало огромную утечку памяти (я уверен, что это уже произошло в 4.0.4).

Чтобы изолировать проблему, ясоздал новый проект с пустым линейным макетом и добавил в него AdView (на самом деле это копия и вставка из примера кода, предоставленного AdMob).Смотрите мой main.xml, MainActivity.java и содержимое манифеста:

main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/linearLayout">
<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello"
    />
</LinearLayout>

MainActivity.java:

package AdsTry.main;

import com.google.ads.AdRequest;
import com.google.ads.AdSize;
import com.google.ads.AdView;

import android.app.Activity;
import android.os.Bundle;
import android.widget.LinearLayout;

public class MainActivity extends Activity {

    private final int AD_VIEW_ID = 1000000; 

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

         // Lookup R.layout.main
        LinearLayout layout = (LinearLayout)findViewById(R.id.linearLayout);

        // Create the adView
        // Please replace MY_BANNER_UNIT_ID with your AdMob Publisher ID
        AdView adView = new AdView(this, AdSize.BANNER, "MY_BANNER_UNIT_ID");
        adView.setId(AD_VIEW_ID);

        // Add the adView to it
        layout.addView(adView);

        // Initiate a generic request to load it with an ad
        AdRequest request = new AdRequest();

        adView.loadAd(request);           
    }

    @Override
    protected void onPause() {
        Log.i("AdsTry", "onPause");

        getAdView().stopLoading();

        super.onPause();
    }

    @Override
    protected void onDestroy() {
        Log.i("AdsTry", "onDestroy");

        getAdView().destroy();

        super.onDestroy();
    }

    private AdView getAdView()
    {
        return (AdView) findViewById(AD_VIEW_ID);
    }
}

манифест:

<application android:icon="@drawable/icon" android:label="@string/app_name">
    <activity android:name=".MainActivity"
              android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <!-- AdMobActivity definition -->
    <activity android:name="com.google.ads.AdActivity"
        android:configChanges="orientation|keyboard|keyboardHidden" />
</application>

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

И это весь код, который у меня есть.

Теперь, когда я запускаю это приложение, я вижу, что и onPause, и onDestory вызываются, и действие прекращается, но проблема в том, что оно будетникогда не будет доступен для GC, поскольку он заставляет InputMethodManager содержать ссылку на действие (см. изображение, полученное из вывода HPROF после того, как действие было уничтожено): MainActivity Merge shortest path to GC Roots

После удаления кода, связанного с AdView (и опять же, это ЕДИНСТВЕННЫЙ код этого приложения) проблема исчезает: Same HPROF output without using AdView

РЕДАКТИРОВАТЬ: также попытался удалить ВСЕ код из onCreate и обновил main.xml, чтобы содержать следующее (по-прежнему получитьтот же результат):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:ads="http://schemas.android.com/apk/lib/com.google.ads"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/linearLayout">
    <TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello"
    />
    <com.google.ads.AdView
    android:id="@+id/Ad"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    ads:adUnitId="MY_ID"
    ads:adSize="BANNER"
    ads:loadAdOnCreate="true"/>
</LinearLayout>

Любые идеи ????

Ответы [ 8 ]

6 голосов
/ 18 июня 2015

Я использую "play-services-ads: 7.5.0", и создание Ad AdMobActivity не требовалось. Работает:

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

mAdView = new AdView(getApplicationContext(), AdSize.BANNER, banner_ad_unit_id); mAdsContainer.addView(mAdView);

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

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

К сожалению, интерстициальные утечки все еще

5 голосов
/ 03 декабря 2011

Вот моя работа для этого беспорядка:

Я ограничил утечку памяти, используя тот же пустой экземпляр действия:

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);
        finish();
    }

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

Дальнейшее объявление будет создано с использованием AdMobActivity.AdMobMemoryLeakWorkAroundActivity .

Вы также должны добавить действие к манифесту, конечно:

<activity
    android:launchMode="singleInstance"
    android:name="com.nu.art.software.android.modules.admob.AdMobActivity" />

Эта реализация идет вразрез с моими убеждениями относительно статических ссылок, которые не являются константами, но эта реализация предотвращает утечку, потому что только один экземпляр действия используется для создания всех объявлений, и, таким образом, больше нет утечек активности, плюс тот факт, что активность полностью пусто.

ПРИМЕЧАНИЕ: Вы должны вызвать метод startAdMobActivity из основного действия приложения onCreate метод.

Адам.

UPDATE

Это решение работает, только если вы создаете объявление динамически и добавляете его в макет с помощью кода ... и не забудьте уничтожить его в Activity.onDestroy ().

3 голосов
/ 11 июля 2011

Одним из способов решения этой проблемы является создание одного экземпляра рекламы, используя базовую активность вашего приложения. Добавьте это объявление к любому желаемому действию, но не забудьте удалить его в действиях метода уничтожения.

Таким образом, в объявлении просачивается только базовая активность, которая почти никогда не должна иметь более одного экземпляра.

Пример:

@Override
public void onCreate(final Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   this.setContentView(R.layout.venue);
   mainLayout = (LinearLayout) findViewById(R.id.venueLayout);
   adview = StaticStateClass.getAdview();

   AdRequest request = new AdRequest();
   request.addKeyword(name);
   mainLayout.addView(adview);
   adview.loadAd(request);
}

@Override
public void onDestroy() {
   mainLayout.removeView(adview);
   super.onDestroy();
}
2 голосов
/ 01 марта 2015

Я обнаружил, что вызов: -

mAdView.destroy(); 

, прежде чем покинуть мероприятие, решает проблему для меня.

Вот как я объявляю рекламные баннеры в xml: -

  <com.google.android.gms.ads.AdView
            android:id="@+id/adView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal|bottom"
            ads:adSize="BANNER"
            ads:adUnitId="@string/banner_ad_unit_id_2" />

Получить ссылку на баннер admob в onCreate (): -

mAdView = (AdView) findViewById(R.id.adView2);
AdRequest banneradRequest = new AdRequest.Builder().build();

mAdView.loadAd(banneradRequest);

и уничтожить его в ondestroy () действия: -

@Override
protected void onDestroy() {
    super.onDestroy();
    mAdView.destroy();
}
1 голос
/ 17 августа 2011

Я столкнулся с той же проблемой. Единственное, что мне помогло - это System.exit (0). Мне это не нравится, но это единственный способ, который я нашел.
AdMob просто остается в оперативной памяти 4ever и не позволяет моему приложению завершиться правильно. Когда я перезагружаю мое приложение, ОС просто вызывает это неживое приложение, и вскоре оно вызывает исключение нехватки памяти.
Моя тема на форуме поддержки AdMob - пока поддержки нет. Похоже, что № 1 заботится.

0 голосов
/ 04 октября 2014

Другой ответ, который решает эту проблему, несмотря на то, что это трудно, - выполнить следующие шаги.

  • отменять обработку всех данных, которые требуются из sharedPreferences или любых других типов сохранения,
    сохранять эти значения в локальных переменных / объектах

  • Протрите все данные вашего приложения

  • повторно сохранить все

Вы можете запустить службу, когда ваше приложение закрывается, чтобы сделать это.Это предотвратит увеличение объема данных из-за утечки памяти.Гадкий способ решения этой проблемы, но я попробовал, и это работает.

0 голосов
/ 03 июня 2011

По сути, это не проблема.Что происходит, так это то, что ваша деятельность получает onDestroy, выполняет его очистку, а затем ждет запуска GC.Когда происходит сборщик мусора, он видит этот старый контекст, лежащий вокруг, и очищает весь основной ганк, но, похоже, он не очищает активность в этом проходе - вот почему ваша «утечка» активности имеет такой маленький след:в основном оболочка.На следующем проходе GC он будет очищен.

Вы можете сами убедиться в этом, активизировав свою деятельность, отступив (чтобы вызвать onDestroy), вернувшись в процесс, запустив GC и дамп hprof., немного подождав, затем запустив еще один GC и дамп hprof.В первом дампе - по крайней мере, в моем тестировании - я увидел результаты, похожие на ваши: дополнительная активность с очень небольшим объемом памяти.Во втором дампе я увидел только текущую активность.

0 голосов
/ 27 мая 2011

Не объединяйте свой пользовательский интерфейс с Admob. Вы можете запустить другой поток, чтобы получить рекламу от Admob.Также вы можете обновить объявление через определенный промежуток времени.Вам будет легче отлаживать там, где может быть проблема с памятью.

Спасибо Deepak

...