zoukankan      html  css  js  c++  java
  • [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)项目

  • 相关阅读:
    Python正则匹配字母大小写不敏感在读xml中的应用
    Python中的正斜杠与反斜杠
    C# 向批处理文件输入字符
    推荐我看过的几本好书给大家(1)
    windows下mysqlpython安装出错
    PJBlog的文章转换成BlogEngine的xml格式文章
    测试Writer
    一个比较好用的DBHelper
    MSN 2009在2008下面的问题
    关于GridView中绑定TemplateField值丢失的问题
  • 原文地址:https://www.cnblogs.com/tiantianbyconan/p/4146512.html
Copyright © 2011-2022 走看看