目前贝壳找房 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
更多内容推荐
15|直播中心搭建(一):如何通过 Video.js 配置直播中心?
从这节课起,我们一起来学习实践直播中心的搭建与配置。
2023-05-26
11|DPlayer 播放器综合应用:怎样实现自己的第一个视频播放器?
这节课,我们一起来学习如何在视频平台中实现自己的第一个视频播放器。
2023-05-17
Flutter 高性能、多功能的全场景滚动容器
目前闲鱼的主要业务场景都已经使用 Flutter 来实现,其中流式布局是最常见的页面布局场景(如搜索、商品详情等)。
贝壳 APP iOS14 权限管理适配总结
本文将详细介绍 iOS14 上对于隐私授权的变更和部分适配方案。
16|直播中心搭建(二):如何通过 VideoJs 配置直播中心?
这节课我们继续推进直播模块的功能开发,把焦点放在直播功能和页面的开发实现上。
2023-05-29
优酷暗黑模式(九):消费场景落地(Android)
本文为《优酷暗黑模式》系列之一。
微信小程序转发朋友圈详解
在2020年7月7日微信小程序低调的开放了一个功能,微信小程序“分享到朋友圈”。最近被产品提了相关需求,过程中遇到了一些坑。作者带着踩坑经验,给大家介绍下这个功能,以及其如何实现。
动态性能分级策略在客户端上的实践
伴鱼绘本发布至今已有 5 年,作为一款主要面向儿童的 App,其包含大量游戏化场景和多媒体资源来保证内容的趣味性、丰富性。我们的产品面向海内外用户,统计发现 iOS 设备中约 3 成是已发布 5 年以上的旧设备。
闲鱼的统一跨端 API 方案 —— Uni API
随着 C 端流量红利的逐渐消失,端外投放已成为业务寻求增长的重要抓手之一。
Fish-Lottie: 纯 Dart 如何实现一个高性能动画框架?
本文介绍闲鱼团队如何利用Lottie实现一个高性能动画框架。
有赞移动消息卡片动态化方案实践
本文介绍有赞移动消息卡片动态化方案实践经验。
30|前台页面的性能优化:如何实现前台页面的性能优化?
在Vue.js主题中,做前端性能优化有两个要点:优化逻辑能独立插件化、尽可能少修改存量代码。核心就是尽量让优化逻辑能独立化,减少对原有项目的干扰。
2023-02-17
0 到 1:闲鱼高复杂度高性能社区圈子开发实录
本文将围绕着会玩圈子的前端设计、开发过程中遇到的典型问题进行介绍。
21|DID 和 PaddleGAN:表情生动的数字人播报员
DID和PaddleGAN
2023-04-24
17|3D 效果:别人的数字大屏很酷炫,你的产品为什么实现不了?
如果你看到别人做的大屏特别好,自己想做却又做不出来,那么可以基于你对软件的了解对症下药。
2023-06-14
他把闲鱼 APP 长列表流畅度翻了倍
闲鱼APP 以 flutter 和原生 Native 的混合工程存在。本文分别就 Android 原生、flutter 页面和大家分享我们的优化思路。
一套 Flutter 混排瀑布流解决方案
流式布局,这是一种当前无论是前端,还是Nativ
从列表式 UI 中升华探讨:卡片式 UI 有哪些创新点(一)
设计定义:什么是卡片式设计
优酷视频互动曝光率优化实践
本文选自《阿里文娱技术精选系列:超级APP背后的移动端技术大揭秘》
【Flutter 专题】117 图解 Dismissible 滑动清除 Widget
this.background, // 滑动背景展示 Widgetthis.secondaryBackground, // 与background相反滑动背景展示 Widgetthis.confirmDismiss, // 是否确定清除当前 Widgetthis.onResize, // 重新修改尺寸回调this.onDismissed,
2021-11-02
推荐阅读
Fragment 极度懒加载 -+-Layout 子线程预加载,奇妙的 APP 启动速度优化思路
2021-11-07
3.3 如何抠掉图片背景色
2023-10-17
veImageX 演进之路:iOS 高性能图片加载 SDK
喜马拉雅直播秒开优化实践
阿里云 EMAS & 魔笔:4 月产品动态
2023-05-08
产品规划 · 第一部分
2023-09-18
9.4 动画特效之倒计时动画
2023-10-17
电子书
大厂实战PPT下载
换一换 陈仲铭( ZOMI 酱) | 华为 昇腾生态技术首席
姜剑峰 | 蚂蚁集团 安全计算技术专家
俞锦星 | 同程旅行 移动端首席架构师
评论