Android ListView获取当前可视区域条目数据


最近在项目中接到一个很奇葩的数据统计需求。

根据出现在屏幕中可视区域内的控件,来上报数据统计。当控件出现可视范围内,则统计相应的数据。如果界面上有多个需要统计的控件,则需要过滤掉上一次出现在可视区域内的数据。如果滑出屏幕可视区域了,再次进入则又要统计。

在网上找也没有找到跟这些相关的,最多就是找到获取ListView当前区域的数据。最后在百度知道里面找一个差不多类似的,根据里面的思路来改的。


@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// TODO Auto-generated method stub
if (performanceWidgetTicket != null && mLiveShowTicketList != null) {//这行代码是我的数据操作所需要的null判断,可换成你需要的条件
// 比较两次可见的item的序号,只曝光新出现的
ArrayList<Integer> list = new ArrayList<Integer>(visibleItemCount);
// 将最新可见item的index加入到临时list中
for (int i = firstVisibleItem; i < firstVisibleItem + visibleItemCount; i++) {
list.add(i);
}
if (visibleList != null && list != null) {
//新可见item的index的集合
ArrayList<Integer> diffList = getDiffrent(list, visibleList);

if (diffList != null) {
for (int x = 0; x < diffList.size(); x++) {
// 曝光操作
// 在这里做相应操作
LogUtils.LOGD(TAG, "diffList.get(x):" + diffList.get(x));

}
//更新list,将最新的可见item的index加入到list
visibleList.clear();
visibleList.addAll(list);

}
}
//清空最新可见item的index的list
if (list != null) {
list.clear();
}
}
}

上面的代码是在百度知道里面找的。思路也是跟一样。其实这块并不难,难点在于查找数据方面。因为我有多个界面需要统计,所以每个界面处理都不一样,但思路是一样的。
首页1
首页2
因为首页有两种条目需要上报的,所以处理也是需要结合两种条目的处理方式一起处理。

下面这个是取出两个list中不同的元素加入到新的list

public static ArrayList<Integer> getDiffrent(List<Integer> list1, List<Integer> list2) {
long st = System.nanoTime();
ArrayList<Integer> diff = new ArrayList<Integer>();
for (Integer index : list1) {
if (!list2.contains(index)) {
diff.add(index);
}
}
return diff;
}

这下面是首页获取统计的主要方法了,我的统计是在滑动停止之后,而不是滑动中所以跟上面代码会有点区别,最主要的就在于获取下标的问题上面。就是第一个循环处

    /** 存放可见的ListView */
