`

高效率下载图片——防止内存溢出

 
阅读更多

在应用中经常需要下载很多的图片,因此,写好图片下载部分的代码非常关键。不好的代码很容易创建太多的对象,导致经常执行GC,接着就出现了ANR;也很容易导致内存溢出OOM。

 

现在,我从防止ANR和OOM的角度写下载图片的代码。再来分析一下需求,当我需要为图片列表下载很多张图片时,我期望图片是有顺序地一张一张显示,而不是开启很多线程同时下载多张图片(注意:这样也会影响每个线程的执行速度)。

 

 

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;

public class ImageDownloadThread extends Thread {
	//单例类
	private ImageDownloadThread() {}
	private static ImageDownloadThread imageDownloadThread = null;
	public static ImageDownloadThread getInstance() {
		if (imageDownloadThread == null) {
			imageDownloadThread = new ImageDownloadThread();
			imageDownloadThread.start();//创建后立刻运行
		}
		return imageDownloadThread;
	}
	
	//缓存下载图片
	private Map<String, String> cache = new HashMap<String, String>();//KEY:图片URL;VALUE:下载后的图片路径
	public boolean isDownload(String imageUrl) {
		return cache.containsKey(imageUrl);
	}
	public Bitmap downloadWithCache(ImageDownloadItem item) {
		if (cache.containsKey(item.imageUrl)) {
			Bitmap bitmap = BitmapFactory.decodeFile(cache.get(item.imageUrl));
			return bitmap;
		} else {
			addDownloadItem(item);
		}
		return null;
	}
	public void downloadWithoutCache(ImageDownloadItem item) {
		addDownloadItem(item);
	}

	//下载队列
	private List<ImageDownloadItem> queue = new ArrayList<ImageDownloadItem>();
	private synchronized void addDownloadItem(ImageDownloadItem item) {
		queue.add(item);
		this.notify();//添加了下载项就激活本线程
	}

	@Override
	public void run() {
		while(true) {
			while(queue.size() > 0) {
				ImageDownloadItem item = queue.remove(0);
				String imagePath = downloadImage(item.imageUrl);
				//缓存图片路径
				cache.put(item.imageUrl, imagePath);

				if (item.downloadListener != null) {//需要执行回调来显示图片
					item.imagePath = imagePath;

					//交由UI线程处理
					Message msg = handler.obtainMessage();
					msg.obj = item;
					handler.sendMessage(msg);
				}
			}
			try {
				synchronized(this) {
					this.wait();//没有下载项时等待
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	private String downloadImage(String imageUrl) {
		//TODO
		//不提供该方法代码
		//下载部分应该有专门下载文件的类(如:FileDownloadUtil.download(imageUrl))
		return "";
	}

	private Handler handler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			ImageDownloadItem item = (ImageDownloadItem)msg.obj;
			Bitmap bitmap = BitmapFactory.decodeFile(item.imagePath);
			item.downloadListener.update(bitmap, item.imageUrl);
		}
	};

	public static class ImageDownloadItem {
		public String imageUrl;//需要下载的图片URL
		public String imagePath;//下载的后图片路径
		private PostDownloadListener downloadListener;//回调监听
		public void setPostDownloadListener(PostDownloadListener listener) {
			this.downloadListener = listener;
		}
	}
	
	public static interface PostDownloadListener {
		//策略模式,由子类实现
		public void update(Bitmap bitmap, String imageUrl);
	}
}

 

下面是使用的代码片段

 

public View getView(int position, View convertView, ViewGroup vg) {
		final ImageView imageView;
		if (convertView != null) {
			imageView = (ImageView)convertView;
		} else {
			imageView = new ImageView(this);
		}
		//在实际应用中imageUrl值是不同的
		String imageUrl = "http://www.nxnet.net/yule/yljj/200710/W020071008388975463611.jpg";
		imageView.setTag(imageUrl);
		
		//设置下载项
		ImageDownloadItem item = new ImageDownloadItem();
		item.imageUrl = imageUrl;
		//如果是无需显示图片的情况(如预下载),无需设置PostDownloadListener监听器
		item.setPostDownloadListener(new PostDownloadListener() {
			@Override
			public void update(Bitmap bitmap, String imageUrl) {
				ImageView imageViewByTag = (ImageView)imageView.findViewWithTag(imageUrl);
				if (imageViewByTag != null) imageViewByTag.setImageBitmap(bitmap);
			}
		});
		
		ImageDownloadThread imageDownloadThread = ImageDownloadThread.getInstance();
		Bitmap bitmap = imageDownloadThread.downloadWithCache(item);
		if (bitmap != null) {//从缓存中取到
			imageView.setImageBitmap(bitmap);
		}
		return imageView;
	}
0
1
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics