【问题标题】:Rewarded ads memory leak admob奖励广告内存泄漏 admob
【发布时间】:2020-12-01 08:19:46
【问题描述】:

我是 android 编码的超级新手,请告诉我这个内存泄漏是否严重到足以让我担心。如果是这样,请提出一些我可以做的事情。

我正在尝试使用 admob 在我的 Android 应用中展示奖励广告,但在实施标准奖励广告之后。当我调查问题并发现 RewardedAdCallback 引用我的 MainActivity 导致内存泄漏时,我的应用程序开始出现性能问题。 在搜索了 3 三天后我该如何解决这个问题我完全迷路了

这是我的 MainActivity

package com.example.ads

import android.app.Activity
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.annotation.NonNull
import com.google.android.gms.ads.AdError
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.LoadAdError
import com.google.android.gms.ads.MobileAds
import com.google.android.gms.ads.rewarded.RewardItem
import com.google.android.gms.ads.rewarded.RewardedAd
import com.google.android.gms.ads.rewarded.RewardedAdCallback
import com.google.android.gms.ads.rewarded.RewardedAdLoadCallback

class MainActivity : AppCompatActivity() {
    lateinit var rewardedAd: RewardedAd

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        MobileAds.initialize(applicationContext)

        rewardedAd = RewardedAd(this,
                "ca-app-pub-3940256099942544/5224354917")
        val adLoadCallback = object: RewardedAdLoadCallback() {
            override fun onRewardedAdLoaded() {
                // Ad successfully loaded.
            }
            override fun onRewardedAdFailedToLoad(adError: LoadAdError) {
                // Ad failed to load.
            }
        }
        rewardedAd.loadAd(AdRequest.Builder().build(), adLoadCallback)
    }

    fun showads(view:View){
        if (rewardedAd.isLoaded) {
            val activityContext: Activity = this@MainActivity
            val adCallback = object : RewardedAdCallback() {
                override fun onRewardedAdOpened() {
                    // Ad opened.
                }

                override fun onRewardedAdClosed() {
                    // Ad closed.
                    rewardedAd = createAndLoadRewardedAd()
                }

                override fun onUserEarnedReward(@NonNull reward: RewardItem) {
                    // User earned reward.
                }

                override fun onRewardedAdFailedToShow(adError: AdError) {
                    // Ad failed to display.
                }
            }
            rewardedAd.show(activityContext, adCallback)
        } else {
            Log.d("TAG", "The rewarded ad wasn't loaded yet.")
        }
    }
    fun createAndLoadRewardedAd(): RewardedAd {
        val rewardedAd = RewardedAd(this, "ca-app-pub-3940256099942544/5224354917")
        val adLoadCallback = object: RewardedAdLoadCallback() {
            override fun onRewardedAdLoaded() {
                // Ad successfully loaded.
            }
            override fun onRewardedAdFailedToLoad(adError: LoadAdError) {
                // Ad failed to load.
            }
        }
        rewardedAd.loadAd(AdRequest.Builder().build(), adLoadCallback)
        return rewardedAd
    }
    fun l(view:View){
        val intent = Intent(this,MainActivity2::class.java)
        startActivity(intent)
    }
}

这是我的 MainActivity2

package com.example.ads

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View

class MainActivity2 : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)
    }
    fun goToSecond(view: View){
        val intent = Intent(this,MainActivity::class.java)
        startActivity(intent)

    }

}

MainActivty 有 2 个按钮,一个用于显示广告 (onClick:showads()),另一个用于启动第二个活动 (onClick:goToSecond()) 和 MainActivity2 有一个启动第一个活动的按钮

重新创建内存泄漏的步骤是:-

  1. 启动应用程序
  2. 在第一个活动上按下按钮转到第二个活动
  3. 在第二个活动上按下按钮转到第一个活动
  4. 现在在第一个活动中按下按钮以显示奖励广告
  5. 当奖励广告结束并且你回到第一个活动时,按下返回按钮现在泄漏金丝雀必须找到内存泄漏

以下是泄漏的金丝雀报告

我的问题是为什么 Google 广告会导致内存泄漏

