Android AdView 泄漏,可能是由于某些内部后台线程
Android AdView leaking, probably due to some internal background thread
我在片段创建的 window 中显示 AdMob 广告横幅。这行得通,但我遇到了一些我还不明白的奇怪的泄漏问题。当我多次打开和关闭应用程序时,广告片段每次都被正确销毁,但是控制这个片段的 MainActivity 正在泄漏:
有罪的是代码中的这一行:
adRequest = new AdRequest.Builder().addTestDevice(DEVICE_ID_MOTO_G).addTestDevice(DEVICE_ID_ZTE).build();
mAdView.loadAd(adRequest);
(您可以在下面看到我已经尝试使 adRequest 无效,但没有结果。)无论如何,当我评论这两行时,不会发生泄漏。我测试了两次,因为很难相信这个调用会泄漏,但确实如此。这是片段代码。如您所见,我什至取消了 onDestroy()
中所有可能的内容。我可以确保 onDestroy()
被调用。 loadAd
启动任何后台线程。我想这与那个问题有关。
public class SnippetFragment extends Fragment
{
private AdView mAdView;
private OnAdFinishedLoadingListener onAdFinishedLoadingListener;
private Context context;
private AdRequest adRequest;
private final String DEVICE_ID_ZTE = "1CA20334345BB1479C43692AFA576456487A48";
private final String DEVICE_ID_MOTO_G = "131465469A7BE11543543065404B168908CB13C8D1";
public SnippetFragment(Context context)
{
this.context = context;
}
@Override
public void onActivityCreated(Bundle bundle)
{
super.onActivityCreated(bundle);
mAdView = (AdView)getView().findViewById(R.id.adView);
mAdView.setAdListener(new AdListener()
{
@Override
public void onAdLoaded()
{
super.onAdLoaded();
if (context != null)
{
onAdFinishedLoadingListener = (OnAdFinishedLoadingListener)context;
onAdFinishedLoadingListener.onAdLoaded();
}
}
});
//THIS SOMEHOW LEAKS!
adRequest = new AdRequest.Builder().addTestDevice(DEVICE_ID_MOTO_G).addTestDevice(DEVICE_ID_ZTE).build();
mAdView.loadAd(adRequest);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_snippet, container, false);
}
/** Called when leaving the activity */
@Override
public void onPause()
{
if (mAdView != null)
{
mAdView.pause();
}
super.onPause();
}
/** Called when returning to the activity */
@Override
public void onResume()
{
super.onResume();
if (mAdView != null)
{
mAdView.resume();
}
}
/** Called before the activity is destroyed */
@Override
public void onDestroy()
{
adRequest = null;
if (mAdView != null)
{
mAdView.setAdListener(null);
mAdView.destroy();
mAdView = null;
}
context = null;
super.onDestroy();
}
}
我幸运地找到了解决方案。在片段被销毁之前,您必须手动将 AdView 踢出周围的布局。在我启动和关闭应用程序大约 20 次后,不再泄漏。这是更新后的片段:
public class SnippetFragment extends Fragment
{
private AdView adView;
private OnAdFinishedLoadingListener onAdFinishedLoadingListener;
private Context context;
private LatLng routeDestination;
private AdRequest adRequest;
private LinearLayout snippetContent;
private final String DEVICE_ID_ZTE = "2353496z35752t3524267854";
private final String DEVICE_ID_MOTO_G = "4568735862378523675427897";
@Override
public void onActivityCreated(Bundle bundle)
{
super.onActivityCreated(bundle);
snippetContent = (LinearLayout)getView().findViewById(R.id.snippet_content);
adView = (AdView)getView().findViewById(R.id.adView);
adView.setAdListener(new AdListener()
{
@Override
public void onAdLoaded()
{
super.onAdLoaded();
if (context != null)
{
onAdFinishedLoadingListener = (OnAdFinishedLoadingListener)getActivity();
onAdFinishedLoadingListener.onAdLoaded();
}
}
});
adRequest = new AdRequest.Builder().addTestDevice(DEVICE_ID_MOTO_G).addTestDevice(DEVICE_ID_ZTE).build();
adView.loadAd(adRequest);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_snippet, container, false);
}
@Override
public void onPause()
{
if (adView != null)
{
adView.pause();
}
super.onPause();
}
@Override
public void onResume()
{
super.onResume();
if (adView != null)
{
adView.resume();
}
}
@Override
public void onDestroy()
{
destroyAdView();
super.onDestroy();
}
private void destroyAdView()
{
if (adView != null)
{
adRequest = null;
adView.removeAllViews();
adView.setAdListener(null);
adView.destroy();
snippetContent.removeView(adView);
adView = null;
snippetContent = null;
}
}
}
我在片段创建的 window 中显示 AdMob 广告横幅。这行得通,但我遇到了一些我还不明白的奇怪的泄漏问题。当我多次打开和关闭应用程序时,广告片段每次都被正确销毁,但是控制这个片段的 MainActivity 正在泄漏:
有罪的是代码中的这一行:
adRequest = new AdRequest.Builder().addTestDevice(DEVICE_ID_MOTO_G).addTestDevice(DEVICE_ID_ZTE).build();
mAdView.loadAd(adRequest);
(您可以在下面看到我已经尝试使 adRequest 无效,但没有结果。)无论如何,当我评论这两行时,不会发生泄漏。我测试了两次,因为很难相信这个调用会泄漏,但确实如此。这是片段代码。如您所见,我什至取消了 onDestroy()
中所有可能的内容。我可以确保 onDestroy()
被调用。 loadAd
启动任何后台线程。我想这与那个问题有关。
public class SnippetFragment extends Fragment
{
private AdView mAdView;
private OnAdFinishedLoadingListener onAdFinishedLoadingListener;
private Context context;
private AdRequest adRequest;
private final String DEVICE_ID_ZTE = "1CA20334345BB1479C43692AFA576456487A48";
private final String DEVICE_ID_MOTO_G = "131465469A7BE11543543065404B168908CB13C8D1";
public SnippetFragment(Context context)
{
this.context = context;
}
@Override
public void onActivityCreated(Bundle bundle)
{
super.onActivityCreated(bundle);
mAdView = (AdView)getView().findViewById(R.id.adView);
mAdView.setAdListener(new AdListener()
{
@Override
public void onAdLoaded()
{
super.onAdLoaded();
if (context != null)
{
onAdFinishedLoadingListener = (OnAdFinishedLoadingListener)context;
onAdFinishedLoadingListener.onAdLoaded();
}
}
});
//THIS SOMEHOW LEAKS!
adRequest = new AdRequest.Builder().addTestDevice(DEVICE_ID_MOTO_G).addTestDevice(DEVICE_ID_ZTE).build();
mAdView.loadAd(adRequest);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_snippet, container, false);
}
/** Called when leaving the activity */
@Override
public void onPause()
{
if (mAdView != null)
{
mAdView.pause();
}
super.onPause();
}
/** Called when returning to the activity */
@Override
public void onResume()
{
super.onResume();
if (mAdView != null)
{
mAdView.resume();
}
}
/** Called before the activity is destroyed */
@Override
public void onDestroy()
{
adRequest = null;
if (mAdView != null)
{
mAdView.setAdListener(null);
mAdView.destroy();
mAdView = null;
}
context = null;
super.onDestroy();
}
}
我幸运地找到了解决方案。在片段被销毁之前,您必须手动将 AdView 踢出周围的布局。在我启动和关闭应用程序大约 20 次后,不再泄漏。这是更新后的片段:
public class SnippetFragment extends Fragment
{
private AdView adView;
private OnAdFinishedLoadingListener onAdFinishedLoadingListener;
private Context context;
private LatLng routeDestination;
private AdRequest adRequest;
private LinearLayout snippetContent;
private final String DEVICE_ID_ZTE = "2353496z35752t3524267854";
private final String DEVICE_ID_MOTO_G = "4568735862378523675427897";
@Override
public void onActivityCreated(Bundle bundle)
{
super.onActivityCreated(bundle);
snippetContent = (LinearLayout)getView().findViewById(R.id.snippet_content);
adView = (AdView)getView().findViewById(R.id.adView);
adView.setAdListener(new AdListener()
{
@Override
public void onAdLoaded()
{
super.onAdLoaded();
if (context != null)
{
onAdFinishedLoadingListener = (OnAdFinishedLoadingListener)getActivity();
onAdFinishedLoadingListener.onAdLoaded();
}
}
});
adRequest = new AdRequest.Builder().addTestDevice(DEVICE_ID_MOTO_G).addTestDevice(DEVICE_ID_ZTE).build();
adView.loadAd(adRequest);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_snippet, container, false);
}
@Override
public void onPause()
{
if (adView != null)
{
adView.pause();
}
super.onPause();
}
@Override
public void onResume()
{
super.onResume();
if (adView != null)
{
adView.resume();
}
}
@Override
public void onDestroy()
{
destroyAdView();
super.onDestroy();
}
private void destroyAdView()
{
if (adView != null)
{
adRequest = null;
adView.removeAllViews();
adView.setAdListener(null);
adView.destroy();
snippetContent.removeView(adView);
adView = null;
snippetContent = null;
}
}
}