2014-10-23 3 views
23

Sto utilizzando AdMob in un frammento. A volte vedo il seguente stackChe cosa sta causando la perdita di ServiceConnection di Google AdMob?

10-23 14:27:38.916: E/ActivityThread(21250): Activity com.applegrew.app.skywifiremote.MainActivity has leaked ServiceConnection [email protected] that was originally bound here 
10-23 14:27:38.916: E/ActivityThread(21250): android.app.ServiceConnectionLeaked: Activity com.applegrew.app.skywifiremote.MainActivity has leaked ServiceConnection [email protected] that was originally bound here 
10-23 14:27:38.916: E/ActivityThread(21250): at android.app.LoadedApk$ServiceDispatcher.<init>(LoadedApk.java:979) 
10-23 14:27:38.916: E/ActivityThread(21250): at android.app.LoadedApk.getServiceDispatcher(LoadedApk.java:873) 
10-23 14:27:38.916: E/ActivityThread(21250): at android.app.ContextImpl.bindServiceCommon(ContextImpl.java:1690) 
10-23 14:27:38.916: E/ActivityThread(21250): at android.app.ContextImpl.bindService(ContextImpl.java:1673) 
10-23 14:27:38.916: E/ActivityThread(21250): at android.content.ContextWrapper.bindService(ContextWrapper.java:517) 
10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.gms.ads.identifier.a.b(SourceFile:179) 
10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.gms.ads.identifier.a.a(SourceFile:207) 
10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.a.t.d(SourceFile:83) 
10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.a.t.b(SourceFile:131) 
10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.a.q.a(SourceFile:258) 
10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.a.q.a(SourceFile:195) 
10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.gms.ads.internal.k.a(SourceFile:76) 
10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.gms.ads.internal.request.c.f_(SourceFile:99) 
10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.gms.ads.internal.util.b.run(SourceFile:17) 
10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.gms.ads.internal.util.d.call(SourceFile:29) 
10-23 14:27:38.916: E/ActivityThread(21250): at com.google.android.gms.ads.internal.util.e.call(SourceFile:49) 
10-23 14:27:38.916: E/ActivityThread(21250): at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
10-23 14:27:38.916: E/ActivityThread(21250): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
10-23 14:27:38.916: E/ActivityThread(21250): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
10-23 14:27:38.916: E/ActivityThread(21250): at java.lang.Thread.run(Thread.java:841) 

Da traccia dello stack sembra che la fonte della fuga è il codice AdMob. Tuttavia, nel mio frammento ho il codice per distruggere la vista di AdMob quando il frammento viene distrutto.

Snippet dal mio frammento.

@Override 
public void onActivityCreated(Bundle savedInstanceState) { 
    super.onActivityCreated(savedInstanceState); 

    initAd(); 
} 

private void initAd() { 
    mAdView = (AdView) getView().findViewById(R.id.remote_pager_ad); 
    if (mAdView != null) { 
     AdRequest adRequest = new AdRequest.Builder().addTestDevice(
       AdRequest.DEVICE_ID_EMULATOR).build(); 
     mAdView.loadAd(adRequest); 
    } 
} 

@Override 
public void onPause() { 
    mAdView.pause(); 
    super.onPause(); 
} 

@Override 
public void onResume() { 
    super.onResume(); 
    mAdView.resume(); 
} 

@Override 
public void onDestroy() { 
    mAdView.destroy(); 
    super.onDestroy(); 
} 
+0

È possibile aggiungere il codice dell'intero frammento? – Simas

+0

Hai mai trovato una soluzione a questo? – johnw182

+0

@ johnw182 Nopes. – AppleGrew

risposta

1

Si vede come se fosse necessario annullare la registrazione del servizio prima che l'attività abbia perso il contesto! Questo è lo stesso problema per Dialog quando si chiama espulsione dopo che Activity ha perso. : -/

6

Stavo riscontrando un problema simile con gli annunci AdMob (Google Play Services) che perdevano enormi quantità di memoria. MAT usato per scoprire che il problema era che ogni annuncio gms veniva mantenuto dalla mia istanza dell'applicazione, nell'array sComponentCallbacks. Quindi ho scavalcato lo registerComponentCallbacks() e lo unregisterComponentCallbacks() per tenere traccia delle istanze che si registrano da sole ma che non annullano mai la registrazione (quando presumo che avrebbero dovuto farlo). Questo esempio di codice presuppone solo il pacchetto .gms.ads è problematico, ma se trovate gli altri che stanno causando una perdita di simile, è possibile aggiungere i pacchetti alla lista pure:

