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