手把手教你封裝本身的圖片緩存工具-ImageLoader

最近一直在學習男神+大神任玉剛老師的Android開發藝術探索,我我的很是推薦這本書,寫的真tm好,很差意思,有點激動。你們有空能夠去看看。看完總以爲要寫點什麼吧,就將其中Bitmap加載和Cache的內容分享給尚未來得及看過的朋友們。git

緩存策略在Android中有着普遍的。。。算了,先輕鬆一下,來張美女鎮樓github

老司機要發車了,來不及解釋了,你們快上車啊。 算法

言歸正傳(畫風一轉)

緩存策略在Android中有着普遍的使用場景,尤爲在圖片加載這個場景下,緩存策略變得更爲重要。今天就帶你們本身動手設計圖片緩存工具。緩存

提到緩存,不得不提目前經常使用的一種緩存算法-LRU(Least Recently Used),LRU是近期最少使用算法。採用這種算法思想的緩存有兩種:LruCache和DiskLruCache,LruCache用於實現內存緩存,而DiskLruCache則充當了存儲設備緩存,經過二者完美結合,就能夠輕鬆實現咱們的ImageLoader。bash

下面咱們就正式開始了。。。網絡

1.首先咱們來看下兩個核心的東西:LruCache和DiskLruCache。

1.1LruCacheapp

LruCache的實現比較簡單,你們能夠參考它的源碼。LruCache主要用來實現內存緩存,咱們拿圖片緩存來舉例子,反手就是一段代碼:異步

int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
int cacheSize = maxMemory / 8;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes() * value.getHeight() / 1024;
            }
        };
複製代碼

能夠看出,咱們只須要提供緩存的總容量大小並重寫sizeOf方法便可。ide

除了LruCache的建立之外,還有緩存的獲取和添加,這也很簡單,從LruCache中獲取一個緩存對象,以下所示。工具

mMemoryCache.get(key)
複製代碼

向LruCache中添加一個緩存對象,以下所示。

mMemoryCache.put(key,bitmap)
複製代碼

從Android3.1開始,LruCache就已是Android源碼的一部分了。

1.2DiskLruCache

DiskCahe用於實現存儲設備緩存,已經獲得了Android官方的推薦,但不屬於SDK的一部分,咱們要導入引用一下:

compile 'com.jakewharton:disklrucache:2.0.2'

1.2.1先來看下DiskLruCache的建立

DiskLruCache提供open方法用於建立自身,以下所示。

pulic static DiskLruCache open(File directory,int appVersion,int valueCount,long maxSize)
複製代碼

這裏有四個參數,稍微解釋下,有興趣的朋友,下去能夠深刻了解下:

directory:磁盤緩存的存儲路徑。

appVersion:版本號,通常設爲1便可。

valueCount:單個節點所對應的數據的個數,通常也設爲1便可。

maxSize:緩存的總大小。

整個建立過程,反手又是一段代碼:

private static final int DISK_CACHE_SIZE = 50*1024*1024;
File diskCacheDir = getDiskCacheDir(mContext, "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();
            }
        }
複製代碼

1.2.2DiskLruCache的緩存添加

String key = hashKeyFormUrl(url);
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
if(editor!=null){
    OutputStream output Stream = editor.newOutputStream(DISK_CACHE_INDEX);
}
複製代碼

這裏的hashKeyFormUrl()方法主要是將url轉成key,之因此這麼作,是由於url中極可能有特殊字符,會影響url在Android中的直接使用。

有了文件輸出流,接下來就是講網絡下載的圖片時的文件流寫入到文件系統上了:

private boolean downloadUrlToStream(String urlString, OutputStream outputStream) {
        HttpURLConnection urlConnection=null;
        BufferedOutputStream out = null;
        BufferedInputStream in = null;
        try {
            URL url = new URL(urlString);
            urlConnection = (HttpURLConnection) url.openConnection();
            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) {
            e.printStackTrace();
        }finally {
            if(urlConnection!=null){
                urlConnection.disconnect();
            }
            MyUtils.close(out);
            MyUtils.close(in);
        }
        return false;
    }
