Fuga de memoria de Admob: evitar mediante el uso de actividad vacía

Nuestra aplicación está siendo golpeada por una pérdida de memoria. Descubrí que la causa raíz es AdMob AdView que mantiene referencias a actividades antiguas. El problema está bastante bien documentado en la preguntaAndroid AdMob causa pérdida de memoria? y los subenlaces en los comentarios / respuestas. He notado que el problema no es aparente en ICS ya que el GC eventualmente limpia las WebViews con referencias a actividades. Sin embargo, mi pan de jengibre stock HTC EVO 3D nunca recopila las actividades y teniendo en cuenta la cantidad de informes de cierre forzado debido a errores de OOM, el problema está muy extendido para nuestra aplicació

Me gustaría seguir la solución provista por TacB0sS,https: //stackoverflow.com/a/8364820/68489. Sugirió crear una actividad vacía y usar esa misma actividad para cada AdMob AdView. La fuga estaría contenida ya que AdView solo mantendrá viva esa actividad vacía. Proporcionó el código para la actividad en sí y cómo hacer referencia a ella, pero no sé cómo integrarlo realmente en nuestra aplicación. Su código nunca llama a nada desde AdMob SDK hasta donde puedo decir.

Actualmente estamos usando AdView en los diseños XML, por lo que no hacemos nada dinámicamente con los anuncios en el código, como call loadAd (). Todos nuestros diseños con anuncios dependen de que el anuncio esté en el XML, ya que se presentan en relación con él. Mis dos preguntas son, entonces, ¿cómo implemento el código TacB0sS y cómo puedo mantener mis relaciones de diseño XML si tenemos que cambiar a crear diseños XML en el código?

Update 3/6:

Gracias Adam (TacB0sS) por responder! No tengo problemas para cambiar a crear el anuncio en el código, pero sigo teniendo dificultades para usar su actividad ficticia al crear anuncios. Mi código actualmente es:

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

He colocado este código en el método onCreate de mi actividad inicial. Obtengo una fuerza cercana en la línea donde creo el AdView, "AdView adView = new AdView (...)". Fragmento de 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

¿Cuál es la forma correcta de inicializar su AdMobActivity y hacer referencia a ella al crear AdView? ¡Gracias de nuevo

Update 2 3/6:

Resolví mis problemas para crear la actividad. Tengo su solución totalmente implementada y la mejor parte es queactualmente resuelve mi pérdida de memoria. Después de pasar dos semanas en este problema, estoy muy feliz de que se haya resuelto. Aquí están los pasos completos que utilicé:

Cree una nueva actividad llamada 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);
    }
}

Agregue lo siguiente a su AndroidManifest.xml

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

Necesita inicializar el AdMobActivity ficticio antes de intentar cargar cualquier anuncio. Esta actividad no contendrá nada. Se mostrará durante una fracción de segundo y luego se cerrará, volviendo a la actividad en la que lo llamó. No puede crearlo en la misma actividad que desea cargar anuncios, ya que debe inicializarse completamente a tiempo antes de usarlo. Lo inicializo en una actividad de pantalla de carga de bienvenida onCreate antes de que comience la actividad principal que contiene un anuncio:

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

Ahora está listo para crear anuncios en código. Agregue el siguiente LinearLayout a su diseño de actividad XML. Alinee todas las demás vistas necesarias alrededor de este diseño. El AdView que creamos en el código se colocará dentro de esta vista.

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

En la actividad que desea cargar un anuncio, cree una variable global para AdView:

AdView adView;

En nuestra aplicación, cargamos diferentes diseños cuando el teléfono gira. Por lo tanto, llamo al siguiente código en cada rotación. Crea el adView si es necesario y lo agrega a 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

Por último, asegúrese de llamar a adView.destroy () en el método de actividades onDestroy ():

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

Cualquier otra persona que lea esto, recuerde que esta es la solución de Adam (TacB0sS), no la mía. Solo quería proporcionar los detalles completos de implementación para facilitar la implementación de otros. Este error de AdMob es un gran problema para las aplicaciones que se ejecutan antes del nido de abeja y la solución de Adam es lo mejor que pude encontrar para evitarlo. @¡Y funciona