IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android:RecyclerView数据采集、埋点 -> 正文阅读

[移动开发]Android:RecyclerView数据采集、埋点

需求

数据埋点,要采集列表里显示的所有卡片。展开讲就是进入界面时把所有已展示的item统计出来,滑动时把新展示的item再统计进来

代码实现

/**
 * 创建人:linmutang
 * 创建时间:9/29/21
 */
interface OnExposeListener {

    /**
     *      返回刚出现的item数组
     * @param list MutableList<Int>
     */
    fun onItemViewVisible(list: MutableList<Int>)

}

/**
 *
 *      用于ScrollView采点用
 *
 * 创建人:linmutang
 * 创建时间:9/29/21
 */
class ScrollViewExposeUtil {

    lateinit var mRecyclerView: RecyclerView
    lateinit var mListener: OnExposeListener

    var lastStart: Int = 0
    var lastEnd: Int = 0


    fun setRecyclerExposeListener(recyclerView: RecyclerView?, listener: OnExposeListener) {

        if (recyclerView == null || recyclerView.visibility != View.VISIBLE) {
            return
        }

        mRecyclerView = recyclerView
        mListener = listener

        mRecyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {

                //关注:SCROLL_STATE_IDLE:停止滚动;  SCROLL_STATE_DRAGGING: 用户慢慢拖动
                // 关注:SCROLL_STATE_SETTLING:惯性滚动
                if (newState == RecyclerView.SCROLL_STATE_IDLE || newState == RecyclerView.SCROLL_STATE_DRAGGING
                    || newState == RecyclerView.SCROLL_STATE_SETTLING) {
                    handleVisibleItems()
                }
            }

            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                handleVisibleItems()
            }
        })

    }

    fun handleVisibleItems() {

        //View.getGlobalVisibleRect(new Rect()),true表示view视觉可见,无论可见多少。
        if (mRecyclerView == null || mRecyclerView.visibility != View.VISIBLE ||
            !mRecyclerView.isShown || !mRecyclerView.getGlobalVisibleRect(Rect())
        ) {
            return
        }
        
        //保险起见,为了不让统计影响正常业务,这里做下try-catch
        try {
            //  获取显示的第一个与最后一个位置,存在数组里
            var range: IntArray? = IntArray(2)
            when (val manager = mRecyclerView.layoutManager) {
                is LinearLayoutManager -> {
                    range = findRangeLinear(manager)
                }
                is GridLayoutManager -> {
                    range = findRangeGrid(manager)
                }
                is StaggeredGridLayoutManager -> {
                    range = findRangeStaggeredGrid(manager)
                }
            }
            if (range == null || range.size < 2) {
                return
            }

            Log.e("linmutang", " range[0] = ${range[0]}   range[1] = ${range[1]}")
            Log.e("linmutang", " lastStart =$lastStart  lastEnd = $lastEnd")

            //  首次进来
            if (lastEnd == 0) {
                var list = arrayListOf<Int>()
                for (i in range[0]..range[1]) {
                    list.add(i)
                }
                mListener.onItemViewVisible(list)
                lastEnd = range[1]
                return
            }
            //  向上滑动
            if (range[1] > lastEnd || range[0] > lastStart) {

                var list = arrayListOf<Int>()
                for (i in (lastEnd + 1)..range[1]) {
                    list.add(i)
                }
                mListener.onItemViewVisible(list)
                lastStart = range[0]
                lastEnd = range[1]
                return
            }
            //  向下滑动
            if (range[0] < lastStart || range[1] < lastEnd) {

                var list = arrayListOf<Int>()
                for (i in range[0] until lastStart) {
                    list.add(i)
                }
                mListener.onItemViewVisible(list)
                lastStart = range[0]
                lastEnd = range[1]
                return
            }

        } catch (e: Exception) {
            e.printStackTrace()
        }

    }
    
    private fun findRangeLinear(manager: LinearLayoutManager): IntArray? {
        val range = IntArray(2)
        range[0] = manager.findFirstVisibleItemPosition()
        range[1] = manager.findLastVisibleItemPosition()
        return range
    }

    private fun findRangeGrid(manager: GridLayoutManager): IntArray? {
        val range = IntArray(2)
        range[0] = manager.findFirstVisibleItemPosition()
        range[1] = manager.findLastVisibleItemPosition()
        return range
    }

    private fun findRangeStaggeredGrid(manager: StaggeredGridLayoutManager): IntArray? {
        val startPos = IntArray(manager.spanCount)
        val endPos = IntArray(manager.spanCount)
        manager.findFirstVisibleItemPositions(startPos)
        manager.findLastVisibleItemPositions(endPos)
        return findRange(startPos, endPos)
    }

    private fun findRange(startPos: IntArray, endPos: IntArray): IntArray {
        var start = startPos[0]
        var end = endPos[0]
        for (i in 1 until startPos.size) {
            if (start > startPos[i]) {
                start = startPos[i]
            }
        }
        for (i in 1 until endPos.size) {
            if (end < endPos[i]) {
                end = endPos[i]
            }
        }
        return intArrayOf(start, end)
    }
}

实现思路比较简单,调用 ScrollView 的 OnScrollListener 方法。滑动时找到当前所有显示item的第一个与最后一个的位置,根据这个范围值对比上次的范围值,确定哪些是新出现的item,把这些记录在数组中返回出去,可以批量处理

使用


ScrollViewExposeUtil().setRecyclerExposeListener(binding.rvData, object : OnExposeListener {

    override fun onItemViewVisible(list: MutableList<Int>) {
        for (i in list) {
            Log.e(TAG, mData[i] )
        }
    }

})

延伸:采集展现超过50%的item


    /**
     *      在上面过滤的基础上再过滤一遍
     *
     * @param view 可见item的view
     * @param position 可见item的position
     * @param orientation recyclerView的方向
     */
    private void setCallbackForLogicVisibleView(View view, int position, int orientation) {
        if (view == null || view.getVisibility() != View.VISIBLE ||
                !view.isShown() || !view.getGlobalVisibleRect(new Rect())) {
            return;
        }

        Rect rect = new Rect();

        boolean cover = view.getGlobalVisibleRect(rect);

        //  item逻辑上可见:可见且可见高度(宽度)>view高度(宽度)50%才行
        boolean visibleHeightEnough = orientation == OrientationHelper.VERTICAL && rect.height() > view.getMeasuredHeight() / 2;
        boolean visibleWidthEnough = orientation == OrientationHelper.HORIZONTAL && rect.width() > view.getMeasuredWidth() / 2;
        boolean isItemViewVisibleInLogic = visibleHeightEnough || visibleWidthEnough;

        if (cover && isItemViewVisibleInLogic) {
           //   此处是符合要求的 position
        }

    }

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-10-01 17:00:30  更:2021-10-01 17:00:45 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 19:42:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码