实现的功能主要是标题,那么接下来我们就分析,如何一步一步的实现这个功能
第一步:创建imgCache文件夹,在里面创建如下几个文件
1.ImgLoaderCallback:用于刷新ImageView
2.ImageManager:用于管理缓存图片,比如图片的读取,还有存储
3.LazyImageLoader:异步处理文件管理器,比如操作获取网络图片的主要步骤就在里面,
4.CallbackManager:用于回调管理
5.创建SimplerImageLoader:真正实现网络图片的读取,调用lazyimgloader方法
6.在util中,编写一个队url加密的文件
第二部:实现步骤
在LazyImageLoader中调用ImageManager中的方法,实现判断这个URL有没有,有的话就从文件缓存中读取,没有的话就保存到文件缓存中,并且在LazyLoaderManager中
开启线程将url放在一个Queue中,一个个的调用出来使用
第三部:下面就是源代码
LazyImageLoader:
package imgCache; import android.content.Context; import android.graphics.Bitmap; import android.os.Bundle; import android.os.Handler; import android.os.Message; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import app.coolweather.com.weibo.weiboApplication; /**异步处理图片管理器 * Created by Administrator on 2016/9/13. */ public class LazyImageLoader { private static final int MESSAGE_ID =1; public static final String EXTRA_IMG_URL="extra_img_url"; public static final String EXTRA_IMG="extra_img"; private Context context; private ImageManager imageManager=new ImageManager(weiboApplication.context); private BlockingQueue<String> urlQueue = new ArrayBlockingQueue<String>(50); //创建这个队列用于存放URL,这个队列慢的时候加入进去,为空的时候就能读 private DownloadImage downloadImage=new DownloadImage(); private CallbackManager callbackManager=new CallbackManager(); /** *用于获取图片,封装的方法在ImageManager中 */ public Bitmap get(String url,ImgLoaderCallback callback){ Bitmap bitmap = ImageManager.userDefualtHead; if(imageManager.contains(url)){ //判断这个对象是否为空,不为空 bitmap=imageManager.getFromCache(url); //获取图片 return bitmap; } else{ callbackManager.put(url,callback); //在这个地方调用回调管理函数,放入对象 startDownloadThread(url); //没有else,就开启线程下载 } return bitmap; } /** * 开启线程 */ private void startDownloadThread(String url){ putUrlToQueue(url); Thread.State state= downloadImage.getState(); if(state== Thread.State.NEW){ //线程刚开启 downloadImage.start(); }else if(state== Thread.State.TERMINATED){ //线程截止了 downloadImage=new DownloadImage(); downloadImage.start(); } } /** * 将url加入到queue队列中 * 对于put方法,若向队尾添加元素的时候发现队列已经满了会发生阻塞一直等待空间,以加入元素。 * add方法在添加元素的时候,若超出了度列的长度会直接抛出异常: * offer方法在添加元素时,如果发现队列已满无法添加的话,会直接返回false。 */ private void putUrlToQueue(String url){ if(!urlQueue.contains(url)){ try { urlQueue.put(url); } catch (InterruptedException e) { e.printStackTrace(); } } } Handler handler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case MESSAGE_ID: //获取文件或者下载的图片,实现UI的更新 { Bundle bundle=msg.getData(); // 获取数据 String url =bundle.getString(EXTRA_IMG_URL); Bitmap bitmap = bundle.getParcelable(EXTRA_IMG); callbackManager.callback(url,bitmap); break; } } } }; //创建一个内部类用于开启线程,来下载图片 private class DownloadImage extends Thread{ private boolean isRun=true; @Override public void run() { super.run(); try{ while(isRun){ String url=urlQueue.poll(); //从队列中获取一个并且删除这个 if(url==null){break;} Bitmap bitmap=imageManager.safeGet(url); //返回从文件中查找到的,或者下载的图片 Message message=handler.obtainMessage(MESSAGE_ID); //在自定义handler中,尽量使用这种方法,而不是new Message() Bundle bundle=message.getData(); //第一句的意思是获取传递过来的Message中的数据集合. bundle.putSerializable(EXTRA_IMG_URL, url); //Bundle的内部实际上是使用了HashMap类型的变量来存放putXxx()方法放入的值 bundle.putParcelable(EXTRA_IMG, bitmap); handler.sendMessage(message); } }catch (Exception E){ } finally { isRun=false; //当线程执行完毕的时候关闭,要不然会一直执行 } } } }
ImageManager:
package imgCache; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import org.apache.commons.httpclient.HttpException; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.lang.ref.SoftReference; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.Map; import Util.MD5Util; /**用于管理缓存图片 * Created by Administrator on 2016/9/13. */ public class ImageManager { Map<String,SoftReference<Bitmap>> imgCache; //用map是为了缓存保存对象,用,SoftReference<Bitmap>是为了更 private Context context; public static Bitmap userDefualtHead; public ImageManager(Context context){ imgCache = new HashMap<String, SoftReference<Bitmap>>(); //在构造函数进行实例化 this.context=context; } /**判断缓存中是否含有这个图片 *Map containsKey(String Key) 判断key有没有对应的value值; 有,则返回true 没有,则返回false */ public boolean contains(String url){ return imgCache.containsKey(url); } /** *先判断从Map缓存中读取数据,如果没有就从file中读取,file位于该包下面 */ public Bitmap getFromCache(String url) { Bitmap bitmap = null; bitmap = this.getFromMapCache(url); if(null == bitmap) { bitmap =getFromFile(url); } return bitmap; } /** * 从Map缓存中获取BitMap * Java语言的关键字,当它synchronized 用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。 */ public Bitmap getFromMapCache(String url) { Bitmap bitmap = null; SoftReference<Bitmap> ref = null; //SoftReference<BitMap>与bitmap不一样 synchronized (this) { ref = imgCache.get(url); } if(null != ref) { bitmap = ref.get(); } return bitmap; } /** * 从文件中获取Bitmap * @param url * @return */ public Bitmap getFromFile(String url) { String fileName = this.getMd5(url); FileInputStream is=null; try { is=context.openFileInput(fileName); //fileName的name不能包含分隔符 return BitmapFactory.decodeStream(is); //将获取的资源解析成bitmap } catch (FileNotFoundException e) { return null; } finally { if(null != is) { try{is.close();}catch(Exception ex){}; } } } /** * 查看文件中有没有图片,有的话放入缓存当中,没有的话就下载 */ public Bitmap safeGet(String url) throws HttpException { Bitmap bitmap = this.getFromFile(url); if(null != bitmap) { synchronized (this) { imgCache.put(url, new SoftReference<Bitmap>(bitmap)); } return bitmap; } return downloadImage(url); } /** * 下载图片并保持文件到系统缓存 */ public Bitmap downloadImage(String urlStr)throws HttpException { try { URL url=new URL(urlStr); try { HttpURLConnection connection =(HttpURLConnection) url.openConnection(); //获取网络连接 String fileName=writerToFile(getMd5(urlStr),connection.getInputStream()); //保存成功返还文件名 return BitmapFactory.decodeFile(fileName); //将系统中的文件转化为一个bitmap图片 } catch (IOException e) { e.printStackTrace(); } } catch (MalformedURLException e) { e.printStackTrace(); } return null; } /** * 获取的网络图片,写入到文件还有缓存中 */ public String writerToFile(String fileName, InputStream is) { BufferedInputStream bis = null; //读取文件 BufferedOutputStream bos = null; //存储数据到文件 try { bis = new BufferedInputStream(is); bos = new BufferedOutputStream(context.openFileOutput(fileName, Context.MODE_PRIVATE)); byte[] buffer = new byte[1024]; //放入缓存当中 int length; while((length = bis.read(buffer)) != -1) { bos.write(buffer, 0, length); } } catch (Exception e) { } finally { try { if(null != bis) { bis.close(); } if(null != bos) { bos.flush(); bos.close(); } } catch (IOException e) { e.printStackTrace(); } } return context.getFilesDir() + "/" + fileName; } /** * 调用Md5方法,用于对URL加密 */ private String getMd5(String src) { return MD5Util.getMD5String(src); } }
lmgLoaderCallback:
/**只管刷新ImageView * Created by Administrator on 2016/9/13. */ public interface ImgLoaderCallback { void refresh(String url, Bitmap bitmap); //用于刷新ImageView,Bitmap用于保存网络上获取的图片 }
simplemageLoader:
package imgCache; import android.graphics.Bitmap; import android.widget.ImageView; import app.coolweather.com.weibo.weiboApplication; /** * Created by Administrator on 2016/9/20. */ public class SimpleImageLoader { public static void showImg(ImageView view,String url) { view.setTag(url); view.setImageBitmap(weiboApplication.lazyImageLoader.get(url, getCallback(url,view))); } private static ImgLoaderCallback getCallback(final String url,final ImageView view) { return new ImgLoaderCallback() { @Override public void refresh(String url, Bitmap bitmap) { if(url.equals(view.getTag().toString())) { view.setImageBitmap(bitmap); } } }; } }
CallbackManager:
package imgCache; import android.graphics.Bitmap; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; /**用于回调管理 * Created by Administrator on 2016/9/13. */ public class CallbackManager { private ConcurrentHashMap<String, List<ImgLoaderCallback>> callbackMap; //创建页面刷新对象 public CallbackManager() { callbackMap = new ConcurrentHashMap<String, List<ImgLoaderCallback>>(); //进行实例化 } /** * 在数组中放入对象 */ public void put(String url,ImgLoaderCallback callback) { if(!callbackMap.contains(url)) //没有这个url,就创建这个url的数组,用于存储imgloaderCallback对象 callbackMap.put(url, new ArrayList<ImgLoaderCallback>()); callbackMap.get(url).add(callback); } public void callback(String url,Bitmap bitmap) //获取对象实现刷新页面 { List<ImgLoaderCallback> callbacks =callbackMap.get(url); if(null == callbacks) return; for (ImgLoaderCallback callback : callbacks) { if(null != callback) callback.refresh(url, bitmap); } callbacks.clear(); callbackMap.remove(url); } }
util中文件的源代码:MD5Util
package Util; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * @author Ivan * @version 1.0 * @briefMD5工具类,提供字符串MD5加密(校验)、文件MD5值获取(校验)功能。 */ public class MD5Util { /** * 16进制字符集 */ private static final char HEX_DIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; /** * 指定算法为MD5的MessageDigest */ private static MessageDigest messageDigest = null; /** * 初始化messageDigest的加密算法为MD5 */ static { try { messageDigest = MessageDigest.getInstance("MD5"); } catch(NoSuchAlgorithmException e) { e.printStackTrace(); } } /** * MD5加密字符串 * @param str 目标字符串 * @return MD5加密后的字符串 */ public static String getMD5String(String str) { return getMD5String(str.getBytes()); } /** * MD5加密以byte数组表示的字符串 * @param bytes 目标byte数组 * @return MD5加密后的字符串 */ public static String getMD5String(byte[] bytes) { messageDigest.update(bytes); return bytesToHex(messageDigest.digest()); } /** * 将字节数组转换成16进制字符串 * @param bytes 目标字节数组 * @return 转换结果 */ public static String bytesToHex(byte bytes[]) { return bytesToHex(bytes, 0, bytes.length); } /** * 将字节数组中指定区间的子数组转换成16进制字符串 * @param bytes 目标字节数组 * @param start 起始位置(包括该位置) * @param end 结束位置(不包括该位置) * @return 转换结果 */ public static String bytesToHex(byte bytes[], int start, int end) { StringBuilder sb = new StringBuilder(); for(int i = start; i < start + end; i++) { sb.append(byteToHex(bytes[i])); } return sb.toString(); } /** * 将单个字节码转换成16进制字符串 * @param bt 目标字节 * @return 转换结果 */ public static String byteToHex(byte bt) { return HEX_DIGITS[(bt & 0xf0) >> 4] + "" + HEX_DIGITS[bt & 0xf]; } }
最后一步:调用
SimpleImageLoader.showImg(holder.user_head,"http://image6.huangye88.com/2013/07/26/370d6cd0c79c4269.jpg");
1.传入你需要的url就行
2.SimpleImageLoader.showImg(holder.img_wb_item_head, s.getUser().getProfileImageURL().toString()); 还可以调用接口获取里里面的图片