我们在使用ListView的时候,一般都会为ListView添加一个响应事件android.widget.AdapterView.OnItemClickListener。本文主要在于对OnItemClickListener的position和id参数做详细的解释,我相信有些人在这上面走了些弯路。

先来看一下官方的文档
position The position of the view in the adapter.
id The row id of the item that was clicked.
而这两行字并没有解释清楚position和id的区别。另外,我们还有个Adapter的getView方法。

public abstractViewgetView(int position,ViewconvertView,ViewGroupparent)

这里也有一个position。 初步接触ListView的同学,一般会直接继承ArrayAdapter,然后(比如我),就想当然的认为OnItemClick的position和getView的position是一样的啊。于是我们就getItem(position)来获取相应的数据。 那么这段代码有没有错呢?如果有错的话,在什么情况会出错呢? 第一个问题的答案是,当我们为ListView添加headerView或者footerView之后,这段代码就不一定是我们想要的了。 出现问题的原因在于,当我们为ListView添加headerView或者footerView之后,ListView在setAdapter时,做了一些事情,这导致,Adapter和OnItemClickListener中的position含义发生了变化。

我们可以来看看ListView中setAdapter的实现

 public void setAdapter(ListAdapter adapter) {      if (mAdapter != null && mDataSetObserver != null) {          mAdapter.unregisterDataSetObserver(mDataSetObserver);      }      resetList();      mRecycler.clear();      if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {          mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);      } else {          mAdapter = adapter;      }
可以看出,如果这个ListView存在headerView或者footerView的话,那么会在我们传入的adapter外面在封装一层HeaderViewListAdapter,这是一个专门用来自动处理headerView和footerView的adapter。在ListView中,本身不区分headerView,footerView。 ListView可以理解成是只负责管理一组View的数组的UI(ViewGroup),headerView和footerView都委托给HeaderViewListAdapter来处理。(从这里也可以看到为什么API文档中提到,addFooterView和addHeaderView要在setAdapter函数之前调用,如果在之后调用,那么就不会生成HeaderViewListAdapter,从而导致显示不出headerView和footerView)。 回到开头的问题,position和id有啥区别。为此,我们找一下position和id是怎么传进来的。 OnItemClickListener在android.widget.AdapterView的 public boolean performItemClick(View view, int position, long id)函数中被调用。 performItemClick在 android.widget.AbsListView.PerformClick.run()中被调用
  private class PerformClick extends WindowRunnnable implements Runnable {      int mClickMotionPosition;      public void run() {          // The data has changed since we posted this action in the event queue,          // bail out before bad things happen          if (mDataChanged) return;          final ListAdapter adapter = mAdapter;          final int motionPosition = mClickMotionPosition;          if (adapter != null && mItemCount > 0 &&                  motionPosition != INVALID_POSITION &&                  motionPosition < adapter.getCount() && sameWindow()) {              final View view = getChildAt(motionPosition - mFirstPosition);              // If there is no view, something bad happened (the view scrolled off the              // screen, etc.) and we should cancel the click              if (view != null) {                  performItemClick(view, motionPosition, adapter.getItemId(motionPosition));              }          }      }  }
可以看到,position事实上就是ListView中被点击的view的位置。注意,在ListView中是不负责处理headerView和footViewer的,所以,这个位置应该是这个被点击的view在数组[所有的headerView,用户添加的view,所有的footerView]中的位置(请自行参考HeaderViewListAdapter的getView实现)。而id是来自于adapter.getItemId(position)。 对于ArrayAdapter的getItemId函数,实现就是return position。id和position是一致的。 然而,对于HeaderViewListAdapter
public long getItemId(int position) {      int numHeaders = getHeadersCount();      if (mAdapter != null && position >= numHeaders) {          int adjPosition = position - numHeaders;          int adapterCount = mAdapter.getCount();          if (adjPosition < adapterCount) {              return mAdapter.getItemId(adjPosition);          }      }      return -1;  }
实现逻辑是,如果position指向了headerView或footerView,那么返回-1,否则,将返回在用户view数组的位置。 也就是说 id=position-headerView的个数(id < headerviewer的个数+用户view的个数),否则=-1 因此,OnItemClickListener的正确实现如下:
void onItemClick(AdapterViewparent, View view, int position, long id){    if(id == -1) {        // 点击的是headerView或者footerView        return;    }    int realPosition=(int)id;    T item=getItem(realPosition);    // 响应代码}

更多相关文章

  1. GreenDao数据库升级解决方案
  2. 【android】 Android(安卓)动画cancle后 view隐藏
  3. 关于Android键盘遮挡
  4. 【攻克Android(安卓)(40)】JSON解析
  5. Android(安卓)7.0导航栏上添加图标
  6. 2018.03.21 头条Android内推一二三面
  7. [Android(安卓)Samples视频系列之ApiDemos] App-Activity-Receiv
  8. android apk如何引用系统framework.jar,settingslib.jar
  9. Android海康监控视频调用demo

随机推荐

  1. android中多选框bug之getCheckItemIds()
  2. 如何让ImageView的背景图片不缩放
  3. android与PC直连的socket问题
  4. Android(安卓)ScrollView嵌套ListView/Gr
  5. 安卓在将来的发展趋势
  6. android 录音事件
  7. Android(安卓)- Handler 、AsyncTask(二)
  8. Android(安卓)View的layout_width属性是
  9. Android(安卓)扇形控件
  10. Android(安卓)计算器解析(一): 建立简单