[Android]在Adapter的getView方法中绑定OnClickListener比较好的方法

简介:

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

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

 

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

复制代码
 1 public View getView(int positon, View convertView, ViewGroup parent){
 2     if(null == convertView){
 3         convertView = LayoutInflater.from(context).inflate(R.layout.item, null);
 4     }
 5 
 6     Button button = ABViewUtil.obtainView(convertView, R.id.item_btn);
 7     button.setOnClickListener(new View.OnClickListener(){
 8         @Override
 9         public void onClick(View v){
10             Toast.makeText(context, "position: " + position, Toast.LENGTH_SHORT).show();
11         }
12     });
13 
14 }
复制代码

然后运行,当然没问题。

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

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

复制代码
 1 public View getView(int positon, View convertView, ViewGroup parent){
 2     if(null == convertView){
 3         convertView = LayoutInflater.from(context).inflate(R.layout.item, null);
 4         Button button = ABViewUtil.obtainView(convertView, R.id.item_btn);
 5         button.setOnClickListener(new View.OnClickListener(){
 6             @Override
 7             public void onClick(View v){
 8                 Toast.makeText(context, "position: " + position, Toast.LENGTH_SHORT).show();
 9             }
10         });
11     }
12 }
复制代码

这个代码看上去没什么问题,但是问题就在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中保存,所以代码演化到如下:

复制代码
 1 public View getView(int positon, View convertView, ViewGroup parent){
 2     if(null == convertView){
 3         convertView = LayoutInflater.from(context).inflate(R.layout.item, null);
 4         Button button = ABViewUtil.obtainView(convertView, R.id.item_btn);
 5         button.setOnClickListener(new OnConvertViewClickListener(convertView, R.id.ab__id_adapter_item_position){
 6                 @Override
 7                 public void onClickCallBack(View registedView, int... positionIds){
 8                     Toast.makeText(context, "position: " + positionIds[0], Toast.LENGTH_SHORT).show();
 9                 }
10         });
11     }
12     convertView.setTag(R.id.ab__id_adapter_item_position, position);
13 }
复制代码

就像上面第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)项目

本文转自天天_byconan博客园博客,原文链接:http://www.cnblogs.com/tiantianbyconan/p/4146512.html ,如需转载请自行联系原作者
相关文章
|
4月前
|
存储 Shell Android开发
基于Android P,自定义Android开机动画的方法
本文详细介绍了基于Android P系统自定义开机动画的步骤,包括动画文件结构、脚本编写、ZIP打包方法以及如何将自定义动画集成到AOSP源码中。
93 2
基于Android P,自定义Android开机动画的方法
|
4月前
|
Android开发
基于android-11.0.0_r39,系统应用的手动签名方法和过程
本文介绍了基于Android 11.0.0_r39版本进行系统应用手动签名的方法和解决签名过程中遇到的错误,包括处理`no conscrypt_openjdk_jni-linux-x86_64`和`RegisterNatives failed`的问题。
229 2
|
2月前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
81 15
Android 系统缓存扫描与清理方法分析
|
3月前
|
ARouter 测试技术 API
Android经典面试题之组件化原理、优缺点、实现方法?
本文介绍了组件化在Android开发中的应用,详细阐述了其原理、优缺点及实现方式,包括模块化、接口编程、依赖注入、路由机制等内容,并提供了具体代码示例。
51 2
|
4月前
|
Android开发
Android在rootdir根目录创建自定义目录和挂载点的方法
本文介绍了在Android高通平台的根目录下创建自定义目录和挂载点的方法,通过修改Android.mk文件并使用`LOCAL_POST_INSTALL_CMD`变量在编译过程中添加目录,最终在ramdisk.img的系统根路径下成功创建了`/factory/bin`目录。
240 1
|
4月前
|
开发工具 uml git
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82
本文分享了下载AOSP源码的方法,包括如何使用repo工具和处理常见的repo sync错误,以及配置Python环境以确保顺利同步特定版本的AOSP代码。
602 0
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82
|
4月前
|
Android开发
Android项目架构设计问题之onFirstItemVisibleChanged方法的调用如何解决
Android项目架构设计问题之onFirstItemVisibleChanged方法的调用如何解决
43 0
|
4月前
|
Java 测试技术 Android开发
Android项目架构设计问题之使用反射调用类的私有方法如何解决
Android项目架构设计问题之使用反射调用类的私有方法如何解决
48 0
|
5月前
|
Android开发
Android面试题之View的invalidate方法和postInvalidate方法有什么区别
本文探讨了Android自定义View中`invalidate()`和`postInvalidate()`的区别。`invalidate()`在UI线程中刷新View,而`postInvalidate()`用于非UI线程,通过消息机制切换到UI线程执行`invalidate()`。源码分析显示,`postInvalidate()`最终调用`ViewRootImpl`的`dispatchInvalidateDelayed`,通过Handler发送消息到UI线程执行刷新。
64 1
|
5月前
|
消息中间件 调度 Android开发
Android经典面试题之View的post方法和Handler的post方法有什么区别?
本文对比了Android开发中`View.post`与`Handler.post`的使用。`View.post`将任务加入视图关联的消息队列,在视图布局后执行,适合视图操作。`Handler.post`更通用,可调度至特定Handler的线程,不仅限于视图任务。选择方法取决于具体需求和上下文。
63 0