我对 Android 编码非常陌生,请告诉我这个内存泄漏是否严重到足以让我担心。如果是这样,请建议我可以做些什么。
我正在尝试使用 admob 在我的 Android 应用程序中显示奖励广告,但在实施标准奖励广告之后。当我调查问题时,我的应用程序开始遇到性能问题,结果发现 RewardedAdCallback 正在引用我的 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 个按钮用于启动第一个活动
重新创建内存泄漏的步骤是:-
以下是泄露的金丝雀报告
我的问题是为什么 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
我也有同样的问题。我发现的最简单的解决方案是将所有内容都等同于 Null。
override fun onDestroy() {
super.onDestroy()
adLoadCallback = null
mRewardedAd = null
}
您可以使用
destroy
功能来销毁广告视图。
在
Activity
中,代码如下:
override fun onDestroy() {
binding.adView.destroy()
super.onDestroy()
}
在
Fragment
中,代码如下:
override fun onDestroyView() {
binding.adView.destroy()
super.onDestroyView()
}
希望对您有帮助!