1. 程式人生 > >Android網路圖片載入三級快取

Android網路圖片載入三級快取

一、概述

網路圖片的載入在Android的開發中是一個必不可少的功能,今天我們就來聊聊網路圖片載入三級快取策略。
所謂的三級快取策略是指通過網路、本地、記憶體三級來快取圖片,減少不必要的網路互動,避免浪費流量。

  • 記憶體快取, 優先載入, 速度最快
  • 本地快取, 次優先載入, 速度快
  • 網路快取, 不優先載入, 速度慢, 浪費流量

二、核心程式碼

網路圖片載入工具類ImageLoader.java

package com.czhappy.helloimageloader;

import android.graphics.Bitmap;
import android.widget.ImageView;

import
com.czhappy.helloimageloader.core.LocalCacheUtils; import com.czhappy.helloimageloader.core.MemoryCacheUtils; import com.czhappy.helloimageloader.core.NetCacheUtils; import com.czhappy.helloimageloader.utils.LogUtil; import com.czhappy.helloimageloader.utils.Utils; /** * Description:網路圖片載入工具類 * User: chenzheng * Date: 2017/2/11 0011 * Time: 11:21 */
public class ImageLoader { private static ImageLoader mInstance = null; private NetCacheUtils mNetCacheUtils; private LocalCacheUtils mLocalCacheUtils; private MemoryCacheUtils mMemoryCacheUtils; public static ImageLoader getInstance(){ if(mInstance==null){ synchronized
(ImageLoader.class){ if(mInstance==null){ mInstance = new ImageLoader(); } } } return mInstance; } private ImageLoader(){ mMemoryCacheUtils=new MemoryCacheUtils(); mLocalCacheUtils=new LocalCacheUtils(); mNetCacheUtils=new NetCacheUtils(mLocalCacheUtils,mMemoryCacheUtils); } /** * 載入網路圖片 * @param mImageView * @param url */ public void loadImageView(ImageView mImageView, String url) { mImageView.setImageResource(R.drawable.empty_photo); if(Utils.isEmpty(url)){ return; } Bitmap bitmap; //記憶體快取 LogUtil.i("嘗試從記憶體中獲取圖片..."); bitmap=mMemoryCacheUtils.getBitmapFromMemory(url); if (bitmap!=null){ mImageView.setImageBitmap(bitmap); return; } //本地快取 LogUtil.i("嘗試從本地獲取圖片..."); bitmap = mLocalCacheUtils.getBitmapFromLocal(url); if(bitmap !=null){ mImageView.setImageBitmap(bitmap); //從本地獲取圖片後,儲存至記憶體中 mMemoryCacheUtils.setBitmapToMemory(url,bitmap); return; } //網路快取 LogUtil.i("嘗試從網路獲取圖片..."); mNetCacheUtils.getBitmapFromNet(mImageView,url); } }

記憶體快取MemoryCacheUtils.java

package com.czhappy.helloimageloader.core;

import android.graphics.Bitmap;
import android.util.LruCache;

/**
 * Description: 記憶體快取
 * User: chenzheng
 * Date: 2017/2/11 0011
 * Time: 11:15
 */
public class MemoryCacheUtils {

    private LruCache<String,Bitmap> mMemoryCache;

    public MemoryCacheUtils(){
        long maxMemory = Runtime.getRuntime().maxMemory()/8;//得到手機最大允許記憶體的1/8,即超過指定記憶體,則開始回收
        //需要傳入允許的記憶體最大值,虛擬機器預設記憶體16M,真機不一定相同
        mMemoryCache=new LruCache<String,Bitmap>((int) maxMemory){
            //在每次存入快取的時候呼叫,用於計算每個條目的大小
            @Override
            protected int sizeOf(String key, Bitmap value) {
                int byteCount = value.getByteCount();
                return byteCount;
            }
        };

    }

    /**
     * 從記憶體中讀圖片
     * @param url
     */
    public Bitmap getBitmapFromMemory(String url) {
        Bitmap bitmap = mMemoryCache.get(url);
        return bitmap;

    }

    /**
     * 往記憶體中寫圖片
     * @param url
     * @param bitmap
     */
    public void setBitmapToMemory(String url, Bitmap bitmap) {
        mMemoryCache.put(url,bitmap);
    }
}

本地快取LocalCacheUtils.java

package com.czhappy.helloimageloader.core;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;

import com.czhappy.helloimageloader.utils.MD5Util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

/**
 * Description: 本地快取
 * User: chenzheng
 * Date: 2017/2/11 0011
 * Time: 11:15
 */
public class LocalCacheUtils {
    private static final String CACHE_PATH= Environment.getExternalStorageDirectory().getAbsolutePath()+"/HelloImageLoader";

    /**
     * 從本地讀取圖片
     * @param url
     */
    public Bitmap getBitmapFromLocal(String url){
        String fileName = null;//把圖片的url當做檔名,並進行MD5加密
        try {
            fileName = MD5Util.GetMD5Code(url);
            File file=new File(CACHE_PATH,fileName);

            if(file.exists()){
                Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(file));
                return bitmap;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 從網路獲取圖片後,儲存至本地快取
     * @param url
     * @param bitmap
     */
    public void setBitmapToLocal(String url,Bitmap bitmap){
        try {
            String fileName = MD5Util.GetMD5Code(url);//把圖片的url當做檔名,並進行MD5加密
            File file=new File(CACHE_PATH,fileName);

            //通過得到檔案的父檔案,判斷父檔案是否存在
            File parentFile = file.getParentFile();
            if (!parentFile.exists()){
                parentFile.mkdirs();
            }

            //把圖片儲存至本地
            bitmap.compress(Bitmap.CompressFormat.JPEG,100,new FileOutputStream(file));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

網路快取NetCacheUtils.java

package com.czhappy.helloimageloader.core;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.widget.ImageView;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * Description: 網路快取
 * User: chenzheng
 * Date: 2017/2/11 0011
 * Time: 11:15
 */
public class NetCacheUtils {
    private LocalCacheUtils mLocalCacheUtils;
    private MemoryCacheUtils mMemoryCacheUtils;

    public NetCacheUtils(LocalCacheUtils localCacheUtils, MemoryCacheUtils memoryCacheUtils) {
        mLocalCacheUtils = localCacheUtils;
        mMemoryCacheUtils = memoryCacheUtils;
    }

    /**
     * 從網路下載圖片
     * @param mImageView 顯示圖片的imageview
     * @param url   下載圖片的網路地址
     */
    public void getBitmapFromNet(ImageView mImageView, String url) {
        new BitmapTask().execute(mImageView, url);//啟動AsyncTask

    }

    /**
     * AsyncTask就是對handler和執行緒池的封裝
     * 第一個泛型:引數型別
     * 第二個泛型:更新進度的泛型
     * 第三個泛型:onPostExecute的返回結果
     */
    class BitmapTask extends AsyncTask<Object, Void, Bitmap> {

        private ImageView mImageView;
        private String url;

        /**
         * 後臺耗時操作,存在於子執行緒中
         * @param params
         * @return
         */
        @Override
        protected Bitmap doInBackground(Object[] params) {
            mImageView = (ImageView) params[0];
            url = (String) params[1];

            return downLoadBitmap(url);
        }

        /**
         * 更新進度,在主執行緒中
         * @param values
         */
        @Override
        protected void onProgressUpdate(Void[] values) {
            super.onProgressUpdate(values);
        }

        /**
         * 耗時方法結束後執行該方法,主執行緒中
         * @param result
         */
        @Override
        protected void onPostExecute(Bitmap result) {
            if (result != null) {
                mImageView.setImageBitmap(result);

                //從網路獲取圖片後,儲存至本地快取
                mLocalCacheUtils.setBitmapToLocal(url, result);
                //儲存至記憶體中
                mMemoryCacheUtils.setBitmapToMemory(url, result);

            }
        }
    }

    /**
     * 網路下載圖片
     * @param url
     * @return
     */
    private Bitmap downLoadBitmap(String url) {
        HttpURLConnection conn = null;
        try {
            conn = (HttpURLConnection) new URL(url).openConnection();
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(5000);
            conn.setRequestMethod("GET");

            int responseCode = conn.getResponseCode();
            if (responseCode == 200) {
                //圖片壓縮
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inSampleSize=2;//寬高壓縮為原來的1/2
                options.inPreferredConfig=Bitmap.Config.ARGB_4444;
                Bitmap bitmap = BitmapFactory.decodeStream(conn.getInputStream(),null,options);
                return bitmap;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            conn.disconnect();
        }

        return null;
    }
}

測試類

package com.czhappy.helloimageloaderdemo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;

import com.czhappy.helloimageloader.ImageLoader;

public class MainActivity extends AppCompatActivity {

    private ImageView my_image;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        my_image = (ImageView) findViewById(R.id.my_image);
    }

    public void beginLoad(View view){
        String url = "http://img06.tooopen.com/images/20161112/tooopen_sy_185726882764.jpg";
        ImageLoader.getInstance().loadImageView(my_image, url);
    }
}

三、實現效果圖

這裡寫圖片描述