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

来自天天博客: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. 寻找Fragment的替代品的尝试

    自从Android在3.0推出Fragment之后,现在很多应用的设计都是建立在Fragment的基础上,像是多个tab切换这种需求,就可以使用Fragment,并且Fragment提供了一系列生命周 ...

  2. [AngularJS] AngularJS系列(2) 中级篇之路由

    目录 原理 angular-route ui-router 事件 深度路由 原理 ng的route本质是监听hashchange事件. 在angular-route中 $rootScope.$on(' ...

  3. LeetCode - Triangle

    题目: Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjace ...

  4. BUG集锦

    1.0 jQuery 序列化表单数据 serialize() 得到的是 ""; 表单元素没有name属性.(用的美工的页面,没注意这个细节.)

  5. 基于<MediaElement>的WPF视频播放器(可拖拽进度条播放)【1】

    一.前言       前两天上峰要求做一个软件使用向导,使用WPF制作.这不,这两天从一张白纸开始学起,做一个播放演示视频的使用向导.以下是粗设计的原型代码: 二.效果图 三.代码 前台代码: < ...

  6. 介绍开源的.net通信框架NetworkComms框架 源码分析(十一)PacketBuilder

    原文网址: http://www.cnblogs.com/csdev Networkcomms 是一款C# 语言编写的TCP/UDP通信框架  作者是英国人  以前是收费的 目前作者已经开源  许可是 ...

  7. ASP.NET MVC 网站开发总结(六)——简谈Json的序列化与反序列化

    首先,先简单的谈一下什么是序列化与反序列化,序列化 (Serialization)将对象的状态信息转换为可以存储或传输的形式的过程.在序列化期间,对象将其当前状态写入到临时或持久性存储区.以后,可以通 ...

  8. Kinect V2 基础教程之彩色图像

    本程序为自己所写,参考素材包括微软官方例子和外文资料,自己做了部分的优化.解释的如果有问题,恳请大家指正. 后台代码: using System.ComponentModel; using Syste ...

  9. 使用NISI制作.Net程序服务安装包

    1.开篇之前先说一说NISI是什么. NSIS(Nullsoft Scriptable Install System)是一个开源的 Windows 系统下安装程序制作程序.它提供了安装.卸载.系统设置 ...

  10. 【Java每日一题】20161104

    package Nov2016; public class Ques1104 { private String num; public void setNum(String num){ num = n ...