Android&listView控件中图像的异步加载


在此先列出参考过的博客:

http://www.iteye.com/topic/685986

http://blog.orange11.nl/2009/09/17/exploring-the-world-of-android-part-2/

http://codehenge.net/blog/2011/06/android-development-tutorial-asynchronous-lazy-loading-and-caching-of-listview-images/


最近在试着自己做一个weibo的android app,用以巩固下已经学过的知识以及尝试下新的东西。在做的过程中碰到了图片异步下载、加载的问题,在网上查了些资料,然后自己动手做了下实验,现在将所学到的东西记录在这里以便以后查阅。


现在的需求是,ListView 的每行既有图片又有文字,这些资源都需要从网上下载然后再加载到界面上。文本的下载速度很快,可以很快的显示,但是图片比较大,如果网络环境不好,会耗很多时间。为了有好的体验,文字要先显示,图片资源异步下载完成后再显示。

那么如何实现呢?

1、listview显示数据需要用到Adapter,而Adapter中控制界面元素显示的是getView()方法;

2、getView()方法会返回一个View,也就是每一行的视图,需要设置的ImageView就在这个View中;

3、这个方法应该尽快的返回,不能因为图片的下载而阻塞,否则列表中没有内容显示,于是图片需要异步下载;

4、但是与每一行相关联的图片在getView()方法中就需要设置好,这里我们需要获得相关的ImageView的引用以便以后在设置与图片的关联;

5、和界面有关的改变需要在主线程也就是UI线程中设置,那么getView方法是否在主线程中呢?当然。


图片的异步下载很简单,你可以用AsyncTask也可以另开工作线程完成,在此我就用上面blog中用的方法

public class AsyncImageLoader {
	private HashMap<String, SoftReference<Drawable>> imageCache;
	public AsyncImageLoader(){
		imageCache = new HashMap<String, SoftReference<Drawable>>();
	}
	public Drawable loadDrawable(final String imageUrl,final ImageCallback imageCallback){

		if(imageCache.containsKey(imageUrl)){
			SoftReference<Drawable> softReference = imageCache.get(imageUrl);
			Drawable drawable = softReference.get();
			if(drawable != null){
				return drawable;
			}
		}

		final Handler handler = new Handler(){
			public void handleMessage(Message msg) {
				imageCallback.imageLoaded((Drawable)msg.obj, imageUrl);
			}	
		};
		new Thread("img"){
			public void run() {
				Bitmap bitmap = ImgUtil.downloadImageFromUrl(imageUrl);//根据url下载图片
				if(bitmap == null){
					return;
				}
				Drawable drawable = new BitmapDrawable(context.getResources(),bitmap);
				imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));
				Message message = handler.obtainMessage(0, drawable);
				handler.sendMessage(message);
			}
		}.start();
		return null;
	}
	
	public interface ImageCallback{
		public void imageLoaded(Drawable imageDrawable, String imageUrl);
	}
}
这里只是给了个大概的框架,便于说明。

上面的代码比较好理解,主要就是loadDrawable这个函数,他另外开了个线程用来下载图片,然后通过message,触发handler里的响应,执行接口里的方法。这里他为什么要大费周折的用到handler呢?因为只有在UI线程中才能改变界面中的显示,而handler是附属与它声明的这个类执行的线程的,在handler里触发执行的方法都是在它附属的那个线程下执行的,在后面的代码中我们可以知道loadDrawable方法是在主线程中执行的。

public View getView(int position, View convertView, ViewGroup parent) {
		View row = convertView;
		if(row == null){
			LayoutInflater inflater = (LayoutInflater)mContext.getSystemService
				      (Context.LAYOUT_INFLATER_SERVICE);
			row = inflater.inflate(R.layout.row, parent,false);
		}
		Holder holder = (Holder) row.getTag();
		if(holder == null){
			holder = new Holder(row);
			row.setTag(holder);
		}
		final String url = listContent.get(position).get("url");
		holder.testimg.setTag(url);
		Drawable cachedimg = async.loadDrawable(url, new ImageCallback() {
			
			public void imageLoaded(Drawable imageDrawable, String imageUrl) {
				ImageView viewBytag = (ImageView) mList.findViewWithTag(url);
				if(viewBytag != null){
					viewBytag.setImageDrawable(imageDrawable);
					Log.v("useimg", "inasync");
				}
			}
		});
		if(cachedimg == null)
			holder.testimg.setImageDrawable(null);
		else
			holder.testimg.setImageDrawable(cachedimg);	
		return row;
	}

这里就是getView方法的实现,我们主要还是关注图片的异步加载,我们可以发现在接口的实现里我们用    ImageView viewBytag = (ImageView) mList.findViewWithTag(url);

获得了与这个图像关联的imageView的引用,然后在接口中我们对imageView的图像资源进行了set。就像上面的一个blog中说的那样,获得这个引用的才是精华,只要获得了引用,设置什么的都好说。


在做这个的时候,异步下载已经不是问题,但是总是想不出怎么异步加载图片,现在看来,还是得灵活的运用面向对象中的各种元素才行。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值