2016/02/14
AdView は動的追加にしないとメモリリークする
AdView
まわりが参照を握っている様子。こういう時の常套手段として、
AdView
しかないアプリを作って動作を確認してみることにしました。Android Studio の AdMob テンプレートでもメモリリークする
結論から言うと、AdView
しか存在しない Activity
でもメモリリークが発生します。確認した環境は以下 。
- Android Studio 1.5.1
- com.google.android.gms:play-services-ads:8.4.0
(Ad Format: Banner) - 動作確認端末
- Android 4.0.4 (Xperia acro HD )
- Android 6.0 (Emulator)
Android Studio で
File → New → New Project...
Activity テンプレート選択画面で
Google AdMob Ads Activity
Ad Format を Banner にする
このアプリを起動すると、以下のように AdView だけの Activity が立ち上がります。
この状態で画面回転して、Activity の再生を促します。
その際の Heap Dump が以下
見事に MainActivity が2つ存在します。
その後、画面回転を繰り返してみましたが、2回目以降に生成された Activity はきちんと破棄される様子。
つまり、Activity が無限に増殖していくわけではないので、大きな画像を使う等メモリを食う Activity でない場合、あまり問題にならず、気づきにくいようです。
回避方法は AdView を動的追加にする
原因がわかって調べてみると、結構あっさりこの問題についてのトピックを見つけることが出来ました。いろいろトリッキーな方法が考案されているのですが、私の環境では単に以下のように
AdView
を動的追加することで問題を回避出来ました。まず
AdView
を layout xml から消して、その代わりに FrameLayout
を追加activity_main.xml
@@ -7,9 +7,11 @@ android:text="@string/hello_world" /> <!-- view for AdMob Banner Ad --> - <com.google.android.gms.ads.AdView android:id="@+id/adView" android:layout_width="wrap_content" - android:layout_height="wrap_content" android:layout_alignParentBottom="true" - android:layout_centerHorizontal="true" ads:adSize="BANNER" - ads:adUnitId="@string/banner_ad_unit_id" /> + <FrameLayout + android:id="@+id/adArea" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignParentBottom="true"> + </FrameLayout>
MainActivity
で動的に AdView を追加この時、
AdView
のコンストラクタには getApplicationContext()
を与えるのがポイントMainActivity.java
@@ -14,14 +16,17 @@ private static final String TOAST_TEXT = "Test ads are being shown. " + "To show live ads, replace the ad unit ID in res/values/strings.xml with your own ad unit ID."; - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Load an ad into the AdMob banner view. - AdView adView = (AdView) findViewById(R.id.adView); + AdView adView = new AdView(getApplicationContext()); // ←これが重要 + adView.setAdSize(AdSize.BANNER); + adView.setAdUnitId(getString(R.string.banner_ad_unit_id)); + ((FrameLayout) findViewById(R.id.adArea)).addView(adView); + AdRequest adRequest = new AdRequest.Builder() .setRequestAgent("android_studio:ad_template").build(); adView.loadAd(adRequest);
どうせなら Fragment にしてみる
AdView
と Activity
を紐付けなければ良さそうなので、以下のような Fragment を作って実験したところ、問題なく動作しました。ただ、AdMob が AdFragment を提供していないことを鑑みると、この方法にも問題があるのかもしれません。ご使用の際は自己責任でお願いします。
public class AdFragment extends Fragment { private AdView mAdView; public AdFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mAdView = new AdView(getContext().getApplicationContext()); mAdView.setAdSize(AdSize.SMART_BANNER); mAdView.setAdUnitId(getString(R.string.banner_ad_unit_id)); return mAdView; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if (mAdView != null) { AdRequest.Builder b = new AdRequest.Builder(); mAdView.loadAd(b.build()); } } @Override public void onResume() { super.onResume(); if (mAdView != null) { mAdView.resume(); } } @Override public void onPause() { if (mAdView != null) { mAdView.pause(); } super.onPause(); } @Override public void onDestroy() { if (mAdView != null) { mAdView.destroy(); mAdView = null; } super.onDestroy(); } }
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:ads="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.kokufu.myapplication.MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> <!-- view for AdMob Banner Ad --> <fragment android:id="@+id/adFragment" android:name="com.kokufu.android.AdFragment" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" /> </RelativeLayout>
0 件のコメント:
コメントを投稿