public List<Integer> visibleList = new ArrayList<Integer>();
/** 获取Holder并且上报 */
public void gameInfoExposure() {

int firstVisible = content.getFirstVisiblePosition();
int lastVisible = content.getLastVisiblePosition();
int index = content.getHeaderViewsCount();

Map<String, Object> mapList = new HashMap<String, Object>();

// 需要上报的游戏Id集合
List<String> gameIds = new ArrayList<String>();
// 将最新可见item的index加入到临时list中
ArrayList<Integer> list = new ArrayList<Integer>();
// 标识是否提交信息
boolean isSubmit = false;
// 遍历的时候下标要减一个
for (int i = firstVisible - 1; i < lastVisible; i++) {

View tmp = content.getChildAt((index + i) - firstVisible - 1);
if (tmp != null) {
Object tag = tmp.getTag();
// 这里要判断两个类型的条目
if (tag != null && tag instanceof HomeGameGridViewItemHolder) {
// 这里是宫格Item的
HomeGameGridViewItemHolder holder = (HomeGameGridViewItemHolder) tag;
GameGridViewItemHolder gameItem = getGameItemHolder(holder, 0);

// 得到第一个Holder下载控件的View,并且判断是否可见
View downloadView = gameItem.getDownloadView();
Rect scrollBounds = new Rect();
downloadView.getHitRect(scrollBounds);

if (downloadView.getLocalVisibleRect(scrollBounds)) {
list.add(i);
mapList.put(i + "", holder);
}

} else if (tag != null && tag instanceof RedGameHolder) {
// 正常Item
RedGameHolder holder = (RedGameHolder) tag;
// 获取下载控件,并且判断是否可见
View downloadView = holder.getDownloadView();
Rect scrollBounds = new Rect();
downloadView.getHitRect(scrollBounds);
// 判断View是否移出去了不可见或者可见
if (downloadView.getLocalVisibleRect(scrollBounds)) {
// View 进入当前屏幕可视,哪怕一个像素
list.add(i);
// RedGameBean gameBean = holder.getGameBean();
mapList.put(i + "", holder);
}
}
}
}

// 新可见item的index的集合
ArrayList<Integer> diffList = DataHelper.getDiffrent(list, visibleList);

if (!diffList.isEmpty()) {

for (Integer i : diffList) {

Object obj = mapList.get("" + i);
if (obj != null && obj instanceof HomeGameGridViewItemHolder) {
// 在这里需要再次反向查找对应View是在可视区域内
HomeGameGridViewItemHolder holder = (HomeGameGridViewItemHolder) obj;
int count = holder.getGridView().getAdapter().getCount();
for (int j = 0; j < count; j++) {
GameGridViewItemHolder item = getGameItemHolder(holder, j);

if (!FileHelper.checkApkExist(mActivity, item.getGameBean().getLocalApkName())) {
String str = item.getGameBean().getType() + ":" + item.getGameBean().getId();
gameIds.add(str);
isSubmit = true;

}
}

} else if (obj != null && obj instanceof RedGameHolder) {
RedGameHolder holder = (RedGameHolder) obj;
RedGameBean gameBean = holder.getGameBean();
if (gameBean != null && !FileHelper.checkApkExist(mActivity, gameBean.getLocalApkName())) {

String str = gameBean.getType() + ":" + gameBean.getId();
gameIds.add(str);
isSubmit = true;

}
}
}
}

// 更新list,将最新的可见item的index加入到list
visibleList.clear();
visibleList.addAll(list);

// 清除Map集合
if (!mapList.isEmpty()) {
mapList.clear();
}

// 清空最新可见item的index的list
if (!list.isEmpty()) {
list.clear();
}

if (isSubmit) {
String ids = "";
if (gameIds.size() > 0) {
for (int i = 0; i < gameIds.size(); i++) {

ids = ids + gameIds.get(i);
if (i != gameIds.size() - 1)
ids = ids + "|";
}
// 这里执行上报
// 该处就是执行你代码提交的地方了
gameIds.clear();
}

isSubmit = false;
}

}

下面就是同一个界面获取同样条目的统计数据了,在这个统计方法里面思路跟上面是一样的,只不过Map集合存的对象我换了而已。
先上个界面列表页

    /** 存放可见的ListView */
private List<Integer> visibleList = new ArrayList<Integer>();
/** 获取Holder并且上报 */
private void gameInfoExposure() {
// TODO
int firstVisible = listView.getFirstVisiblePosition();
int lastVisible = listView.getLastVisiblePosition();
int index = listView.getHeaderViewsCount();
// 加载的数据类型,1为分类,默认为0榜单
int type = loadDataType == 1 ? 1 : 0;

Map<String, RedGameBean> mapList = new HashMap<String, RedGameBean>();

// 需要上报的游戏Id集合
List<String> gameIds = new ArrayList<String>();
// 将最新可见item的index加入到临时list中
ArrayList<Integer> list = new ArrayList<Integer>();
// 标识是否提交游戏信息
boolean isSubmit = false;
int count = firstVisible > 0 ? firstVisible - 1 : 0;
// 遍历的时候下标要减一个,不然会有问题
for (int i = count - 1; i <= lastVisible; i++) {

View tmp = listView.getChildAt((index + i) - firstVisible);
if (tmp != null) {
Object tag = tmp.getTag();

if (tag != null && tag instanceof RedGameHolder) {
RedGameHolder holder = (RedGameHolder) tag;
// 获取下载控件,并且判断是否可见
View downloadView = holder.getDownloadView();

Rect scrollBounds = new Rect();
downloadView.getHitRect(scrollBounds);
// 判断View是否移出去了不可见或者可见
if (downloadView.getLocalVisibleRect(scrollBounds)) {
// View 进入当前屏幕可视,哪怕一个像素
list.add(i);
RedGameBean gameBean = holder.getGameBean();
mapList.put("" + i, gameBean);

}
}
}

}
// 新可见item的index的集合
ArrayList<Integer> diffList = DataHelper.getDiffrent(list, visibleList);

if (!diffList.isEmpty()) {

for (Integer i : diffList) {

RedGameBean gameBean = mapList.get("" + i);
if (gameBean != null && !FileHelper.checkApkExist(mActivity, gameBean.getLocalApkName())) {
String str = AppDefine.NA + ":" + gameBean.getId();
gameIds.add(str);
isSubmit = true;
}
}
}
// 更新list,将最新的可见item的index加入到list
visibleList.clear();
visibleList.addAll(list);

// 清除Map集合
if (!mapList.isEmpty()) {
mapList.clear();
}

// 清空最新可见item的index的list
if (!list.isEmpty()) {
list.clear();
}

if (isSubmit) {
String ids = "";
if (gameIds.size() > 0) {
for (int i = 0; i < gameIds.size(); i++) {

ids = ids + gameIds.get(i);
if (i != gameIds.size() - 1)
ids = ids + "|";
}
// 这里执行上报
// 该处就是执行你代码提交的地方了
gameIds.clear();
}

isSubmit = false;
}

}

