ListView中含有Button时setOnclickListener应写在Adapter的什么地方

做Android开发,ListView是最常见不过了,因此对于ListView的自定义Adapter写法,应该也非常的熟悉,高效的Adapter编码,会使得携带大量ListView的数据展现显得非常容易。关于Adapter的写法,网上也有很多的例子,在此不再唠叨。为了提高ListView重绘时对已有对象的复用大抵是这样的:

 

  1. @Override  
  2. public View getView(final int position, View convertView, ViewGroup parent) {  
  3.     ViewHolder holder = null;  
  4.     if (convertView == null) {  
  5.         convertView = View.inflate(mContext, R.layout.listview_item, null);  
  6.         holder = new ViewHolder();  
  7.         holder.no = (TextView) convertView.findViewById(R.id.no);  
  8.         holder.click = (TextView) convertView.findViewById(R.id.click);  
  9.         convertView.setTag(holder);  
  10.     } else {  
  11.         holder = (ViewHolder) convertView.getTag();  
  12.     }  
  13.     String value = list.get(position);  
  14.     holder.no.setText(value);  
  15.       
  16.     OnClick listener = new OnClick(position);  
  17.     holder.click.setOnClickListener(listener);  
  18.       
  19.     Log.d(TAG,  
  20.             "position is " + position + " listener is "  
  21.                     + listener.toString());  
  22.     return convertView;  
  23. }  

在这里我们讨论的是在ListView当中含有需要处理OnClick事件的写法,之前也写过一篇关于ListView当中含有Spinner的处理情况,这篇文章讲了如何处理Spinner的Onlick事件和对其状态的保持。虽然Onclick事件处理的比较高效,但是在方法上还有待提高。以下文章将列举出网上关于ListView中含有Onclick事件需要处理的普遍写法和本文的重点推荐高效写法。

 

普遍写法:

 

  1. package com.yang.listviewclick.adapter;  
  2.   
  3. import java.util.List;  
  4.   
  5. import android.content.Context;  
  6. import android.util.Log;  
  7. import android.view.View;  
  8. import android.view.ViewGroup;  
  9. import android.view.View.OnClickListener;  
  10. import android.widget.BaseAdapter;  
  11. import android.widget.TextView;  
  12.   
  13. import com.yang.listviewclick.R;  
  14.   
  15. public class IneffectiveListViewAdapter extends BaseAdapter {  
  16.     private Context mContext;  
  17.     private List<String> list = null;  
  18.   
  19.     private static final String TAG = "ListViewAdapter";  
  20.   
  21.     public IneffectiveListViewAdapter(Context mContext, List<String> list) {  
  22.         this.mContext = mContext;  
  23.         this.list = list;  
  24.     }  
  25.   
  26.     @Override  
  27.     public int getCount() {  
  28.         return list.size();  
  29.     }  
  30.   
  31.     @Override  
  32.     public Object getItem(int position) {  
  33.         return list.get(position);  
  34.     }  
  35.   
  36.     @Override  
  37.     public long getItemId(int position) {  
  38.         return 0;  
  39.     }  
  40.   
  41.     class ViewHolder {  
  42.         TextView no;  
  43.         TextView click;  
  44.     }  
  45.   
  46.     @Override  
  47.     public View getView(final int position, View convertView, ViewGroup parent) {  
  48.         ViewHolder holder = null;  
  49.         if (convertView == null) {  
  50.             convertView = View.inflate(mContext, R.layout.listview_item, null);  
  51.             holder = new ViewHolder();  
  52.             holder.no = (TextView) convertView.findViewById(R.id.no);  
  53.             holder.click = (TextView) convertView.findViewById(R.id.click);  
  54.             convertView.setTag(holder);  
  55.         } else {  
  56.             holder = (ViewHolder) convertView.getTag();  
  57.         }  
  58.         String value = list.get(position);  
  59.         holder.no.setText(value);  
  60.         //问题出在这里,对于每次重绘,都新建了一个listener对象进行处理  
  61.         OnClick listener = new OnClick(position);  
  62.         holder.click.setOnClickListener(listener);  
  63.           
  64.         Log.d(TAG,  
  65.                 "position is " + position + " listener is "  
  66.                         + listener.toString());  
  67.         return convertView;  
  68.     }  
  69.   
  70.     class OnClick implements OnClickListener {  
  71.         private int position;  
  72.         public OnClick(int position){  
  73.             this.position = position;  
  74.         }  
  75.         @Override  
  76.         public void onClick(View v) {  
  77.             Log.d(TAG, list.get(position));  
  78.         }  
  79.     }  
  80. }  