┬───
│ GC Root: Global variable in native code
│
├─ ns instance
│    Leaking: UNKNOWN
│    ↓ ns.a
│         ~
├─ com.google.android.gms.ads.internal.webview.x instance
│    Leaking: UNKNOWN
│    mContext instance of com.google.android.gms.ads.internal.webview.ax, not wrapping activity
│    View#mParent is null
│    View#mAttachInfo is null (view detached)
│    View.mWindowAttachCount = 1
│    ↓ x.a
│        ~
├─ com.google.android.gms.ads.internal.webview.ab instance
│    Leaking: YES (View detached and has parent)
│    mContext instance of com.google.android.gms.ads.internal.webview.ax, not wrapping activity
│    View#mParent is set
│    View#mAttachInfo is null (view detached)
│    View.mWindowAttachCount = 1
│    ↓ ab.mListenerInfo
├─ android.view.View$ListenerInfo instance
│    Leaking: YES (ab↑ is leaking)
│    ↓ View$ListenerInfo.mOnClickListener
├─ com.google.android.gms.ads.nonagon.ad.webview.f instance
│    Leaking: YES (ab↑ is leaking)
│    ↓ f.a
├─ com.google.android.gms.ads.nonagon.ad.webview.l instance
│    Leaking: YES (ab↑ is leaking)
│    ↓ l.d
├─ com.google.android.gms.ads.nonagon.ad.event.cz instance
│    Leaking: YES (ab↑ is leaking)
│    ↓ cz.b
├─ java.util.HashMap instance
│    Leaking: YES (ab↑ is leaking)
│    ↓ HashMap.table
├─ java.util.HashMap$Node[] array
│    Leaking: YES (ab↑ is leaking)
│    ↓ HashMap$Node[].[2]
├─ java.util.HashMap$Node instance
│    Leaking: YES (ab↑ is leaking)
│    ↓ HashMap$Node.key
├─ com.google.android.gms.ads.nonagon.ad.event.cd instance
│    Leaking: YES (ab↑ is leaking)
│    ↓ cd.g
├─ com.google.android.gms.ads.nonagon.slot.rewarded.u instance
│    Leaking: YES (ab↑ is leaking)
│    ↓ u.c
├─ java.util.concurrent.atomic.AtomicReference instance
│    Leaking: YES (ab↑ is leaking)
│    ↓ AtomicReference.value
├─ com.google.android.gms.ads.internal.rewarded.client.f instance
│    Leaking: YES (ab↑ is leaking)
│    ↓ f.a
├─ com.google.android.gms.internal.ads.zzauy instance
│    Leaking: YES (ab↑ is leaking)
│    ↓ zzauy.zzdvi
├─ com.example.logicpuzzle.MainActivity$giveHint$adCallback$1 instance
│    Leaking: YES (ab↑ is leaking)
│    Anonymous subclass of com.google.android.gms.ads.rewarded.RewardedAdCallback
│    ↓ MainActivity$giveHint$adCallback$1.this$0
╰→ com.example.logicpuzzle.MainActivity instance
​     Leaking: YES (ObjectWatcher was watching this because com.example.logicpuzzle.MainActivity received Activity#onDestroy() callback and Activity#mDestroyed is true)
​     key = ab343657-b3f0-47fc-a4cf-281413e4765d
​     watchDurationMillis = 5652
​     retainedDurationMillis = 650

METADATA

Build.VERSION.SDK_INT: 29
Build.MANUFACTURER: samsung
LeakCanary version: 2.4
App process name: com.example.app
Analysis duration: 18616

【问题讨论】:

  • 或许可以使用minimal reproducible example
  • @RyanM 我已经添加了尽可能多的详细代码,请帮助我这个内存泄漏真的开始让我对 android 开发失去动力

标签: android memory-leaks admob leakcanary admob-rewardedvideoad


【解决方案1】:

我遇到了同样的问题。我找到的最简单的解决方案是将所有内容等同于 Null。

override fun onDestroy() {
        super.onDestroy()
        adLoadCallback = null
        mRewardedAd = null
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-08
    • 2018-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多