以下内容为原创,欢迎转载,转载请注明

来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/4146512.html 

给ListView中每个item绑定点击事件的方法,比较常见的如下这种方式:

 public View getView(int positon, View convertView, ViewGroup parent){
if(null == convertView){
convertView = LayoutInflater.from(context).inflate(R.layout.item, null);
} Button button = ABViewUtil.obtainView(convertView, R.id.item_btn);
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Toast.makeText(context, "position: " + position, Toast.LENGTH_SHORT).show();
}
}); }

然后运行,当然没问题。

但是这里有一个可以优化的地方,注意代码第7行,每次调用getView方法都会设置Button的OnClickListener,会生成很多不必要的OnClickListener对象。

所以,我们可以想到,在生成convertView时,同时设置Button的OnClickListener,convertView是被不断地复用的,这样的OnClickListener也就可以被不断地服用,也就是说在第3行和第4行之间进行这一步。这样,代码演化到如下:

 public View getView(int positon, View convertView, ViewGroup parent){
if(null == convertView){
convertView = LayoutInflater.from(context).inflate(R.layout.item, null);
Button button = ABViewUtil.obtainView(convertView, R.id.item_btn);
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Toast.makeText(context, "position: " + position, Toast.LENGTH_SHORT).show();
}
});
}
}

这个代码看上去没什么问题,但是问题就在onClick回调的的第8行中使用的position的时候,因为这里使用的是匿名内部类(这个匿名内部类实现了View.OnClickListener这个接口),所以如果需要在onClick中使用position这个变量的话,需要把position声明为final。一旦声明了final,等到编译之后,这个position就会被作为这个匿名内部类中的一个private的成员变量。这样,ListView往下滚动,下面需要显示的item会重用上面不显示的convertView,convertView中的Button设置的OnClickListener实现类的对象,回调onClick时,使用的position其实是该OnClickListener实现类的成员变量position(这个position的值只是在构造的时候被初始化了而已!)。所以,这个ListView刚加载完数据后,还未滚动时,点击屏幕上的item都是正常的,但是如果一旦滚动,有view被重用了,这个时候,position的值就错乱了,所以在onClick中通过position获取到的item的数据当然也是错乱的了。

所以,要解决这个问题,就需要让onClick方法回调的时候得到的position是个正确的值,我们可以选择使用把当前显示的convertView对应的position值保存在convertView中,然后把这个convertView对象传入OnClickListener中保存,所以代码演化到如下:

 public View getView(int positon, View convertView, ViewGroup parent){
if(null == convertView){
convertView = LayoutInflater.from(context).inflate(R.layout.item, null);
Button button = ABViewUtil.obtainView(convertView, R.id.item_btn);
button.setOnClickListener(new OnConvertViewClickListener(convertView, R.id.ab__id_adapter_item_position){
@Override
public void onClickCallBack(View registedView, int... positionIds){
Toast.makeText(context, "position: " + positionIds[0], Toast.LENGTH_SHORT).show();
}
});
}
convertView.setTag(R.id.ab__id_adapter_item_position, position);
}

就像上面第5行这样,Button绑定的是OnConvertViewClickListener,它是OnClickListener的一个实现类可以保存convertView到Listener中,到时候回调onClick方法的时候可以从保存的convertView中获取到当前显示的item的position(这个position是以tag的方式保存在convertView中的)。

当然,还需要做第12行这一步,它的目的是把当前显示的position保存到convertView中,提供给OnConvertViewClickListener获取当前的position。

这样就ok了,可以在onClickCallBack()方法中进行点击事件的处理了,每个button永远只有一个onClickListener。

