我们在使用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 abstract View getView (int positionView convertView, ViewGroup parent)

这里也有一个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);
// 响应代码
}

REFERENCES:http://blog.csdn.net/gg137608987/article/details/7995671

ListView 的position和id的区别的更多相关文章

  1. ListView onItemClick(AdapterView<?> parent, View view, int position, long id)参数详解

    public void onItemClick(AdapterView<?> parent, View view, int position, long id) { parent.getA ...

  2. ListView OnItemClickListener position 索引不正确

    在使用ListView添加如下代码时 listview.setOnItemClickListener(new OnItemClickListener() { @Override public void ...

  3. onItemClick(AdapterView<?> parent, View view, int position, long id)

    Public Methods public abstract void onItemClick (AdapterView<?> parent, View view, int positio ...

  4. 正确处理listview的position

    当ListView包含有HeaderView或FooterView时,传入getView或者onItemClick的position是怎样的,这是个值得探讨的问题 先列出错误的用法 定义: priva ...

  5. Android之RecyclerView的原生Bug-Inconsistency detected. Invalid view holder adapter positionViewHolder{a1bbfa3 position=2 id=-1, oldPos=-1, pLpos:-1 no parent}

    今天在运行自己编写的App时,突然发现App在运行时闪退,然后就查看了Android Studio的Log,发现了这个错误,上网查了一下,才知道是RecyclerView的原生Bug,在数据更新时会出 ...

  6. JS中class和id的区别

    class和id的区别 class用于css的,id用于js的. 1)class页面上可以重复.id页面上唯一,不能重复. 2)一个标签可以有多个class,用空格隔开.但是id只能有id.

  7. android:id="@+id/button1" 与 android:id="@id/button1" 区别 @string

    一.android:id="@+id/button1" 与 android:id="@id/button1" 区别 android:id="@+id/ ...

  8. DIV滚动条滚动到指定位置(jquery的position()与offset()方法区别小记)

    相对浏览器,将指定div滚到到指定位置,其用法如下 $("html,body").animate({scrollTop: $(obj).offset().top},speed); ...

  9. Windows中句柄和ID的区别

    写在前面:这里介绍句柄 对于“句柄”,在下一直停留在一知半解的认识层面,近日在下学习Windows编程,决定趁此机会将句柄彻底搞清楚.查阅了一些网络上的资料,发现网络上的讲解大概可以分为两类:一种是以 ...

随机推荐

  1. 彻底理解PHP的SESSION机制

    http://www.cnblogs.com/acpp/archive/2011/06/10/2077592.html 一.默认机制,用磁盘文件来实现PHP会话.php.ini配置:session.s ...

  2. Java Web应用启动间隔执行的程序

    Reference:<Java定时器timer.schedule在Web中间隔执行任务和定时><[Java]Timer和TimerTask详解> 做了一个Demo,完成如下的功 ...

  3. mysqldump: unknown option '--no-beep'

    想要备份mysql数据库时,输入mysqldump命令出现如题所示的错误,在网上找了好久,终于从一个帖子上得到了一些提示,就动手试了下,嘿  还真成了!! mysqldump --no-default ...

  4. 节点的创建--对比jQuery与JavaScript 方法

    一.  创建节点: 节点是DOM结构的基础,根据DOM规范,节点是一个很宽泛的概念,包含元素.属性.文本.文档和注释.但在实际开发中,要动态创建内容,主要操作的节点包括元素.属性和文本. 1.需求:创 ...

  5. 16_MyBatis中期小结

    [MyBatis是什么] MyBatis是一个持久层框架,Mybatis是一个不完全的ORM框架,SQL语句需要程序员自己去编写,但是MyBatis也有映射(输入参数映射.输出结果映射). MyBat ...

  6. visual studio vs2010 vs2013 显示详细调试信息方法;vs debug 出错怎么办,你需要的不是答案,是方法。

    显示详细的输出信息: 选项--项目和解决方案--生成并运行--MSBuild项目生成输出详细信息: 这样在输出目录就会显示详细的错误信息,可以自己分析了.

  7. C++中string类型对象和double型变量之间的互相转换

    //convert string type value to double type value string s = "23"; double d; istringstream ...

  8. ScrollView 尽量避免嵌套RelativeLayout,非常惨痛的教训

    <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android=&q ...

  9. linux采用模块方法,添加一个新的设备

    该文转载自:http://rangercyh.blog.51cto.com/1444712/521244 系统调用是操作系统内核和应用程序之间的接口,而设备驱动程序是操作系统内核和机器硬件之间的接口. ...

  10. js微博发布框

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...