下面的代码就是自己备忘的了,有需要的同鞋也可以参照着改哈。思路完全是跟上面的一样,只不过界面不一样了而已
搜索1

    /** 存放可见的ListView */
private List<Integer> visibleList = new ArrayList<Integer>();
/** 获取游戏Holder并且上报游戏曝光 */
private void gameInfoExposure() {
// TODO 这个界面因为别人实现的,只能根据封装的界面去反向查找,界面看上去像一个ListView其实里面有包含有多个子ListView,所以需要拿拿到对应的Holder再找到里面的ListView再次查找
int firstVisible = searchListview.getFirstVisiblePosition();
int lastVisible = searchListview.getLastVisiblePosition();
int index = searchListview.getHeaderViewsCount();

Map<String, RedGameBean> mapList = new HashMap<String, RedGameBean>();

// 需要上报的游戏Id集合
List<String> gameIds = new ArrayList<String>();
// 将最新可见item的index加入到临时list中
ArrayList<Integer> list = new ArrayList<Integer>();
// 标识是否提交游戏信息
boolean isSubmit = false;
// int count = firstVisible > 0 ? firstVisible - 1 : 0;
// 遍历的时候下标要减一个,不然会有问题
for (int i = firstVisible; i <= lastVisible; i++) {

View tmp = searchListview.getChildAt((index + i) - firstVisible);
if (tmp != null) {
Object tag = tmp.getTag();
// 如果不是游戏条目则就不进入了
if (tag != null && tag instanceof SearchRedGameHolder) {

SearchRedGameHolder holder = (SearchRedGameHolder) tag;
ListView lv = holder.getListView();
if(lv != null){

int lvFirstVisible = lv.getFirstVisiblePosition();
int lvLastVisible = lv.getLastVisiblePosition();
int lvIndex = lv.getHeaderViewsCount();
// 这里进行第二次遍历
for (int j = lvFirstVisible; j <= lvLastVisible; j++) {
View view = lv.getChildAt((lvIndex + j) - firstVisible);
if (view != null) {

Object viewTag = view.getTag();
if (viewTag != null && viewTag instanceof RedGameHolder) {

RedGameHolder gameHolder = (RedGameHolder) viewTag;
View downloadView = gameHolder.getDownloadView();

Rect scrollBounds = new Rect();
downloadView.getHitRect(scrollBounds);
// 判断View是否移出去了不可见或者可见
if (downloadView.getLocalVisibleRect(scrollBounds)) {
// View 进入当前屏幕可视,哪怕一个像素
list.add(j);
RedGameBean gameBean = gameHolder.getGameBean();
mapList.put("" + j, gameBean);

}
}
}
}
}
}
}

}

// 新可见item的index的集合
ArrayList<Integer> diffList = DataHelper.getDiffrent(list, visibleList);

if (!diffList.isEmpty()) {
for (Integer i : diffList) {

RedGameBean gameBean = mapList.get("" + i);
// 判断游戏是否安装
if (gameBean != null && !FileHelper.checkApkExist(mActivity, gameBean.getLocalApkName())) {
String str = AppDefine.NA + ":" + gameBean.getId();
gameIds.add(str);
isSubmit = true;
}
}
}

// 更新list,将最新的可见item的index加入到visibleList
visibleList.clear();
visibleList.addAll(list);

// 清除Map集合
if (!mapList.isEmpty()) {
mapList.clear();
}

// 清空最新可见item的index的list
if (!list.isEmpty()) {
list.clear();
}

if (isSubmit) {
String ids = "";
if (gameIds.size() > 0) {
for (int i = 0; i < gameIds.size(); i++) {

ids = ids + gameIds.get(i);
if (i != gameIds.size() - 1)
ids = ids + "|";
}
// 这里执行上报
gameIds.clear();
}
isSubmit = false;
}
}

