精华内容
下载资源
问答
  • 近期pm提出需要统计首页商品的曝光亮,由于我们的首页是的recylerview实现的,这里就来讲下如何使用监听recylerview的滚动事件来实现子view的曝光量统计,我们这里说的view都是列表中的子item条目(子view) ...

    近期pm提出需要统计首页商品的曝光亮,由于我们的首页是用的recylerview实现的,这里就来讲下如何使用监听recylerview的滚动事件来实现子view的曝光量统计,我们这里说的view都是列表中的子item条目(子view)

    先来看下统计结果图
    image.png
    左边是我们的列表,右边是我们统计到每个条目的曝光量。下面就来讲讲具体实现步骤。

    一,activity中使用recylerview并显示数据

    这里我不再啰嗦,recylerview最基础的使用。

    二,监听recylerview的滚动事件OnScrollListener

    onScrollStateChanged:监听滚动状态
    onScrolled:监听滚动
    我们接下来的统计工作,就是拿这两个方法做文章。

    //检测recylerview的滚动事件
            recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    /*
                    我这里通过的是停止滚动后屏幕上可见view。如果滚动过程中的可见view也要统计,你可以根据newState去做区分
                    SCROLL_STATE_IDLE:停止滚动
                    SCROLL_STATE_DRAGGING: 用户慢慢拖动
                    SCROLL_STATE_SETTLING:惯性滚动
                    */
                    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                        .....
                    }
    
                }
    
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                   ........
                }
            });
    

    首先再次明确下,我们要统计的是用户停止滑动时,显示在屏幕的上控件。所以我们要监测到onScrollStateChanged 方法中
    newState == RecyclerView.SCROLL_STATE_IDLE 时,也就是用户停止滚动。然后在这里做文章。

    三,获取屏幕内可见条目的起始位置

    这里的起始位置就是指我们屏幕当中最上面和最下面条目的位置。比如下图的0就是最上面的可见条目,3就是最下面的可见条目。我们次数的曝光view就是0,1,2,3 这个时候这四个条目显示在屏幕中。我们这时就要对这4个view的曝光量进行加1
    image.png
    那么接下来的重点就是要去获取屏幕内可见条目的起始位置。获取到起始位置后,当前屏幕里的可见条目就都能拿到了。
    而recylerview的manager正好给我们提供的有对应的方法。
    findFirstVisibleItemPosition()和findLastVisibleItemPosition() 看字面意思就能知道这时干嘛用的。
    但是我们的manager不止LinearLayoutManager一种,所以我们要做下区分,

    //这里我们用一个数组来记录起始位置
    int[] range = new int[2];
    RecyclerView.LayoutManager manager = reView.getLayoutManager();
    if (manager instanceof LinearLayoutManager) {
        range = findRangeLinear((LinearLayoutManager) manager);
    } else if (manager instanceof GridLayoutManager) {
        range = findRangeGrid((GridLayoutManager) manager);
    } else if (manager instanceof StaggeredGridLayoutManager) {
        range = findRangeStaggeredGrid((StaggeredGridLayoutManager) manager);
    }
    

    LinearLayoutManager和GridLayoutManager获取起始位置方法如下

    private int[] findRangeLinear(LinearLayoutManager manager) {
        int[] range = new int[2];
        range[0] = manager.findFirstVisibleItemPosition();
        range[1] = manager.findLastVisibleItemPosition();
        return range;
    }
    private int[] findRangeGrid(GridLayoutManager manager) {
        int[] range = new int[2];
        range[0] = manager.findFirstVisibleItemPosition();
        range[1] = manager.findLastVisibleItemPosition();
        return range;
    }
    

    StaggeredGridLayoutManager获取起始位置有点复杂,如下

    private int[] findRangeStaggeredGrid(StaggeredGridLayoutManager manager) {
            int[] startPos = new int[manager.getSpanCount()];
            int[] endPos = new int[manager.getSpanCount()];
            manager.findFirstVisibleItemPositions(startPos);
            manager.findLastVisibleItemPositions(endPos);
            int[] range = findRange(startPos, endPos);
            return range;
        }
    
        private int[] findRange(int[] startPos, int[] endPos) {
            int start = startPos[0];
            int end = endPos[0];
            for (int i = 1; i < startPos.length; i++) {
                if (start > startPos[i]) {
                    start = startPos[i];
                }
            }
            for (int i = 1; i < endPos.length; i++) {
                if (end < endPos[i]) {
                    end = endPos[i];
                }
            }
            int[] res = new int[]{start, end};
            return res;
        }
    

    四,获取到起始位置以后,我们就根据位置获取到view及view中的数据

    上面第三步拿到屏幕内可见条目的起始位置以后,我们就用一个for循环,获取当前屏幕内可见的所有子view

    for (int i = range[0]; i <= range[1]; i++) {
     View view = manager.findViewByPosition(i);
      recordViewCount(view);
    }
    

    recordViewCount是我自己写的用于获取子view内绑定数据的方法

    //获取view绑定的数据
    private void recordViewCount(View view) {
        if (view == null || view.getVisibility() != View.VISIBLE ||
                !view.isShown() || !view.getGlobalVisibleRect(new Rect())) {
            return;
        }
        int top = view.getTop();
        int halfHeight = view.getHeight() / 2;
        int screenHeight = UiUtils.getScreenHeight((Activity) view.getContext());
        int statusBarHeight = UiUtils.getStatusBarHeight(view.getContext());
        if (top < 0 && Math.abs(top) > halfHeight) {
            return;
        }
        if (top > screenHeight - halfHeight - statusBarHeight) {
            return;
        }
        //这里获取的是我们view绑定的数据,相应的你要去在你的view里setTag,只有set了,才能get
        ItemData tag = (ItemData) view.getTag();
        String key = tag.toString();
        if (TextUtils.isEmpty(key)) {
            return;
        }
        hashMap.put(key, !hashMap.containsKey(key) ? 1 : (hashMap.get(key) + 1));
        Log.i("qcl0402", key + "----出现次数:" + hashMap.get(key));
    }
    

    这里有几点需要注意

    • 1,这这里起始位置的view显示区域如果不超过50%,就不算这个view可见,进而也就不统计曝光。
    • 2,我们通过view.getTag();获取view里的数据,必须在此之前setTag()数据,我这里setTag是在viewholder中把数据set进去的
      image.png

    到这里我们就实现了recylerview列表中view控件曝光量的统计了。下面贴出来完整的代码给大家

    package com.example.qcl.demo.xuexi.baoguang;
    
    import android.app.Activity;
    import android.graphics.Rect;
    import android.support.v7.widget.GridLayoutManager;
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.support.v7.widget.StaggeredGridLayoutManager;
    import android.text.TextUtils;
    import android.util.Log;
    import android.view.View;
    
    import com.example.qcl.demo.utils.UiUtils;
    
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
     * 2019/4/2 13:31
     * author: qcl
     * desc: 安卓曝光量统计工具类
     * wechat:2501902696
     */
    public class ViewShowCountUtils {
    
        //刚进入列表时统计当前屏幕可见views
        private boolean isFirstVisible = true;
    
        //用于统计曝光量的map
        private ConcurrentHashMap<String, Integer> hashMap = new ConcurrentHashMap<String, Integer>();
    
    
        /*
         * 统计RecyclerView里当前屏幕可见子view的曝光量
         *
         * */
        void recordViewShowCount(RecyclerView recyclerView) {
            hashMap.clear();
            if (recyclerView == null || recyclerView.getVisibility() != View.VISIBLE) {
                return;
            }
            //检测recylerview的滚动事件
            recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    /*
                    我这里通过的是停止滚动后屏幕上可见view。如果滚动过程中的可见view也要统计,你可以根据newState去做区分
                    SCROLL_STATE_IDLE:停止滚动
                    SCROLL_STATE_DRAGGING: 用户慢慢拖动
                    SCROLL_STATE_SETTLING:惯性滚动
                    */
                    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                        getVisibleViews(recyclerView);
                    }
    
                }
    
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    //刚进入列表时统计当前屏幕可见views
                    if (isFirstVisible) {
                        getVisibleViews(recyclerView);
                        isFirstVisible = false;
                    }
                }
            });
    
        }
    
        /*
         * 获取当前屏幕上可见的view
         * */
        private void getVisibleViews(RecyclerView reView) {
            if (reView == null || reView.getVisibility() != View.VISIBLE ||
                    !reView.isShown() || !reView.getGlobalVisibleRect(new Rect())) {
                return;
            }
            //保险起见,为了不让统计影响正常业务,这里做下try-catch
            try {
                int[] range = new int[2];
                RecyclerView.LayoutManager manager = reView.getLayoutManager();
                if (manager instanceof LinearLayoutManager) {
                    range = findRangeLinear((LinearLayoutManager) manager);
                } else if (manager instanceof GridLayoutManager) {
                    range = findRangeGrid((GridLayoutManager) manager);
                } else if (manager instanceof StaggeredGridLayoutManager) {
                    range = findRangeStaggeredGrid((StaggeredGridLayoutManager) manager);
                }
                if (range == null || range.length < 2) {
                    return;
                }
                Log.i("qcl0402", "屏幕内可见条目的起始位置:" + range[0] + "---" + range[1]);
                for (int i = range[0]; i <= range[1]; i++) {
                    View view = manager.findViewByPosition(i);
                    recordViewCount(view);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        //获取view绑定的数据
        private void recordViewCount(View view) {
            if (view == null || view.getVisibility() != View.VISIBLE ||
                    !view.isShown() || !view.getGlobalVisibleRect(new Rect())) {
                return;
            }
            int top = view.getTop();
            int halfHeight = view.getHeight() / 2;
    
            int screenHeight = UiUtils.getScreenHeight((Activity) view.getContext());
            int statusBarHeight = UiUtils.getStatusBarHeight(view.getContext());
    
            if (top < 0 && Math.abs(top) > halfHeight) {
                return;
            }
            if (top > screenHeight - halfHeight - statusBarHeight) {
                return;
            }
    
            //这里获取的是我们view绑定的数据,相应的你要去在你的view里setTag,只有set了,才能get
            ItemData tag = (ItemData) view.getTag();
            String key = tag.toString();
            if (TextUtils.isEmpty(key)) {
                return;
            }
            hashMap.put(key, !hashMap.containsKey(key) ? 1 : (hashMap.get(key) + 1));
            Log.i("qcl0402", key + "----出现次数:" + hashMap.get(key));
        }
    
    
        private int[] findRangeLinear(LinearLayoutManager manager) {
            int[] range = new int[2];
            range[0] = manager.findFirstVisibleItemPosition();
            range[1] = manager.findLastVisibleItemPosition();
            return range;
        }
    
        private int[] findRangeGrid(GridLayoutManager manager) {
            int[] range = new int[2];
            range[0] = manager.findFirstVisibleItemPosition();
            range[1] = manager.findLastVisibleItemPosition();
            return range;
    
        }
    
        private int[] findRangeStaggeredGrid(StaggeredGridLayoutManager manager) {
            int[] startPos = new int[manager.getSpanCount()];
            int[] endPos = new int[manager.getSpanCount()];
            manager.findFirstVisibleItemPositions(startPos);
            manager.findLastVisibleItemPositions(endPos);
            int[] range = findRange(startPos, endPos);
            return range;
        }
    
        private int[] findRange(int[] startPos, int[] endPos) {
            int start = startPos[0];
            int end = endPos[0];
            for (int i = 1; i < startPos.length; i++) {
                if (start > startPos[i]) {
                    start = startPos[i];
                }
            }
            for (int i = 1; i < endPos.length; i++) {
                if (end < endPos[i]) {
                    end = endPos[i];
                }
            }
            int[] res = new int[]{start, end};
            return res;
        }
    
    
    }
    

    使用就是在我们的recylerview设置完数据以后,把recylerview传递进去就可以了。如下图:
    image.png

    我们统计到曝光量,拿到曝光view绑定的数据,就可以结合后面的view点击,来看下那些商品view的曝光量高,那些商品的转化率高。当然,这都是运营小伙伴的事了,我们只需要负责把曝光量统计到即可。
    如果你有任何编程方面的问题,可以加我微信交流 2501902696(备注编程)

    展开全文
  • 近期pm提出需要统计首页商品的曝光亮,由于我们的首页是的recylerview实现的,这里就来讲下如何使用监听recylerview的滚动事件来实现子view的曝光量统计,我们这里说的view都是列表中的子item条目(子view) ...

    近期pm提出需要统计首页商品的曝光亮,由于我们的首页是用的recylerview实现的,这里就来讲下如何使用监听recylerview的滚动事件来实现子view的曝光量统计,我们这里说的view都是列表中的子item条目(子view)

    先来看下统计结果图

    左边是我们的列表,右边是我们统计到每个条目的曝光量。下面就来讲讲具体实现步骤。

    一,activity中使用recylerview并显示数据

    这里我不再啰嗦,recylerview最基础的使用。

    二,监听recylerview的滚动事件OnScrollListener

    onScrollStateChanged:监听滚动状态 onScrolled:监听滚动 我们接下来的统计工作,就是拿这两个方法做文章。

    //检测recylerview的滚动事件
            recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    /*
                    我这里通过的是停止滚动后屏幕上可见view。如果滚动过程中的可见view也要统计,你可以根据newState去做区分
                    SCROLL_STATE_IDLE:停止滚动
                    SCROLL_STATE_DRAGGING: 用户慢慢拖动
                    SCROLL_STATE_SETTLING:惯性滚动
                    */
                    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                        .....
                    }
    
                }
    
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                   ........
                }
            });
    复制代码

    首先再次明确下,我们要统计的是用户停止滑动时,显示在屏幕的上控件。所以我们要监测到onScrollStateChanged 方法中 newState == RecyclerView.SCROLL_STATE_IDLE 时,也就是用户停止滚动。然后在这里做文章。

    三,获取屏幕内可见条目的起始位置

    这里的起始位置就是指我们屏幕当中最上面和最下面条目的位置。比如下图的0就是最上面的可见条目,3就是最下面的可见条目。我们次数的曝光view就是0,1,2,3 这个时候这四个条目显示在屏幕中。我们这时就要对这4个view的曝光量进行加1

    那么接下来的重点就是要去获取屏幕内可见条目的起始位置。获取到起始位置后,当前屏幕里的可见条目就都能拿到了。 而recylerview的manager正好给我们提供的有对应的方法。 findFirstVisibleItemPosition()和findLastVisibleItemPosition() 看字面意思就能知道这时干嘛用的。 但是我们的manager不止LinearLayoutManager一种,所以我们要做下区分,

    //这里我们用一个数组来记录起始位置
    int[] range = new int[2];
    RecyclerView.LayoutManager manager = reView.getLayoutManager();
    if (manager instanceof LinearLayoutManager) {
        range = findRangeLinear((LinearLayoutManager) manager);
    } else if (manager instanceof GridLayoutManager) {
        range = findRangeGrid((GridLayoutManager) manager);
    } else if (manager instanceof StaggeredGridLayoutManager) {
        range = findRangeStaggeredGrid((StaggeredGridLayoutManager) manager);
    }
    复制代码

    LinearLayoutManager和GridLayoutManager获取起始位置方法如下

    private int[] findRangeLinear(LinearLayoutManager manager) {
        int[] range = new int[2];
        range[0] = manager.findFirstVisibleItemPosition();
        range[1] = manager.findLastVisibleItemPosition();
        return range;
    }
    private int[] findRangeGrid(GridLayoutManager manager) {
        int[] range = new int[2];
        range[0] = manager.findFirstVisibleItemPosition();
        range[1] = manager.findLastVisibleItemPosition();
        return range;
    }
    复制代码

    StaggeredGridLayoutManager获取起始位置有点复杂,如下

    private int[] findRangeStaggeredGrid(StaggeredGridLayoutManager manager) {
            int[] startPos = new int[manager.getSpanCount()];
            int[] endPos = new int[manager.getSpanCount()];
            manager.findFirstVisibleItemPositions(startPos);
            manager.findLastVisibleItemPositions(endPos);
            int[] range = findRange(startPos, endPos);
            return range;
        }
    
        private int[] findRange(int[] startPos, int[] endPos) {
            int start = startPos[0];
            int end = endPos[0];
            for (int i = 1; i < startPos.length; i++) {
                if (start > startPos[i]) {
                    start = startPos[i];
                }
            }
            for (int i = 1; i < endPos.length; i++) {
                if (end < endPos[i]) {
                    end = endPos[i];
                }
            }
            int[] res = new int[]{start, end};
            return res;
        }
    复制代码

    四,获取到起始位置以后,我们就根据位置获取到view及view中的数据

    上面第三步拿到屏幕内可见条目的起始位置以后,我们就用一个for循环,获取当前屏幕内可见的所有子view

    for (int i = range[0]; i <= range[1]; i++) {
     View view = manager.findViewByPosition(i);
      recordViewCount(view);
    }
    复制代码

    recordViewCount是我自己写的用于获取子view内绑定数据的方法

    //获取view绑定的数据
    private void recordViewCount(View view) {
        if (view == null || view.getVisibility() != View.VISIBLE ||
                !view.isShown() || !view.getGlobalVisibleRect(new Rect())) {
            return;
        }
        int top = view.getTop();
        int halfHeight = view.getHeight() / 2;
        int screenHeight = UiUtils.getScreenHeight((Activity) view.getContext());
        int statusBarHeight = UiUtils.getStatusBarHeight(view.getContext());
        if (top < 0 && Math.abs(top) > halfHeight) {
            return;
        }
        if (top > screenHeight - halfHeight - statusBarHeight) {
            return;
        }
        //这里获取的是我们view绑定的数据,相应的你要去在你的view里setTag,只有set了,才能get
        ItemData tag = (ItemData) view.getTag();
        String key = tag.toString();
        if (TextUtils.isEmpty(key)) {
            return;
        }
        hashMap.put(key, !hashMap.containsKey(key) ? 1 : (hashMap.get(key) + 1));
        Log.i("qcl0402", key + "----出现次数:" + hashMap.get(key));
    }
    复制代码

    这里有几点需要注意

    • 1,这这里起始位置的view显示区域如果不超过50%,就不算这个view可见,进而也就不统计曝光。
    • 2,我们通过view.getTag();获取view里的数据,必须在此之前setTag()数据,我这里setTag是在viewholder中把数据set进去的

    到这里我们就实现了recylerview列表中view控件曝光量的统计了。下面贴出来完整的代码给大家

    package com.example.qcl.demo.xuexi.baoguang;
    
    import android.app.Activity;
    import android.graphics.Rect;
    import android.support.v7.widget.GridLayoutManager;
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.support.v7.widget.StaggeredGridLayoutManager;
    import android.text.TextUtils;
    import android.util.Log;
    import android.view.View;
    
    import com.example.qcl.demo.utils.UiUtils;
    
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
     * 2019/4/2 13:31
     * author: qcl
     * desc: 安卓曝光量统计工具类
     * wechat:2501902696
     */
    public class ViewShowCountUtils {
    
        //刚进入列表时统计当前屏幕可见views
        private boolean isFirstVisible = true;
    
        //用于统计曝光量的map
        private ConcurrentHashMap<String, Integer> hashMap = new ConcurrentHashMap<String, Integer>();
    
    
        /*
         * 统计RecyclerView里当前屏幕可见子view的曝光量
         *
         * */
        void recordViewShowCount(RecyclerView recyclerView) {
            hashMap.clear();
            if (recyclerView == null || recyclerView.getVisibility() != View.VISIBLE) {
                return;
            }
            //检测recylerview的滚动事件
            recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    /*
                    我这里通过的是停止滚动后屏幕上可见view。如果滚动过程中的可见view也要统计,你可以根据newState去做区分
                    SCROLL_STATE_IDLE:停止滚动
                    SCROLL_STATE_DRAGGING: 用户慢慢拖动
                    SCROLL_STATE_SETTLING:惯性滚动
                    */
                    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                        getVisibleViews(recyclerView);
                    }
    
                }
    
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    //刚进入列表时统计当前屏幕可见views
                    if (isFirstVisible) {
                        getVisibleViews(recyclerView);
                        isFirstVisible = false;
                    }
                }
            });
    
        }
    
        /*
         * 获取当前屏幕上可见的view
         * */
        private void getVisibleViews(RecyclerView reView) {
            if (reView == null || reView.getVisibility() != View.VISIBLE ||
                    !reView.isShown() || !reView.getGlobalVisibleRect(new Rect())) {
                return;
            }
            //保险起见,为了不让统计影响正常业务,这里做下try-catch
            try {
                int[] range = new int[2];
                RecyclerView.LayoutManager manager = reView.getLayoutManager();
                if (manager instanceof LinearLayoutManager) {
                    range = findRangeLinear((LinearLayoutManager) manager);
                } else if (manager instanceof GridLayoutManager) {
                    range = findRangeGrid((GridLayoutManager) manager);
                } else if (manager instanceof StaggeredGridLayoutManager) {
                    range = findRangeStaggeredGrid((StaggeredGridLayoutManager) manager);
                }
                if (range == null || range.length < 2) {
                    return;
                }
                Log.i("qcl0402", "屏幕内可见条目的起始位置:" + range[0] + "---" + range[1]);
                for (int i = range[0]; i <= range[1]; i++) {
                    View view = manager.findViewByPosition(i);
                    recordViewCount(view);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        //获取view绑定的数据
        private void recordViewCount(View view) {
            if (view == null || view.getVisibility() != View.VISIBLE ||
                    !view.isShown() || !view.getGlobalVisibleRect(new Rect())) {
                return;
            }
            int top = view.getTop();
            int halfHeight = view.getHeight() / 2;
    
            int screenHeight = UiUtils.getScreenHeight((Activity) view.getContext());
            int statusBarHeight = UiUtils.getStatusBarHeight(view.getContext());
    
            if (top < 0 && Math.abs(top) > halfHeight) {
                return;
            }
            if (top > screenHeight - halfHeight - statusBarHeight) {
                return;
            }
    
            //这里获取的是我们view绑定的数据,相应的你要去在你的view里setTag,只有set了,才能get
            ItemData tag = (ItemData) view.getTag();
            String key = tag.toString();
            if (TextUtils.isEmpty(key)) {
                return;
            }
            hashMap.put(key, !hashMap.containsKey(key) ? 1 : (hashMap.get(key) + 1));
            Log.i("qcl0402", key + "----出现次数:" + hashMap.get(key));
        }
    
    
        private int[] findRangeLinear(LinearLayoutManager manager) {
            int[] range = new int[2];
            range[0] = manager.findFirstVisibleItemPosition();
            range[1] = manager.findLastVisibleItemPosition();
            return range;
        }
    
        private int[] findRangeGrid(GridLayoutManager manager) {
            int[] range = new int[2];
            range[0] = manager.findFirstVisibleItemPosition();
            range[1] = manager.findLastVisibleItemPosition();
            return range;
    
        }
    
        private int[] findRangeStaggeredGrid(StaggeredGridLayoutManager manager) {
            int[] startPos = new int[manager.getSpanCount()];
            int[] endPos = new int[manager.getSpanCount()];
            manager.findFirstVisibleItemPositions(startPos);
            manager.findLastVisibleItemPositions(endPos);
            int[] range = findRange(startPos, endPos);
            return range;
        }
    
        private int[] findRange(int[] startPos, int[] endPos) {
            int start = startPos[0];
            int end = endPos[0];
            for (int i = 1; i < startPos.length; i++) {
                if (start > startPos[i]) {
                    start = startPos[i];
                }
            }
            for (int i = 1; i < endPos.length; i++) {
                if (end < endPos[i]) {
                    end = endPos[i];
                }
            }
            int[] res = new int[]{start, end};
            return res;
        }
    
    
    }
    复制代码

    使用就是在我们的recylerview设置完数据以后,把recylerview传递进去就可以了。如下图:

    我们统计到曝光量,拿到曝光view绑定的数据,就可以结合后面的view点击,来看下那些商品view的曝光量高,那些商品的转化率高。当然,这都是运营小伙伴的事了,我们只需要负责把曝光量统计到即可。 如果你有任何编程方面的问题,可以加我微信交流 2501902696(备注编程)

    转载于:https://juejin.im/post/5ca3067ae51d452dc82ed77f

    展开全文
  • 现在存储过全量跑数据需要20多个小时,如果数据对不上检查、解决问题后还要重新跑,严重影响开发进度。也想过使用java的多线程来处理,但是时间紧急,而且不知道如何划分线程。请大神们...
  • 统计网站流量

    2010-05-19 17:57:38
    大家在做完成一个网站的如果需要加入流量统计,请问怎么做。也就是说,我需要知道这个页面今天访问了多少次,那个页面访问了多少次。大家都的是什么解决方案。例如我们的做的项目中用的建了一个session 监听器。当...
  • 数据分析是指适当的统计分析方法对收集来的大量数据进行分析,提取有用信息和形成结论而对数据加以详细研究和概括总结的过程。这一过程也是质量管理体系的支持过程。 在实际工作中,数据分析可帮助企业作出判断,...

    之前听朋友吐槽过,他们是上千人的企业,但做数据分析居然还是靠手动上传数据,而且还是用的excel做的。但其实excel并不是企业做数据分析的好工具。
    数据分析是指用适当的统计分析方法对收集来的大量数据进行分析,提取有用信息和形成结论而对数据加以详细研究和概括总结的过程。这一过程也是质量管理体系的支持过程。
    在实际工作中,数据分析可帮助企业作出判断,以便采取适当行动。我们先来看看企业数据分析的过程:
    在这里插入图片描述

    既然说到Excel做数据分析,那就先看看excel是如何分析数据的
    一般接触信息化和数据库系统,过程中需要帮处理很多数据问题,包括数据采集,初始化,也需要帮客户完成数据报表,这会的工作工具是自己的系统+EXCEL完成报表样式,没错就是下面这样的:

    在这里插入图片描述

    然后交由IT进行开发,效率低下,而且没有样式,现在想想真是极其难看。而且,Excel做做表层分析也还行,很多深入的数据分析都需要用复杂的公式、函数,中间如果一步有误,很多步骤都需要重新调整,浪费大量时间。
    那么有什么企业数据分析工具可以代替excel做数据分析?当然有,如python,它们都是数据分析以及做图表的得力助手,但它们的不足也是显而易见的:操作繁琐,复用性差,功能相对局限单一。反反复复也没有那么容易!
    另一个就是BI工具,对于不会写代码的业务人员来世,Smartbi将会是一个非常好的选择。Smartbi作为一个自助式分析工具。你说它是报表工具,但是我却认为这是一个集合了数据校验、权限分配、excel导入、手机填报等高度定制化人性化的功能,系统也受到了领导和业务人员的普遍欢迎。
    它所呈现的效果是,这样:

    在这里插入图片描述
    在这里插入图片描述

    其实,我们做报表,最经常用到的就是填报、查询、权限管理和可视化了吧。数据过于分散,难以有效利用,效率低准确性差,这应该是报表比较大的难点之一,很多企业的报表竟然还是用手工收集,而且系统数据很多,基本上不可能在同一张报表里分析,这就造成了决策分析的困难。Smartbi可以连接多种数据库和大数据平台,只需简单的在数据库查询对话框中写入 SQL 查询语句,将数据库表中的对应数据取出来即可。大多数使用者还是IT人员和数据部门,那业务部门如市场、财务、销售这些人,所以使用低代码零代码的Smartbi企业数据分析工具就是最佳的选择!

    展开全文
  • 如何判断某日是否星期天 某个日期是星期几 什么函数可以显示当前星期 求本月天数 显示昨天的日期 关于取日期 如何对日期进行上、中、下旬区分 如何获取一个月的最大天数 日期格式转换公式 【排名及排序筛选】 一个...
  • EXCEL函数公式集

    热门讨论 2010-03-16 03:26:38
    如何判断某日是否星期天 某个日期是星期几 什么函数可以显示当前星期 求本月天数 显示昨天的日期 关于取日期 如何对日期进行上、中、下旬区分 如何获取一个月的最大天数 日期格式转换公式 【排名及排序筛选】 一个...
  • 如何统计一段中英文混合字符的字符数 排序法都有哪些,其算法都是怎样的 如何将十进制字符串、十六进制字符串和二进制字符串互相转化 如何随机选号 第15章 发布程序 如何给软件加密和解密 如何使程序在开机时就...
  • 16.1.1为什么需要用例图 16.1.2什么是用例图 16.2详解用例图 16.2.1系统边界 16.2.2参与者 16.2.3用例 16.2.4箭头 16.2.5注释 16.2.6用Rational Rose画用例图 16.2.7用例规约 16.3一个案例 16.3.1案例...
  • 面试题

    2020-08-19 11:25:21
    linux中如何查看已内存 free 命令显示系统使用和空闲的内存情况,包括物理内存、交互区内存(swap)和内核缓冲区内存。 直接输入free命令,显示如下 free命令默认是显示单位kb,可以采用free -m和free -g命令查看,...

    linux中如何查看已用内存

    free 命令显示系统使用和空闲的内存情况,包括物理内存、交互区内存(swap)和内核缓冲区内存。
    直接输入free命令,显示如下

    在这里插入图片描述

    free命令默认是显示单位kb,可以采用free -m和free -g命令查看,分别表示MB和GB
    另外,free -h会自动选择以适合理解的容量单位显示

    在这里插入图片描述
    Mem:表示物理内存统计,如果机器剩余内存非常小,一般小于总内存的20%,则判断为系统物理内存不够
    Swap: 表示硬盘上交换分区的使用情况,如剩余空间较小,需要留意当前系统内存使用情况及负载,当Swap的used值大于0时,则表示操作系统物理内存不够,已经开始使用硬盘内存了。
    第1行数据11G表示物理内存总量;6.5G表示总计分配给缓存(包含buffers与cache)使用的数量,但其中可能部分缓存并未实际使用;
    1.3G表示未被分配的内存;shared表示共享内存;4.0G表示系统分配但未被使用的buffers数量;4.7G表示系统分配但未被使用的available数量

    10w条数据的插入(批量插入)

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
     
     
    public class HomeWork02
    {
        //预处理--注入数据
        public static void main(String[]args) throws Exception
        {
            //加载数据库
            Class.forName("com.mysql.jdbc.Driver");
     
            //获取连接对象
            String url = "jdbc:mysql://localhost:3306/db1?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=UTF-8";
            Connection conn = DriverManager.getConnection(url, "username", "password");
     
            //连接操作数据库
            String sql = "insert into homework VALUES (?,?,?) ";
            PreparedStatement pst = conn.prepareStatement(sql);
            for (int i = 1; i <= 100000 ; i++)
            {
                pst.setObject(1,i);
                pst.setObject(2,i+"号");
                pst.setObject(3,i*10+"¥");
                pst.addBatch();
            }
     
            //操作完成,提交
            pst.executeBatch();
          
            //释放资源
            pst.close();
            conn.close();
     
        }
    }
    

    springBoot和SpringMVC的区别(今天面试被问懵啦~)

    两者联系:
    spring在刚开始的时候使用工厂模式(DI)和代理模式(AOP)解耦应用组件,进而开发出适用于Web开发的SpringMVC,在实际开发过程当中会使用到很多样板代码,就开发出了懒人版的SpringBoot;

    区别:
    1、springMVC是Spring的一个模式,是一个Web框架,提供了一个轻度耦合的方式来开发Web应用;

    2、SpringBoot是习惯优于配置,降低了项目搭建的难度;

    3、springMVC需要使用到TomCat服务器,SpringBoot的话是内嵌了Tomcat服务器的;

    Spring MVC是基于 Servlet 的一个 MVC 框架 主要解决 WEB 开发的问题

    Spring MVC的功能

    Spring MVC提供了一种轻度耦合的方式来开发web应用。

    Spring MVC是Spring的一个模块,式一个web框架。通过Dispatcher Servlet, ModelAndView 和 View Resolver,开发web应用变得很容易。解决的问题领域是网站应用程序或者服务开发——URL路由、Session、模板引擎、静态Web资源等等。

    Spring Boot的功能

    Spring Boot实现了自动配置,降低了项目搭建的复杂度。

    众所周知Spring框架需要进行大量的配置,Spring Boot引入自动配置的概念,让项目设置变得很容易。Spring Boot本身并不提供Spring框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于Spring框架的应用程序。也就是说,它并不是用来替代Spring的解决方案,而是和Spring框架紧密结合用于提升Spring开发者体验的工具。同时它集成了大量常用的第三方库配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot应用中这些第三方库几乎可以零配置的开箱即用(out-of-the-box),大部分的Spring Boot应用都只需要非常少量的配置代码,开发者能够更加专注于业务逻辑。Spring Boot只是承载者,辅助你简化项目搭建过程的。如果承载的是WEB项目,使用Spring MVC作为MVC框架,那么工作流程和你上面描述的是完全一样的,因为这部分工作是Spring MVC做的而不是Spring Boot。对使用者来说,换用Spring Boot以后,项目初始化方法变了,配置文件变了,另外就是不需要单独安装Tomcat这类容器服务器了,maven打出jar包直接跑起来就是个网站,但你最核心的业务逻辑实现与业务流程实现没有任何变化。

    用最简练的语言概括就是:

    • Spring 是一个“引擎”;
    • Spring MVC 是基于Spring的一个 MVC 框架 ;
    • Spring Boot 是基于Spring4的条件注册的一套快速开发整合包。

    MY SQL 获取本月第一天 获取下月的第一天

    select curdate();                       --获取当前日期
    select last_day(curdate());                    --获取当月最后一天。
    select DATE_ADD(curdate(),interval -day(curdate())+1 day);   --获取本月第一天
    select date_add(curdate()-day(curdate())+1,interval 1 month); -- 获取下个月的第一天
    select DATEDIFF(date_add(curdate()-day(curdate())+1,interval 1 month ),DATE_ADD(curdate(),interval -day(curdate())+1 day)) from dual; --获取当前月的天数
    

    什么是反射?

    反射就是动态加载对象,然后可以拿到这个对象的所有方法和属性,对于任何一个对象都能动态获取它的任何属性或者任意一个方法,这种动态调用对象的人以信息信息的功能就是 java的反射机制

    如何使用java的反射?

    1丶通过全限定类型名 : Class.ForName(“全限定类名”)
    2丶类名.Class
    3丶对象.GetClass()

    反射的应用场景?

    1丶通常用在框架的底层
    2丶实现ORM,通过读取数据表,然后运用反射机制,创建对象及其属性

    如何通过反射获取类的Private属性?

    1丶在父类中填写该属性的Get丶Set方法,通过反射调用方法获取
    2丶先获取对象,然后通过GetDeclaredField方法获取私有字段
    通过SetAccessible让jvm不检查权限
    通过Set方法设置对象具为具体的值

    通过获取构造方法来创建对象?

    1丶NewInstance()
    2丶GetConstructor()
    3丶区别newInstance犯法只能获取空参的构造
    GetConstructor方法可以通过传入的参数类型或数量来获取

    让方法执行?

    Method.invoke(obj示例对象,obj可变参数)----------(是有返回值的)

    List Set Map 结构图
    在这里插入图片描述
    list和set是实现了Collection接口的

    List:

    1丶可以允许重复的对象
    2丶可以插入多个null元素
    3丶是一个有序容器,保持了每个元素的插入顺序,输出的顺序就是插入的顺序
    4丶常用的实现类有ArrayList、LinkedList 和 Vector。ArrayList 最为流行,它提供了使用索引的随意访问,而 LinkedList 则对于经常需要从 List 中添加或删除元素的场合更为合适。

    Set:

    1丶不允许重复对象
    2丶无序容器,你无法保证每个元素的存储顺序,TreeSet通过Comparator或者Comparable维护了一个排序顺序
    3丶只允许一个null元素
    4丶Set 接口最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于 HashMap 实现的 HashSet;TreeSet 还实现了 SortedSet 接口,因此 TreeSet 是一个根据其 compare() 和 compareTo() 的定义进行排序的有序容器。
    在这里插入图片描述
    Map不是collection的子接口或者实现类Map是一个接口
    Map的每个entry 都持有两个对象,也就是一个键一个值,Map可能会持有相同的值对象,但键对象必须是唯一的
    TreeMap 也通过 Comparator 或者 Comparable 维护了一个排序顺序。
    Map 里你可以拥有随意个 null 值但最多只能有一个 null 键。
    Map 接口最流行的几个实现类是 HashMap、LinkedHashMap、Hashtable 和 TreeMap。(HashMap、TreeMap最常用)

    什么场景下使用list,set,map呢?

    • list:有序访问、索引访问
    • set(HashSet、LinkedHashSet 或者 TreeSet):去重

    map:键值存储

    展开全文
  • 2.2.4 实际中如何用哈尔或沃尔什函数构建图像变换矩阵? 58 2.2.5 哈尔变换的基元图像看起来是什么样的? 61 2.2.6 可以定义元素仅为+1 或.1 的正交矩阵吗? 65 B2.5 对沃尔什函数的排列方式 65 2.2.7 哈达玛/...
  • C#编程经验技巧宝典

    热门讨论 2008-06-01 08:59:33
    54 <br>0075 回溯法找出n个自然数中取r个数的全排列 55 <br>0076 约瑟夫环问题 56 <br>0077 猴子选大王 57 <br>0078 如何判断IP是否正确 57 <br>0079 如何将小写金额转换为大写金额 57...
  • 实例209 统计图书的销售 实例210 单例模式的应用 实例211 员工间的差异 实例212 重写父类中的方法 实例213 计算几何图形的面积 实例214 简单的汽车销售商场 实例215 利用拷贝构造函数简化实例创建 实例216...
  • 实例209 统计图书的销售 实例210 单例模式的应用 实例211 员工间的差异 实例212 重写父类中的方法 实例213 计算几何图形的面积 实例214 简单的汽车销售商场 实例215 利用拷贝构造函数简化实例创建 实例216...
  • 难就难在如何判断哪些索引是必要的,哪些又是不必要的。判断的最终标准是看这些索引是否对我们的数据库性能有所帮助。具体到方法上,就必须熟悉数据库应用程序中的所有SQL语句,从中统计出常用的可能对性能有影响的...
  • 恶意病毒,不论机器狗如何变种,不需要通过补丁更新方式防御。 · 动静态暂存区 许多用户在使用传统机房维护产品过程中都曾经遇到过蓝屏死机的问题,这是由于暂存区空间不够造 成的,噢易机房BOSS系统采用了暂存...
  • 宏昕医院管理软件,医院收费系统

    热门讨论 2011-04-12 10:16:59
     综合统计查询系统主要提供收费员收费日报,收费项目综合统计,收费项目分类综合统计,科室、医生收入金额与就诊人数等工作综合统计,药品的日消耗统计,药品的进、出库综合统计,药品的进货价格对照分析,药品的...
  • 2019数据运营思维导图

    2019-03-29 21:34:09
    宏观走势,是否需要进行市场投放 判断是否存在渠道作弊行为、渠道包被下架等问题 日一次会话用户数 即新登用户中只有一次会话,且会话时长低于门阀值 ——解决问题 推广渠道是否有刷作弊行为 渠道推广质量是否合格...
  • asp.net知识库

    2015-06-18 08:45:45
    如何判断ArrayList,Hashtable,SortedList 这类对象是否相等 帮助解决网页和JS文件中的中文编码问题的小工具 慎const关键字 装箱,拆箱以及反射 动态调用对象的属性和方法——性能和灵活性兼备的方法 消除由try/...
  • 数据运营思维导图

    2018-04-26 14:24:22
    判断是否存在渠道作弊行为、渠道包被下架等问题 日一次会话用户数 即新登用户中只有一次会话,且会话时长低于门阀值 ——解决问题 推广渠道是否有刷作弊行为 渠道推广质量是否合格 用户导入是否存在障碍点,...
  • SSO-WebDemo

    2013-08-12 20:25:57
    本文除了从多个方面和角度给出了对单点登录(SSO)的全面分析,还并且讨论了如何将现有的应用和SSO服务结合起来,能够帮助应用架构师和系统分析人员从本质上认识单点登录,从而更好地设计出符合需要的安全架构。...
  • 3、jdom解析xml文件时如何解决中文问题?如何解析? 114 4、编程JAVA解析XML的方式. 115 5、XML文档定义有几种形式?它们之间有何本质区别?解析XML文档有哪几种方式? 117 七. 流行的框架与新技术 117 1、谈谈你...
  • 程序开发范例宝典>>

    2012-10-24 10:41:28
    实例071 在ListView控件中对数据排序或统计 92 实例072 在ListView控件中绘制底纹 93 实例073 在列表视图中拖动视图项 94 实例074 使ListView控件中的选择项高亮显示 97 实例075 带复选框的ListView...
  • SQL注入的原理 什么SQL注入 将SQL代码插入到应用程序的输入参数中,之后,SQL代码被传递到数据库执行。从而达到对应用程序的攻击目的。... 有了执行计划和执行时间我们就很容易判断一条SQL语句执行效率高不高
  • 实例071 在ListView控件中对数据排序或统计 92 实例072 在ListView控件中绘制底纹 93 实例073 在列表视图中拖动视图项 94 实例074 使ListView控件中的选择项高亮显示 97 实例075 带复选框的ListView控件 ...
  • 实例071 在ListView控件中对数据排序或统计 92 实例072 在ListView控件中绘制底纹 93 实例073 在列表视图中拖动视图项 94 实例074 使ListView控件中的选择项高亮显示 97 实例075 带复选框的ListView控件 ...
  • 我们需要给消费者的需求和影响需求的因素之间的关系下一个定义。方程式211对问题做了简化,我们可以由此入手进行研究:  Qd=f(P,Ps,Pc,…) (2.1.1)  这里:  Qd=对某种商品的需求  P=...
  • 实例071 在ListView控件中对数据排序或统计 92 实例072 在ListView控件中绘制底纹 93 实例073 在列表视图中拖动视图项 94 实例074 使ListView控件中的选择项高亮显示 97 实例075 带复选框的ListView控件 99 2.7 ...
  • C#程序开发范例宝典(第2版).part02

    热门讨论 2012-11-12 07:55:11
    实例071 在ListView控件中对数据排序或统计 92 实例072 在ListView控件中绘制底纹 93 实例073 在列表视图中拖动视图项 94 实例074 使ListView控件中的选择项高亮显示 97 实例075 带复选框的ListView控件 99 2.7...
  • C#程序开发范例宝典(第2版).part13

    热门讨论 2012-11-12 20:17:14
    实例071 在ListView控件中对数据排序或统计 92 实例072 在ListView控件中绘制底纹 93 实例073 在列表视图中拖动视图项 94 实例074 使ListView控件中的选择项高亮显示 97 实例075 带复选框的ListView控件 99 2.7...

空空如也

空空如也

1 2 3 4 5
收藏数 89
精华内容 35
关键字:

如何判断需要用统计量