写点什么

精细化曝光策略

  • 2019-09-23
  • 本文字数:2453 字

    阅读完需:约 8 分钟

目前贝壳找房 APP 端的曝光时机是写死的, 触发条件:卡片必须要完整展示在界面上; 在列表界面上下/左右滑动时单次/多次曝光同一个卡片。


现有方案的不足:


1.门限条件应改为 API 下发的;


2.缺少卡片在界面上显示的时长;


反例:


1.比如说列表有 1000 条记录,快速滑动列表到最后一条;用户并没有看清中间的 900 多条记录,这时要不要为这些记录做曝光埋点?


2.例如一个卡片高度为 100px,实际上只显示了 80px,是否要做一次曝光埋点。



当前问题:


如果只滑动这个程度,目前 app 不会为“附近地图”做曝光埋点,但该卡片的主要信息都已经展示了


行业对标:


今日头条、手机百度的曝光埋点策略做的很细, 比如卡片划入、划出时间,卡片显示多少比例可以算曝光等等。

解决方案

参考今日头条、手机百度的做法,实现类似的曝光策略。


1.为每种卡片设置不同的曝光策略;


2.APP 根据 API 下发的门限条件触发埋点;


3.记录卡片移入、移出屏幕的时间, 统计每个卡片真正显示的时长;


4.界面销毁、显示/隐藏是否触发曝光埋点。例如按 home 键时是否触发曝光埋点,再次进入是否触发埋点。 这些场景由 API 下发配置开关。



双向队列缓存当前 RecyclerView 显示的所有 ViewHolder, 用于执行卡片的曝光埋点函数。


在监听 RecyclerView 滑动事件时得到第一个可见位置、最后一个可见位置,根据参数判断是上滑或下滑,通过判断 ViewHolder 的 itemView top、bottom 参数值得出刚刚移入屏幕的卡片显示比例, 并根据 API 下发的门限值(最低显示比例)记录开始时间,在卡片即将划出屏幕时(API 下发的门限值)触发曝光埋点。 从而得出卡片的显示周期。


参考代码

滑动回调