搜索结果更多

    更多界面重跟列表一样就行了
/** 存放可见的ListView */
private List<Integer> visibleList = new ArrayList<Integer>();
/** 获取游戏Holder并且上报游戏曝光 */
private void gameInfoExposure() {
int firstVisible = searchListview.getFirstVisiblePosition();
int lastVisible = searchListview.getLastVisiblePosition();
int index = searchListview.getHeaderViewsCount();

Map<String, RedGameBean> mapList = new HashMap<String, RedGameBean>();

// 需要上报的游戏Id集合
List<String> gameIds = new ArrayList<String>();
// 将最新可见item的index加入到临时list中
ArrayList<Integer> list = new ArrayList<Integer>();
// 标识是否提交游戏信息
boolean isSubmit = false;
int count = firstVisible > 0 ? firstVisible - 1 : 0;
// 遍历的时候下标要减一个,不然会有问题
for (int i = count; i <= lastVisible; i++) {

View tmp = searchListview.getChildAt((index + i) - firstVisible -2);
if (tmp != null) {
Object tag = tmp.getTag();

if (tag != null && tag instanceof RedGameHolder) {

RedGameHolder holder = (RedGameHolder) tag;
// 获取下载控件,并且判断是否可见
View downloadView = holder.getDownloadView();

Rect scrollBounds = new Rect();
downloadView.getHitRect(scrollBounds);
// 判断View是否移出去了不可见或者可见
if (downloadView.getLocalVisibleRect(scrollBounds)) {
// View 进入当前屏幕可视,哪怕一个像素
list.add(i);
RedGameBean gameBean = holder.getGameBean();
mapList.put("" + i, gameBean);

}
}
}

}
// 新可见item的index的集合
ArrayList<Integer> diffList = DataHelper.getDiffrent(list, visibleList);

if (!diffList.isEmpty()) {

for (Integer i : diffList) {

RedGameBean gameBean = mapList.get("" + i);
if (gameBean != null && !FileHelper.checkApkExist(mActivity, gameBean.getLocalApkName())) {
String str = AppDefine.NA + ":" + gameBean.getId();
gameIds.add(str);
isSubmit = true;
}
}
}
// 更新list,将最新的可见item的index加入到list
visibleList.clear();
visibleList.addAll(list);

// 清除Map集合
if (!mapList.isEmpty()) {
mapList.clear();
}

// 清空最新可见item的index的list
if (!list.isEmpty()) {
list.clear();
}

if (isSubmit) {
String ids = "";
if (gameIds.size() > 0) {
for (int i = 0; i < gameIds.size(); i++) {

ids = ids + gameIds.get(i);
if (i != gameIds.size() - 1)
ids = ids + "|";
}
// 这里执行上报

gameIds.clear();
}

isSubmit = false;
}

}

详情推荐

这个界面只需要取其中的一条,所以处理也类似,并且View是GridView所以就没像上面那样处理了。
/** 存放可见的ListView */
private List<Integer> visibleList = new ArrayList<Integer>();

/** 获取游戏Holder并且上报游戏曝光 */
private void gameInfoExposure() {

int firstVisible = listView.getFirstVisiblePosition();
int lastVisible = listView.getLastVisiblePosition();
// int index = listView.getHeaderViewsCount();
// 需要上报的游戏Id集合
List<String> gameIds = new ArrayList<String>();
// 将最新可见item的index加入到临时list中
ArrayList<Integer> list = new ArrayList<Integer>();
// 标识是否提交游戏信息
boolean isSubmit = false;
// 遍历的时候下标要减一个,不然会有问题
for (int i = firstVisible; i <= lastVisible; i++) {

View tmp = listView.getChildAt(i - firstVisible);
if (tmp != null) {
Object tag = tmp.getTag();
if (tag != null && tag instanceof GameDetailRelatedHolder) {
GameDetailRelatedHolder holder = (GameDetailRelatedHolder) tag;

// 得到第一个GridView的Holder,有时候可能为空,下面要做判断
GameGridViewItemHolder gameItem = getGameItemHolder(holder, 0);
Rect scrollBounds = new Rect();
// 得到第一个下载控件的View,并且判断是否可见
View downloadView = gameItem.getDownloadView();
downloadView.getHitRect(scrollBounds);
if (downloadView.getLocalVisibleRect(scrollBounds)) {
list.add(i);
// 新可见item的index的集合,这个是用来做操作的。
ArrayList<Integer> diffList = DataHelper.getDiffrent(list, visibleList);
if (diffList.size() > 0) {
// 重新获取可见的
GridView gView = holder.getGridView();
int count = gView.getAdapter().getCount();

for (int j = 0; j < count; j++) {
GameGridViewItemHolder item = getGameItemHolder(holder, j);

if (!FileHelper.checkApkExist(mActivity, item.getGameBean().getLocalApkName())) {
String str = AppDefine.NA + ":" + item.getGameBean().getId();
gameIds.add(str);
isSubmit = true;
}
}

}
// 更新list,将最新的可见item的index加入到list
visibleList.clear();
visibleList.addAll(list);

} else {
// 清空可见视图集合
visibleList.clear();
}
}
}
}

// 清空最新可见item的index的list
if (list != null) {
list.clear();
}

if (isSubmit) {
String ids = "";
if (gameIds.size() > 0) {
for (int i = 0; i < gameIds.size(); i++) {

ids = ids + gameIds.get(i);
if (i != gameIds.size() - 1)
ids = ids + "|";
}
// 这里执行上报

gameIds.clear();
}

isSubmit = false;
}

}

