赞
踩
- package com.example.utils;
-
- 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.LinkedBlockingDeque;
- import java.util.concurrent.ThreadFactory;
- import java.util.concurrent.ThreadPoolExecutor;
- import java.util.concurrent.TimeUnit;
- import java.util.concurrent.atomic.AtomicInteger;
-
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.os.Build;
- import android.os.Handler;
- import android.os.Looper;
- import android.os.Message;
- import android.os.StatFs;
- import android.os.Build.VERSION_CODES;
- import android.os.Environment;
- import android.support.v4.util.LruCache;
- import android.util.Log;
- import android.widget.ImageView;
-
- 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;
- private static final long KEEP_ALIVE = 10L;
- private static final int IO_BUFFER_SIZE = 8 * 1024;
- private static final int DISK_CACHE_INDEX = 0;
- private boolean mIsDiskLruCacheCreated = false;
- private Context mContext;
- private DiskLruCache mDiskLruCache;
- private static final int TAG_KEY_URI = 100;
- private ImageResizer mImageResizer = new ImageResizer();
- private LruCache<String, Bitmap> mMemoryCache;
- private static final long DISK_CACHE_SIZE = 1024 * 1024 * 50;
- // 创建线程工厂,使用原子类保证线程安全
- private static final ThreadFactory sThreadFactory = new ThreadFactory() {
- // 内部被volatile修饰,线程安全
- private final AtomicInteger mCount = new AtomicInteger(1);
-
- @Override
- public Thread newThread(Runnable r) {
- // 执行任务r,线程名"ImageLoader#"+mCount.getAndIncrement()
- 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 LinkedBlockingDeque<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);
- //解决快速滑动时imageView复用,uri变化而使得图片错位
- if (uri.equals(result.uri)) {
- imageView.setImageBitmap(result.bitmap);
- } else {
- Log.w(TAG, "url is change,ignored!");
- }
- };
- };
-
- // 异步加载接口设计
- public void bindBitmap(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(uri, reqWidth, reqHeight);
- if (bitmap != null) {
- LoaderResult result = new LoaderResult(imageView, uri,
- bitmap);
- // obtainMessage().sendToTarget()和sendMessage()区别在于前者是从MessagePool拿的,后者是自己创建的
- mMainHandler.obtainMessage(MESSAGE_POST_RESULT, result)
- .sendToTarget();
- }
- }
- };
- THREAD_POOL_EXECUTOR.execute(loadBitmapTask);
- }
-
- // 同步加载接口设计
- protected Bitmap loadBitmap(String uri, int reqWidth, int reqHeight) {
- Bitmap bitmap = loadBitmapFromMemCache(uri);
- if (bitmap != null) {
- return bitmap;
- }
- bitmap = loadBitmapFromDiskCache(uri, reqWidth, reqHeight);
- if (bitmap != null) {
- return bitmap;
- }
- try {
- bitmap = loadBitmapFromHttp(uri, reqWidth, reqWidth);
- } catch (IOException e) {
- e.printStackTrace();
- }
- if (bitmap == null && !mIsDiskLruCacheCreated) {
- bitmap = downloadBitmapFromUrl(uri);
- }
- return bitmap;
- }
-
- // 从网络加载bitmap数据
- private Bitmap downloadBitmapFromUrl(String uri) {
- Bitmap bitmap = null;
- HttpURLConnection urlConnection = null;
- BufferedInputStream is = null;
- try {
- URL url = new URL(uri);
- urlConnection = (HttpURLConnection) url.openConnection();
- is = new BufferedInputStream(urlConnection.getInputStream(),
- IO_BUFFER_SIZE);
- bitmap = BitmapFactory.decodeStream(is);
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- if (urlConnection != null) {
- urlConnection.disconnect();
- }
- IOutil.close(is);
- }
- return bitmap;
- }
-
- // 从网络加载bitmap数据,并将其写入到磁盘缓存
- private Bitmap loadBitmapFromHttp(String uri, int reqWidth, int reqHeight)
- throws IOException {
- if (Looper.myLooper() == Looper.getMainLooper()) {
- throw new RuntimeException("can not visit network from UI Thread.");
- }
- String key = hashKeyFormUrl(uri);
- // 磁盘缓存写入
- DiskLruCache.Editor editor = mDiskLruCache.edit(key);
- if (editor != null) {
- // 磁盘缓存输出流
- OutputStream os = editor.newOutputStream(DISK_CACHE_INDEX);
- // 写入成功则返回true
- if (downloadUrlToStream(uri, os)) {
- // 提交
- editor.commit();
- } else {
- // 撤销
- editor.abort();
- }
- mDiskLruCache.flush();
- }
- return loadBitmapFromDiskCache(uri, reqWidth, reqHeight);
- }
-
- private boolean downloadUrlToStream(String uri, OutputStream os) {
- HttpURLConnection urlConnection = null;
- BufferedOutputStream out = null;
- BufferedInputStream in = null;
- try {
- URL url = new URL(uri);
- urlConnection = (HttpURLConnection) url.openConnection();
- in = new BufferedInputStream(urlConnection.getInputStream());
- out = new BufferedOutputStream(os, IO_BUFFER_SIZE);
- int length = 0;
- while ((length = in.read()) != -1) {
- out.write(length);
- }
- return true;
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- if (urlConnection != null) {
- urlConnection.disconnect();
- }
- IOutil.close(out);
- IOutil.close(in);
- }
- return false;
- }
-
- // 加载磁盘缓存中的图片
- private Bitmap loadBitmapFromDiskCache(String uri, int reqWidth,
- int reqHeight) {
- if (Looper.getMainLooper() == Looper.myLooper()) {
- Log.w(TAG, "load bitmap from UI Thread,it's not recommended!");
- }
- if (mDiskLruCache == null) {
- return null;
- }
- Bitmap bitmap = null;
- String key = hashKeyFormUrl(uri);
- try {
- DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);
- if (snapshot != null) {
- FileInputStream fis = (FileInputStream) snapshot
- .getInputStream(DISK_CACHE_INDEX);
- // 获取该文件输入流fis相关的文件描述对象fileDescriptor
- FileDescriptor fileDescriptor = fis.getFD();
- bitmap = mImageResizer.decodeSampledBitmapFromFileDescriptor(
- fileDescriptor, reqWidth, reqHeight);
- if (bitmap != null) {
- //成功获取磁盘缓存的图片后将其添加到内存缓存
- addBitmapToMemoryCache(key, bitmap);
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- return bitmap;
- }
-
- // 加载内存缓存中的图片
- private Bitmap loadBitmapFromMemCache(String uri) {
- final String key = hashKeyFormUrl(uri);
- Bitmap bitmap = getBitmapFromMemoryCache(key);
- return bitmap;
- }
-
- // 私有构造方法,初始化成员变量
- private ImageLoader(Context context) {
- mContext = context;
- int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
- int cacheMemory = maxMemory / 8;
- mMemoryCache = new LruCache<String, Bitmap>(cacheMemory) {
- @Override
- protected int sizeOf(String key, Bitmap value) {
- return value.getRowBytes() * value.getHeight() / 1024;
- }
- };
- File diskCacheDir = getDiskCacheDir(context, "bitmap");
- if (diskCacheDir.exists()) {
- diskCacheDir.mkdirs();
- }
- if (getUsableSpace(diskCacheDir) > DISK_CACHE_SIZE) {
- try {
- mDiskLruCache = DiskLruCache.open(diskCacheDir, 1, 1,
- DISK_CACHE_SIZE);
- mIsDiskLruCacheCreated = true;
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
-
- // 往内存缓存中添加bitmap数据
- private void addBitmapToMemoryCache(String key, Bitmap bitmap) {
- if (getBitmapFromMemoryCache(key) == null) {
- mMemoryCache.put(key, bitmap);
- }
- }
-
- // 从内存缓存中获取Bitmap对象
- private Bitmap getBitmapFromMemoryCache(String key) {
- return mMemoryCache.get(key);
- }
-
- // 返回ImageLoader对象
- public static ImageLoader build(Context context) {
- return new ImageLoader(context);
- }
-
- // 获取文件的可用空间
- private long getUsableSpace(File path) {
- // 判断SDK版本是否大于姜饼版本(2.3版本)
- 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 File getDiskCacheDir(Context context, String uniqueName) {
- // 判断SD卡是否存在并且没有被移除
- 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);
- }
-
- private String bytesToHexString(byte[] bytes) {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < bytes.length; i++) {
- // 将字节数组转换为字符数组,清除高位二十四比特(byte为8位,int为32位)
- String hex = Integer.toHexString(0xFF & bytes[i]);
- if (hex.length() == 1) {
- sb.append('0');
- }
- sb.append(hex);
- }
- return sb.toString();
- }
-
- // 给url地址进行MD5加密
- 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;
- }
-
- // 将imageView,url,bitmap封装成实体类,以便Handler传输数据
- 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;
- }
- }
- }
实现功能:图片的同步加载、图片的异步加载、图片压缩、内存缓存、磁盘缓存、网络垃圾
详情见图片和代码注释
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。