androidkotlinandroid-recyclerviewadmobandroid-viewholder

How to prevent admob native ads in recyclerview from recycling or reloading when scrolling down/up


I successfully added the AdMob native ads in my app, every 10 items it loads and show one ad, the problem is when I scroll out from it it's destroyed and the second list (10 items) load the second ad, and so on..., to understand issue see this video

Video thumbnail
**video on youtube

this makes some delay in loading ads each time it depends of the internet speed of the user, so I wanna make the ad unit "space" in reclcerview not recycled when the user scrolled, I tried some methods like onViewRecycled and holder.setIsRecyclable(false) on bindViewHolder but neither of it is working

here's my Adapter class

class PostAdapter(
    items: List<Item>, private val titleAndGridLayout: TitleAndGridLayout
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    private val items: List<Item>
    private var nativeAd: NativeAd? = null

    private val VIEW_TYPE_CONTENT = 1
    private val VIEW_TYPE_AD_CARD_LAYOUT = 2
    internal val VIEW_TYPE_AD_GRID_LAYOUT = 3

    private var adsCnt = 3


    var viewType = 0
        set(value) {
            field = value
            notifyDataSetChanged()
        }


    override fun getItemViewType(position: Int): Int {

        return when (viewType) {
            CARD, CARD_MAGAZINE -> {
                if (position != 0 && position % 10 == 0) VIEW_TYPE_AD_CARD_LAYOUT else VIEW_TYPE_CONTENT
            }
            TITLE -> {
                if ((position + 1) % 9 == 0 && (position + 1) != 1) VIEW_TYPE_AD_GRID_LAYOUT else VIEW_TYPE_CONTENT
            }
            GRID -> {
                if ((position + 1) % 10 == 0 && (position + 1) != 1) VIEW_TYPE_AD_GRID_LAYOUT else VIEW_TYPE_CONTENT
            }
            else -> VIEW_TYPE_CONTENT
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        val nativeAdRowBinding = AdUnifiedBinding.inflate(inflater, parent, false)
        val nativeAdRowTitleGridBinding =
            NativeAdRowTitleGridBinding.inflate(inflater, parent, false)
        when (viewType) {
            VIEW_TYPE_CONTENT -> {
                when (this.viewType) {
                    CARD -> {
                        val cardLayoutBinding: CardLayoutBinding =
                            CardLayoutBinding.inflate(inflater, parent, false)
                        return CardViewHolder(cardLayoutBinding)
                    }
                    CARD_MAGAZINE -> {
                        val cardMagazineBinding: CardMagazineBinding =
                            CardMagazineBinding.inflate(
                                LayoutInflater.from(parent.context),
                                parent,
                                false
                            )
                        return CardMagazineViewHolder(cardMagazineBinding)
                    }
                    TITLE -> {
                        val titleLayoutBinding: TitleLayoutBinding =
                            TitleLayoutBinding.inflate(inflater, parent, false)
                        return TitleViewHolder(titleLayoutBinding)
                    }
                    else -> {
                        val gridLayoutBinding: GridLayoutBinding =
                            GridLayoutBinding.inflate(inflater, parent, false)
                        return GridViewHolder(gridLayoutBinding)
                    }
                }
            }
            VIEW_TYPE_AD_CARD_LAYOUT -> {

                //                view = inflater.inflate(R.layout.ad_unified, false)
                return AdViewHolder(nativeAdRowBinding)

            }
            else -> {

                //                view = inflater.inflate(R.layout.ad_unified, false)
                return AdViewHolderGrid(nativeAdRowTitleGridBinding)
            }
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val item: Item = items[position]
//        val document = Jsoup.parse(item.content)
//        val elements = document.select("img")

        val intent = Intent(holder.itemView.context, DetailsActivity::class.java)

        if (getItemViewType(position) == VIEW_TYPE_CONTENT) {
            when (this.viewType) {
                CARD -> if (holder is CardViewHolder) {
                    holder.bind(item)
                    holder.itemView.setOnClickListener { view: View ->
                        intent.putExtra("postItem", item)
                        view.context.startActivity(intent)
                    }
                }
                CARD_MAGAZINE -> if (holder is CardMagazineViewHolder) {
                    holder.bind(item)
                    holder.itemView.setOnClickListener { view: View ->
                        intent.putExtra("postItem", item)
                        view.context.startActivity(intent)
                    }
                }
                TITLE -> if (holder is TitleViewHolder) {

                    holder.bind(item)

                    if (position == itemCount - 1)
                        titleAndGridLayout.tellFragmentToGetItems("titleLayout")

                    holder.itemView.setOnClickListener { view: View ->
                        intent.putExtra("postItem", item)
                        view.context.startActivity(intent)
                    }
                }
                GRID -> if (holder is GridViewHolder) {

                    holder.bind(item)
                    if (position == itemCount - 1) {
                        titleAndGridLayout.tellFragmentToGetItems("gridLayout")
                    }
                    holder.itemView.setOnClickListener { view: View ->
                        intent.putExtra("postItem", item)
                        view.context.startActivity(intent)
                    }
                }
            }
        } else if (getItemViewType(position) == VIEW_TYPE_AD_CARD_LAYOUT) {
            if (holder is AdViewHolder) {
                holder.bindAdData()
                holder.setIsRecyclable(false)
            }
        } else {
            holder as AdViewHolderGrid
            holder.bindAdData()
            holder.setIsRecyclable(false)
            if (position == itemCount - 1) {
                titleAndGridLayout.tellFragmentToGetItems("gridLayout")
            }
        }
    }
    

//    override fun onViewRecycled(holder: RecyclerView.ViewHolder) {
//        super.onViewRecycled(holder)
//        if(holder is AdViewHolder){
//            getItemViewType(holder.bindingAdapterPosition)
//
//        }
//    }

    override fun getItemCount(): Int {
        return items.size
    }

//    override fun getItemId(position: Int): Long {
//        return position.toLong()
//    }

    class CardViewHolder(private val cardLayoutBinding: CardLayoutBinding) :
        RecyclerView.ViewHolder(cardLayoutBinding.root) {
        fun bind(item: Item) {
            val document = Jsoup.parse(item.content)
            val elements = document.select("img")

//        Log.e("IMAGE", document.getAllElements().select("img").get(0).attr("src"));
            var date: Date? = Date()
            val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault())
            cardLayoutBinding.postTitle.text = item.title
            try {
//                Log.e("IMAGE", elements[0].attr("src"))
                Glide.with(cardLayoutBinding.root).load(elements[0].attr("src"))
                    .transition(DrawableTransitionOptions.withCrossFade(600))
                    .placeholder(R.drawable.loading_animation)
                    .error(R.drawable.no_image)
                    .into(cardLayoutBinding.postImage)
            } catch (e: IndexOutOfBoundsException) {
                cardLayoutBinding.postImage.setImageResource(R.drawable.no_image)
//                Log.e(TAG, e.toString())
            }
            cardLayoutBinding.postDescription.text = document.text()
            try {
                date = format.parse(item.published)
            } catch (e: ParseException) {
                e.printStackTrace()
            }
            val prettyTime = PrettyTime()
            cardLayoutBinding.postDate.text = prettyTime.format(date)
        }

    }

    class CardMagazineViewHolder(private val cardMagazineBinding: CardMagazineBinding) :
        RecyclerView.ViewHolder(cardMagazineBinding.root) {

        fun bind(item: Item) {
            val document = Jsoup.parse(item.content)
            val elements = document.select("img")
            var date: Date? = Date()
            val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault())


//        Log.e("IMAGE", document.getAllElements().select("img").get(0).attr("src"));
            cardMagazineBinding.postTitle.text = item.title
            try {
//                Log.e("IMAGE", elements[0].attr("src"))
                Glide.with(itemView.context).load(elements[0].attr("src"))
                    .transition(DrawableTransitionOptions.withCrossFade(600))
                    .placeholder(R.drawable.loading_animation)
                    .error(R.drawable.no_image)
                    .into(cardMagazineBinding.postImage)
            } catch (e: IndexOutOfBoundsException) {
                cardMagazineBinding.postImage.setImageResource(R.drawable.no_image)
//                Log.e(TAG, e.toString())
            }
            try {
                date = format.parse(item.published)
            } catch (e: ParseException) {
                e.printStackTrace()
            }
            val prettyTime = PrettyTime()
            cardMagazineBinding.postDate.text = prettyTime.format(date)
        }

    }

    inner class TitleViewHolder(private val binding: TitleLayoutBinding) :
        RecyclerView.ViewHolder(binding.root) {

        fun bind(item: Item) {
            val document = Jsoup.parse(item.content)
            val elements = document.select("img")

//        Log.e("IMAGE", document.getAllElements().select("img").get(0).attr("src"));
            binding.postTitle.text = item.title
            try {
//                Log.e("IMAGE", elements[0].attr("src"))
                Glide.with(itemView.context).load(elements[0].attr("src"))
                    .transition(DrawableTransitionOptions.withCrossFade(600))
                    .placeholder(R.drawable.loading_animation)
                    .error(R.drawable.no_image)
                    .into(binding.postImage)
            } catch (e: IndexOutOfBoundsException) {
                binding.postImage.setImageResource(R.drawable.no_image)
//                Log.e(TAG, e.toString())
            }
        }


    }

    inner class GridViewHolder constructor(private val binding: GridLayoutBinding) :
        RecyclerView.ViewHolder(binding.root) {
        fun bind(item: Item) {
            val document = Jsoup.parse(item.content)
            val elements = document.select("img")

//        Log.e("IMAGE", document.getAllElements().select("img").get(0).attr("src"));
            binding.postTitle.text = item.title
            try {
//                Log.e("IMAGE", elements[0].attr("src"))
                Glide.with(itemView.context).load(elements[0].attr("src"))
                    .transition(DrawableTransitionOptions.withCrossFade(600))
                    .placeholder(R.drawable.loading_animation)
                    .error(R.drawable.no_image)
                    .into(binding.postImage)
            } catch (e: IndexOutOfBoundsException) {
                binding.postImage.setImageResource(R.drawable.no_image)
//                Log.e(TAG, e.toString())
            }
        }

    }


    companion object {
        private const val CARD = 0
        private const val CARD_MAGAZINE = 1
        private const val TITLE = 2
        private const val GRID = 3
        private const val TAG = "POST_ADAPTER"
    }

    init {
        this.items = items
//        this.fragment = fragment
//        this.postViewModel = postViewModel
    }

    inner class AdViewHolder(private val binding: AdUnifiedBinding) :
        RecyclerView.ViewHolder(binding.root) {

        private val videoOptions = VideoOptions.Builder()
            .setStartMuted(false)
            .build()


        private var adOptions = NativeAdOptions.Builder()
            .setVideoOptions(videoOptions)
            .build()

        fun bindAdData() {
            val builder =
                AdLoader.Builder(binding.root.context, "ca-app-pub-3940256099942544/2247696110")

            builder.forNativeAd { nativeAd ->
                // OnUnifiedNativeAdLoadedListener implementation.
                // If this callback occurs after the activity is destroyed, you must call
                // destroy and return or you may get a memory leak.
               this@PostAdapter.nativeAd = nativeAd
                populateNativeAdView(nativeAd,binding)
            }

            builder.withNativeAdOptions(adOptions)


            val adLoader = builder
                    .withAdListener(
                        object : AdListener() {
                            override fun onAdFailedToLoad(loadAdError: LoadAdError) {

                                if(adsCnt > 0) {
                                    bindAdData()
                                }
                                else {
                                    adsCnt-=1
                                }

                                val error =
                                    """
           domain: ${loadAdError.domain}, code: ${loadAdError.code}, message: ${loadAdError.message}
          """"
                                Toast.makeText(
                                    binding.root.context,
                                    "Failed to load native ad with error $error",
                                    Toast.LENGTH_SHORT
                                )
                                    .show()
                            }
                        }
                    )
                    .build()

            adLoader.loadAd(AdRequest.Builder().build())


        }

        private fun populateNativeAdView(nativeAd: NativeAd, unifiedAdBinding: AdUnifiedBinding) {
            val nativeAdView = unifiedAdBinding.root

            // Set the media view.
            nativeAdView.mediaView = unifiedAdBinding.adMedia

            // Set other ad assets.
            nativeAdView.headlineView = unifiedAdBinding.adHeadline
            nativeAdView.bodyView = unifiedAdBinding.adBody
            nativeAdView.callToActionView = unifiedAdBinding.adCallToAction
            nativeAdView.iconView = unifiedAdBinding.adAppIcon
            nativeAdView.priceView = unifiedAdBinding.adPrice
            nativeAdView.starRatingView = unifiedAdBinding.adStars
            nativeAdView.storeView = unifiedAdBinding.adStore
            nativeAdView.advertiserView = unifiedAdBinding.adAdvertiser

            // The headline and media content are guaranteed to be in every UnifiedNativeAd.
            unifiedAdBinding.adHeadline.text = nativeAd.headline
            nativeAd.mediaContent?.let { unifiedAdBinding.adMedia.setMediaContent(it) }

            // These assets aren't guaranteed to be in every UnifiedNativeAd, so it's important to
            // check before trying to display them.
            if (nativeAd.body == null) {
                unifiedAdBinding.adBody.visibility = INVISIBLE
            } else {
                unifiedAdBinding.adBody.visibility = View.VISIBLE
                unifiedAdBinding.adBody.text = nativeAd.body
            }

            if (nativeAd.callToAction == null) {
                unifiedAdBinding.adCallToAction.visibility = INVISIBLE
            } else {
                unifiedAdBinding.adCallToAction.visibility = View.VISIBLE
                unifiedAdBinding.adCallToAction.text = nativeAd.callToAction
            }

            if (nativeAd.icon == null) {
                unifiedAdBinding.adAppIcon.visibility = View.GONE
            } else {
                unifiedAdBinding.adAppIcon.setImageDrawable(nativeAd.icon?.drawable)
                unifiedAdBinding.adAppIcon.visibility = View.VISIBLE
            }

            if (nativeAd.price == null) {
                unifiedAdBinding.adPrice.visibility = INVISIBLE
            } else {
                unifiedAdBinding.adPrice.visibility = View.VISIBLE
                unifiedAdBinding.adPrice.text = nativeAd.price
            }

            if (nativeAd.store == null) {
                unifiedAdBinding.adStore.visibility = INVISIBLE
            } else {
                unifiedAdBinding.adStore.visibility = View.VISIBLE
                unifiedAdBinding.adStore.text = nativeAd.store
            }

            if (nativeAd.starRating == null) {
                unifiedAdBinding.adStars.visibility = INVISIBLE
            } else {
                unifiedAdBinding.adStars.rating = nativeAd.starRating!!.toFloat()
                unifiedAdBinding.adStars.visibility = View.VISIBLE
            }

            if (nativeAd.advertiser == null) {
                unifiedAdBinding.adAdvertiser.visibility = INVISIBLE
            } else {
                unifiedAdBinding.adAdvertiser.text = nativeAd.advertiser
                unifiedAdBinding.adAdvertiser.visibility = View.VISIBLE
            }

            // This method tells the Google Mobile Ads SDK that you have finished populating your
            // native ad view with this native ad.
            nativeAdView.setNativeAd(nativeAd)


        }
    }

    inner class AdViewHolderGrid(private val nativeAdRowTitleGridBinding: NativeAdRowTitleGridBinding) :
        RecyclerView.ViewHolder(nativeAdRowTitleGridBinding.root) {

        fun bindAdData() {
            val adLoader =
                AdLoader.Builder(
                    nativeAdRowTitleGridBinding.root.context,
                    "ca-app-pub-3940256099942544/2247696110"
                )
                    .forNativeAd { nativeAd: NativeAd ->


                        this@PostAdapter.nativeAd = nativeAd
//                        populateNativeADView(nativeAd)


                        val styles =
                            NativeTemplateStyle.Builder().withMainBackgroundColor(
                                ColorDrawable(
                                    ContextCompat.getColor(
                                        nativeAdRowTitleGridBinding.root.context,
                                        R.color.backgroundColor
                                    )
                                )
                            ).build()

                        val template: TemplateView = nativeAdRowTitleGridBinding.myTemplate

                        Log.d(TAG, "bindAdData: ${nativeAd.body}")
                        
                        template.setStyles(styles)
                        template.setNativeAd(nativeAd)


                    }
                    .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(
                                nativeAdRowTitleGridBinding.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())
        }
    }

    fun destroyNativeAd() {
        nativeAd?.destroy()
        Log.d(TAG, "destroyNativeAd: ${nativeAd?.body}")
    }


}