游戏帖子详情

详情界面数据是在ListViewHeader里面在里面又封装了个ListView。所以查找方式也是一样的,可要不是ListView的话这种方式就不可用了。具体的就需要根据你实现的方式来调整了
/** 存放可见的ListView */
private List<Integer> visibleList = new ArrayList<Integer>();
/** 获取游戏Holder并且上报游戏曝光 */
private void gameInfoExposure() {

if (messageDetailMain == null || headViewHolder == null || headViewHolder instanceof ReplyHeaderStrategyView) {
return;
}

if (messageDetailMain.getContentType() != MsgContentType.MSG_CONTENT_TYPE_ARTICLE_CONTAIN_GAME) {
return;
}

ReplyActivityHeadViewHolder headHolder = (ReplyActivityHeadViewHolder) headViewHolder;
ListView listView = headHolder.getListView();

if (listView == null || listView.getVisibility() != View.VISIBLE) {
return;
}

int firstVisible = listView.getFirstVisiblePosition();
int lastVisible = listView.getLastVisiblePosition();
int index = listView.getHeaderViewsCount();

Map<String, RedGameBean> mapList = new HashMap<String, RedGameBean>();
// 需要上报的游戏Id集合
List<String> gameIds = new ArrayList<String>();
// 将最新可见item的index加入到临时list中
ArrayList<Integer> list = new ArrayList<Integer>();
// 标识是否提交游戏信息
boolean isSubmit = false;
int count = firstVisible > 0 ? firstVisible : 0;
// 遍历的时候下标要减一个,不然会有问题
for (int i = count; i <= lastVisible; i++) {

View tmp = listView.getChildAt((index + i) - firstVisible);
if (tmp != null) {
Object tag = tmp.getTag();

if (tag != null && tag instanceof RedGameHolder) {

RedGameHolder holder = (RedGameHolder) tag;
// 获取下载控件,并且判断是否可见
View downloadView = holder.getDownloadView();
//
Rect scrollBounds = new Rect();
downloadView.getHitRect(scrollBounds);
// // 判断View是否移出去了不可见或者可见
RedGameBean gameBean = holder.getGameBean();
if (downloadView.getLocalVisibleRect(scrollBounds)) {
// View 进入当前屏幕可视,哪怕一个像素
list.add(i);
mapList.put("" + i, gameBean);
}
}
}

}
// 新可见item的index的集合
ArrayList<Integer> diffList = DataHelper.getDiffrent(list, visibleList);

if (!diffList.isEmpty()) {

for (Integer i : diffList) {

RedGameBean gameBean = mapList.get("" + i);
if (gameBean != null && !FileHelper.checkApkExist(mActivity, gameBean.getLocalApkName())) {
String str = AppDefine.NA + ":" + gameBean.getId();
gameIds.add(str);
isSubmit = true;
}
}
}
// 更新list,将最新的可见item的index加入到list
visibleList.clear();
visibleList.addAll(list);

// 清空最新可见item的index的list
if (list != null) {
list.clear();
}

if (isSubmit) {
String ids = "";
if (gameIds.size() > 0) {
for (int i = 0; i < gameIds.size(); i++) {

ids = ids + gameIds.get(i);
if (i != gameIds.size() - 1)
ids = ids + "|";
}
// 这里执行上报

gameIds.clear();
}

isSubmit = false;
}

}

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com