複製代碼

還有不要忘記了,editor要提交寫入操做。

editor.commit();
複製代碼

1.2.3DiskLruCache緩存的查找

private Bitmap loadBitmapFromDiskCache(String url, int reqWidth, int reqHeight)
    throws IOException{
        if (Looper.myLooper() == Looper.getMainLooper()) {
            throw new RuntimeException("load bitmap from UI Thread,it's not recommended");
        }
        if(mDiskLruCache ==null){
        return null;
        }
        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.decodeSampleFromFileDescriptor(fileDescriptor,reqWidth,reqHeight);
            if(bitmap !=null){
                addBitmapToMemoryCache(key,bitmap);
            }
        }
        return bitmap;
    }
複製代碼

代碼的意思應該好理解,將url轉成key,經過get方法獲得一個Snapshot對象,經過這個對象便可獲得緩存的輸入流,有了輸入流,還怕拿不到bitmap對象嗎。

好了,介紹完兩個核心的知識點,喝口雪碧壓壓驚。

接下來就是重頭戲了,就是ImageLoader的實現。

2.ImageLoader的實現

要實現整個完整的ImageLoader功能,要怎麼作呢?先捋下思想,應該具有如下幾個功能:

-圖片的同步加載

-圖片的異步加載

-圖片壓縮

-內存緩存

-磁盤緩存

-網絡拉取

接下來,咱們一步一步的實現。

2.1圖片壓縮功能的實現

將壓縮圖片功能抽出來單獨造成一個類,就叫ImageResizer吧,看下實現:

public class ImageResizer {
    private static final String TAG = "ImageResizer";
    public Bitmap decodeSampleFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res,resId,options);
    }
    public Bitmap decodeSampleFromFileDescriptor(FileDescriptor fd, int reqWidth, int reqHeight) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFileDescriptor(fd, null, options);
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFileDescriptor(fd, null, options);
    }
    private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        if (reqWidth == 0 || reqHeight == 0) {
            return 1;
        }
        int width = options.outWidth;
        int height = options.outHeight;
        int inSampleSize = 1;
        if (width < reqWidth || height < reqHeight) {
            return inSampleSize;
        }
        inSampleSize *= 2;
        while (width /inSampleSize>=reqWidth&&height/inSampleSize>=reqHeight){
            inSampleSize *=2;
        }
        Log.e(TAG, "inSampleSize: "+inSampleSize);
       return inSampleSize;
    }
}
複製代碼

2.2內存緩存和磁盤緩存的實現

以前介紹過了,這裏放下具體實現:

初始化:

public ImageLoader(Context context) {
        mImageResizer = new ImageResizer();
        mContext = context;
        int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        int cacheSize = maxMemory / 8;
        mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes() * value.getHeight() / 1024;
            }
        };
        File diskCacheDir = getDiskCacheDir(mContext, "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();
            }
        }
    }
複製代碼

內存緩存添加和獲取

private void addBitmapToMemoryCache(String key, Bitmap bitmap) {
        Log.e(TAG, "addBitmapToMemoryCache: ");
        if (getBitmapFromMemoryCache(key) == null) {
            mMemoryCache.put(key, bitmap);
        }
    }
private Bitmap getBitmapFromMemoryCache(String key) {
        return mMemoryCache.get(key);
    }
複製代碼

磁盤緩存添加和獲取

private Bitmap loadBitmapFromHttp(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;
        }
        String key = hashKeyFormUrl(url);
        DiskLruCache.Editor editor = mDiskLruCache.edit(key);
        if(editor!=null){
            OutputStream outputStream = editor.newOutputStream(DISK_CACHE_INDEX);
            if(downloadUrlToStream(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()) {
            throw new RuntimeException("load bitmap from UI Thread,it's not recommended");
        }
        if(mDiskLruCache ==null){
        return null;
        }
        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.decodeSampleFromFileDescriptor(fileDescriptor,reqWidth,reqHeight);
            if(bitmap !=null){
                addBitmapToMemoryCache(key,bitmap);
            }
        }
        return bitmap;
    }