public class CardExposureHelper extends RecyclerView.OnScrollListener { //缓存卡片的双向队列  private Deque<BaseHomeCard> deque;  //队列顶部Card的position  private int preFirstExposure;  //队列底部Card的position  private int preLastExposure;  /**   * 处理垂直方向卡片曝光   * @param manager   * @param isUp 是否向上滑动   */  private void onVerticalExposure(LinearLayoutManager manager,boolean isUp) {    int firstVisiblePosition = manager.findFirstVisibleItemPosition();    int lastVisiblePosition = manager.findLastVisibleItemPosition();    //根据曝光比例判断第一个可见卡片是否需要曝光    firstVisiblePosition = isVerticalExposure(firstVisiblePosition)?firstVisiblePosition:firstVisiblePosition+1;    //根据曝光比例判断最后一个可见卡片是否需要曝光    lastVisiblePosition = isVerticalExposure(lastVisiblePosition)?lastVisiblePosition:lastVisiblePosition-1;    //第一次曝光,曝光所有符合曝光比例的Card    if (preFirstExposure==0&&preLastExposure==0){      offerVerticalVisibleQueue(firstVisiblePosition,lastVisiblePosition,true);    }else if (isUp){      //向上滑动,把顶部不可见Card从顶部出队,底部进入可曝光的卡片入队      popVerticalVisibleQueue(preFirstExposure,firstVisiblePosition-1,true);      offerVerticalVisibleQueue(preLastExposure+1,lastVisiblePosition,false);    }else {      //对应向下滑动的策略      popVerticalVisibleQueue(lastVisiblePosition+1,preLastExposure,false);      offerVerticalVisibleQueue(firstVisiblePosition,preFirstExposure-1,true);    }    //更新队列的顶部position和底部position    preFirstExposure = firstVisiblePosition;    preLastExposure = lastVisiblePosition;  }    /**   * 入队操作   * @param start   * @param end   * @param isFirst 是否从顶部入队   */  private void offerVerticalVisibleQueue(int start,int end,boolean isFirst){    if (start>=0 && end<recyclerView.getAdapter().getItemCount() && start<=end){      if (isFirst){        for (int i=end;i>=start;i--){          onVerticalItemSlideInto(i,true);        }      }else {        for (int i=start;i<=end;i++){          onVerticalItemSlideInto(i,false);        }      }    }  }   /**   * 出队操作   * @param start   * @param end   * @param isFirst 是否从顶部出队   */  private void popVerticalVisibleQueue(int start,int end,boolean isFirst){    if (start>=0 && end<recyclerView.getAdapter().getItemCount() && start<=end){      if (isFirst){        for (int i=start;i<=end;i++){          onVerticalItemSlideOut(i,isFirst);        }      }else {        for (int i=end;i>=start;i--){          onVerticalItemSlideOut(i,isFirst);        }      }    }  }   /**   * 处理滑入(入队)可曝光的卡片   * @param position   * @param isFirst 是否从顶部滑入(入队)   */  private void onVerticalItemSlideInto(int position,boolean isFirst){    BaseHomeCard card = getBaseHomeCard(position);    if (isFirst){      deque.offerFirst(card);    }else {      deque.offerLast(card);    }    //回调卡片开始曝光事件    callItemExposure(card,position);  }    /**   * 处理滑出(出队)停止曝光的卡片   * @param position   * @param isFirst 是否从顶部滑出(出队)   */  private void onVerticalItemSlideOut(int position,boolean isFirst){    BaseHomeCard card;    if (isFirst){      card = deque.removeFirst();    }else {      card = deque.removeLast();    }    //回调卡片结束曝光事件    callItemEndExposure(card,position,isFirst);  }        
复制代码

展望

目前这是 APP 端做的技术储备, 如需上线仍需要产品经理做更细致的产品规划。


作者介绍:


高瑞 、贺宇成,Android 工程师,负责贝壳找房 app 安卓端研发工作。


本文转载自公众号贝壳产品技术(ID:gh_9afeb423f390)。


原文链接:


https://mp.weixin.qq.com/s/TKgFlupncu-Fol-mH8OEYA


2019-09-23 10:091076

评论

发布
暂无评论
发现更多内容

博文推荐 | Apache Pulsar 对现代数据堆栈至关重要的四个原因

Apache Pulsar

kafka 架构 Apache Pulsar 数据堆栈 DataStax

自定义View:多点触摸与实现任意拖动图片控

Changing Lin

11月日更

Web 用户体验设计提升实践

Shopee技术团队

大前端 web开发 用户体验 交互设计 可访问性

一文讲透自适应熔断的原理和实现

万俊峰Kevin

微服务 熔断 Go 语言 熔断器 限流熔断

NodeJs深入浅出之旅:内存控制(下)🐯

空城机

大前端 Node 11月日更

Go 语言,测试功能详解 - 下

微客鸟窝

Go 语言 11月日更

开源数据库风起云涌,openGauss 恰逢其时

openGauss

#数据库

堪称“高并发”教程天花板的Alibaba《基础+实战+源码+面试+架构》

收到请回复

Java 程序员 后端 java面试

译文 | 科普:Pulsar 和 Kafka 架构对比

Apache Pulsar

kafka 架构 分布式 中间件 Apache Pulsar

Nginx中间件渗透总结

网络安全学海

网络安全 信息安全 渗透测试 WEB安全 漏洞挖掘

openGauss支持国密SM3和SM4算法

openGauss

#数据库

11.25直播预告|开源与SaaS水火不容?「观测云-可观测之路」第2期技术大咖为您解惑!

观测云

Ta们用数字种植绿色山河:牛津博士与储能之变

脑极体

盲盒app开发

北鲲云超算携手西安电子科技大学开展高性能计算培训

北鲲云

一个基于DPoS共识算法的区块链案例解析

Regan Yue

区块链 11月日更 细讲区块链

什么是低代码平台?

石云升

低代码平台 11月日更

如何穿透ToB客户生命周期的全链增长?

ToB行业头条

从 Linux源码 看 Socket(TCP)的accept

赖猫

c++ Linux 后端 服务器 epoll

【云小课】如何初步定位GaussDB(for openGauss)慢SQL

华为云数据库小助手

GaussDB GaussDB(for openGauss) 华为云数据库

经验分享|参与内部开源的心路历程

云智慧AIOps社区

大前端 数据可视化 知识分享 开源治理 flyfish

点进来,与白洞一起体验一场沉浸式智慧轨道之旅

脑极体

VR和AR只是入门,真正的元宇宙远不止于此

CECBC

16 K8S之容器健康监测

穿过生命散发芬芳

k8s 11月日更

Python Qt GUI设计:QTimer计时器类、QThread多线程类和事件处理类(基础篇—8)

不脱发的程序猿

Python PyQt GUI 计时器 多线程类和事件处理

十月热点:EasyDL八大国产芯片实现模型部署全适配,度目智能门禁机CM-A1重磅发布!

百度大脑

人工智能 百度

双十一还是孤身一人?超强AI神器送你一个"对象"

百度大脑

人工智能 百度

“元宇宙”到底是啥?为啥火了?鼓励探索警惕忽悠

CECBC

【Quarkus技术系列】「云原生架构体系」配置参考指南相关的功能机制配置介绍分析

洛神灬殇

入门 配置信息 Quarkus 11月日更

你找的网络安全系列书籍,都在这了!

喀拉峻

网络安全 安全 信息安全

消息队列表结构设计

guangbao

精细化曝光策略_文化 & 方法_高瑞 、贺宇成_InfoQ精选文章