我的插页式广告导致内存泄漏?

9
我也尝试使用ApplicationContext,但由于某些原因它仍然泄漏。

在这里找到了一个类似的问题 AdMob(SDK 7.0)Android上的AdActivity泄漏,但没有答案。

还尝试在onDestroy()中将广告监听器和广告设置为null,但是没有成功,活动仍然泄漏。

我的代码在onCreate()中被调用

private void refreshInterstitial(){
        mInterstitialAd = new InterstitialAd(this);
        mInterstitialAd.setAdUnitId("AD_ID");
        mInterstitialAd.loadAd(new AdRequest.Builder().addTestDevice(AdRequest.DEVICE_ID_EMULATOR).addTestDevice("877BCC97E130A0DC62B2E5770D854496").build());

        mInterstitialAd.setAdListener(new AdListener() {
            @Override
            public void onAdLoaded() {
                mInterstitialAd.show();
            }
            @Override
            public void onAdClosed() {
            }
        });
}

Leakcanary 泄漏跟踪

 ┬───
    │ GC Root: Global variable in native code
    │
    ├─ mx instance
    │    Leaking: UNKNOWN
    │    ↓ mx.a
    │         ~
    ├─ com.google.android.gms.ads.internal.webview.w instance
    │    Leaking: UNKNOWN
    │    mContext instance of com.google.android.gms.ads.internal.webview.ay, not wrapping activity
    │    View#mParent is nullView#mAttachInfo is null (view detached)
    │    View.mWindowAttachCount = 1
    │    ↓ w.a
    │        ~
    ├─ com.google.android.gms.ads.internal.webview.aa instance
    │    Leaking: YES (View detached and has parent)
    │    mContext instance of com.google.android.gms.ads.internal.webview.ay, not wrapping activity
    │    View#mParent is set
    │    View#mAttachInfo is null (view detached)
    │    View.mWindowAttachCount = 1
    │    ↓ aa.mListenerInfo
    ├─ android.view.View$ListenerInfo instance
    │    Leaking: YES (aa↑ is leaking)
    │    ↓ View$ListenerInfo.mOnClickListener
    ├─ com.google.android.gms.ads.nonagon.ad.webview.f instance
    │    Leaking: YES (aa↑ is leaking)
    │    ↓ f.a
    ├─ com.google.android.gms.ads.nonagon.ad.webview.l instance
    │    Leaking: YES (aa↑ is leaking)
    │    ↓ l.e
    ├─ com.google.android.gms.ads.nonagon.ad.event.bs instance
    │    Leaking: YES (aa↑ is leaking)
    │    ↓ bs.a
    ├─ java.util.HashMap instance
    │    Leaking: YES (aa↑ is leaking)
    │    ↓ HashMap.table
    ├─ java.util.HashMap$Node[] array
    │    Leaking: YES (aa↑ is leaking)
    │    ↓ HashMap$Node[].[1]
    ├─ java.util.HashMap$Node instance
    │    Leaking: YES (aa↑ is leaking)
    │    ↓ HashMap$Node.key
    ├─ com.google.android.gms.ads.nonagon.shim.k instance
    │    Leaking: YES (aa↑ is leaking)
    │    ↓ k.a
    ├─ com.google.android.gms.ads.internal.client.ae instance
    │    Leaking: YES (aa↑ is leaking)
    │    ↓ ae.a
    ├─ com.google.android.gms.internal.ads.zzuc instance
    │    Leaking: YES (aa↑ is leaking)
    │    ↓ zzuc.zzcbw
    ├─ com.test.Activity$1 instance
    │    Leaking: YES (aa↑ is leaking)
    │    Anonymous subclass of com.google.android.gms.ads.AdListener
    │    ↓ EqualizerActivity$1.this$0
    ╰→ com.test.Activity instance
    ​     Leaking: YES (ObjectWatcher was watching this because Activity received Activity#onDestroy() callback and Activity#mDestroyed is true)
    ​     key = 40a1eb8e-c9e6-4062-b5f7-053e642e812f
    ​     watchDurationMillis = 5288
    ​     retainedDurationMillis = 258

1
你尝试过将mInterstitialAd变成本地变量吗? - Harry Timothy
如果是这种情况,请告诉我,这样我就可以编写答案并获得赏金了 :) - Harry Timothy
请看我的回答 :) - Harry Timothy
我也遇到了同样的问题。看起来是他们那边的一个bug。 - Sahil Manchanda
1
@kasptom 是的,除了我只是使用基本插页式广告而不是奖励视频,但我刚刚看了评论,有人在#84上有完全相同的问题。 - Vince VD
显示剩余5条评论
3个回答