複製代碼

2.3同步加載和異步加載接口的設計

看下同步加載:

public Bitmap loadBitmap(String uri,int reqWidth,int reqHeight){
        Bitmap bitmap = loadBitmapFromMemCache(uri);
        if(bitmap!=null){
            Log.e(TAG, "loadBitmapFromMemCache,url "+uri);
            return bitmap;
        }
        try {
            bitmap = loadBitmapFromDiskCache(uri,reqWidth,reqHeight);
            if(bitmap!=null){
                Log.e(TAG, "loadBitmapFromDiskCache,url "+uri );
                return bitmap;
            }
            bitmap = loadBitmapFromHttp(uri,reqWidth,reqHeight);
            Log.e(TAG, "loadBitmapFromHttp,url "+uri);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if(bitmap==null&&!mIsDiskLruCacheCreated){
            Log.e(TAG, "encounter error,DiskLruCache is not created.");
            bitmap = downLoadBitmapFromUrl(uri);
        }
        return bitmap;
    }
複製代碼

再看下異步加載

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);
                  Message message = mMainHandler.obtainMessage(MESSAGE_POST_RESULT,result);
                  message.sendToTarget();
//                  sendToTarget();
              }
          }
      };
      THREAD_POOL_EXECUTOR.execute(loadBitmapTask);
    }
複製代碼

仔細的同窗發現了,這裏面好像用到了線程池和Handler,關於線程池的內容這裏就不扯了,你們本身去度娘。

這裏直接把擼好的代碼放上來:

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);
            if(uri.equals(result.uri)){
                imageView.setImageBitmap(result.bitmap);
            }else {
                Log.d(TAG, "set image bitmap,but url has changed,ignored!");
            }
        }
    };
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);
        @Override
        public Thread newThread(@NonNull 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 LinkedBlockingDeque<Runnable>(),sThreadFactory);
複製代碼

哇哈哈哈哈哈哈哈哈。。。。。

終於要接近尾聲了,提取的很差,你們多見諒(有興趣的同窗必定要去看看任玉剛老師的書)。

下面仍是給下ImageLoader的完整代碼。

