Admob 内存泄漏 - 通过使用空活动来避免 [英] Admob Memory Leak - avoiding by using empty activity

查看:16
本文介绍了Admob 内存泄漏 - 通过使用空活动来避免的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们的应用程序受到内存泄漏的严重打击.我发现根本原因是 AdMob AdView 保留对旧活动的引用.这个问题在 Android AdMob 导致内存泄漏? 和子链接中得到了很好的记录评论/答案.我注意到这个问题在 ICS 中并不明显,因为 GC 最终会使用对活动的引用来清理 WebView.但是,我的 HTC EVO 3D 跑步股票姜饼从不收集活动,考虑到由于 OOM 错误导致的强制关闭报告的数量,这个问题在我们的应用程序中非常普遍.

Our app is getting hit pretty hard by a memory leak. I've found that the root cause is the AdMob AdView keeping references to old activities. The problem is pretty well documented in question Android AdMob causes memory leak? and the sublinks in the comments/answers. I have noticed that the problem is not apparent in ICS as the GC eventually cleans up the WebViews with references to activities. However, my HTC EVO 3D running stock gingerbread never collects the activities and considering the number of force close reports due to OOM errors, the problem is very widespread for our app.

我想遵循 TacB0sS 提供的解决方案,https://stackoverflow.com/a/8364820/684893.他建议创建一个空活动,并为每个 AdMob AdView 使用相同的活动.泄漏将得到控制,因为 AdView 只会让那个空活动保持活动状态.他提供了活动本身的代码以及如何引用它,但我不知道如何将它实际集成到我们的应用程序中.据我所知,他的代码从未调用 AdMob SDK 中的任何内容.

I would like to follow the solution provided by TacB0sS, https://stackoverflow.com/a/8364820/684893. He has suggested to create an empty activity and use that same activity for each AdMob AdView. The leak would be contained since AdView will only keep alive that one empty activity. He provided the code for the activity itself and how to reference it but I'm at a loss of how to actually integrate it into our app. His code never calls anything from AdMob SDK as far as I can tell.

我们目前在 XML 布局中使用 AdView,因此我们不会在代码中动态地对广告执行任何操作,例如调用 loadAd().我们所有的广告布局都依赖于 XML 中的广告,因为它们是相对于它进行布局的.因此,我的两个问题是,如何实现 TacB0sS 代码以及如果我们必须切换到在代码中创建 XML 布局,我该如何保留我的 XML 布局关系?

We are currently using AdView in the XML layouts so we don't dynamically do anything with the ads in code such as call loadAd(). All of our layouts with ads rely on the ad being in the XML since they are laid out relative to it. My two questions are thus, how do I implement TacB0sS code and how can I retain my XML layout relationships if we have to switch to creating the XML layouts in code?

更新 3/6:

感谢 Adam (TacB0sS) 的回复!我切换到在代码中创建广告没有问题,但在创建广告时我仍然无法使用您的虚拟活动.我的代码目前是:

Thanks Adam (TacB0sS) for responding! I have no problem switching to creating the Ad in code but I am still having difficulty using your dummy activity when creating Ads. My code currently is:

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

我已将此代码放在初始活动的 onCreate 方法中.我在创建 AdView 的行上强制关闭,AdView adView = new AdView(...)".堆栈跟踪代码段:

I have placed this code in the onCreate method of my initial activity. I get a force close on the line where I create the 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

在创建 AdView 时初始化 AdMobActivity 并引用它的正确方法是什么?再次感谢!

What is the proper way to initialize your AdMobActivity and reference it when creating the AdView? Thanks again!

更新 2 3/6:

我发现了创建活动的问题.我已经完全实施了您的解决方案,最好的部分是它实际上解决了我的内存泄漏.在这个问题上花了两周时间后,我很高兴它得到了解决.以下是我使用的完整步骤:

I figured out my problems creating the activity. I have your solution fully implemented and the best part is that it actually solves my memory leak. After spending two weeks on this problem, I am so happy that it's resolved. Here are the full steps I used:

创建一个名为 AdMobActivity 的新活动:

Create a new activity called 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);
    }
}

将以下内容添加到您的 AndroidManifest.xml

Add the following to your AndroidManifest.xml

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

在尝试加载任何广告之前,您需要初始化虚拟 AdMobActivity.此活动将不包含任何内容.它将显示一秒钟然后关闭,返回到您调用它的活动.您不能在要加载广告的同一活动中创建它,因为它必须在使用前及时完全初始化.在包含广告的主要活动开始之前,我在启动加载屏幕活动的 onCreate 中对其进行初始化:

