RecyclerView的曝光统计

 

本文字数:6661

预计阅读时间:17分钟

 

本文提供了一种Android列表曝光统计的功能实现。使开发者无需关心数据收集过程,只需简单的设置即可在适当的曝光时机通知开发者所需的曝光数据。

产品需求中我们经常会有统计recyclerView的每个item的曝光需求:

  1. recyclerView上下滚动每个item从不可见进入到屏幕可见范围(这里包含item的可见范围,还有item的曝光时长)

  2. 在tab切换,或者页面切换的时候会引起recyclerView从不可见到可见的变化(当前屏幕上可见的item都算一次曝光)

  3. 数据变化引起的曝光

为了达到产品需求,我们首先需要数据收集,在滑动过程中收集所有需要上报的item,然后在适当的时机进行上报比如滑动停止、页面切换。

我们希望开发者在使用的时候,不需要自己关心数据收集,只需要注册了对应的曝光回调,就可以在适当的时机返回需要上报的item数据。

1 使用方法

//设置露出多少算曝光
myAdapter.setOutPercent(0.1f);
//设置显示多长时间算曝光
myAdapter.setExposureTime(0);
 
//设置曝光监听
myAdapter.setExposureFunc(items->{
    //返回需要曝光的数据列表
    for (ExpItem<NewFeedBean> item : items) {
        LogUtil.d("kami","exposure position = " + item.getPostion() + ": " +item.getData().sourceFeed.content + ",duration = " + (item.getEndTime() - item.getStartTime()));
    }
    return null;
},item->{
    //自定义需要曝光筛选:比如只曝光广告数据
    return item.getData().isAd();
});

这里我们会返回一个ExpItem列表即需要曝光的数据,开发者只需要在这里写对应的上报逻辑即可。

ExpItem包含数据如下:

class ExpItem<T> {
    //对应item的itemView
    var itemView: View? = null
    //所在位置
    var postion: Int = 0
    //对应item的关联数据
    var data: T? = null
    //开始曝光时间
    var startTime = 0L
    //结束曝光时间
    var endTime = 0L
}

2 解决方案

通过上面的需求分析,我们可以知道recyclerView的曝光主要分为滑动曝光和可见性变化曝光,还有数据变化曝光。

所以接下来我们也分成这三个部分去分别实现:

  •  1  滑动曝光 

  • 我们可以通过监听recyclerView的滑动过程,在滑动的过程中收集曝光的数据(因为曝光行为就是在滑动过程中产生的),然后当滑动停止的时候去进行一个曝光上报(这样既能保证实时性,又可以兼顾手机的性能)。

  •  2  可见性变化曝光 

  • 这里我们需要监听recyclerView的可见性变化,但是并没有提供给我们View可见性变化的监听。虽然有一些焦点变化的监听,但是并不能完全覆盖View的可见性变化。所以这里我们必须想别的办法来实现,这里我通过Actvity的生命周期的onResume和onPause想到有没有可能实现Fragment的onFragmentResume和onFragmentPause来监听Fragment的可见性,监听到Fragment的可见性,也就相当于监听到recyclerView的可见性。然后遍历当前可见的Item收集,并上报即可。

  •  3  数据变化引起的曝光 

  • 有时候数据变化也会引起相应的曝光,这种的我们比较好处理只需要监听相应的数据变化。然后对可见的需要曝光的item进行曝光处理即可。

接下来将从三个方面分析具体的实现原理。

3 实现原理

因为Adatper控制着RecyclerView的ViewHolder的创建和绑定,并且对应的数据适配都是在Adapter中完成的,所以这里选择重写Adapter来实现曝光功能。

3.1 recyclerView滑动过程中引起的曝光

首先我们需要在recyclerView的滑动过程中进行数据收集,即收集显示到屏幕上需要曝光的item。

  • 我们知道当recylerView的ViewHolder加载到屏幕上会先调用onViewAttachedToWindow(holder: VH),所以我们就选择在这个方法进行数据收集。只要显示到屏幕的数据都会被收集到collectDatas列表当中

    /**
     * 进行曝光items收集
     */
    override fun onViewAttachedToWindow(holder: VH) {
        val item = ExpItem<T>()
        item.data = holder.mData
        item.itemView = holder.itemView
        item.postion = holder.mPosition
        collectDatas.add(item)
        super.onViewAttachedToWindow(holder)
        //检查曝光范围,并更新曝光开始时间
        if (innerCheckExposureData(item)){
            item.startTime = TimeUtil.getCurrentTimeMillis()
        }
 
    }
  • 接着我们需要筛选需要进行曝光的数据,计算每个Item在屏幕上的位置,自定义筛选条件(比如:只曝光广告)这个筛选我们需要在recyclerView的滚动过程中进行计算,因为滚动过程中ViewHolder的露出范围是不断发生改变的,然后我们把筛选的数据从collectDatas中移动到expDatas列表当中

  • 1.为什么这个筛选过程要放在onScrolled过程中?

首先曝光的行为是在滑动过程中达成的,比如我们不断的上下滑动recyclerView,导致item_1不断的出现在屏幕中和消失在屏幕中。假如这个过程中item_1曝光了5次,滑动停止后回到我们初始的滑动位置。如果我们在滑动停止的时候来筛选曝光的item,可能会认为完全没有新曝光的item。因为我们滑动停止在了原来初始的位置,显然这个计算是不对的。想要正确的记录曝光的item,就必须要在recyclerView的滑动过程中去筛选达到曝光条件的item。

其次考虑到曝光时间,在滑动过程中Item达到曝光条件,这时候我们就应该记录曝光的开始时间。在其他的时机无法正确的记录曝光时间。

  • 2.在onScrolled的过程中进行筛选计算是否会影响recyclerView的性能,导致滑动不流畅?

这个筛选计算分为两个部分,一个部分是需要开发者定义的筛选逻辑,这里就需要开发者自己注意不要有耗时的判断逻辑。 第二个部分是内部的筛选逻辑,主要是判断item的露出高度是否达到曝光要求。

这个判断是否会影响recyclerView的性能?其实也是不会的。

首先item的自身的高度、位置(滑动偏移量)在滑动过程中每一帧的渲染之前都是已经由recyclerView计算好的,否则recyclerView也没有办法把每个item绘制在正确的位置。所以显然这个计算肯定不会影响recyclerView的流畅性。

而我们需要做的判断主要是拿到当前item的位置信息,进行比较看是否达到曝光要求,这个显然也不是一个耗时操作。我们是通过 itemView!!.getGlobalVisibleRect(rect)这个方法来获取item的位置信息的,通过代码跟踪,我们可以看下具体

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值