Android AdMob导致内存泄漏?

时间:2011-05-27 06:52:48

标签: android memory memory-leaks admob

我已将AdMob v4.1.0集成到我的应用程序中,它似乎导致了巨大的内存泄漏(非常确定它已经发生在4.0.4上)。

为了隔离问题,我创建了一个具有空白线性布局的新项目,并向其添加了AdView(这实际上是AdMob提供的示例代码中的复制和粘贴)。请参阅我的main.xml,MainActivity.java和清单内容:

main.xml中:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/linearLayout">
<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello"
    />
</LinearLayout>

MainActivity.java:

package AdsTry.main;

import com.google.ads.AdRequest;
import com.google.ads.AdSize;
import com.google.ads.AdView;

import android.app.Activity;
import android.os.Bundle;
import android.widget.LinearLayout;

public class MainActivity extends Activity {

    private final int AD_VIEW_ID = 1000000; 

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

         // Lookup R.layout.main
        LinearLayout layout = (LinearLayout)findViewById(R.id.linearLayout);

        // Create the adView
        // Please replace MY_BANNER_UNIT_ID with your AdMob Publisher ID
        AdView adView = new AdView(this, AdSize.BANNER, "MY_BANNER_UNIT_ID");
        adView.setId(AD_VIEW_ID);

        // Add the adView to it
        layout.addView(adView);

        // Initiate a generic request to load it with an ad
        AdRequest request = new AdRequest();

        adView.loadAd(request);           
    }

    @Override
    protected void onPause() {
        Log.i("AdsTry", "onPause");

        getAdView().stopLoading();

        super.onPause();
    }

    @Override
    protected void onDestroy() {
        Log.i("AdsTry", "onDestroy");

        getAdView().destroy();

        super.onDestroy();
    }

    private AdView getAdView()
    {
        return (AdView) findViewById(AD_VIEW_ID);
    }
}

清单:

<application android:icon="@drawable/icon" android:label="@string/app_name">
    <activity android:name=".MainActivity"
              android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <!-- AdMobActivity definition -->
    <activity android:name="com.google.ads.AdActivity"
        android:configChanges="orientation|keyboard|keyboardHidden" />
</application>

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

这就是我的所有代码。

现在,在运行此应用程序时,我可以看到onPause和onDestory都被调用并且Activity被终止,但问题是它永远不会用于GC,因为它会导致InputMethodManager保持对活动(参见活动销毁后从HPROF输出中获取的图像): MainActivity Merge shortest path to GC Roots

删除与AdView相关的代码后(再次,这是此应用程序的唯一代码)问题就消失了: Same HPROF output without using AdView

编辑: 还尝试从onCreate中删除所有代码并更新main.xml以包含以下内容(仍然得到相同的结果):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:ads="http://schemas.android.com/apk/lib/com.google.ads"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/linearLayout">
    <TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello"
    />
    <com.google.ads.AdView
    android:id="@+id/Ad"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    ads:adUnitId="MY_ID"
    ads:adSize="BANNER"
    ads:loadAdOnCreate="true"/>
</LinearLayout>

任何想法????

8 个答案:

答案 0 :(得分:6)

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

以动态方式创建广告

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

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

mAdView.setAdListener(null);
mAdsContainer.removeAllViews();
mAdView.destroy();

不幸的非页内广告仍在泄密

答案 1 :(得分:5)

这是我为这场混乱做的工作:

我通过使用相同的空活动实例来限制内存泄漏:

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);
        finish();
    }

    public static final void startAdMobActivity(Activity activity) {
        Intent i = new Intent();
        i.setComponent(new ComponentName(activity.getApplicationContext(), AdMobActivity.class));
        activity.startActivity(i);
    }
}

可以使用 AdMobActivity.AdMobMemoryLeakWorkAroundActivity 创建更多广告。

您还需要将活动添加到清单中:

<activity
    android:launchMode="singleInstance"
    android:name="com.nu.art.software.android.modules.admob.AdMobActivity" />

这种实现违背了我对静态引用的看法,这些静态引用不是常量,但是这种实现可以防止泄漏,因为只有一个活动实例用于创建所有广告,因此没有更多的活动泄漏,加上活动的事实完全是空的。

注意:您应该从应用主要活动 onCreate 方法调用 startAdMobActivity 方法。

亚当。

<强>更新

此解决方案仅在您动态创建广告时才有效,并使用代码将其添加到布局中...并且不要忘记在Activity.onDestroy()中将其销毁。

答案 2 :(得分:3)

解决此问题的一种方法是使用应用程序的基本活动创建一个单一的adview实例。将此广告添加到您想要的任何活动中,但请记住在destroy方法的活动中将其删除。

这样,adview只会泄漏基本活动,您几乎不应该有多个实例。

示例:

@Override
public void onCreate(final Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   this.setContentView(R.layout.venue);
   mainLayout = (LinearLayout) findViewById(R.id.venueLayout);
   adview = StaticStateClass.getAdview();

   AdRequest request = new AdRequest();
   request.addKeyword(name);
   mainLayout.addView(adview);
   adview.loadAd(request);
}

@Override
public void onDestroy() {
   mainLayout.removeView(adview);
   super.onDestroy();
}

答案 3 :(得分:2)

我发现那个叫: -

mAdView.destroy(); 
离开活动之前

为我解决了泄漏。

以下是我在xml中声明横幅广告的方式: -

  <com.google.android.gms.ads.AdView
            android:id="@+id/adView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal|bottom"
            ads:adSize="BANNER"
            ads:adUnitId="@string/banner_ad_unit_id_2" />

在onCreate()中获取admob横幅的引用: -

mAdView = (AdView) findViewById(R.id.adView2);
AdRequest banneradRequest = new AdRequest.Builder().build();

mAdView.loadAd(banneradRequest);

并在活动的ondestroy()中销毁它: -

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

答案 4 :(得分:1)

我面临同样的问题。唯一有一件事帮助了我 - 它的System.exit(0)。我不喜欢它,但这是我找到的唯一方法 AdMob只停留在RAM 4ever中,不要让我的应用程序正常完成。当我重新启动我的应用程序操作系统时,只会引发该不死应用程序,很快就会导致内存不足异常 My AdMob support forum topic - 迄今为止没有任何支持。看起来像没关心。

答案 5 :(得分:0)

解决此问题的另一个答案,即使这样做很麻烦,也要遵循以下步骤。

  • 取消使用sharedPreferences或任何其他类型的存储持久性所需的所有数据,
    将这些值存储在局部变量/对象

  • 擦除所有应用程序数据

  • 重新坚持一切

您可以在应用关闭时启动服务。这会阻止数据因内存泄漏而变得非常大。令人讨厌的方式来解决它,但我已经尝试过它,它的工作原理。

答案 6 :(得分:-1)

Donot将您的用户界面与Admob合并,您可以运行其他线程从Admob获取广告。您也可以按特定时间间隔刷新广告。您可以更轻松地调试内存问题。

由于 迪帕克

答案 7 :(得分:-2)

基本上,这不是一个真正的问题。发生了什么事情是你的活动是接收onDestroy,进行清理,然后等待GC运行。当GC发生时,它会看到这个旧的上下文并清理所有底层的垃圾,但它似乎没有清除该传递中的Activity - 这就是为什么你的“泄露”活动占用的空间很小:它是基本上是一个shell。在下一次GC通过时,它将被清理。

您可以通过激活您的活动,退出(触发onDestroy),返回进程,触发GC和hprof转储,等待一点,然后再触发另一个GC和hprof转储来看到这一点。在第一次转储中 - 至少在我的测试中 - 我看到了类似于你的结果:一个额外的活动,内存占用非常小。在第二个转储中,我只看到了当前正在运行的活动。