2014-10-23 12 views
23

Tôi đang sử dụng AdMob trong một đoạn. Đôi khi tôi thấy ngăn xếp sau đâyĐiều gì khiến Google AdMob bị rò rỉ ServiceConnection?

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) 

Từ theo dõi ngăn xếp có vẻ như nguồn rò rỉ là mã AdMob. Tuy nhiên, trong đoạn của tôi, tôi có mã để hủy chế độ xem AdMob khi đoạn bị phá hủy.

Đoạn trích từ đoạn của tôi.

@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

Bạn có thể thêm toàn bộ đoạn mã không? – Simas

+0

Bạn đã bao giờ tìm thấy một giải pháp cho điều này? – johnw182

+0

@ johnw182 Nopes. – AppleGrew

Trả lời

1

Có vẻ như bạn cần phải hủy đăng ký Dịch vụ trước khi Hoạt động của bạn bị mất bối cảnh! Đây cũng là vấn đề tương tự đối với Hộp thoại khi bạn bỏ qua sau khi Hoạt động bị mất. : -/

6

Tôi đã gặp sự cố tương tự với quảng cáo AdMob (Dịch vụ của Google Play) làm rò rỉ lượng bộ nhớ khổng lồ. MAT được sử dụng để thấy rằng vấn đề là mỗi quảng cáo gms đã được giữ lại bởi cá thể Ứng dụng của tôi, trong mảng sComponentCallbacks. Vì vậy, tôi ghi đè registerComponentCallbacks()unregisterComponentCallbacks() để theo dõi các cá thể đang đăng ký nhưng không bao giờ hủy đăng ký (khi tôi cho rằng họ nên làm như vậy). Ví dụ mã này đảm nhận việc chỉ gói .gms.ads là có vấn đề, nhưng nếu bạn thấy người khác đang gây ra một sự rò rỉ tương tự, bạn có thể thêm những gói vào danh sách cũng như:

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

Sau đó, trong BaseActivity tôi onPause() (hoặc onDestroy()) phương pháp, tôi gọi phương thức forceUnregisterComponentCallbacks() tôi:

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

Lưu ý rằng ComponentCallbacks đã được giới thiệu trong ICS, vì vậy nếu bạn đang gặp sự cố trên các phiên bản trước ICS, thì đây không phải là vấn đề.

(Tôi cũng nhận ra rằng điều này không giải quyết được vấn đề chính xác được xác định trong OP, vì điều đó phải làm với bindService(), chứ không phải là ComponentCallbacks.Nhưng nó đã cứu chúng ta khỏi rò rỉ bộ nhớ khá lớn. một hotfix có thể được phát hành.)

+0

Hack tuyệt vời, cảm ơn bạn đã chia sẻ! Tôi hy vọng nó không phá vỡ một cái gì đó khác trong ứng dụng của tôi. Trong trường hợp của tôi [ComponentCallbacks' của WebView không tự hủy đăng ký mặc dù tôi đã gọi 'destroy()' trên nó] (https: // github.com/vickychijwani/quill/issues/75 # issuecomment-115012824) và nó đang giữ lại Hoạt động của tôi gây ra rò rỉ bộ nhớ lớn. –

+0

Một năm sau, tôi phát hiện ra điều này là do lỗi lập trình của tôi. Rõ ràng ['WebView' cần được loại bỏ khỏi hệ thống phân cấp khung nhìn trước khi là' destroy() 'ed] (https://developer.android.com/reference/android/webkit/WebView.html#destroy%28%29). Làm như vậy có vẻ như sửa lỗi bị rò rỉ mà không phải dùng đến bản hack này. –

Các vấn đề liên quan