Solution

  • UPDATE , "SOLVED"

    The trick was in the following

    replace this method

    loadAd(AdManagerAdRequest adManagerAdRequest)
    

    with this, the second parameter is for the number of ads requested for the first time to preload ads

    loadAds(AdRequest adRequest, int maxNumberOfAds)
    

    Okay, I contacted Google Mobile Ads SDK Technical Forum, and their replay was

    You may check this guide which will teach you how to preload native ads.

    and I followed the steps in the guide they provided to me, but unfortunately, I was facing some troubles with implementation, it contains many deprecated libs and tools, such as 'com.google.firebase:firebase-ads:15.0.0' and the current version is 21.1.0, also classpath 'com.android.tools.build:gradle:3.3.1' in build.gradle (project module), I tried to update all of this but the app not working, then I tried to run the final code with minimum acceptable libs and it's works and the ads cached successfully, I requested from them to update this guide or send another one with the last version of Admob ads,

    thier replied

    Aside from what my colleague's implementation guide provided, there is no other sample app that shows this kind of implementation. You can then try to recreate one and have this as a reference for it. Kindly note that it's important that publishers not keep old ads around too long without displaying them. Any ad objects that have been held for longer than an hour without being displayed should be discarded and replaced with new ads from a new request.

    then I decided to discover the issue by myself and after spending a lot of hours trying to solve this issue, the last result I reached is I was able to implement the sample old work (as reference) with my project but and I see the first ad is cached successfully, but unfortunately, all next native ads in recyclerView not showing when scrolling and I got this in logcat

    2022-08-07 10:36:34.226 3498-3498/com.mml.dummyapp_kotlin D/DynamitePackage: Instantiating com.google.android.gms.ads.ChimeraNativeAdViewDelegateCreatorImpl
    2022-08-07 10:36:34.258 3498-3498/com.mml.dummyapp_kotlin D/DynamitePackage: Instantiating com.google.android.gms.ads.ChimeraNativeAdViewDelegateCreatorImpl
    2022-08-07 10:36:38.006 3498-3498/com.mml.dummyapp_kotlin D/DynamitePackage: Instantiating com.google.android.gms.ads.ChimeraNativeAdViewDelegateCreatorImpl
    2022-08-07 10:36:38.023 3498-3498/com.mml.dummyapp_kotlin D/DynamitePackage: Instantiating com.google.android.gms.ads.ChimeraNativeAdViewDelegateCreatorImpl
    2022-08-07 10:36:44.094 3498-3498/com.mml.dummyapp_kotlin D/DynamitePackage: Instantiating com.google.android.gms.ads.ChimeraNativeAdViewDelegateCreatorImpl
    2022-08-07 10:36:48.596 3498-3498/com.mml.dummyapp_kotlin I/chatty: uid=10428(com.mml.dummyapp_kotlin) identical 4 lines
    

    I replied to their email with the current result and issue, so I'll post my result here as a solution until they replied o my last email

    1. I split the AdViewHolder with a new file and update it like this
    class AdViewHolder(private val binding: AdUnifiedBinding) :
        RecyclerView.ViewHolder(binding.root) {
    
    
        val adView get() = binding
    
        }
    
    1. I changed the items in my Post Adapter to take MutableList<Any> instead of List<Item> and some other changes on
    
    class PostAdapter(
        items: MutableList<Any>, private val titleAndGridLayout: TitleAndGridLayout
    ) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
        private val items: MutableList<Any>
    //    private var nativeAd: NativeAd? = null
    
        val VIEW_TYPE_CONTENT = 1
        val VIEW_TYPE_AD_CARD_LAYOUT = 2
        val VIEW_TYPE_AD_GRID_LAYOUT = 3
    
        private var adsCnt = 3
    
    
        var viewType = 0
            set(value) {
                field = value
                notifyDataSetChanged()
            }
    
    //    var itemViewType = 0
    //        set(value) {
    //            field = value
    //            notifyDataSetChanged()
    //        }
    
    
        override fun getItemViewType(position: Int): Int {
    
    //        val recyclerViewItem:Any = this.items[position]
    
    
            return when (viewType) {
                CARD, CARD_MAGAZINE -> {
                    if ( position != 0 && position % 10 == 0) VIEW_TYPE_AD_CARD_LAYOUT else VIEW_TYPE_CONTENT
                }
                TITLE -> {
                    if (  (position + 1) % 9 == 0 && (position + 1) != 1) VIEW_TYPE_AD_GRID_LAYOUT else VIEW_TYPE_CONTENT
                }
                GRID -> {
                    if (  (position + 1) % 10 == 0 && (position + 1) != 1) VIEW_TYPE_AD_GRID_LAYOUT else VIEW_TYPE_CONTENT
                }
                else -> VIEW_TYPE_CONTENT
            }
        }
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
            val inflater = LayoutInflater.from(parent.context)
    
            val nativeAdRowTitleGridBinding =
                NativeAdRowTitleGridBinding.inflate(inflater, parent, false)
            when (viewType) {
                VIEW_TYPE_CONTENT -> {
                    when (this.viewType) {
                        CARD -> {
                            val cardLayoutBinding: CardLayoutBinding =
                                CardLayoutBinding.inflate(inflater, parent, false)
                            return CardViewHolder(cardLayoutBinding)
                        }
                        CARD_MAGAZINE -> {
                            val cardMagazineBinding: CardMagazineBinding =
                                CardMagazineBinding.inflate(
                                    LayoutInflater.from(parent.context),
                                    parent,
                                    false
                                )
                            return CardMagazineViewHolder(cardMagazineBinding)
                        }
                        TITLE -> {
                            val titleLayoutBinding: TitleLayoutBinding =
                                TitleLayoutBinding.inflate(inflater, parent, false)
                            return TitleViewHolder(titleLayoutBinding)
                        }
                        else -> {
                            val gridLayoutBinding: GridLayoutBinding =
                                GridLayoutBinding.inflate(inflater, parent, false)
                            return GridViewHolder(gridLayoutBinding)
                        }
                    }
                }
                VIEW_TYPE_AD_CARD_LAYOUT -> {
    
                    //                view = inflater.inflate(R.layout.ad_unified, false)
                    val nativeAdRowBinding = AdUnifiedBinding.inflate(inflater, parent, false)
                    return AdViewHolder(nativeAdRowBinding)
    
                }
                else -> {
    
                    //                view = inflater.inflate(R.layout.ad_unified, false)
                    return AdViewHolderGrid(nativeAdRowTitleGridBinding)
                }
            }
        }
    
        override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    
            var item: Item? = null
    
            if (items[position] is Item) {
                item = items[position] as Item
            }
    //        val document = Jsoup.parse(item.content)
    //        val elements = document.select("img")
    
            val intent = Intent(holder.itemView.context, DetailsActivity::class.java)
    
            if (getItemViewType(position) == VIEW_TYPE_CONTENT) {
                when (this.viewType) {
                    CARD -> if (holder is CardViewHolder) {
                        if (item != null) {
                            holder.bind(item)
                        }
                        holder.itemView.setOnClickListener { view: View ->
                            intent.putExtra("postItem", item)
                            view.context.startActivity(intent)
                        }
                    }
                    CARD_MAGAZINE -> if (holder is CardMagazineViewHolder) {
                        if (item != null) {
                            holder.bind(item)
                        }
                        holder.itemView.setOnClickListener { view: View ->
                            intent.putExtra("postItem", item)
                            view.context.startActivity(intent)
                        }
                    }
                    TITLE -> if (holder is TitleViewHolder) {
    
                        if (item != null) {
                            holder.bind(item)
                        }
    
                        if (position == itemCount - 1)
                            titleAndGridLayout.tellFragmentToGetItems("titleLayout")
    
                        holder.itemView.setOnClickListener { view: View ->
                            intent.putExtra("postItem", item)
                            view.context.startActivity(intent)
                        }
                    }
                    GRID -> if (holder is GridViewHolder) {
    
                        if (item != null) {
                            holder.bind(item)
                        }
                        if (position == itemCount - 1) {
                            titleAndGridLayout.tellFragmentToGetItems("gridLayout")
                        }
                        holder.itemView.setOnClickListener { view: View ->
                            intent.putExtra("postItem", item)
                            view.context.startActivity(intent)
                        }
                    }
                }
            } else if (getItemViewType(position) == VIEW_TYPE_AD_CARD_LAYOUT) {
                if (holder is AdViewHolder) {
    
                    val adItem: Any = items[position]
    
                    if (adItem is NativeAd) {
    
    //                    val nativeAd = items[position] as NativeAd
                        populateNativeAdView(adItem, holder.adView)
                    }
    //                holder.setIsRecyclable(false)
                }
            } else {
                holder as AdViewHolderGrid
                holder.bindAdData()
    //            holder.setIsRecyclable(false)
                if (position == itemCount - 1) {
                    titleAndGridLayout.tellFragmentToGetItems("gridLayout")
                }
            }
        }
    //
    //    override fun onFailedToRecycleView(holder: RecyclerView.ViewHolder): Boolean {
    //        return if (holder is AdViewHolder) {
    //            // Don't recycle the ad view, keep it around
    //            true
    //        } else {
    //            super.onFailedToRecycleView(holder)
    //        }
    //    }
    
    
    //    override fun onViewRecycled(holder: RecyclerView.ViewHolder) {
    //        super.onViewRecycled(holder)
    //        if(holder is AdViewHolder){
    //            getItemViewType(holder.bindingAdapterPosition)
    //
    //        }
    //    }
    
        override fun getItemCount(): Int {
            return items.size
        }
    
    
        class CardViewHolder(private val cardLayoutBinding: CardLayoutBinding) :
            RecyclerView.ViewHolder(cardLayoutBinding.root) {
            fun bind(item: Item) {
                val document = Jsoup.parse(item.content)
                val elements = document.select("img")
    
    //        Log.e("IMAGE", document.getAllElements().select("img").get(0).attr("src"));
                var date: Date? = Date()
                val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault())
                cardLayoutBinding.postTitle.text = item.title
                try {
    //                Log.e("IMAGE", elements[0].attr("src"))
                    Glide.with(cardLayoutBinding.root).load(elements[0].attr("src"))
                        .transition(DrawableTransitionOptions.withCrossFade(600))
                        .placeholder(R.drawable.loading_animation)
                        .error(R.drawable.no_image)
                        .into(cardLayoutBinding.postImage)
                } catch (e: IndexOutOfBoundsException) {
                    cardLayoutBinding.postImage.setImageResource(R.drawable.no_image)
    //                Log.e(TAG, e.toString())
                }
                cardLayoutBinding.postDescription.text = document.text()
                try {
                    date = format.parse(item.published)
                } catch (e: ParseException) {
                    e.printStackTrace()
                }
                val prettyTime = PrettyTime()
                cardLayoutBinding.postDate.text = prettyTime.format(date)
            }
    
        }
    
        class CardMagazineViewHolder(private val cardMagazineBinding: CardMagazineBinding) :
            RecyclerView.ViewHolder(cardMagazineBinding.root) {
    
            fun bind(item: Item) {
                val document = Jsoup.parse(item.content)
                val elements = document.select("img")
                var date: Date? = Date()
                val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault())
    
    
    //        Log.e("IMAGE", document.getAllElements().select("img").get(0).attr("src"));
                cardMagazineBinding.postTitle.text = item.title
                try {
    //                Log.e("IMAGE", elements[0].attr("src"))
                    Glide.with(itemView.context).load(elements[0].attr("src"))
                        .transition(DrawableTransitionOptions.withCrossFade(600))
                        .placeholder(R.drawable.loading_animation)
                        .error(R.drawable.no_image)
                        .into(cardMagazineBinding.postImage)
                } catch (e: IndexOutOfBoundsException) {
                    cardMagazineBinding.postImage.setImageResource(R.drawable.no_image)
    //                Log.e(TAG, e.toString())
                }
                try {
                    date = format.parse(item.published)
                } catch (e: ParseException) {
                    e.printStackTrace()
                }
                val prettyTime = PrettyTime()
                cardMagazineBinding.postDate.text = prettyTime.format(date)
            }
    
        }
    
        inner class TitleViewHolder(private val binding: TitleLayoutBinding) :
            RecyclerView.ViewHolder(binding.root) {
    
            fun bind(item: Item) {
                val document = Jsoup.parse(item.content)
                val elements = document.select("img")
    
    //        Log.e("IMAGE", document.getAllElements().select("img").get(0).attr("src"));
                binding.postTitle.text = item.title
                try {
    //                Log.e("IMAGE", elements[0].attr("src"))
                    Glide.with(itemView.context).load(elements[0].attr("src"))
                        .transition(DrawableTransitionOptions.withCrossFade(600))
                        .placeholder(R.drawable.loading_animation)
                        .error(R.drawable.no_image)
                        .into(binding.postImage)
                } catch (e: IndexOutOfBoundsException) {
                    binding.postImage.setImageResource(R.drawable.no_image)
    //                Log.e(TAG, e.toString())
                }
            }
    
    
        }
    
        inner class GridViewHolder constructor(private val binding: GridLayoutBinding) :
            RecyclerView.ViewHolder(binding.root) {
            fun bind(item: Item) {
                val document = Jsoup.parse(item.content)
                val elements = document.select("img")
    
    //        Log.e("IMAGE", document.getAllElements().select("img").get(0).attr("src"));
                binding.postTitle.text = item.title
                try {
    //                Log.e("IMAGE", elements[0].attr("src"))
                    Glide.with(itemView.context).load(elements[0].attr("src"))
                        .transition(DrawableTransitionOptions.withCrossFade(600))
                        .placeholder(R.drawable.loading_animation)
                        .error(R.drawable.no_image)
                        .into(binding.postImage)
                } catch (e: IndexOutOfBoundsException) {
                    binding.postImage.setImageResource(R.drawable.no_image)
    //                Log.e(TAG, e.toString())
                }
            }
    
        }
    
    
        companion object {
            private const val CARD = 0
            private const val CARD_MAGAZINE = 1
            private const val TITLE = 2
            private const val GRID = 3
            private const val TAG = "POST_ADAPTER"
        }
    
        init {
            this.items = items
    //        this.fragment = fragment
    //        this.postViewModel = postViewModel
        }
    
        private fun populateNativeAdView(nativeAd: NativeAd, unifiedAdBinding: AdUnifiedBinding) {
            val nativeAdView = unifiedAdBinding.root
    
            // Set the media view.
            nativeAdView.mediaView = unifiedAdBinding.adMedia
    
            // Set other ad assets.
            nativeAdView.headlineView = unifiedAdBinding.adHeadline
            nativeAdView.bodyView = unifiedAdBinding.adBody
            nativeAdView.callToActionView = unifiedAdBinding.adCallToAction
            nativeAdView.iconView = unifiedAdBinding.adAppIcon
            nativeAdView.priceView = unifiedAdBinding.adPrice
            nativeAdView.starRatingView = unifiedAdBinding.adStars
            nativeAdView.storeView = unifiedAdBinding.adStore
            nativeAdView.advertiserView = unifiedAdBinding.adAdvertiser
    
            // The headline and media content are guaranteed to be in every UnifiedNativeAd.
            unifiedAdBinding.adHeadline.text = nativeAd.headline
            nativeAd.mediaContent?.let { unifiedAdBinding.adMedia.setMediaContent(it) }
    
            // These assets aren't guaranteed to be in every UnifiedNativeAd, so it's important to
            // check before trying to display them.
            if (nativeAd.body == null) {
                unifiedAdBinding.adBody.visibility = INVISIBLE
            } else {
                unifiedAdBinding.adBody.visibility = View.VISIBLE
                unifiedAdBinding.adBody.text = nativeAd.body
            }
    
            if (nativeAd.callToAction == null) {
                unifiedAdBinding.adCallToAction.visibility = INVISIBLE
            } else {
                unifiedAdBinding.adCallToAction.visibility = View.VISIBLE
                unifiedAdBinding.adCallToAction.text = nativeAd.callToAction
            }
    
            if (nativeAd.icon == null) {
                unifiedAdBinding.adAppIcon.visibility = View.GONE
            } else {
                unifiedAdBinding.adAppIcon.setImageDrawable(nativeAd.icon?.drawable)
                unifiedAdBinding.adAppIcon.visibility = View.VISIBLE
            }
    
            if (nativeAd.price == null) {
                unifiedAdBinding.adPrice.visibility = INVISIBLE
            } else {
                unifiedAdBinding.adPrice.visibility = View.VISIBLE
                unifiedAdBinding.adPrice.text = nativeAd.price
            }
    
            if (nativeAd.store == null) {
                unifiedAdBinding.adStore.visibility = INVISIBLE
            } else {
                unifiedAdBinding.adStore.visibility = View.VISIBLE
                unifiedAdBinding.adStore.text = nativeAd.store
            }
    
            if (nativeAd.starRating == null) {
                unifiedAdBinding.adStars.visibility = INVISIBLE
            } else {
                unifiedAdBinding.adStars.rating = nativeAd.starRating!!.toFloat()
                unifiedAdBinding.adStars.visibility = View.VISIBLE
            }
    
            if (nativeAd.advertiser == null) {
                unifiedAdBinding.adAdvertiser.visibility = INVISIBLE
            } else {
                unifiedAdBinding.adAdvertiser.text = nativeAd.advertiser
                unifiedAdBinding.adAdvertiser.visibility = View.VISIBLE
            }
    
            // This method tells the Google Mobile Ads SDK that you have finished populating your
            // native ad view with this native ad.
            nativeAdView.setNativeAd(nativeAd)
    
    
        }
    
        inner class AdViewHolderGrid(private val nativeAdRowTitleGridBinding: NativeAdRowTitleGridBinding) :
            RecyclerView.ViewHolder(nativeAdRowTitleGridBinding.root) {
    
            fun bindAdData() {
                val adLoader =
                    AdLoader.Builder(
                        nativeAdRowTitleGridBinding.root.context,
                        "ca-app-pub-3940256099942544/2247696110"
                    )
                        .forNativeAd { nativeAd: NativeAd ->
    
    
    //                        this@PostAdapter.nativeAd = nativeAd
    //                        populateNativeADView(nativeAd)
    
    
                            val styles =
                                NativeTemplateStyle.Builder().withMainBackgroundColor(
                                    ColorDrawable(
                                        ContextCompat.getColor(
                                            nativeAdRowTitleGridBinding.root.context,
                                            R.color.backgroundColor
                                        )
                                    )
                                ).build()
    
                            val template: TemplateView = nativeAdRowTitleGridBinding.myTemplate
    
                            Log.d(TAG, "bindAdData: ${nativeAd.body}")
    
                            template.setStyles(styles)
                            template.setNativeAd(nativeAd)
    
    
                        }
                        .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(
                                    nativeAdRowTitleGridBinding.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())
            }
        }
    }
    
    1. And finally I updated my fragment and changed the list of items with a list of any and added this as global vars
        private lateinit var adLoader: AdLoader
    
        // List of MenuItems and native ads that populate the RecyclerView.
        private val mRecyclerViewItems: MutableList<Any> = ArrayList()
    
        // List of native ads that have been successfully loaded.
        private val mNativeAds: MutableList<NativeAd> = ArrayList()
    
        val NUMBER_OF_ADS = 5
    

    then I declared a function to load native ads like this

       private fun loadNativeAds() {
            val builder =
                AdLoader.Builder(requireContext(), "ca-app-pub-3940256099942544/2247696110")
            adLoader =
                builder.forNativeAd { nativeAd -> // A native ad loaded successfully, check if the ad loader has finished loading
                    // and if so, insert the ads into the list.
    
                    // A native ad loaded successfully, check if the ad loader has finished loading
                    // and if so, insert the ads into the list.
    //                val localNativeAd = nativeAd
                    mNativeAds.add(nativeAd)
                    if (!adLoader.isLoading) {
                        mRecyclerViewItems.add(nativeAd)
                    }
                }.withAdListener(
                    object : AdListener() {
                        override fun onAdFailedToLoad(p0: LoadAdError) {
                            super.onAdFailedToLoad(p0)
    
                            // A native ad failed to load, check if the ad loader has finished loading
                            // and if so, insert the ads into the list.
                            Log.e(
                                "MainActivity", "The previous native ad failed to load. Attempting to"
                                        + " load another."
                            )
                            if (!adLoader.isLoading) {
    //                            insertAdsInMenuItems()
                                loadNativeAds()
                            }
    
                        }
                    }).build()
    
            // Load the Native ads.
            adLoader.loadAds(AdRequest.Builder().build(), NUMBER_OF_ADS)
        }
    

    and called it when the Internet is available

     networkListener.checkNetworkAvailability(requireContext()).collect { stats ->
                    Log.d(TAG, "networkListener: $stats")
                    postViewModel.networkStats = stats
                    postViewModel.showNetworkStats()
                    if (stats && savedInstanceState == null) {
                        requestApiData()
                        requestHomeBanner()
                        loadNativeAds()
    

    I'll waiting their replay on last issue and If they discover the cause I'll post update with solution