你的位置:首页 > 操作系统

[操作系统]ListView实现Item局部刷新


   对于ListView数据的刷新大家都知道,改变Adapter的数据源,然后调用Adapter的notifyDateSetChanged()方法即可。

  但是博主在做公司项目的时候,有个下载模块,因为可能同时下载好几个数据,所以用的listview展示所有正在下载的内容。因为下载进度要实时更新,所以要不停的调用notifyDateSetChanged刷新数据。这样会不停的重新绘制整个listview的界面,性能开销非常大。而且如果每个item有图片的话,每个item的图片都需要重新加载,就算图片做了内存缓存,刷新一下图片也会闪一下,不停的刷新就会导致各个item的图片不停的闪,体验一点都不好。

  那么对于上面问题,有没有解决办法呢?当然是有的。我们可以针对某一个item进行局部更新,而不影响其它没有修改的item。那么具体如何实现的呢?我们看下面的代码。

 1   private void updateView(int itemIndex) { 2     //得到第一个可显示控件的位置, 3     int visiblePosition = mListView.getFirstVisiblePosition(); 4     //只有当要更新的view在可见的位置时才更新,不可见时,跳过不更新 5     if (itemIndex - visiblePosition >= 0) { 6       //得到要更新的item的view 7       View view = mListView.getChildAt(itemIndex - visiblePosition); 8       //调用adapter更新界面 9       mAdapter.updateView(view, itemIndex);10     }11   }

  这个函数主要是根据传入的itemIndex来获取第itemIndex的数据所显示的view。itemIndex就是要修改的数据再List集合中的位置,比如我这里下载进度有更新,发了一个广播这里接收到了,需要修改该下载内容的进度条,广播接收器可以这么写:

 1     @Override 2     public void onReceive(Context context, Intent intent) { 3       AppContent appContent = intent.getParcelableExtra("appContent"); 4       if(appContent == null) return; 5       int itemIndex = 0; 6       for(AppContent appContent1 : mList) { 7         if(appContent.getUrl().equals(appContent1.getUrl())) { 8           itemIndex = mList.indexOf(appContent1); 9           appContent1.setDownloadPercent(appContent.getDownloadPercent());10           break;11         }12       }13       updateView(itemIndex);14     }

  下面看Adapter的具体代码:

 1 public class AppContentAdapter extends BaseAdapter{ 2  3   private List<AppContent> mDates = null; 4   private Context mContext; 5  6   public AppContentAdapter(Context context) { 7     this.mContext = context; 8   } 9  10   @Override 11   public int getCount() { 12     return mDates.size(); 13   } 14  15   @Override 16   public Object getItem(int position) { 17     return mDates.get(position); 18   } 19  20   @Override 21   public long getItemId(int position) { 22     return position; 23   } 24  25   public void setDates(List<AppContent> mDates) { 26     this.mDates = mDates; 27   } 28  29   @Override 30   public View getView(int position, View convertView, ViewGroup parent) { 31     ViewHolder holder = null; 32     if (convertView == null) { 33       holder = new ViewHolder(); 34       convertView = LayoutInflater.from(mContext).inflate( 35           R.layout.listitem_download, null); 36       holder.statusIcon = (DownloadPercentView) convertView.findViewById(R.id.status_icon); 37       holder.name = (TextView) convertView.findViewById(R.id.name); 38       holder.downloadPercent = (TextView) convertView.findViewById(R.id.download_percent); 39       holder.progressBar = (ProgressBar) convertView.findViewById(R.id.progressbar); 40       convertView.setTag(holder); 41     } else { 42       holder = (ViewHolder) convertView.getTag(); 43     } 44     setData(holder, position); 45     return convertView; 46   } 47  48   /** 49    * 设置viewHolder的数据 50    * @param holder 51    * @param itemIndex 52   */ 53   private void setData(ViewHolder holder, int itemIndex) { 54     AppContent appContent = mDates.get(itemIndex); 55     holder.name.setText(appContent.getName()); 56     holder.progressBar.setProgress(appContent.getDownloadPercent()); 57     setIconByStatus(holder.statusIcon, appContent.getStatus()); 58     if(appContent.getStatus() == AppContent.Status.PENDING) { 59       holder.downloadPercent.setVisibility(View.INVISIBLE); 60     } else { 61       holder.downloadPercent.setVisibility(View.VISIBLE); 62       holder.statusIcon.setProgress(appContent.getDownloadPercent()); 63       holder.downloadPercent.setText("下载进度:" + appContent.getDownloadPercent() + "%"); 64     } 65   } 66  67  68   /** 69    * 局部刷新 70    * @param view 71    * @param itemIndex 72   */ 73   public void updateView(View view, int itemIndex) { 74     if(view == null) { 75       return; 76     } 77     //从view中取得holder 78     ViewHolder holder = (ViewHolder) view.getTag(); 79     holder.statusIcon = (DownloadPercentView) view.findViewById(R.id.status_icon); 80     holder.name = (TextView) view.findViewById(R.id.name); 81     holder.downloadPercent = (TextView) view.findViewById(R.id.download_percent); 82     holder.progressBar = (ProgressBar) view.findViewById(R.id.progressbar); 83     setData(holder, itemIndex); 84   } 85  86   /** 87    * 根据状态设置图标 88    * @param downloadPercentView 89    * @param status 90   */ 91   private void setIconByStatus(DownloadPercentView downloadPercentView, AppContent.Status status) { 92     downloadPercentView.setVisibility(View.VISIBLE); 93     if(status == AppContent.Status.PENDING) { 94       downloadPercentView.setStatus(DownloadPercentView.STATUS_PEDDING); 95     } 96     if(status == AppContent.Status.DOWNLOADING) { 97       downloadPercentView.setStatus(DownloadPercentView.STATUS_DOWNLOADING); 98     } 99     if(status == AppContent.Status.WAITING) {100       downloadPercentView.setStatus(DownloadPercentView.STATUS_WAITING);101     }102     if(status == AppContent.Status.PAUSED) {103       downloadPercentView.setStatus(DownloadPercentView.STATUS_PAUSED);104     }105     if(status == AppContent.Status.FINISHED) {106       downloadPercentView.setStatus(DownloadPercentView.STATUS_FINISHED);107     }108   }109 110   private class ViewHolder {111     private DownloadPercentView statusIcon;112     private TextView name;113     private TextView downloadPercent;114     private ProgressBar progressBar;115   }116 }

  其实这些代码就是我上篇博文《AsyncTask实现多任务多线程下载》的例子中的,如果需要可以去下载。