對於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實現多任務多線程下載》的例子中的,如果需要可以去下載。