最近项目需要实现一个下载模块,界面布局就采用常见的ListView方式,实现的界面效果:
可是在事件监听的过程中出现问题了,内部组件如Button无法捕获到点击事件OnClick : 这个问题还好解决,通过给Button设定
android:focusable="false"
然后给ListView的item布局文件的最顶层组件添加:
android:descendantFocusability="blocksDescendants"
这样就可以同时相应Button的点击事件和Item的点击事件了。
但是,在点击后面的下载按钮时,会出现同时有两个按钮状态发生变化,ListView的Adapter的代码如下:
private class DownloadListAdapter extends BaseAdapter{ private Context mContext; private LayoutInflater inflater; private List<Download> data; private int resource; public DownloadListAdapter(Context context, List<Download> data, int resource) { super(); mContext = context; inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); this.data = data; this.resource = resource; } @Override public int getCount() { return data.size(); } @Override public Object getItem(int position) { if(position < data.size()){ return data.get(position); } return null; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent){ final Download down = (Download)getItem(position); if(convertView == null){ convertView = inflater.inflate(resource, parent,false); ImageButton btn = (ImageButton)convertView.findViewById(R.id.down_pause); //添加事件监听 btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Log.d(TAG,"添加事件监听:"+ v.hashCode() +" - "+down.getId()); if(down.getStatus() == Downloader.STATUS_RUNNING){ Log.d(TAG, "暂停下载 : "+down.getId()); mDownloader.pause(down.getId()); down.setStatus(Downloader.STATUS_PAUSED); }else if(down.getStatus() == Downloader.STATUS_PAUSED){ Log.d(TAG, "继续下载 : "+down.getId()); mDownloader.continueDownload(down.getId()); down.setStatus(Downloader.STATUS_RUNNING); } //DownloadListAdapter.this.notifyDataSetChanged(); return ; } }); } TextView nameText = (TextView)convertView.findViewById(R.id.down_name); ProgressBar bar = (ProgressBar)convertView.findViewById(R.id.down_progress); ImageButton btn = (ImageButton)convertView.findViewById(R.id.down_pause); int progress = (int)(down.getDownloadSize()*100/down.getSize()); String name = down.getName(); nameText.setText(name); bar.setProgress(progress); Log.d(TAG, "状态:"+down.getStatus()); return convertView; }
事件监听器是在每个Item第一次初始化的时候添加的,而且也只添加了一次,同时日志跟踪,在点击最后一个按钮的时候,OnClick里面的日志也显示只调用了一次,但是界面的上的第一个按钮的状态也跟着发生变化。
纠结了很久都没弄清楚到底是哪里的问题。分析可能的原因:ImageButton btn =(ImageButton)convertView.findViewById(R.id.down_pause);是通过这种方式获得,而ListView里面所有的Item都共用一个布局文件,也就是上面的所有的convertView都是通过一个布局文件构造出来的,感觉这里会发生问题,但是貌似又没问题,在添加事件监听的过程中,打印的对应组件的hashCode又是不一样的,也就是每个按钮的事件监听器都是不一样的,这样分析之后又困惑了!
最后改用下面的方式解决问题了,关键部分代码如下:
@Override public View getView(int position, View convertView, ViewGroup parent){ final Download down = (Download)getItem(position); Holder holder = null; if(convertView == null){ convertView = inflater.inflate(resource, parent,false); holder = new Holder(); holder.text = (TextView)convertView.findViewById(R.id.down_name); holder.bar = (ProgressBar)convertView.findViewById(R.id.down_progress); holder.imageBtn = (ImageButton)convertView.findViewById(R.id.down_pause); convertView.setTag(holder); //添加事件监听 holder.imageBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Log.d(TAG,"添加事件监听:"+ v.hashCode() +" - "+down.getId()); if(down.getStatus() == Downloader.STATUS_RUNNING){ Log.d(TAG, "暂停下载 : "+down.getId()); mDownloader.pause(down.getId()); down.setStatus(Downloader.STATUS_PAUSED); }else if(down.getStatus() == Downloader.STATUS_PAUSED){ Log.d(TAG, "继续下载 : "+down.getId()); mDownloader.continueDownload(down.getId()); down.setStatus(Downloader.STATUS_RUNNING); } //DownloadListAdapter.this.notifyDataSetChanged(); return ; } }); }else{ holder = (Holder)convertView.getTag(); } int progress = (int)(down.getDownloadSize()*100/down.getSize()); String name = down.getName(); holder.text.setText(name); holder.bar.setProgress(progress); Log.d(TAG, "状态:"+down.getStatus()); return convertView; }
Holder定义如下:
class Holder { public TextView text; public ImageButton imageBtn; public ProgressBar bar; }
分析上面的代码,感觉没大的区别,虽然问题解决了,但是没搞懂为什么?
悲剧,在新插入item以后,问题又出现了!