一行代码搞定 Android 复杂列表埋点曝光

2022-03-21  本文已影响0人  minminaya

一个好的产品离不开数据分析,在手机 APP 中,数据分析极致化需要细致到某个时刻列表曝光的了哪几个 Item。

2022 年了,基本上目前 Android 上可以滑动的复杂列表都是 RecyclerView 或者其扩展,这里分享一个封装的思路。

一、基本思路


什么是列表曝光


简单的理解就是用户在肉眼可感知范围内真正看到了数据就算曝光,包括数据刷新了

如果非要细化细节:

一些方案的对比


各种方案核心都差不多,最关键的就是通过 LayoutManager 获取屏幕内第一个可见和最后一个可见 item position,上报其区间内的 Item。这里简称这个逻辑为检查上报逻辑

但是触发时机有所不同,通常如下方案一和二所述,当然除了方案一和方案二外,还有一些别的方案,比如监听 RecyclerView 的布局树变化触发检查上报逻辑等方案。

方案一

方案二

这个是在想降低曝光埋点复杂度时,阅读 RecyclerView 源码,并且经过 Demo 不断测试和调试发现的新路子 😊

可以发现方案二相比方案一更有利于减少各种回调的注册和周期的控制,下文会在方案二的基础上,阐述用法和相关实现思路。

二、RecyclerViewExposure 库用法


仓库地址:RecyclerViewExposure


优点:

缺点:

业务场景:

配置 Gradle 依赖

API 说明

使用方法

首先我们先实现一个列表(部分实现省略)

接入 RecyclerViewExposure 库

其他优化

三、源码实现

源码目录

源码分析

这里会主要说明一些主要逻辑,需要完整的逻辑可以 fork 仓库 查看

思路说明

源码设计

1、为 RecyclerViewExposure 库提供页面可见非可见状态监听

思路来自于 lifecycle 的设计,这里主要是想让 Activity/Fragment 提供可见和不可见的状态变化给外部订阅

2、RecyclerView 的Item 可见项和非可见管理和收集

对 List Item 的收集处理是 RecyclerViewExposure 最核心的收集数据逻辑,这里针对在 Activity 的使用作为例子。上文已经讲述如何做一个 PageLifeCycleHolder 为其他组件提供页面可见状态,下文将直接使用。

3、针对 ListAdapter 精简使用方法

abstract class AbsListAdapterImprEventHelper<L : ListAdapter<T, RecyclerView.ViewHolder>, T : IEntityForImpr> :
    AbsListImprEventHelper<L, T> {

    constructor(
        recyclerView: RecyclerView,
        componentActivity: ComponentActivity
    ) : super(recyclerView, componentActivity)

    constructor(
        recyclerView: RecyclerView,
        fragment: Fragment
    ) : super(recyclerView, fragment)

    @Suppress("UNCHECKED_CAST", "IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE")
    override fun getAdapterEntityForPosition(
        bindingAdapterPosition: Int,
        viewHolder: RecyclerView.ViewHolder
    ): T? {
        return (viewHolder.bindingAdapter as? L)?.let {
            it.currentList.run {
                if (bindingAdapterPosition >= this.size) {
                    return null
                }
                return this[bindingAdapterPosition]
            }
        }
    }

}
class ListAdapterImprEventHelper(
    recyclerView: RecyclerView,
    fragment: Fragment
) : AbsListAdapterImprEventHelper<ItemRecyclerViewListAdapter,
        PlaceholderContent.PlaceholderItem>(
    recyclerView,
    fragment
) {
    override fun needPostEvent(entity: PlaceholderContent.PlaceholderItem): Boolean {
        return true
    }

    override fun onItemExposure(
        entity: PlaceholderContent.PlaceholderItem,
        absoluteAdapterPosition: Int,
        bindingAdapterPosition: Int
    ) {
        Log.d(
            "ListAdapterImprEventHelper",
            "onItemExposure:---- absoluteAdapterPosition:$absoluteAdapterPosition ,$entity"
        )
    }

}

四、总结


上一篇 下一篇

猜你喜欢

热点阅读