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) {
				}
			}


		}


	}
}

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