Admob Memory Leak - 通过使用空活动来避免

rav*_*shi 26 android memory-leaks admob

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

我想按照TacB0sS提供的解决方案,https: //stackoverflow.com/a/8364820/684893 .他建议创建一个空活动,并为每个AdMob AdView使用相同的活动.泄漏将被包含,因为AdView将只保留一个空活动.他提供了活动本身的代码以及如何引用它,但我不知道如何将它实际集成到我们的应用程序中.据我所知,他的代码从来没有从AdMob SDK调用任何东西.

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

更新3/6:

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

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);
Run Code Online (Sandbox Code Playgroud)

我已将此代码放在我初始活动的onCreate方法中.我在创建AdView的行上关闭了一个力量,"AdView adView = new AdView(...)".Stacktrace片段:

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
Run Code Online (Sandbox Code Playgroud)

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

更新2 3/6:

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

创建一个名为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);
    }
}
Run Code Online (Sandbox Code Playgroud)

将以下内容添加到AndroidManifest.xml中

<activity android:name="org.udroid.wordgame.AdMobActivity"
    android:launchMode="singleInstance" />
Run Code Online (Sandbox Code Playgroud)

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

// 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);
}
Run Code Online (Sandbox Code Playgroud)

现在您已准备好在代码中创建广告.将以下LinearLayout添加到XML活动布局中.对齐此布局所需的所有其他视图.我们在代码中创建的AdView将放置在此视图中.

<LinearLayout
android:id="@+id/adviewLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true" />
Run Code Online (Sandbox Code Playgroud)

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

AdView adView;
Run Code Online (Sandbox Code Playgroud)

在我们的应用程序中,我们在手机旋转时加载不同的布局.因此,我在每次旋转时调用以下代码.如有必要,它会创建adView并将其添加到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
Run Code Online (Sandbox Code Playgroud)

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

@Override
protected void onDestroy() {
    adView.destroy();
super.onDestroy();
}
Run Code Online (Sandbox Code Playgroud)

其他任何人都读到这个,请记住这是亚当的解决方案(TacB0sS),而不是我的解决方案.我只是想提供完整的实现细节,以便其他人更容易实现.这个AdMob错误对于运行预蜂窝的应用程序来说是一个巨大的问题,而Adam的解决方案是我能找到的绕过它的最好的方法. 它的工作原理!

Tac*_*0sS 17

Ravishi,

你的问题是关键,我没有在我的解决方案中解决它.至于我可以告诉解决方案,我发现只能动态地工作,你可以在调用sdk时选择你的活动......

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

我真的怀疑你可以简单地使用Android XML来避免内存泄漏.

在任何情况下,如果你进入内存泄漏业务,你不妨检查你的AsyncTask使用情况......它也有自己的内存泄漏行为......所以这是我的解决方案

祝你好运......

- 更新 - 2014年10月7日

有人刚刚赞成我的答案,这个问题仍然存在,这已经过去了差不多三年,我的原始答案已经差不多三年了,人们的应用程序中仍有内存泄漏,因为AdMob ......来自谷歌...这使得Android ... ..

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

- 更新 - 2016年2月28日

四年...

- 更新 - 09/03/17

五年......有人在谷歌请醒来,并雇用真正的猴子来做这个工作:)

亚当.


Jul*_*ian 6

我正在使用"play-services-ads:7.5.0",并且创建de AdMobActivity并不是必需的.它的工作原理是:

  • 以动态方式创建adView

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

  • 在销毁和销毁adView时从linearLayout中删除所有视图

                mAdView.setAdListener(null);
                mAdsContainer.removeAllViews();
                mAdView.destroy();
    
    Run Code Online (Sandbox Code Playgroud)

不幸的是,间隙仍在泄漏