I am writing code to laod MaxNative ad from Applovins into recyclerView. I load it first time and use it for every new call. here is the code
fun showNativeAd2(adContainer: FrameLayout) {
val params = adContainer.layoutParams
params.height = 300.px
adContainer.layoutParams = params
if (isPremium()) {
adContainer.visibility = View.GONE
return
}
adContainer.visibility = View.VISIBLE
val nativeAdLoader = MaxNativeAdLoader(adMobIds.nativeId, adContainer.context)
nativeAdLoader.setNativeAdListener(object : MaxNativeAdListener() {
override fun onNativeAdLoaded(nativeAdView: MaxNativeAdView?, ad: MaxAd) {
// Clean up any pre-existing native ad to prevent memory leaks.
if (nativeAd != null) {
nativeAdLoader.destroy(nativeAd)
}
nativeAd = ad
globalNativeAd = nativeAdView
adContainer.removeAllViews()
adContainer.addView(nativeAdView)
}
override fun onNativeAdLoadFailed(adUnitId: String, error: MaxError) {
// We recommend retrying with exponentially higher delays up to a maximum delay
log("$adUnitId $error")
}
override fun onNativeAdClicked(ad: MaxAd) {
log("$ad")
}
})
if (globalNativeAd == null)
nativeAdLoader.loadAd()
else{
adContainer.removeAllViews()
adContainer.addView(globalNativeAd)
}
}
here globalNative is global variable that is initialized only one's on first call of function if globalNative is null and for each new call it just shows that which is stored in globalNative variable. but while loading so recyclerview shows error.
here is stacktrace.
2023-04-27 12:15:29.952 10265-10265/com.thesrb.bluewords E/CustomActivityOnCrash: The previous app process crashed. This is the stack trace of the crash:
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
at android.view.ViewGroup.addViewInner(ViewGroup.java:5269)
at android.view.ViewGroup.addView(ViewGroup.java:5090)
at android.view.ViewGroup.addView(ViewGroup.java:5030)
at android.view.ViewGroup.addView(ViewGroup.java:5003)
at com.thesrb.bluewords.ads_libs.AppLovinUtils.showNativeAd2(AppLovinUtils.kt:161)
at com.thesrb.bluewords.adapter.WordAdapter.setAds(WordAdapter.kt:217)
at com.thesrb.bluewords.adapter.WordAdapter.onBindViewHolder(WordAdapter.kt:188)
at com.thesrb.bluewords.adapter.WordAdapter.onBindViewHolder(WordAdapter.kt:32)
at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:7254)
at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:7337)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:6194)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6460)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6300)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6296)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2330)
at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1631)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1591)
I have created an extension function (in kotlin) to avoid such crashes and it is working for me perfectly.
Add this function into any file or Object
type class
fun ViewGroup.addCleanView(view: View?) {
(view?.parent as? ViewGroup)?.removeView(view)
this.removeAllViews()
this.addView(view)
}
Now, usage is simple as follow:
adContainer.addCleanView(globalNativeAd)
here too,
adContainer.addCleanView(nativeAdView)
No need to remove views or etc. my extension function will handle all.