这种写法能够实现基本功能,即在点击某个组件时,它能够准确的定位到所点击的那个条目,并作出相应的处理。那么这是一种高效的写法吗?我们打印以下它的listener.

 


大家知道

 

  1. position is 19 listener is com.yang.listviewclick.adapter.IneffectiveListViewAdapter$OnClick@4057f250  

@后面的值是这个对象的HashCode,对于不同的对象来说,其HashCode是不同的,而这里打印出来的所有HashCode都不相同,说明每次拖动ListView,其会对每个条目重新申请一个对象,而且这些对象不是复用的,是全新的对象。你可以想象以下,如果有一千个条目,这拖动一次就是一千个对象,而且你再回到顶部又是一千个对象,效率可见一斑。

 

推荐写法:

 

  1. package com.yang.listviewclick.adapter;  
  2.   
  3. import java.util.List;  
  4.   
  5. import com.yang.listviewclick.R;  
  6.   
  7. import android.content.Context;  
  8. import android.util.Log;  
  9. import android.view.View;  
  10. import android.view.View.OnClickListener;  
  11. import android.view.ViewGroup;  
  12. import android.widget.BaseAdapter;  
  13. import android.widget.TextView;  
  14.   
  15. public class EffectiveListViewAdapter extends BaseAdapter {  
  16.     private Context mContext;  
  17.     private List<String> list = null;  
  18.   
  19.     private static final String TAG = "ListViewAdapter";  
  20.   
  21.     public EffectiveListViewAdapter(Context mContext, List<String> list) {  
  22.         this.mContext = mContext;  
  23.         this.list = list;  
  24.     }  
  25.   
  26.     @Override  
  27.     public int getCount() {  
  28.         return list.size();  
  29.     }  
  30.   
  31.     @Override  
  32.     public Object getItem(int position) {  
  33.         return list.get(position);  
  34.     }  
  35.   
  36.     @Override  
  37.     public long getItemId(int position) {  
  38.         return 0;  
  39.     }  
  40.   
  41.     class ViewHolder {  
  42.         TextView no;  
  43.         TextView click;  
  44.     }  
  45.   
  46.     @Override  
  47.     public View getView(final int position, View convertView, ViewGroup parent) {  
  48.         ViewHolder holder = null;  
  49.         OnClick listener = null;  
  50.         if (convertView == null) {  
  51.             convertView = View.inflate(mContext, R.layout.listview_item, null);  
  52.             holder = new ViewHolder();  
  53.             holder.no = (TextView) convertView.findViewById(R.id.no);  
  54.             holder.click = (TextView) convertView.findViewById(R.id.click);  
  55.             listener = new OnClick();//在这里新建监听对象  
  56.             holder.click.setOnClickListener(listener);  
  57.             convertView.setTag(holder);  
  58.             convertView.setTag(holder.click.getId(), listener);//对监听对象保存  
  59.         } else {  
  60.             holder = (ViewHolder) convertView.getTag();  
  61.             listener = (OnClick) convertView.getTag(holder.click.getId());//重新获得监听对象  
  62.         }  
  63.         String value = list.get(position);//设置监听对象的值  
  64.         holder.no.setText(value);  
  65.         listener.setPosition(position);  
  66.         Log.d(TAG,  
  67.                 "position is " + position + " listener is "  
  68.                         + listener.toString());  
  69.         return convertView;  
  70.     }  
  71.   
  72.     class OnClick implements OnClickListener {  
  73.         int position;  
  74.   
  75.         public void setPosition(int position) {  
  76.             this.position = position;  
  77.         }  
  78.   
  79.         @Override  
  80.         public void onClick(View v) {  
  81.             Log.d(TAG, list.get(position));  
  82.         }  
  83.     }  
  84.   
  85. }  

打印以下Listener

 



大家可以看到,这里监听对象实现了复用。每次滑动都是第一次创建的监听对象的复用。

实现这种机制的关键就是,使用convertView.setTag(holder.click.getId(), listener);对已有的对象进行保存,同时在使用时,使用listener = (OnClick) convertView.getTag(holder.click.getId())再获得这些对象。同时对这些复用的对象赋予不同的值listener.setPosition(position);。好了,今天就说到这里,测试项目的下载地址如下。

原文地址:https://www.cnblogs.com/LiaoHao/p/3366055.html