Android AdMob导致内存泄漏?

Muz*_*ant 21 memory android 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>
Run Code Online (Sandbox Code Playgroud)

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

表现:

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

这就是我所拥有的所有代码.

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

删除与AdView相关的代码后(再次,这是此应用程序的唯一代码)问题就消失了: 不使用AdView的HPROF输出相同

编辑:还尝试从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>
Run Code Online (Sandbox Code Playgroud)

有任何想法吗 ????

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

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

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

不幸的是,间隙仍在泄漏


Tac*_*0sS 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

将使用AdMobActivity.AdMobMemoryLeakWorkAroundActivity创建更多广告.

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

<activity
    android:launchMode="singleInstance"
    android:name="com.nu.art.software.android.modules.admob.AdMobActivity" />
Run Code Online (Sandbox Code Playgroud)

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

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

亚当.

UPDATE

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


Sun*_*hoo -1

不要将您的 UI 与 Admob 合并,您可以运行另一个线程从 Admob 获取广告。您还可以在特定的时间间隔刷新广告。这样您就可以更轻松地调试内存问题所在的位置。

谢谢迪帕克