天天看點

android 解決listview.notifyDataSetChanged重新整理時Imageloader加載圖檔閃爍問題

今天,簡單講講android裡再listview調用notifyDataSetChanged重新整理界面時,Imageloader加載圖檔會閃爍的問題。

最近,發現app裡的listview圖檔會出現閃爍的情況。我發現是由于調用notifyDataSetChanged這個方法時候,圖檔全部閃爍一下,原因是圖檔全部重新加載了一次,導緻閃爍。後來修改為局部重新整理,但是還是還是存在是不是閃爍的情況,于是在網上查找資料,最終解決了問題。這裡記錄一下。

一.網上無用的解決代碼

網上關于圖檔閃爍的解決代碼很多,但是大多不是我想要的。比如有人說:

    真正的閃爍原因不是display和imageload方法的緣故,而是在設定option時,設定了.displayer(new FadeInBitmapDisplayer(200))的緣故,直接設定為.displayer(new SimpleBitmapDisplayer()),然後再getview方法中調用display方法,就不會閃爍了.這個我試過了,沒有一點效果。

還有人說:

在一個頻繁重新整理的ListView中使用ImageLoader後,在某些手機上會發現圖檔閃動。經過分析,原來是DisplayImageOptions的問題。

之前的DisplayImageOptions是這樣寫的:

imageOptions = new DisplayImageOptions.Builder().bitmapConfig(Bitmap.Config.RGB_565).showStubImage(R.drawable.icon_default)  
                     .showImageForEmptyUri(R.drawable.icon_default).showImageOnFail(R.drawable.icon_default).cacheInMemory(true)  
                     .cacheOnDisc(true).build();             

其中的showStubImage()造成了加載前先顯示預設圖檔的問題,造成了閃動。修改為以下代碼後就正常了:

imageOptions = new DisplayImageOptions.Builder().bitmapConfig(Bitmap.Config.RGB_565)  
                     .showImageForEmptyUri(R.drawable.icon_default).showImageOnFail(R.drawable.icon_default).cacheInMemory(true)  
                     .cacheOnDisc(true).build();             

這個隻是解決加載圖檔前顯示預設加載圖檔的問題,和我的因為頻繁重新整理導緻的問題不一樣。

二.解決問題的代碼

下面是我之前的getView方法中。下面的ImageLoader直接調用,造成每次notifyDataSetChanged,重新調用了ImageLoader方法。

@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		ViewHolder holder;
		if (convertView == null) {
			convertView = LayoutInflater.from(context).inflate(R.layout.item_app_wall2, parent, false);
			holder = new ViewHolder();
			holder.icon = (ImageView) convertView.findViewById(R.id.app_icon);
			holder.name = (MarqueeText) convertView.findViewById(R.id.app_name);
			// holder.grade = (ImageView)
			// convertView.findViewById(R.id.grade);
			holder.size = (TextView) convertView.findViewById(R.id.app_size);
			holder.count = (TextView) convertView.findViewById(R.id.app_count);
			holder.ratingBar = (RatingBar) convertView.findViewById(R.id.grade);
			convertView.setTag(holder);
		} else {
			holder = (ViewHolder) convertView.getTag();
		}
		ImageLoader.getInstance().displayImage(searchAppList.get(position).getHttpIco(), holder.icon,
				DisplayImageOptionUtil.getInstance().getOptions());
		holder.name.setText(searchAppList.get(position).getName().trim());
		holder.size.setText(CommonUtil.format(searchAppList.get(position).getApkSize() / (float) 1024) + "M");
		AppStatistics statistics = searchAppList.get(position).getAppStatistics();
		if (statistics != null) {
			holder.count.setText(statistics.getDownloadCount() + "次");
		}
		holder.ratingBar.setRating(searchAppList.get(position).getAveccore() / 2f);
		return convertView;
	}           

下面我做出了修改,如果目前圖檔是之前的圖檔,則不會調用ImageLoader,否則調用ImageLoader。

public View getView(int position, View convertView, ViewGroup parent) {
		ViewHolder holder;
		if (convertView == null) {
			convertView = LayoutInflater.from(context).inflate(R.layout.item_app_wall2, parent, false);
			holder = new ViewHolder();
			holder.icon = (ImageView) convertView.findViewById(R.id.app_icon);
			holder.name = (MarqueeText) convertView.findViewById(R.id.app_name);
			// holder.grade = (ImageView)
			// convertView.findViewById(R.id.grade);
			holder.size = (TextView) convertView.findViewById(R.id.app_size);
			holder.count = (TextView) convertView.findViewById(R.id.app_count);
			holder.ratingBar = (RatingBar) convertView.findViewById(R.id.grade);
			convertView.setTag(holder);
		} else {
			holder = (ViewHolder) convertView.getTag();
		}
		if (searchAppList.get(position).getHttpIco().equals(holder.icon.getTag())) {
		} else {
			// 如果不相同,就加載。現在在這裡來改變閃爍的情況
			ImageLoader.getInstance().displayImage(searchAppList.get(position).getHttpIco(), holder.icon,
					DisplayImageOptionUtil.getInstance().getOptions());
			holder.icon.setTag(searchAppList.get(position).getHttpIco());
		}
		holder.name.setText(searchAppList.get(position).getName().trim());
		holder.size.setText(CommonUtil.format(searchAppList.get(position).getApkSize() / (float)1024) + "M");
		AppStatistics statistics = searchAppList.get(position).getAppStatistics();
		if (statistics != null){
			holder.count.setText(statistics.getDownloadCount() + "次");
		}
		holder.ratingBar.setRating(searchAppList.get(position).getAveccore() / 2f);
		return convertView;
}           

通過ImageView.getTag和setTag方法來,判定目前圖檔是否是之前的,如果是之前,則不會重新整理圖檔,如果不是,再重新整理。

簡單講講,其實就是在每次getView時,ImageView通過setTag将家中圖檔的路徑儲存起來,當調用notifyDataSetChanged時,需要重新整理界面,首先判斷需要重新加載的圖檔路徑和ImageView.getTag是否相同,如果相同,就不需要重新加載,這樣避免了無用的重複加載相同圖檔。

android 解決listview.notifyDataSetChanged重新整理時Imageloader加載圖檔閃爍問題就講完了。

就這麼簡單。