带有分页库的无限RecyclerView中的AdMob广告

时间:2019-06-05 12:56:32

标签: android android-recyclerview admob recycler-adapter android-paging

我正在使用paging library从服务器中获取数据,我想每10个项目显示一次广告。因此,当用户向下滚动时,将提取新项目并将其添加到PagedList。我希望在RecyclerView中加载并添加新广告,就像Instagram在feed中显示广告一样。因此,如果用户滚动到200个项目,则将逐渐显示20个广告!我已经阅读了一些教程,但是还没有找到简单的方法。

这是我的适配器。

class RequestsPagedAdapter(
        private val retryCallback: () -> Unit, private val from: From)
    : PagedListAdapter<RequestsQuery.Request, RecyclerView.ViewHolder>(POST_COMPARATOR) {
    private var networkState: NetworkState? = null

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when (getItemViewType(position)) {
            R.layout.z_request_item -> (holder as RequestViewHolder).bind(getItem(position)!!, from)
            R.layout.network_state_item -> (holder as NetworkStateItemViewHolder).bindTo(networkState)
            R.layout.ad_admob_banner -> (holder as AdMobViewHolder)
        }
    }

    override fun onBindViewHolder(
            holder: RecyclerView.ViewHolder,
            position: Int,
            payloads: MutableList<Any>) {
        if (payloads.isNotEmpty()) {
            val item = getItem(position)
            (holder as RequestViewHolder).updateProduct(item!!)
        } else {
            onBindViewHolder(holder, position)
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return when (viewType) {
            R.layout.z_request_item -> RequestViewHolder.create(parent)
            R.layout.network_state_item -> NetworkStateItemViewHolder.create(parent, retryCallback)
            R.layout.ad_admob_banner -> AdMobViewHolder.create(parent)
            else -> throw IllegalArgumentException("unknown view type $viewType")
        }
    }

    private fun hasExtraRow() = networkState != null && networkState != NetworkState.LOADED

    override fun getItemViewType(position: Int): Int {
        return when {
            hasExtraRow() && position == itemCount - 1 -> R.layout.network_state_item
            position % ITEMS_PER_AD == 0 + 2 -> R.layout.ad_admob_banner
            else -> R.layout.z_request_item
        }
    }

    override fun getItemCount(): Int {
        return super.getItemCount() + if (hasExtraRow()) 1 else 0
    }

    fun setNetworkState(newNetworkState: NetworkState?) {
        val previousState = this.networkState
        val hadExtraRow = hasExtraRow()
        this.networkState = newNetworkState
        val hasExtraRow = hasExtraRow()
        if (hadExtraRow != hasExtraRow) {
            if (hadExtraRow) {
                notifyItemRemoved(super.getItemCount())
            } else {
                notifyItemInserted(super.getItemCount())
            }
        } else if (hasExtraRow && previousState != newNetworkState) {
            notifyItemChanged(itemCount - 1)
        }
    }

    companion object {
        val POST_COMPARATOR = object : DiffUtil.ItemCallback<RequestsQuery.Request>() {
            override fun areContentsTheSame(oldItem: RequestsQuery.Request, newItem: RequestsQuery.Request): Boolean =
                    oldItem == newItem

            override fun areItemsTheSame(oldItem: RequestsQuery.Request, newItem: RequestsQuery.Request): Boolean =
                    oldItem.id() == newItem.id()
        }
    }
}

这是将数据从PagedList提交到Fragment的方式。

private fun getRequests() {
    subcategoryRequestsListViewModel.requests.observe(viewLifecycleOwner, Observer {
        adapter.submitList(it)
    })
    subcategoryRequestsListViewModel.networkState.observe(viewLifecycleOwner, Observer {
        adapter.setNetworkState(it)
    })
}

还有ViewHolder

class AdMobViewHolder(view: View) : RecyclerView.ViewHolder(view) {
    companion object {
        fun create(parent: ViewGroup): AdMobViewHolder {
            val view = LayoutInflater.from(parent.context)
                    .inflate(R.layout.ad_admob_banner, parent, false)
            return AdMobViewHolder(view)
        }
    }
}

4 个答案:

答案 0 :(得分:1)

第一步必须声明适配器中的字段,如blew

private val ADS_ITEM = 0
private val NORMAL_ITEM = 1

因此,下一步,您必须创建两个类型实例viewHolder

