Android ListView内部组件事件响应

最近项目需要实现一个下载模块,界面布局就采用常见的ListView方式,实现的界面效果:


可是在事件监听的过程中出现问题了,内部组件如Button无法捕获到点击事件OnClick : 这个问题还好解决,通过给Button设定

Xml代码 复制代码 收藏代码
  1. android:focusable="false" 

然后给ListView的item布局文件的最顶层组件添加:

Xml代码 复制代码 收藏代码
  1. android:descendantFocusability="blocksDescendants" 

这样就可以同时相应Button的点击事件和Item的点击事件了。

但是,在点击后面的下载按钮时,会出现同时有两个按钮状态发生变化,ListView的Adapter的代码如下:

Java代码 复制代码 收藏代码
  1. private class DownloadListAdapter extends BaseAdapter{ 
  2.         private Context mContext; 
  3.         private LayoutInflater inflater; 
  4.         private List<Download> data; 
  5.         private int resource; 
  6.          
  7.         public DownloadListAdapter(Context context, 
  8.                 List<Download> data, int resource) { 
  9.             super(); 
  10.             mContext = context; 
  11.             inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
  12.             this.data = data; 
  13.             this.resource = resource; 
  14.         } 
  15.          
  16.         @Override 
  17.         public int getCount() { 
  18.             return data.size(); 
  19.         } 
  20.          
  21.         @Override 
  22.         public Object getItem(int position) { 
  23.             if(position < data.size()){ 
  24.                 return data.get(position); 
  25.             } 
  26.             return null
  27.         } 
  28.          
  29.         @Override 
  30.         public long getItemId(int position) { 
  31.             return position; 
  32.         } 
  33.          
  34.         @Override 
  35.         public View getView(int position, View convertView, ViewGroup parent){ 
  36.             final Download down = (Download)getItem(position); 
  37.             if(convertView == null){ 
  38.                 convertView = inflater.inflate(resource, parent,false); 
  39.                  
  40.                 ImageButton btn = (ImageButton)convertView.findViewById(R.id.down_pause); 
  41.                 //添加事件监听 
  42.                 btn.setOnClickListener(new OnClickListener() { 
  43.                     @Override 
  44.                     public void onClick(View v) { 
  45.                         Log.d(TAG,"添加事件监听:"+ v.hashCode() +" - "+down.getId()); 
  46.                         if(down.getStatus() == Downloader.STATUS_RUNNING){ 
  47.                             Log.d(TAG, "暂停下载 : "+down.getId()); 
  48.                             mDownloader.pause(down.getId()); 
  49.                             down.setStatus(Downloader.STATUS_PAUSED); 
  50.                         }else if(down.getStatus() == Downloader.STATUS_PAUSED){ 
  51.                             Log.d(TAG, "继续下载 : "+down.getId()); 
  52.                             mDownloader.continueDownload(down.getId()); 
  53.                             down.setStatus(Downloader.STATUS_RUNNING); 
  54.                         } 
  55.                         //DownloadListAdapter.this.notifyDataSetChanged(); 
  56.                         return
  57.                     } 
  58.                 }); 
  59.             } 
  60.             TextView nameText = (TextView)convertView.findViewById(R.id.down_name); 
  61.             ProgressBar bar = (ProgressBar)convertView.findViewById(R.id.down_progress); 
  62.             ImageButton btn = (ImageButton)convertView.findViewById(R.id.down_pause); 
  63.              
  64.             int progress = (int)(down.getDownloadSize()*100/down.getSize()); 
  65.             String name = down.getName(); 
  66.              
  67.             nameText.setText(name); 
  68.             bar.setProgress(progress); 
  69.             Log.d(TAG, "状态:"+down.getStatus()); 
  70.              
  71.             return convertView; 
  72.         } 

事件监听器是在每个Item第一次初始化的时候添加的,而且也只添加了一次,同时日志跟踪,在点击最后一个按钮的时候,OnClick里面的日志也显示只调用了一次,但是界面的上的第一个按钮的状态也跟着发生变化。

纠结了很久都没弄清楚到底是哪里的问题。分析可能的原因:ImageButton btn =(ImageButton)convertView.findViewById(R.id.down_pause);是通过这种方式获得,而ListView里面所有的Item都共用一个布局文件,也就是上面的所有的convertView都是通过一个布局文件构造出来的,感觉这里会发生问题,但是貌似又没问题,在添加事件监听的过程中,打印的对应组件的hashCode又是不一样的,也就是每个按钮的事件监听器都是不一样的,这样分析之后又困惑了!

最后改用下面的方式解决问题了,关键部分代码如下:

Java代码 复制代码 收藏代码
  1. @Override 
  2.         public View getView(int position, View convertView, ViewGroup parent){ 
  3.             final Download down = (Download)getItem(position); 
  4.             Holder holder = null
  5.             if(convertView == null){ 
  6.                 convertView = inflater.inflate(resource, parent,false); 
  7.                  
  8.                 holder = new Holder(); 
  9.                 holder.text = (TextView)convertView.findViewById(R.id.down_name); 
  10.                 holder.bar = (ProgressBar)convertView.findViewById(R.id.down_progress); 
  11.                 holder.imageBtn = (ImageButton)convertView.findViewById(R.id.down_pause); 
  12.                  
  13.                 convertView.setTag(holder); 
  14.                  
  15.                 //添加事件监听 
  16.                 holder.imageBtn.setOnClickListener(new OnClickListener() { 
  17.                     @Override 
  18.                     public void onClick(View v) { 
  19.                         Log.d(TAG,"添加事件监听:"+ v.hashCode() +" - "+down.getId()); 
  20.                         if(down.getStatus() == Downloader.STATUS_RUNNING){ 
  21.                             Log.d(TAG, "暂停下载 : "+down.getId()); 
  22.                             mDownloader.pause(down.getId()); 
  23.                             down.setStatus(Downloader.STATUS_PAUSED); 
  24.                         }else if(down.getStatus() == Downloader.STATUS_PAUSED){ 
  25.                             Log.d(TAG, "继续下载 : "+down.getId()); 
  26.                             mDownloader.continueDownload(down.getId()); 
  27.                             down.setStatus(Downloader.STATUS_RUNNING); 
  28.                         } 
  29.                         //DownloadListAdapter.this.notifyDataSetChanged(); 
  30.                         return
  31.                     } 
  32.                 }); 
  33.             }else
  34.                 holder = (Holder)convertView.getTag(); 
  35.             } 
  36.              
  37.             int progress = (int)(down.getDownloadSize()*100/down.getSize()); 
  38.             String name = down.getName(); 
  39.              
  40.             holder.text.setText(name); 
  41.             holder.bar.setProgress(progress); 
  42.             Log.d(TAG, "状态:"+down.getStatus()); 
  43.  
  44.              
  45.             return convertView; 
  46.         } 

Holder定义如下:

Java代码 复制代码 收藏代码
  1. class Holder { 
  2.             public TextView text; 
  3.             public ImageButton imageBtn; 
  4.             public ProgressBar bar; 
  5.         } 

分析上面的代码,感觉没大的区别,虽然问题解决了,但是没搞懂为什么?

悲剧,在新插入item以后,问题又出现了!

转自:http://aswang.iteye.com/blog/1490245

原文地址:https://www.cnblogs.com/bmate/p/2674003.html