You need to initialize the dummy AdMobActivity before trying to load any ads. This activity won't contain anything. It will be displayed for a split second and then close, returning back to the activity you called it in. You can not create it in the same activity you want to load Ads since it must be fully initialized in time before using. I initialize it in a splash load screen activity's onCreate before the main activity that contains an ad starts:

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

现在您可以在代码中创建广告了.将以下 LinearLayout 添加到您的 XML 活动布局.围绕此布局对齐所有其他必要的视图.我们在代码中创建的 AdView 将放置在此视图中.

Now you are ready to create ads in code. Add the following LinearLayout to your XML activity layout. Align all other views necessary around this layout. The AdView we create in code will be placed inside this view.

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

在要加载广告的活动中,为 AdView 创建一个全局变量:

In the activity you want to load an ad, create a global variable for the AdView:

AdView adView;

在我们的应用中,我们会在手机旋转时加载不同的布局.因此,我在每次旋转时调用以下代码.如有必要,它会创建 adView 并将其添加到 adviewLayout.

In our app, we load different layouts when the phone rotates. Therfore, I call the following code on every rotate. It creates the adView if necessary and adds it to the 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

最后,确保在活动的 onDestroy() 方法中调用 adView.destroy():

Lastly, make sure you call adView.destroy() in the activities onDestroy() method:

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

阅读本文的其他人,请记住,这是 Adam 的解决方案 (TacB0sS),而不是我的.我只是想提供完整的实现细节,让其他人更容易实现.这个 AdMob 错误对于运行 pre-honeycomb 的应用程序来说是一个巨大的问题,Adam 的解决方案是我能找到的最好的方法来规避它.它有效!

Anyone else that reads this, please remember that this is Adam's solution (TacB0sS), not mine. I just wanted to provide the full implementation details to make it easier for others to implement. This AdMob bug is a huge problem for apps running pre-honeycomb and Adam's solution is the best thing I could find to circumvent it. And it works!

推荐答案

Ravis

您的问题很重要,我的解决方案中没有解决.据我所知,我发现的解决方案只能动态工作,您可以在调用 sdk 时选择您的活动...

Your question is to the point, and I have failed to address it in my solution. As far as I can tell the solution I've found works only dynamically, where you can choose your activity while calling the sdk...

我的代码没有使用示例的原因是因为我的解决方案比我提供的解决方案稍微复杂一些,涉及我围绕 Android 框架构建的整个包装框架,其中 AdMob 与应用程序的关系是通过一个中间模块,它使用单个活动实例动态地放置广告.

The reason my code does not have a use example, is because my solution is a bit more complicated then the one I presented, involving an entire wrapping framework I've build around the Android framework, where the AdMob relation to the application is via an intermediate module, which puts the ad dynamically using the single activity instance.

我真的怀疑您是否可以仅使用 Android XML 来避免内存泄漏.

I really doubt you can avoid the memory leak simply using the Android XML.

无论如何,如果您从事内存泄漏业务,您不妨检查一下您的 AsyncTask 使用情况……它也有自己的内存泄漏行为……所以这是我的 解决方案

In any case, if you are into the memory leak business, you might as well check out your AsyncTask usage... it also has its own memory leak behavior... so here is my solution

祝你好运...

-- 更新 -- 14 年 7 月 10 日

-- UPDATE -- 07/10/14

刚刚有人对我的回答投了赞成票,这个问题仍然存在真是太荒谬了,距离我最初的回答已经快三年了,人们仍然因为 AdMob 的应用程序存在内存泄漏......来自谷歌......这使得安卓....

Someone just upvoted my answer, its preposterous that this issue still exists, it has been almost three years since my original answer, and people still have memory leaks in their apps because of AdMob... from Google... that made Android....

无论如何,我只想补充一点,您可能应该将 AdMobActivity 的主题设置为透明,这样可以防止闪烁.

Anyway, I just wanted to add that you should probably set the theme of the AdMobActivity to transparent, it would prevent the flickering.

-- 更新 -- 28/02/16

-- UPDATE -- 28/02/16

四年...

-- 更新 -- 09/03/17

-- UPDATE -- 09/03/17

五年...谷歌的人请醒醒,聘请真正的猴子来做这项工作:)

Five years... Someone at Google please wake up, and hire real monkey to do the job :)

亚当.

这篇关于Admob 内存泄漏 - 通过使用空活动来避免的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