2012-03-04 20 views
25

Ứng dụng của chúng tôi bị tấn công khá mạnh do rò rỉ bộ nhớ. Tôi đã tìm thấy nguyên nhân gốc rễ là AdView AdMob giữ tham chiếu đến các hoạt động cũ. Vấn đề là khá tốt tài liệu trong câu hỏi Android AdMob causes memory leak? và các liên kết phụ trong các ý kiến ​​/ câu trả lời. Tôi đã nhận thấy rằng vấn đề là không rõ ràng trong ICS khi GC cuối cùng làm sạch các WebViews với các tham chiếu đến các hoạt động. Tuy nhiên, HTC EVO 3D của tôi chạy Gingerbread chứng khoán không bao giờ thu thập các hoạt động và xem xét số lượng các báo cáo chặt chẽ do lỗi OOM, vấn đề là rất phổ biến cho ứng dụng của chúng tôi.Lỗi bộ nhớ AdMob - tránh bằng cách sử dụng hoạt động trống

Tôi muốn thực hiện theo giải pháp được cung cấp bởi TacB0sS, https://stackoverflow.com/a/8364820/684893. Anh ấy đã đề xuất tạo một hoạt động trống và sử dụng cùng hoạt động đó cho từng AdView AdMob. Sự rò rỉ sẽ được chứa kể từ khi AdView sẽ chỉ tiếp tục sống mà một hoạt động trống. Anh ấy đã cung cấp mã cho hoạt động đó và cách tham khảo nó nhưng tôi không biết cách tích hợp nó vào ứng dụng của chúng tôi. Mã của anh ấy không bao giờ gọi bất cứ thứ gì từ AdMob SDK theo như tôi có thể nói.

Hiện tại chúng tôi đang sử dụng AdView trong các bố cục XML để chúng tôi không tự động làm bất kỳ điều gì với quảng cáo trong mã chẳng hạn như loadAdAd(). Tất cả bố cục của chúng tôi với quảng cáo đều dựa vào quảng cáo nằm trong XML vì chúng được đặt ra tương đối so với quảng cáo. Hai câu hỏi của tôi là như vậy, làm cách nào để triển khai mã TacB0sS và làm cách nào để giữ lại các mối quan hệ bố cục XML của mình nếu chúng ta phải chuyển sang tạo các bố cục XML trong mã?

Cập nhật 3/6:

Cảm ơn Adam (TacB0sS) cho đáp ứng! Tôi không có vấn đề gì khi chuyển đổi để tạo Quảng cáo trong mã nhưng tôi vẫn gặp khó khăn khi sử dụng hoạt động giả của bạn khi tạo Quảng cáo. Mã của tôi hiện tại là:

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

Tôi đã đặt mã này vào phương thức onCreate hoạt động ban đầu của tôi. Tôi nhận được một lực lượng gần trên dòng nơi tôi tạo 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 

Cách thích hợp để khởi tạo AdMobActivity của bạn và tham khảo nó khi tạo AdView là gì? Cảm ơn một lần nữa!

Cập nhật 2 3/6:

tôi đã tìm ra vấn đề của tôi tạo ra hoạt động này. Tôi đã giải pháp của bạn hoàn toàn được triển khai và phần tốt nhất là nó thực sự giải quyết rò rỉ bộ nhớ của tôi. Sau khi trải qua hai tuần về vấn đề này, tôi rất vui vì nó đã được giải quyết. Dưới đây là các bước đầy đủ tôi đã sử dụng:

Tạo một hoạt động mới gọi là 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); 
    } 
} 

Thêm dòng sau vào AndroidManifest.xml của bạn

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

Bạn cần phải khởi tạo AdMobActivity giả trước khi cố gắng để tải bất kỳ quảng cáo nào. Hoạt động này sẽ không chứa bất cứ điều gì. Nó sẽ được hiển thị trong một giây và sau đó đóng lại, quay trở lại hoạt động bạn đã gọi nó. Bạn không thể tạo nó trong cùng hoạt động bạn muốn tải Quảng cáo vì nó phải được khởi tạo hoàn toàn kịp thời trước khi sử dụng.Tôi khởi tạo nó trong hoạt động trên màn hình tải khởi động của onCreate trước khi hoạt động chính chứa quảng cáo bắt đầu:

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

Bây giờ bạn đã sẵn sàng tạo quảng cáo bằng mã. Thêm LinearLayout sau vào bố cục hoạt động XML của bạn. Căn chỉnh tất cả các khung nhìn khác cần thiết xung quanh bố cục này. AdView mà chúng tôi tạo trong mã sẽ được đặt bên trong chế độ xem này.

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

Trong hoạt động bạn muốn tải một quảng cáo, tạo một biến toàn cầu cho AdView:

AdView adView; 

Trong ứng dụng của chúng tôi, chúng tôi tải bố trí khác nhau khi xoay điện thoại. Vì vậy, tôi gọi đoạn mã sau trên mỗi lần xoay. Nó tạo ra các adView nếu cần thiết và thêm nó vào 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 

Cuối cùng, hãy chắc chắn bạn gọi adView.destroy() trong các hoạt động onDestroy() phương pháp:

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