public class MyApplication extends Application { 
    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) 
    @Override 
    public void registerComponentCallbacks(ComponentCallbacks callback) { 
     super.registerComponentCallbacks(callback); 
     ComponentCallbacksBehavioralAdjustmentToolIcs.INSTANCE.onComponentCallbacksRegistered(callback); 
    } 

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) 
    @Override 
    public void unregisterComponentCallbacks(ComponentCallbacks callback) { 
     ComponentCallbacksBehavioralAdjustmentToolIcs.INSTANCE.onComponentCallbacksUnregistered(callback); 
     super.unregisterComponentCallbacks(callback); 
    } 

    public void forceUnregisterComponentCallbacks() { 
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 
      ComponentCallbacksBehavioralAdjustmentToolIcs.INSTANCE.unregisterAll(this); 
     } 
    } 


    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) 
    private static class ComponentCallbacksBehavioralAdjustmentToolIcs { 
     static ComponentCallbacksBehavioralAdjustmentToolIcs INSTANCE = new ComponentCallbacksBehavioralAdjustmentToolIcs(); 

     private WeakHashMap<ComponentCallbacks, ApplicationErrorReport.CrashInfo> mCallbacks = new WeakHashMap<>(); 
     private boolean mSuspended = false; 

     public void onComponentCallbacksRegistered(ComponentCallbacks callback) { 
      Throwable thr = new Throwable("Callback registered here."); 
      ApplicationErrorReport.CrashInfo ci = new ApplicationErrorReport.CrashInfo(thr); 

      if (BuildConfig.DEBUG) Log.w(TAG, "registerComponentCallbacks: " + callback, thr); 

      if (!mSuspended) { 
       if (callback.getClass().getName().startsWith("com.google.android.gms.ads")) { 
        mCallbacks.put(callback, ci); 
       } 
       // TODO: other classes may still prove to be problematic? For now, only watch for .gms.ads, since we know those are misbehaving 
      } else { 
       if (BuildConfig.DEBUG) Log.e(TAG, "ComponentCallbacks was registered while tracking is suspended!"); 
      } 
     } 

     public void onComponentCallbacksUnregistered(ComponentCallbacks callback) { 
      if (!mSuspended) { 
       if (BuildConfig.DEBUG) { 
        Log.i(TAG, "unregisterComponentCallbacks: " + callback, new Throwable()); 
       } 

       mCallbacks.remove(callback); 
      } 
     } 

     public void unregisterAll(Context context) { 
      mSuspended = true; 

      for (Map.Entry<ComponentCallbacks, ApplicationErrorReport.CrashInfo> entry : mCallbacks.entrySet()) { 
       ComponentCallbacks callback = entry.getKey(); 
       if (callback == null) continue; 

       if (BuildConfig.DEBUG) { 
        Log.w(TAG, "Forcibly unregistering a misbehaving ComponentCallbacks: " + entry.getKey()); 
        Log.w(TAG, entry.getValue().stackTrace); 
       } 

       try { 
        context.unregisterComponentCallbacks(entry.getKey()); 
       } catch (Exception exc) { 
        if (BuildConfig.DEBUG) Log.e(TAG, "Unable to unregister ComponentCallbacks", exc); 
       } 
      } 

      mCallbacks.clear(); 
      mSuspended = false; 
     } 
    } 
} 

Poi, nel mio BaseActivity onPause() (o il metodo onDestroy()), che io chiamo il mio forceUnregisterComponentCallbacks() metodo:

@Override 
public void onPause() { 
    ((MyApplication) getApplicationContext()).forceUnregisterComponentCallbacks() 
    super.onPause(); 
} 

noti che ComponentCallbacks è stato introdotto in ICS, quindi se stai vedendo problemi sulle versioni precedenti ICS, allora questo non è il problema.

(mi rendo anche conto che questo non affrontare il problema esatto identificato nel PO, come che ha a che fare con bindService(), non ComponentCallbacks. Ma ci ha salvato da una bella grave perdita di memoria che ci ha costretti a disabilitare AdMob del tutto fino a quando potrebbe essere rilasciato un hotfix.)

+0

Branding, grazie per la condivisione! Spero che non rompere qualcos'altro nella mia app. Nel mio caso ['Web ComponentCallbacks' di WebView non sta annullando la registrazione, anche se ho chiamato' destroy() 'su di esso] (https: // github.com/vickychijwani/quill/issues/75 # issuecomment-115012824), e si sta aggrappando alla mia attività causando enormi perdite di memoria. –

+0

Un anno dopo: ho scoperto che ciò era dovuto a un errore di programmazione da parte mia. Apparentemente ['WebView' deve essere rimosso dalla gerarchia della vista prima di essere' destroy() 'ed] (https://developer.android.com/reference/android/webkit/WebView.html#destroy%28%29). Ciò sembra risolvere la perdita senza ricorrere a questo hack. –