欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

17、网络图片加载

程序员文章站 2022-03-11 10:43:01
...
        如上节,有时候需要显示网络图片,QListView的Item中或其他地方。写一个类负责将网络图片下载下来,供使用。
public class ImageLoad {
	private Context context;
	private Map<String, Drawable> imageMap;
	private ThreadPoolExecutor executor = null;
	BlockingQueue<Runnable> queue =null;
	 
	private String path=Environment.getExternalStorageDirectory()+"/Dp Notes/Cache/PreImage";
	private int threadMaxNum=Runtime.getRuntime().availableProcessors()>1?Runtime.getRuntime().availableProcessors():2;
	private int cacheMaxNum=1;
	
	private Drawable errorDrawable,loadingDrawable;
	
	@SuppressLint("NewApi")
	public ImageLoad(Context context){
		this.context=context;
		
		imageMap=new LinkedHashMap<String, Drawable>();
		queue =new ArrayBlockingQueue<Runnable>(this.threadMaxNum);
		executor=new ThreadPoolExecutor(this.threadMaxNum,this.threadMaxNum,1,TimeUnit.MINUTES,queue,new ThreadPoolExecutor.CallerRunsPolicy());
		
		errorDrawable=context.getResources().getDrawable(R.drawable.ic_launcher);
		loadingDrawable=context.getResources().getDrawable(R.drawable.ic_launcher);
		
//		File dir=new File(this.path);
//		if(!dir.exists()){
//			dir.mkdirs();
//		}
	}
	
	public void setcacheMaxNum(int maxNum){
		this.cacheMaxNum=maxNum;
	}
	
	public Drawable loadImage(final View viewParent,final int viewTag,final String imageUrl,final ImageLoadCallback callback){
		
		if (imageMap.containsKey(imageUrl)) {
			Drawable drawable=imageMap.get(imageUrl);
			if(drawable==null){
				return loadingDrawable;
			}
			else if(drawable!=errorDrawable){
				return drawable;
			}
		}
//		int index=imageUrl.lastIndexOf("/");
//		index=index>=0?index:0;
//		String filename=imageUrl.substring(index);
//		final String filepath=path+filename+".0";
//		
//		final File mf=new File(filepath);
//		if(mf.exists()){
//			Bitmap bitmap=BitmapFactory.decodeFile(filepath);
//			BitmapDrawable draw=new BitmapDrawable(context.getResources(),bitmap);
//			if(draw!=null){
//				imageMap.put(imageUrl,draw);
//				chackMapSize();
//				return draw;
//			}
//		}
		imageMap.put(imageUrl,null);
		
		final Handler handler = new Handler() {

			@SuppressLint("HandlerLeak")
			public void handleMessage(Message message) {
				if(callback!=null){
					if(message.what==1){
						callback.onSuccess((Drawable) message.obj,viewTag,viewParent);
					}
				}
			}
		};

		executor.execute(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				URL url = null;
				InputStream inputStream = null;
				try {
					url = new URL(imageUrl);
					inputStream = url.openStream();
					Drawable drawable = Drawable.createFromStream(inputStream, "src");
					
					Message message;
					if(drawable==null){
						drawable=errorDrawable;
					}
					message=handler.obtainMessage(1,drawable);
					handler.sendMessage(message);
					
					imageMap.put(imageUrl,drawable);
					chackMapSize();
					
//					if(drawable!=errorDrawable){
//						try {
//							if(!mf.exists()){
//								try {
//											mf.createNewFile();
//								} catch (IOException e) {
//									// TODO Auto-generated catch block
//									e.printStackTrace();
//								}
//							}
//							FileOutputStream fout=new FileOutputStream(mf);
//							Bitmap bitmap=((BitmapDrawable)drawable).getBitmap();
//							bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fout);
//						} catch (FileNotFoundException e) {
//							// TODO Auto-generated catch block
//							e.printStackTrace();
//						}
//					}
					
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					try {
						if (inputStream != null)
							inputStream.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		});
		
		return loadingDrawable;
	}
	
	private void chackMapSize(){

		if(imageMap.size()>cacheMaxNum){
			for(Entry<String, Drawable> m:imageMap.entrySet()){
				imageMap.remove(m.getKey());
				break;
			}
		}
		
	}

	public interface ImageLoadCallback {
		public void onSuccess(Drawable drawable,int tag,View viewParent);
	}
	
}

        原理很简单,当有图片下载请求时,就新建一个线程去从网络中获取数据,并存放到一个Map中,下载完成时使用Handler去通知并在回调函数中返回图片数据。
        Map使用图片的网络路径作为索引,存放图片数据Drawable,将下载好的图片数据加入到最后,并判断总数超出限制数量则将最前的去除。
        为了避免一次请求图片过多,新建的线程过多,使用ThreadPoolExecutor进行管理。
加载图片的方法loadImage()传入网络图片路径、加载完毕的监听器,及两个其他参数(会在回调函数中附带,解决ListView Item中图片错位的问题)。
        具体下载图片数据则直接使用Drawable.createFromStream生成Drawable。

        使用如下:

private ImageLoad imgload;		//定义类对象
imgload=new ImageLoad(activity);	//构建

//合适的地方启动加载:
Drawable pre=imgload.loadImage(viewparent,tagpre,data.preurl,ilcallback);
if(drawable!=null){
	holder.rl_data.setBackground(pre);
}

private ImageLoadCallback ilcallback=new ImageLoadCallback() {
	
	@SuppressLint("NewApi")
	@Override
	public void onSuccess(Drawable drawable, int tag, View viewParent) {
		// TODO Auto-generated method stub
		if(drawable!=null){
			holder.rl_data.setBackground(drawable);
		}
	}
};

        效果可以用一个ImageView试一下,之后会在QListView中使用。

人定胜天——2017/05/21