In my app, I have implemented ad mob native ads inside my PostAdapter
class, I have 7 different fragments, and I need to know when the fragment is detached or destroyed to call nativeAd.destroy()
to avoid leaks like said in the documentation
Be sure to use the destroy() method on loaded native ads. This frees up utilized resources and prevents memory leaks.
so my trying to solve this problem, I created an Interface and put it into adapter contractor and a method that returns a boolean state when the fragment isDetached
or isRemoving
but both didn't work
interface AdapterAndFragmentsUtils {
fun isFragmentDestroyed(): Boolean
}
The PostAdapter class
class PostAdapter(
items: List<Item>, private val adapterAndFragmentsUtils: AdapterAndFragmentsUtils
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val items: List<Item>
.....some unrelated issue codes
inner class AdViewHolder(private val binding: NativeAdRowBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bindAdData() {
val adLoader =
AdLoader.Builder(binding.root.context, "ca-app-pub-3940256099942544/2247696110")
.forNativeAd { nativeAd: NativeAd ->
// populateNativeADView(nativeAd)
val styles =
NativeTemplateStyle.Builder().withMainBackgroundColor(
ColorDrawable(
ContextCompat.getColor(
binding.root.context,
R.color.backgroundColor
)
)
)
.build()
val template: TemplateView = binding.myTemplate
template.setStyles(styles)
template.setNativeAd(nativeAd)
if (adapterAndFragmentsUtils.isFragmentDestroyed()) {
nativeAd.destroy()
Log.d(TAG,"nativeAdDestroyed")
return@forNativeAd
}
//
}
.withAdListener(object : AdListener() {
override fun onAdClicked() {
super.onAdClicked()
Log.d(TAG, "onAdClicked: ")
}
override fun onAdClosed() {
super.onAdClosed()
Log.d(TAG, "onAdClosed: ")
}
override fun onAdLoaded() {
super.onAdLoaded()
Log.d(TAG, "onAdLoaded: ")
}
override fun onAdOpened() {
super.onAdOpened()
Log.d(TAG, "onAdOpened: ")
}
override fun onAdFailedToLoad(adError: LoadAdError) {
// Handle the failure by logging, altering the UI, and so on.
Toast.makeText(
binding.root.context,
adError.message,
Toast.LENGTH_SHORT
).show()
Log.e(TAG, "onAdFailedToLoad: ${adError.cause.toString()}")
}
})
.withNativeAdOptions(
NativeAdOptions.Builder()
// Methods in the NativeAdOptions.Builder class can be
// used here to specify individual options settings.
.build()
)
.build()
adLoader.loadAd(AdRequest.Builder().build())
}
}
}
Implementation of the interface in each fragment
class HomeFragment : Fragment(), AdapterAndFragmentsUtils {
....
override fun isFragmentDestroyed(): Boolean {
Log.d(TAG, "isFragmentDestroyed: ${this.isDetached}")
return isDetached
}
CodePudding user response:
Instead of an interface method, you can create a method in the adapter itself
first, make nativeAd is global
private var nativeAd: NativeAd?=null
then create the method
fun destroyNativeAd(){
nativeAd?.destroy()
}
and finally, you can call it from fragments onDestroyView
override fun onDestroyView() {
super.onDestroyView()
adapter.destroyNativeAd()
}