inner class MyViewHolder(itemView: View) : ViewHolder(itemView) {
    var title: TextView = itemView.item_text

}

inner class AdsMyViewHolder(itemView: View) : ViewHolder(itemView) {
    var title: TextView = itemView.item_text
}

并创建一个适合viewHolder的新实例

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    val inflater = LayoutInflater.from(parent.context)
    return if (viewType == NORMAL_ITEM) {
        val v = inflater.inflate(R.layout.item, parent, false)
        vh = MyViewHolder(v)
        vh as MyViewHolder
    } else {
        val v = inflater.inflate(R.layout.item_ads, parent, false)
        vh = AdsMyViewHolder(v)
        vh as AdsMyViewHolder
    }
}

不要忘记覆盖getItemViewType

override fun getItemViewType(position: Int): Int {
    return when (getItems()[position]) {
        is AdsSampleModel -> ADS_ITEM
        else -> NORMAL_ITEM
    }
}

具有适当数据的最后一步绑定项目

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    when (holder) {
        is MyViewHolder -> {
            vh = holder
            val model = getItems()[position] as SampleModel
            (vh as MyViewHolder).title.text = model.getId().toString()
        }
        else -> {
            vh = holder
            val model = getItems()[position] as AdsSampleModel
            (vh as AdsMyViewHolder).title.text = model.getText()
        }
    }
}

分页后添加新项

fun view () {
    endless = object : EndlessRecyclerViewScrollListener(layoutManager) {
        fun onLoadMore(page: Int, totalItemsCount: Int, view: RecyclerView) {
            getNext()
        }
    }
    recyclerView.addOnScrollListener(endless)
}


fun getNext() {
    if (hasNextPage) {
        page++
        val callBack = object : YourCallback {
            override fun onSuccess(response: ResponseValue?) {
                if (response!!.getList().size() == 0)
                    hasNextPage = false
                else
                    addData(response!!.getList())
            }
            override fun onError() {
                // error handling
            }
        }
    }
}


private fun addData(models: List<YourModel>?) {
    for (i in models?.indices) {
        if (i % 10 == 0) {
            list.add(ADS_TYPE)
        }
    }

    // notify adapter must be doing by main thread
    runOnUiThread { adapter.notifyDataSetChanged() }
}

答案 1 :(得分:1)

没有比google example here更简单的例子了 唯一的区别是,它从保存在原始文件中的XML文件中获取数据,而从其他位置获取数据。希望您可以根据需要轻松修改此示例。

答案 2 :(得分:1)

您可以在适配器中添加如下广告列表:

    private val nativeAds = mutableListOf<UnifiedNativeAd>()

然后您的onBindViewHolder将如下所示:

   override fun onBindViewHolder(holder: BaseViewHolder<Any>, position: Int) {
    when (getItemViewType(position)) {
        NATIVE_AD -> {
            val adPosition = position * nativeAds.size / itemCount
            val nativeAd = nativeAds[adPosition]
            holder.performBind(nativeAd)
        }
        else ->  holder.performBind(getItem(position))
    }

}

您的getItemViewType像这样:

 override fun getItemViewType(position: Int): Int {
    val nativeAdRows = getNativeAdRows()
   return if(hasNativeAds() && nativeAdRows.contains(position)){
        NATIVE_AD
    }else {
       //get other model item
   }
}

代码的其余部分:

fun onNativeAdLoaded() {
    val rows = getNativeAdRows()
    Timber.d("Native Ad Rows: $rows")
    Timber.d("Total items: $itemCount")
    rows.forEach {
        notifyItemInserted(it)
    }
}

private fun hasNativeAds(): Boolean {
    return nativeAds.isNotEmpty()
}

private fun getNativeAdRows(): List<Int>{
    val rows = mutableListOf<Int>()
    for (i in 0 .. itemCount){
        if(i != 0 && i % Config.NATIVE_AD_AFTER_POSTS == 0){
            rows.add(i)
        }
    }
    return rows
}

检查此要旨是否为sample code

答案 3 :(得分:0)

您可以在Android Feed中使用AdMob原生高级广告。

Native是一种基于组件的广告格式,可让发布商自由定制广告标题和号召性用语等广告资产在其应用中的显示方式。通过自己选择字体,颜色和其他详细信息,发布者可以创建自然,醒目的广告演示,从而增加丰富的用户体验。请点击以下链接:-

https://codelabs.developers.google.com/codelabs/admob-native-advanced-feed-android/#0