Bất cứ ai khác mà đọc này, hãy nhớ rằng đây là giải pháp của Adam (TacB0sS), không phải của tôi. Tôi chỉ muốn cung cấp chi tiết triển khai đầy đủ để giúp người khác thực hiện dễ dàng hơn. Lỗi AdMob này là một vấn đề lớn đối với các ứng dụng chạy trước tổ ong và giải pháp của Adam là điều tốt nhất tôi có thể tìm thấy để phá vỡ nó. Và nó hoạt động!

+0

trình như một say mê !! Cảm ơn cả hai bạn @ravishi và @ TacB0sS !! – Regis

+0

Hi ravishi ... Tôi đang gặp rắc rối với giải pháp này. Bạn có thể giúp tôi không. Đây là câu hỏi của tôi http://stackoverflow.com/questions/15583994/activity-does-not-launch-from-the-recent-activities-android –

+0

Có liên kết đến mã đầy đủ @ravishi không? –

Trả lời

17

Ravishi,

Câu hỏi của bạn đến điểm, và tôi đã thất bại trong việc giải quyết nó trong giải pháp của tôi. Theo như tôi có thể cho biết các giải pháp tôi đã tìm thấy chỉ hoạt động tự động, nơi bạn có thể chọn hoạt động của bạn trong khi gọi sdk ...

Lý do mã của tôi không có một ví dụ sử dụng, là vì giải pháp của tôi là một phức tạp hơn một chút, cái mà tôi đã trình bày, liên quan đến toàn bộ khuôn khổ gói mà tôi đã xây dựng xung quanh khung công tác Android, trong đó mối quan hệ AdMob với ứng dụng là thông qua mô-đun trung gian, đặt quảng cáo động bằng cách sử dụng cá thể hoạt động đơn lẻ.

Tôi thực sự nghi ngờ bạn có thể tránh rò rỉ bộ nhớ đơn giản bằng cách sử dụng XML của Android.

Trong mọi trường hợp, nếu bạn là thành công việc kinh doanh bộ nhớ bị rò rỉ, bạn cũng có thể kiểm tra việc sử dụng AsyncTask của bạn ... nó cũng có hành vi rò rỉ bộ nhớ riêng của mình ... vì vậy đây là tôi solution

tốt nhất may mắn ...

- CẬP NHẬT - 07/10/14

có người chỉ upvoted câu trả lời của tôi, nó propustorase rằng vấn đề này vẫn còn tồn tại, nó đã được gần ba năm kể từ khi câu trả lời ban đầu của tôi, và người vẫn có rò rỉ bộ nhớ trong ứng dụng của họ vì AdMob ... từ Google ... đã tạo Android ...

Dù sao, tôi chỉ muốn thêm rằng bạn có lẽ nên đặt chủ đề của AdMobActivity thành minh bạch, nó sẽ ngăn chặn nhấp nháy.

- CẬP NHẬT - 28/02/16

Bốn năm ...

- CẬP NHẬT - 09/03/17

Năm năm ... người làm việc tại Google xin vui lòng thức dậy, và thuê khỉ thực để thực hiện công việc :)

Adam.

+0

Cảm ơn Adam! Vui lòng xem bài đăng đã chỉnh sửa của tôi để biết thêm câu hỏi trực tiếp. Cảm ơn bạn đã chỉ ra vấn đề AsyncTask. Tôi đã may mắn không chạy vào nó được nêu ra hoặc nếu tôi có, nó đã không được một rò rỉ rất lớn như AdMob. – ravishi

+0

Phiên bản AdMob nào bạn sử dụng? Bạn đã gọi nó trước hoặc sau super.onCreate (...)? Bạn sẽ khởi tạo AdView, Hoạt động giả hoặc hoạt động giao diện người dùng thực tế trong hoạt động nào. – TacB0sS

+1

Tôi nhận được nó hoạt động. Xem chỉnh sửa trong câu hỏi ban đầu để biết chi tiết. Cám ơn rất nhiều! – ravishi

1

Tôi đã nhìn thấy sự rò rỉ tương tự này với 6.1.0 SDK, nhưng đã có thể giải quyết nó bằng cách gọi tiêu hủy() trên AdView được đề cập trong Hoạt động của tôi trênDự phá. Tôi nghĩ họ đã sửa nó. Destroy() dường như loại bỏ các PhantomReferences mà WebView của AdView đã có cho Hoạt động của tôi đã giữ cho Hoạt động không bị GC.

6

Tôi đang sử dụng "play-services-ads: 7.5.0" và không cần thiết phải tạo de AdMobActivity. Nó làm việc bằng cách:

  • Tạo adview dinamically

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

  • Loại bỏ tất cả các quan điểm từ LinearLayout trên phá hủy và phá hủy adview

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

Unfortunatelly kẽ vẫn rò rỉ

+1

Cảm ơn rất nhiều người. Tôi đã có một rò rỉ 'LeakCanary' tham chiếu' MainActivity -> references ht.a -> static hk.o'.Điều này đã giúp tôi giải quyết nó, đó là rò rỉ 'NativeExpressAdView' trên' GridLayoutManager' của tôi. Tôi đã không xóa tất cả các khung nhìn khỏi 'GridLayoutManager' hoặc đặt' setAdListener' thành null. Google hoàn toàn bỏ lỡ điều này trong hướng dẫn 'NativeExpressAdView' của họ. –

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