Android ListView2 加載圖片不錯位

用ListView用的也不少,但都因爲懶而沒有深入研究過具體實現,參考了下別人的研究成果,然後自己寫了個demo.

對於爲什麼要用ViewHold這個類,爲什麼會出現圖片閃現、錯位等狀況,可以用參考下面鏈接的分析

參考鏈接:http://www.cnblogs.com/lesliefang/p/3619223.html 

我從Adapter類的getView()開始分析,然後是強引用緩存,軟引用緩存,本地SDcard緩存,到異步加載圖片

@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		Viewhold viewhold;
		if (convertView == null) {
			convertView = inflater.inflate(R.layout.item_imagelist, null);
			viewhold = new Viewhold();
			viewhold.imageView = (ImageView) convertView
					.findViewById(R.id.imageView1);
			viewhold.textView = (TextView) convertView
					.findViewById(R.id.textView1);
			convertView.setTag(viewhold);
		} else {
			viewhold = (Viewhold) convertView.getTag();
		}
		viewhold.imageView.setTag(urls[position]);<span style="white-space:pre">			</span>//我給要顯示的ImageView組件設置一個標誌位,通過標誌位來判斷顯示圖片的ImageView是不是正在要顯示圖片的ImageView(感覺有點繞)
		viewhold.imageView.setImageResource(R.drawable.ic_launcher);
		LoadImage.loadimage(viewhold.imageView, urls[position]);<span style="white-space:pre">	</span>//此處顯示完成圖片的顯示
		viewhold.textView.setText("這是" + position + "副圖");
		return convertView;
	}

	class Viewhold {
		ImageView imageView;
		TextView textView;
	}


LoadImage類的分析:

public class LoadImage {


	public static void loadimage(ImageView imageview, String str) {
		Bitmap bitmap = null;
		// 從強引用中獲取圖片資源
		bitmap = lrucache.get(str);
		if (bitmap != null) {
			if (!imageview.getTag().equals(str)) { // 防止錯位和閃現
				return;
			}
			imageview.setImageBitmap(bitmap);
			return;
		}
		// 從軟應用中獲取圖片資源
		bitmap = getBitmapFromSoftCache(str);
		if (bitmap != null) {
			if (!imageview.getTag().equals(str)) {
				return;
			}
			imageview.setImageBitmap(bitmap);
			// 軟引用有此資源則應該添加到強引用中,將來獲取就可能從強引用中獲得了
			lrucache.put(str, bitmap);
			return;
		}
		// 從SDcard中獲取圖片資源
		bitmap = getBitmapFromSDcard(str);
		if (bitmap != null) {
			if (!imageview.getTag().equals(str)) {
				return;
			}
			imageview.setImageBitmap(bitmap);
			// 本地有此資源則應該添加到強引用中,將來獲取就可能從強引用中獲得了
			lrucache.put(str, bitmap);
			return;
		}
		// 異步加載圖片
		new DownImage(imageview, str).execute(str);


	}


	// 從SDcard獲取圖片的具體實現
	private static Bitmap getBitmapFromSDcard(String str) {
		File rootFile = Environment.getExternalStorageDirectory();
		File file = new File(rootFile, "mypics");
		if (!file.exists()) {
			file.mkdir();
		}
		File[] files = file.listFiles();
		if (files == null) {
			return null;
		}
		String[] split = str.split("/");
		String filename = split[split.length - 1];
		for (File file1 : files) {
			// 逐一匹配名字,滿足條件則返回
			if (file1.getName().equals(filename)) {
				return BitmapFactory.decodeFile(file1.getPath());
			}
		}
		return null;
	}


	// 強引用的申明,大小一般是用內存大小的1/8
	public static LruCache<String, Bitmap> lrucache = new LruCache<String, Bitmap>(
			(int) (Runtime.getRuntime().maxMemory() / 8)) {


		@Override
		protected void entryRemoved(boolean evicted, String key,
				Bitmap oldValue, Bitmap newValue) {
			if (evicted) {
				addsoftcache(key, oldValue);
			}
		}


		@Override
		protected int sizeOf(String key, Bitmap value) {
			// return value.getByteCount();從這個方法需要有版本要求,用下面方法間接得到圖片大小
			return value.getHeight() * value.getRowBytes();
		}


	};


	// 軟引用申明
	public static HashMap<String, SoftReference<Bitmap>> softcache = new HashMap<String, SoftReference<Bitmap>>();


	// 從軟引用中得到圖片資源的具體實現
	public static Bitmap getBitmapFromSoftCache(String str) {
		// 曾經我在這裏摔了一跤,我得到圖片直接用softcache.get(str).get(),結果報空指針異常,我還納悶了半天
		// 需要對獲得的軟引用進行空指針判斷,避免空指針,不必要的錯誤
		SoftReference<Bitmap> softReference = softcache.get(str);
		if (softReference != null) {
			Bitmap bitmap = softReference.get();
			if (bitmap != null) {
				return bitmap;
			}
		}
		return null;
	}


	// 添加到軟應用中
	public static void addsoftcache(String str, Bitmap bitmap) {
		softcache.put(str, new SoftReference<Bitmap>(bitmap));
	}


	// 添加資源到強引用中,在異步加載時,軟引用,sdcard有資源時需要調用
	public static void addToLruCache(String str, Bitmap bitmap) {
		lrucache.put(str, bitmap);
	}
}


異步加載的分析


public class DownImage extends AsyncTask<String, Void, Bitmap> {
	ImageView imageview;
	String urlstr;


	public DownImage(ImageView imageview, String urlstr) {
		this.imageview = imageview;
		this.urlstr = urlstr;
	}


	// 在工作線程中實現圖片的下載操作,同時將結果返回到onPostExecute()中
	@Override
	protected Bitmap doInBackground(String... params) {
		try {
			URL url1 = new URL(params[0]);
			HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
			InputStream is = conn.getInputStream();
			Bitmap bitmap = BitmapFactory.decodeStream(is);
			saveBitmapToSDcard(bitmap, params[0]);
			LoadImage.addToLruCache(params[0], bitmap);
			return bitmap;
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}


	@Override
	protected void onPostExecute(Bitmap result) {
		if (!imageview.getTag().equals(urlstr)) {
			return;
		}
		imageview.setImageBitmap(result);
		saveBitmapToSDcard(result, urlstr);
		LoadImage.addToLruCache(urlstr, result);
		super.onPostExecute(result);
	}


	// 保存到SDcard的具體實現
	public static void saveBitmapToSDcard(Bitmap bitmap, String str) {
		File rootFile = Environment.getExternalStorageDirectory();
		File file = new File(rootFile, "mypics");
		if (!file.exists()) {
			file.mkdir();
		}
		String[] split = str.split("/");
		String filename = split[split.length - 1];
		File file2 = new File(file, filename);
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(file2);
			bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
		} catch (FileNotFoundException e) {
		} finally {
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
				}
			}


		}


	}
}

有錯誤大家一起糾正呀,哈哈哈
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章