Android开源中国客户端学习 异步加载图片<3>

这次的内容又是很简单 异步加载图片大家可能做的也很多了 通过阅读osc的源码 也算是 学习人家的一种架构吧,好歹作者的经验也比我丰富。

其实osc的图片异步加载也是使用了两级结构,即 内存缓存和sd卡缓存。整体思路:显示图片时先从内存缓存中找,如果找到,就直接返回这个bitmap并显示,如果找不到从sd卡找,找到就显示,找不到就从网路获取并保存到内存缓存和sd卡中

时序图如下

Android开源中国客户端学习 异步加载图片<3>_第1张图片


那么就来分析一下流程吧这里只提及重要的步骤了,其他的步骤请参考代码

1.在Adapter等地方设置这个显示这个图片,其实是调用了BitmapManager的loadBitmap函数

bmpManager.loadBitmap(imgSmall, listItemView.image, BitmapFactory.decodeResource(context.getResources(), R.drawable.image_loading));


2.loadBitmap函数代码


 public void loadBitmap(String url, ImageView imageView, Bitmap defaultBmp, int width, int height) {  
        imageViews.put(imageView, url);  
        Bitmap bitmap = getBitmapFromCache(url);  
   
        if (bitmap != null) {  
			//显示缓存图片
            imageView.setImageBitmap(bitmap);  
        } else {  
        	//加载SD卡中的图片缓存
        	String filename = FileUtils.getFileName(url);
        	String filepath = imageView.getContext().getFilesDir() + File.separator + filename;
    		File file = new File(filepath);
    		if(file.exists()){
				//显示SD卡中的图片缓存
    			Bitmap bmp = ImageUtils.getBitmap(imageView.getContext(), filename);
        		imageView.setImageBitmap(bmp);
        	}else{
				//线程加载网络图片
        		imageView.setImageBitmap(defaultBmp);
        		queueJob(url, imageView, width, height);
        	}
        }  
    }  

这里先分析从内存Cache中获取Bitmap的实现:

在分析获取缓存之前有个imageViews成员变量需要解释一下

 imageViews.put(imageView, url);  

这个 imageViews.put(imageView, url);  的定义是


Map<ImageView, String>

 imageViews = Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
这里的Collections.synchronizedMap 是为了让HashMap可以用于多线程的环境 


而 WeakHashMap当某个键不再正常使用时,将自动移除其条目。这个imageViews是为了在线程池中把imageview和url(其实就是从网络取回来的bitmap)一一对应 稍后还会看到。

4.getBitmpaFromCache函数


    public Bitmap getBitmapFromCache(String url) {  
    	Bitmap bitmap = null;
        if (cache.containsKey(url)) {  
            bitmap = cache.get(url).get();  
        }  
        return bitmap;  
    }  
那么,这个Cache是个什么东西呢?



 private static HashMap<String, SoftReference<Bitmap>> cache;  
 cache = new HashMap<String, SoftReference<Bitmap>>();  

原来是一个HashMap 其中他的键值String是那个需要显示的Bitmap的url 我以前做的项目是把这个url md5了 市面上很多应用比如京东也是进行的md5再放入缓存 

至于SofrReference请自行google。

继续看代码,。如果从缓存中取到了bitmap,就直接显示,若没有就执行


	Bitmap bmp = ImageUtils.getBitmap(imageView.getContext(), filename);
从sd卡取,如果sd卡没有这个文件,那直接从网路下载了 在此之前 还让imageview显示了一个默认图片


7.queueJob()

 public void queueJob(final String url, final ImageView imageView, final int width, final int height) {  
        /* Create handler in UI thread. */  
        final Handler handler = new Handler() {  
            public void handleMessage(Message msg) {  
                String tag = imageViews.get(imageView);  
                if (tag != null && tag.equals(url)) {  
                    if (msg.obj != null) {  
                        imageView.setImageBitmap((Bitmap) msg.obj);  
                        try {
                        	//向SD卡中写入图片缓存
							ImageUtils.saveImage(imageView.getContext(), FileUtils.getFileName(url), (Bitmap) msg.obj);
						} catch (IOException e) {
							e.printStackTrace();
						}
                    } 
                }  
            }  
        };  
  
        pool.execute(new Runnable() {   
            public void run() {  
                Message message = Message.obtain();  
                message.obj = downloadBitmap(url, width, height);  
                handler.sendMessage(message);  
            }  
        });  
    } 

这里又是一个handler+thread了

有同学会说,这里木有thread,其实那个post就是一个线程池了

看定义

  private static ExecutorService pool;  
 pool = Executors.newFixedThreadPool(5);  //固定线程池

就是把downloadBitmap的任务放到线程池中执行了,等执行完了就发消息给handler

handler会使用从imageviews中保存的url进行匹配,如果消息写到的url是imageview需要显示的那个,就显示到imageview上

注意在从网路download取回bitmap之后会把bitmap放到cache'中 这句话在downloadBitmap()函数中

cache.put(url, new SoftReference<Bitmap>(bitmap));
13.最后异步就是把获取到的bitmap保存到sd卡了

//向SD卡中写入图片缓存
							ImageUtils.saveImage(imageView.getContext(), FileUtils.getFileName(url), (Bitmap) msg.obj);


你可能感兴趣的:(Android开源中国客户端学习 异步加载图片<3>)