注:使用OnConvertViewClickListener可以依赖AndroidBucket(https://github.com/wangjiegulu/AndroidBucket)项目

[Android]在Adapter的getView方法中绑定OnClickListener比较好的方法的更多相关文章

  1. CI中的控制器中要用model中的方法,是统一写在构造器方法中,还是在每一个方法中分别写

    Q: CI中的控制器中要用model中的方法,是统一写在构造器方法中,还是在每一个方法中分别写 A: 建议统一写,CI框架会自动识别已经加载过的类,所以不用担心重复加载的问题 class C_User ...

  2. 为什么static方法中不可以调用非static方法

    Java是面向对象的语言,所有的变量,方法都是针对对象而言的.一般来说,要调用一个方法,你需要new 这个方法的对象. 什么时候用static? 如果你想要: 对于一个类的所有对象共享一个变量或者是方 ...

  3. jQuery中绑定事件的几种方法

    以click事件为例,jQuery中绑定事件有三种方法: (1)target.click(function(){});  (2)target.bind("click",functi ...

  4. BackgroundWorker的DoWork方法中发生异常无法传递到RunWorkedCompleted方法

    在使用C#的BackgroundWorker时需要在UI界面上显示DoWork中发生的异常,但怎么调试都无法跳转到界面上,异常也不会传递到RunWorkerCompleted方法中(e.Error为空 ...

  5. hibernate方法中参数传入数组的查询方法

    public List<T> getByIds(Long[] ids) { return getSession().createQuery(// "FROM User WHERE ...

  6. Android开发面试经——4.常见Android进阶笔试题(更新中...)

      Android开发(29)  版权声明:本文为寻梦-finddreams原创文章,请关注:http://blog.csdn.net/finddreams 关注finddreams博客:http:/ ...

  7. .Net中的AOP系列之《方法执行前后——边界切面》

    返回<.Net中的AOP>系列学习总目录 本篇目录 边界切面 PostSharp方法边界 方法边界 VS 方法拦截 ASP.NET HttpModule边界 真实案例--检查是否为移动端用 ...

  8. jQuery中绑定事件bind() on() live() one()的异同

    jQuery中绑定事件的四种方法,他们可以同时绑定一个或多个事件 bind()-------------------------版本号小于3.0(在Jquery3.0中已经移除,相应unbind()也 ...

  9. Android总结篇系列:Activity中几个主要函数详解

    Activity作为Android系统中四大基本组件之一,包含大量的与其他的各大组件.intent.widget以及系统各项服务等之间的交互的函数.在此,本文主要选取实际项目开发中常用的,但完全理解又 ...

随机推荐

  1. QT学习笔记2

    初探信号槽 代码如下: QPushButton *button=new QPushButton("quit"); QObject::connect(button,SIGNAL(cl ...

  2. UsefulSQL

    FindObject: ---在当前Server上找某某object,注意只需修改"要找的object"就可以使用EXEC sp_MSforeachdb 'use ? ;IF EX ...

  3. Emit学习(3) - OpCodes - 动态添加属性、构造函数、方法

    上一篇介绍了 IL 的部分, 基础的部分, 暂时就介绍到那里了, 接下来要进入代码编写阶段了. 今天的主题是 在代码运行的过程中, 去动态的创建类, 属性, 方法. 来源:http://www.cnb ...

  4. JS框架avalon简单例子 行编辑 添加 修改 删除 验证

    为什么要写这个例子:做表单的时候,表单包含主子表,对于子表的编辑,使用的是easyui datagrid的行编辑功能,由于业务比较复杂,实现起来比较麻烦,代码写的也很多,因为插件的封装,无法操作原始的 ...

  5. C#常用字符串加解密方法封装

    C#中常用的字符串加密.解密方法封装,包含只加密但不解密的方法.收藏起来备用. //方法一 //须添加对System.Web的引用 //using System.Web.Security; /// & ...

  6. VS2015如何创建单元测试并启动调试

    1: 添加单元测试 2:打开单元测试类 关键点: 类上加上标记:[TestClass],方法上添加标记:[TestMethod],方法输出使用:Assert.IsNotNull(s,"测试失 ...

  7. 提高生产性工具 - Model代码生成器(NET / JAVA) (一)

    原来在上一家公司,整整一年都在做工具,提高生产性,那个项目特别巨大,所以总共为老东家节约了500K左右的美金. (除了表扬之外,我个人什么好处都没有,领导们都升官发财了,郁闷) 到了新公司,也准备开发 ...

  8. SqlServer中的自增的ID的最后的值:

    SqlServer中的自增的ID的最后的值: SELECT SCOPE_IDENTITY() --返回插入到同一作用域中的 IDENTITY 列内的最后一个 IDENTITY 值.SELECT @@I ...

  9. Win10 IoT C#开发 2 - 创建基于XAML的UI程序 及 应用的三种部署方法

    Windows 10 IoT Core 是微软针对物联网市场的一个重要产品,与以往的Windows版本不同,是为物联网设备专门设计的,硬件也不仅仅限于x86架构,同时可以在ARM架构上运行. 上一章我 ...

  10. 写PHP代码你搞过单元测试吗

    其实一开始我内心是想做单元测试(unit testing)的,但时间久了,也就不想了. 要想通过PHP编程成为技术领域的专家,其实功夫在PHP之外.数据库至少得看几本书,xml至少得看一本书,单元测试 ...