2

这对我有效:(在ActivityMain()中):

MobileAds.initialize(WeakReference(applicationContext).get()){}

分段:

adView= AdView(WeakReference(requireActivity().application).get())

LeakCanary 显示:

==================================== 堆分析结果 ==================================== 0 个应用程序泄漏。


1
我是第二个点赞这个答案的人,但经过进一步测试发现这个答案不起作用。不要使用它 - Lance Samaria

2
根据InterstitialAd文档,一个单独的InterstitialAd对象可以用于在活动生命周期内请求和显示多个插页式广告,因此您只需要构建一次。
在重新查看您的代码后,我注意到每次调用refreshInterstitial()方法时都会重新构建mInterstitialAd。但是根据上面的文档,您应该仅在onCreate()期间构建一次mInterstitialAd。
在您的情况下,内存泄漏的主要原因是:您仍然有一个活动侦听器(绑定到Activity寿命),但您使用另一个侦听器重构了新的InterstitialAd实例。
因此,解决方案是重复使用InterstitialAd实例及其侦听器而不进行重新分配。我建议将您的refreshInterstitial()方法简化为以下内容:
private void refreshInterstitial() {
    mInterstitialAd.loadAd(new AdRequest.Builder().addTestDevice(AdRequest.DEVICE_ID_EMULATOR).addTestDevice("877BCC97E130A0DC62B2E5770D854496").build());
}

接下来将mInterstitialAd赋值给onCreate()。 这个解决方案类似于你可以在这里找到的解决方案(链接)


我不明白这个?我的方法refreshInterstitial()是在onCreate()中调用的代码,当我启动我的活动时它只会被调用一次。此外,如果没有adlistener,插页式广告将不会显示,因为我必须在广告加载完成后调用mInterstitialAd.show()。 - Vince VD
现在让我问你:在整个Activity的生命周期中,你只调用refreshInterstitial()一次吗?因为如果你多次调用它,根据你的代码,会发生内存泄漏。 - Harry Timothy
只是一次。我把它放在一个方法里,因为我的onCreate里有很多代码。 - Vince VD
那么能否更新一下你的问题,展示一下onCreate()里面的内容,这样我们才能找到解决办法呢?因为泄漏跟踪日志显示“正在泄漏:是(ObjectWatcher正在监视此对象,因为Activity已接收到Activity#onDestroy()回调并且Activity#mDestroyed为true)”。这意味着你的代码中有一部分会触发onDestroy()然后重新创建Activity,导致InterstitialAd被构建多次。 - Harry Timothy
这是因为我返回到我的上一个活动,该活动是第二个活动而不是我的主要活动。因此,当我按下返回按钮时,ObjectWatcher被销毁,这是正常的。 - Vince VD
1
很不幸,我认为这是他们那边的一个漏洞。即使是他们从谷歌本身获取的github示例也存在这个泄漏问题。 - Vince VD

1

我在插屏广告中遇到了相同的问题,通过在所有重写方法中将FullScreenContentCallback设置为null来解决了这个问题。

 interstitial.setFullScreenContentCallback(new FullScreenContentCallback() {
        @Override
        public void onAdDismissedFullScreenContent() {
            super.onAdDismissedFullScreenContent();
            
            interstitial.setFullScreenContentCallback(null);}}

我知道我的内存泄漏与FullScreenContentCallback的特定设置有关。然而,即使将其设置为null,我仍然会遇到内存泄漏问题。 - Pablo Alfonso

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接