标签:
package com.ncuhome.usconnection.cache; import android.annotation.TargetApi; import android.content.Context; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Build; import android.os.Build.VERSION_CODES; import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.StatFs; import android.support.v4.util.LruCache; import android.util.Log; import android.widget.ImageView; import com.ncuhome.usconnection.R; import com.ncuhome.usconnection.util.DiskLruCache; import com.ncuhome.usconnection.util.ImageResizer; import com.ncuhome.usconnection.util.MyUtils; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class ImageLoader { private static final String TAG = "ImageLoader"; public static final int MESSAGE_POST_RESULT = 1; private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); private static final int CORE_POOL_SIZE = CPU_COUNT + 1;//核心线程数 private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;//最大容量为CPU2倍 +1 private static final long KEEP_ALIVE = 10L;//线程闲置超时时长 10S // private static final int TAG_KEY_URI = R.id.imageloader_uri; private static final long DISK_CACHE_SIZE = 1024 * 1024 * 50; //50M的硬盘内存 private static final int IO_BUFFER_SIZE = 8 * 1024; // private static final int DISK_CACHE_INDEX = 0; private boolean mIsDiskLruCacheCreated = false; //线程工厂 private static final ThreadFactory sThreadFactory = new ThreadFactory() { private final AtomicInteger mCount = new AtomicInteger(1); public Thread newThread(Runnable r) { return new Thread(r, "ImageLoader#" + mCount.getAndIncrement()); } }; //创建线程池 public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor( CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), sThreadFactory); private Handler mMainHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { LoaderResult result = (LoaderResult) msg.obj; ImageView imageView = result.imageView; imageView.setImageBitmap(result.bitmap); String uri = (String) imageView.getTag(TAG_KEY_URI); //这里判断它的url是否发生变化,如果改变就不需要给它设置图片 if (uri.equals(result.uri)) { imageView.setImageBitmap(result.bitmap); } else { Log.e(TAG, "set image bitmap,but url has changed, ignored!"); } } }; /** * build a new instance of ImageLoader * * @param context * @return a new instance of ImageLoader */ public static ImageLoader build(Context context) { return new ImageLoader(context); } private Context mContext; private ImageResizer mImageResizer = new ImageResizer(); private LruCache<String, Bitmap> mMemoryCache; private DiskLruCache mDiskLruCache; public ImageLoader(Context context) { mContext = context.getApplicationContext(); //当前应用程序可用内存/1024 单位为KB int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); int cacheSize = maxMemory / 8; //内存缓存的创建 ,还有获取get 添加操作 删除 mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { //sizeof是计算缓存对象的大小/1024 单位为KB,特殊情况下会重写entryRemoved方法 移除旧缓存时候会用此方法,在这里进行一些资源回收的工作 @Override protected int sizeOf(String key, Bitmap bitmap) { return bitmap.getRowBytes() * bitmap.getHeight() / 1024; } }; File diskCacheDir = getDiskCacheDir(mContext, "bitmap"); if (!diskCacheDir.exists()) { //可以在不存在的目录中创建文件夹 diskCacheDir.mkdirs(); } if (getUsableSpace(diskCacheDir) > DISK_CACHE_SIZE) { try { //第一个参数就是目录,也可以指定SD卡上的缓存目录, //第二个参数版本号,当版本号改变时会清空之前的所有缓存文件,但是,很多情况下,版本号发生改变缓存文件还是有效的. //大三个参数单个节点所对应的数据的个数 //第四个参数缓存的总大小 这里是50M mDiskLruCache = DiskLruCache.open(diskCacheDir, 1, 1, DISK_CACHE_SIZE); mIsDiskLruCacheCreated = true; } catch (IOException e) { e.printStackTrace(); } } } private void addBitmapToMemoryCache(String key, Bitmap bitmap) { if (getBitmapFromMemCache(key) == null) { mMemoryCache.put(key, bitmap); } } private Bitmap getBitmapFromMemCache(String key) { return mMemoryCache.get(key); } /** * 异步加载接口 * load bitmap from memory cache or disk cache or network async, then bind imageView and bitmap. * NOTE THAT: should run in UI Thread * * @param uri http url * @param imageView bitmap‘s bind object */ public void bindBitmap(Context mContext, final String uri, final ImageView imageView) { bindBitmap(mContext, uri, imageView, 0, 0); } public void bindBitmap(final Context mContext, final String uri, final ImageView imageView, final int reqWidth, final int reqHeight) { imageView.setTag(TAG_KEY_URI, uri); Bitmap bitmap = loadBitmapFromMemCache(uri); if (bitmap != null) { imageView.setImageBitmap(bitmap); return; } Runnable loadBitmapTask = new Runnable() { @Override public void run() { Bitmap bitmap = loadBitmap(mContext, uri, reqWidth, reqHeight); if (bitmap != null) { LoaderResult result = new LoaderResult(imageView, uri, bitmap); mMainHandler.obtainMessage(MESSAGE_POST_RESULT, result).sendToTarget(); } } }; THREAD_POOL_EXECUTOR.execute(loadBitmapTask); } /** * 同步加载接口,会在异步借口中调用 * load bitmap from memory cache or disk cache or network. * * @param uri http url * @param reqWidth the width ImageView desired * @param reqHeight the height ImageView desired * @return bitmap, maybe null. */ public Bitmap loadBitmap(Context mContext, String uri, int reqWidth, int reqHeight) { Bitmap bitmap = loadBitmapFromMemCache(uri); if (bitmap != null) { Log.d(TAG, "loadBitmapFromMemCache,url:" + uri); return bitmap; } try { bitmap = loadBitmapFromDiskCache(uri, reqWidth, reqHeight); if (bitmap != null) { Log.d(TAG, "loadBitmapFromDisk,url:" + uri); return bitmap; } bitmap = loadBitmapFromHttp(mContext, uri, reqWidth, reqHeight); Log.d(TAG, "loadBitmapFromHttp,url:" + uri); } catch (IOException e) { e.printStackTrace(); } if (bitmap == null && !mIsDiskLruCacheCreated) { Log.w(TAG, "encounter error, DiskLruCache is not created."); //从网络中获取 bitmap = downloadBitmapFromUrl(mContext, uri); } return bitmap; } private Bitmap loadBitmapFromMemCache(String url) { final String key = hashKeyFormUrl(url); Bitmap bitmap = getBitmapFromMemCache(key); return bitmap; } private Bitmap loadBitmapFromHttp(Context mContext, String url, int reqWidth, int reqHeight) throws IOException { if (Looper.myLooper() == Looper.getMainLooper()) { throw new RuntimeException("can not visit network from UI Thread."); } if (mDiskLruCache == null) { return null; } //在这里添加缓存,首先获取URL(图片的网络地址)对应的Key, String key = hashKeyFormUrl(url); //如果正在编辑就会返回null DiskLruCache.Editor editor = mDiskLruCache.edit(key); if (editor != null) { //在open中设置了一个节点只能有一个数据,所以这里设为0 //图片可以通过这个文件输出流写入到文件系统上 OutputStream outputStream = editor.newOutputStream(DISK_CACHE_INDEX); if (downloadUrlToStream(mContext, url, outputStream)) { editor.commit(); } else { editor.abort();//退出整个编辑过程 } mDiskLruCache.flush(); } return loadBitmapFromDiskCache(url, reqWidth, reqHeight); } //从磁盘缓存中 private Bitmap loadBitmapFromDiskCache(String url, int reqWidth, int reqHeight) throws IOException { if (Looper.myLooper() == Looper.getMainLooper()) { Log.w(TAG, "load bitmap from UI Thread, it‘s not recommended!"); } if (mDiskLruCache == null) { return null; } //DiskLruCache缓存查找 ,snapshot 得到文件输入流,有了输入流自然就有bitmap图片了 Bitmap bitmap = null; String key = hashKeyFormUrl(url); DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key); if (snapShot != null) { FileInputStream fileInputStream = (FileInputStream) snapShot.getInputStream(DISK_CACHE_INDEX); //得到文件描述符 FileDescriptor fileDescriptor = fileInputStream.getFD(); bitmap = mImageResizer.decodeSampledBitmapFromFileDescriptor(fileDescriptor, reqWidth, reqHeight); if (bitmap != null) { addBitmapToMemoryCache(key, bitmap); } } return bitmap; } //通过文件输出流将图片写入到文件系统上 public boolean downloadUrlToStream(Context mContext, String urlString, OutputStream outputStream) { HttpURLConnection urlConnection = null; BufferedOutputStream out = null; BufferedInputStream in = null; try { final URL url = new URL(urlString); SharedPreferences sp = mContext.getSharedPreferences("remember", Context.MODE_PRIVATE); String authorization = sp.getString("Authorization", null); Log.e("TAG", "标签1"); urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setRequestProperty("Authorization", authorization); in = new BufferedInputStream(urlConnection.getInputStream(), IO_BUFFER_SIZE); out = new BufferedOutputStream(outputStream, IO_BUFFER_SIZE); int b; while ((b = in.read()) != -1) { out.write(b); } return true; } catch (IOException e) { Log.e(TAG, "downloadBitmap failed." + e); } finally { if (urlConnection != null) { urlConnection.disconnect(); } MyUtils.close(out); MyUtils.close(in); } return false; } private Bitmap downloadBitmapFromUrl(Context mContext, String urlString) { Bitmap bitmap = null; HttpURLConnection urlConnection = null; BufferedInputStream in = null; SharedPreferences sp = mContext.getSharedPreferences("remember", Context.MODE_PRIVATE); String authorization = sp.getString("Authorization", null); try { Log.e("TAG", "标签2"); final URL url = new URL(urlString); urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setRequestProperty("Authorization", authorization); in = new BufferedInputStream(urlConnection.getInputStream(), IO_BUFFER_SIZE); //输入流解析成图片 bitmap = BitmapFactory.decodeStream(in); } catch (final IOException e) { Log.e(TAG, "Error in downloadBitmap: " + e); } finally { if (urlConnection != null) { urlConnection.disconnect(); } MyUtils.close(in); } return bitmap; } //图片的URL转换为KEY private String hashKeyFormUrl(String url) { String cacheKey; try { final MessageDigest mDigest = MessageDigest.getInstance("MD5"); mDigest.update(url.getBytes()); cacheKey = bytesToHexString(mDigest.digest()); } catch (NoSuchAlgorithmException e) { cacheKey = String.valueOf(url.hashCode()); } return cacheKey; } //字节数组 转换为字符串 private String bytesToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { String hex = Integer.toHexString(0xFF & bytes[i]); if (hex.length() == 1) { sb.append(‘0‘); } sb.append(hex); } return sb.toString(); } //文件存储目录 public File getDiskCacheDir(Context context, String uniqueName) { boolean externalStorageAvailable = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED); final String cachePath; if (externalStorageAvailable) { cachePath = context.getExternalCacheDir().getPath(); } else { cachePath = context.getCacheDir().getPath(); } return new File(cachePath + File.separator + uniqueName); } @TargetApi(VERSION_CODES.GINGERBREAD) private long getUsableSpace(File path) { if (Build.VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) { return path.getUsableSpace(); } final StatFs stats = new StatFs(path.getPath()); return (long) stats.getBlockSize() * (long) stats.getAvailableBlocks(); } private static class LoaderResult { public ImageView imageView; public String uri; public Bitmap bitmap; public LoaderResult(ImageView imageView, String uri, Bitmap bitmap) { this.imageView = imageView; this.uri = uri; this.bitmap = bitmap; } } }
标签:
原文地址:http://www.cnblogs.com/zrui513/p/5041594.html