La nostra app viene colpita da una perdita di memoria. Ho scoperto che la causa principale è AdMob AdView che mantiene i riferimenti alle vecchie attività. Il problema è abbastanza ben documentato nella domanda Android AdMob causes memory leak? e il sottolinking nei commenti/risposte. Ho notato che il problema non è evidente in ICS in quanto il GC alla fine pulisce le WebViews con riferimenti alle attività. Tuttavia, il mio gingerbread di HTC EVO 3D non raccoglie mai le attività e, considerando il numero di report di chiusura forzata dovuti a errori OOM, il problema è molto diffuso per la nostra app.Perdita di memoria Admob - evitando utilizzando attività vuota
Vorrei seguire la soluzione fornita da TacB0sS, https://stackoverflow.com/a/8364820/684893. Ha suggerito di creare un'attività vuota e utilizzare la stessa attività per ogni AdMob AdView. La perdita sarebbe contenuta poiché AdView manterrà in vita solo un'attività vuota. Ha fornito il codice per l'attività stessa e come farvi riferimento, ma non riesco a integrarlo nella nostra app. Il suo codice non chiama mai nulla da AdMob SDK per quanto posso dire.
Attualmente stiamo utilizzando AdView nei layout XML in modo da non eseguire dinamicamente alcunché con gli annunci nel codice come call loadAd(). Tutti i nostri layout con pubblicità si basano sul fatto che l'annuncio sia nell'XML poiché sono disposti in relazione ad esso. Le mie due domande sono quindi, come posso implementare il codice TacB0sS e come posso mantenere le mie relazioni di layout XML se dobbiamo passare alla creazione dei layout XML nel codice?
Aggiornamento 3/6:
Grazie Adam (TacB0sS) per la risposta! Non ho alcun problema a passare alla creazione del codice Annuncio in, ma sto ancora avendo difficoltà a utilizzare l'attività fittizia durante la creazione di annunci. Il mio codice è attualmente:
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);
Ho inserito questo codice nel metodo onCreate della mia attività iniziale. Prendo una forza vicino alla linea in cui creo l'AdView, "AdView adView = new AdView (...)". Stacktrace Snippet:
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
Qual è il modo corretto di inizializzare l'AdMobActivity e farvi riferimento durante la creazione del AdView? Grazie ancora!
Aggiornamento 2: 3/6:
ho capito i miei problemi che creano l'attività. Ho completamente implementato la tua soluzione e la parte migliore è che lo risolve effettivamente la mia perdita di memoria. Dopo aver trascorso due settimane su questo problema, sono così felice che è stato risolto. Ecco i passi pieni che ho usato:
creare una nuova attività denominata 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);
}
}
Aggiungere il seguente al vostro AndroidManifest.xml
<activity android:name="org.udroid.wordgame.AdMobActivity"
android:launchMode="singleInstance" />
È necessario inizializzare l'AdMobActivity manichino prima di provare caricare qualsiasi annuncio. Questa attività non conterrà nulla. Verrà visualizzato per una frazione di secondo e poi chiuso, ritornando all'attività in cui è stato chiamato. Non è possibile crearlo nella stessa attività in cui si desidera caricare Ads poiché deve essere inizializzato completamente in tempo prima dell'utilizzo.Inizializzo in onCreate di un'attività schermata di caricamento iniziale prima che l'attività principale che contiene un annuncio inizia:
// 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);
}
Ora siete pronti per creare annunci nel codice. Aggiungi il seguente LinearLayout al tuo layout di attività XML. Allinea tutte le altre viste necessarie attorno a questo layout. L'AdView che creiamo in codice sarà posizionata all'interno di questa vista.
<LinearLayout
android:id="@+id/adviewLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true" />
Nell'attività si desidera caricare un annuncio, creare una variabile globale per l'AdView:
AdView adView;
Nella nostra applicazione, abbiamo caricare diversi layout durante la rotazione del telefono. Pertanto, chiamo il seguente codice ad ogni rotazione. Crea l'adView, se necessario, e lo aggiunge al 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
Infine, assicuratevi di chiamare adView.destroy() nelle attività OnDestroy() metodo:
@Override
protected void onDestroy() {
adView.destroy();
super.onDestroy();
}
chiunque altro che legge questo, si ricorda che questa è la soluzione di Adamo (TacB0sS), non mio. Volevo solo fornire i dettagli completi dell'implementazione per renderlo più semplice da implementare per gli altri. Questo bug AdMob è un grosso problema per le app che eseguono pre-honeycomb e la soluzione di Adam è la cosa migliore che riesco a trovare per aggirarlo. E funziona!
funziona come un fascino !! Grazie ad entrambi @ravishi e @ TacB0sS !! – Regis
Ciao ravishi ... Sto avendo problemi con questa soluzione. Potete per favore aiutarmi. Questa è la mia domanda http://stackoverflow.com/questions/15583994/activity-does-not-launch-from-the-recent-activities-android –
C'è un collegamento al codice completo @ravishi? –