public class ImageLoader {
    private static final String TAG = "ImageLoader";
    private Context mContext;
    private LruCache<String, Bitmap> mMemoryCache;
    private DiskLruCache mDiskLruCache;
    private Bitmap bitmap;
    private static final int DISK_CACHE_SIZE = 50*1024*1024;
    private boolean mIsDiskLruCacheCreated;
    private static final int DISK_CACHE_INDEX  = 0;
    private ImageResizer mImageResizer;
    private String cachePath;
    private static final int IO_BUFFER_SIZE = 8*1024;
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    private static final int TAG_KEY_URI = R.id.imageloader_uri;
    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 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);
            if(uri.equals(result.uri)){
                imageView.setImageBitmap(result.bitmap);
            }else {
                Log.d(TAG, "set image bitmap,but url has changed,ignored!");
            }
        }
    };
    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);
        @Override
        public Thread newThread(@NonNull 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 LinkedBlockingDeque<Runnable>(),sThreadFactory);
    private static final int MESSAGE_POST_RESULT = 1;
    public ImageLoader(Context context) {
        mImageResizer = new ImageResizer();
        mContext = context;
        int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        int cacheSize = maxMemory / 8;
        mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes() * value.getHeight() / 1024;
            }
        };
        File diskCacheDir = getDiskCacheDir(mContext, "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();
            }
        }
    }
    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
    private long getUsableSpace(File path) {
         if(Build.VERSION.SDK_INT> Build.VERSION_CODES.GINGERBREAD){
             return path.getUsableSpace();
         }
        StatFs statFs = new StatFs(path.getPath());
         return statFs.getBlockSize()*statFs.getAvailableBlocks();
    }
    private File getDiskCacheDir(Context mContext, String uniqueName) {
     boolean externalStorageAvailable = Environment
             .getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
       if(externalStorageAvailable){
            cachePath = mContext.getExternalCacheDir().getPath();
       }else {
           cachePath = mContext.getCacheDir().getPath();
       }
       return new File(cachePath+File.separator+uniqueName);
    }
    /**
     * 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(String uri,int reqWidth,int reqHeight){
        Bitmap bitmap = loadBitmapFromMemCache(uri);
        if(bitmap!=null){
            Log.e(TAG, "loadBitmapFromMemCache,url "+uri);
            return bitmap;
        }
        try {
            bitmap = loadBitmapFromDiskCache(uri,reqWidth,reqHeight);
            if(bitmap!=null){
                Log.e(TAG, "loadBitmapFromDiskCache,url "+uri );
                return bitmap;
            }
            bitmap = loadBitmapFromHttp(uri,reqWidth,reqHeight);
            Log.e(TAG, "loadBitmapFromHttp,url "+uri);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if(bitmap==null&&!mIsDiskLruCacheCreated){
            Log.e(TAG, "encounter error,DiskLruCache is not created.");
            bitmap = downLoadBitmapFromUrl(uri);
        }
        return bitmap;
    }
    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);
                  Message message = mMainHandler.obtainMessage(MESSAGE_POST_RESULT,result);
                  message.sendToTarget();
//                  sendToTarget();
              }
          }
      };
      THREAD_POOL_EXECUTOR.execute(loadBitmapTask);
    }
    private Bitmap downLoadBitmapFromUrl(String uri) {
        Bitmap bitmap = null;
        HttpURLConnection urlConnection = null;
        BufferedInputStream in = null;
        try {
            URL url = new URL(uri);
            urlConnection = (HttpURLConnection) url.openConnection();
            in = new BufferedInputStream(urlConnection.getInputStream(),IO_BUFFER_SIZE);
            bitmap = BitmapFactory.decodeStream(in);
        } catch (IOException e) {
            Log.e(TAG, "Error in downloadBitmap:"+e);
        }finally {
            if(urlConnection!=null){
                urlConnection.disconnect();
            }
            MyUtils.close(in);
        }
        return bitmap;
    }
    private Bitmap loadBitmapFromMemCache(String url) {
        String key = hashKeyFormUrl(url);
        Bitmap bitmap = getBitmapFromMemoryCache(key);
        return bitmap;
    }
    private void addBitmapToMemoryCache(String key, Bitmap bitmap) {
        Log.e(TAG, "addBitmapToMemoryCache: ");
        if (getBitmapFromMemoryCache(key) == null) {
            mMemoryCache.put(key, bitmap);
        }
    }
    private Bitmap getBitmapFromMemoryCache(String key) {
        return mMemoryCache.get(key);
    }
    private Bitmap loadBitmapFromHttp(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;
        }
        String key = hashKeyFormUrl(url);
        DiskLruCache.Editor editor = mDiskLruCache.edit(key);
        if(editor!=null){
            OutputStream outputStream = editor.newOutputStream(DISK_CACHE_INDEX);
            if(downloadUrlToStream(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()) {
            throw new RuntimeException("load bitmap from UI Thread,it's not recommended");
        }
        if(mDiskLruCache ==null){
        return null;
        }
        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.decodeSampleFromFileDescriptor(fileDescriptor,reqWidth,reqHeight);
            if(bitmap !=null){
                addBitmapToMemoryCache(key,bitmap);
            }
        }
        return bitmap;
    }
    private boolean downloadUrlToStream(String urlString, OutputStream outputStream) {
        HttpURLConnection urlConnection=null;
        BufferedOutputStream out = null;
        BufferedInputStream in = null;
        try {
            URL url = new URL(urlString);
            urlConnection = (HttpURLConnection) url.openConnection();
            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) {
            e.printStackTrace();
        }finally {
            if(urlConnection!=null){
                urlConnection.disconnect();
            }
            MyUtils.close(out);
            MyUtils.close(in);
        }
        return false;
    }
    private String hashKeyFormUrl(String url) {
        String cacheKey;
        MessageDigest mDigest;
        try {
            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();
    }
}
複製代碼

本身模仿着寫了個項目分享到github上了。
Github地址

相關文章
相關標籤/搜索