目前贝壳找房 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
更多内容推荐
有赞移动消息卡片动态化方案实践
本文介绍有赞移动消息卡片动态化方案实践经验。
Android 多子视图嵌套通用解决方案
本文介绍Android多子view嵌套通用解决方案。
一套 Flutter 混排瀑布流解决方案
流式布局,这是一种当前无论是前端,还是Nativ
性能优化之老生新谈:飞一般的 iPad
本文选自《阿里文娱技术精选系列:超级APP背后的移动端技术大揭秘》
iOS 稳定性问题治理:卡死崩溃监控原理及最佳实践
目前业界 iOS 生产环境中的卡死监控方案其实主要是基于卡顿监控,即当用户在使用 App 的过程中页面响应时间超过一定的卡顿的阈值(一般是几百 ms)之后判定为一次卡顿
他把闲鱼 APP 长列表流畅度翻了倍
闲鱼APP 以 flutter 和原生 Native 的混合工程存在。本文分别就 Android 原生、flutter 页面和大家分享我们的优化思路。
为什么不能使用 Application Context 显示 Dialog?(1)
Token(ActivityRecord activity, Intent intent) {weakActivity = new WeakReference<>(activity);name = intent.getComponent().flattenToShortString();}
2021-11-05
11|DPlayer 播放器综合应用:怎样实现自己的第一个视频播放器?
这节课,我们一起来学习如何在视频平台中实现自己的第一个视频播放器。
2023-05-17
Android 多子 view 嵌套通用解决方案
百度App在17年的版本中实现2个子view嵌套滚动
百度 App H5 页面性能监控和优化实践
在 GMTC 深圳 2019 大会上,阚光远讲师做了《百度App H5页面性能监控和优化实践》主题演讲。
揭秘!如何用 Flutter 设计一个 100% 准确的埋点框架?(二)
用户行为埋点是用来记录用户在操作时的一系列行为
17|3D 效果:别人的数字大屏很酷炫,你的产品为什么实现不了?
如果你看到别人做的大屏特别好,自己想做却又做不出来,那么可以基于你对软件的了解对症下药。
2023-06-14
34|升级收益:这两年 React Native 都做了哪些升级?
一文解析现阶段 React Native 的发展如何?新架构是否真的可用?是否应该对自己的业务进行升级?
2023-06-01
21|DID 和 PaddleGAN:表情生动的数字人播报员
DID和PaddleGAN
2023-04-24
【Flutter 专题】117 图解 Dismissible 滑动清除 Widget
this.background, // 滑动背景展示 Widgetthis.secondaryBackground, // 与background相反滑动背景展示 Widgetthis.confirmDismiss, // 是否确定清除当前 Widgetthis.onResize, // 重新修改尺寸回调this.onDismissed,
2021-11-02
Android 发现系列之不一样的拍照方式
Android中的拍照是一件很繁琐的事情,因为它必须使用Intent,并通过startActivityForResult方法去启动相机,完成后需要在onActivityResult中接受回调,获得拍照的结果,也就是说拍照和拍照的回调结果是隔离的。
动态性能分级策略在客户端上的实践
伴鱼绘本发布至今已有 5 年,作为一款主要面向儿童的 App,其包含大量游戏化场景和多媒体资源来保证内容的趣味性、丰富性。我们的产品面向海内外用户,统计发现 iOS 设备中约 3 成是已发布 5 年以上的旧设备。
闲鱼如何利用端计算提升推荐场景的 ctr
闲鱼作为电商场景的 APP
16|直播中心搭建(二):如何通过 VideoJs 配置直播中心?
这节课我们继续推进直播模块的功能开发,把焦点放在直播功能和页面的开发实现上。
2023-05-29
02. 必用的快捷键与鼠标操作技巧(下)
2023-10-17
推荐阅读
9.1 动画特效之图表动画
2023-10-17
APP 出海的现状与挑战
2023-05-31
课程介绍|成为 AI Native 个体
2023-11-13
实现长图片自动循环滚动效果
2021-11-07
推送内容有误怎么办?MobPush 撤回 / 取消推送为您排忧解难
2023-10-26
NFTScan 与 NodeReal 达成战略合作:NFT API 已上架 NodeReal API Marketplace
2023-04-17
16. 给客户送什么礼物最合适?为何有时送礼会适得其反?
2023-10-17
电子书

大厂实战PPT下载
换一换 
柴思远 | 智谱 企业商业技术中心的总经理
肖然 | Thoughtworks 全球数字化转型专家
张登 | 前圆通 科技架构负责人






评论