天天看點

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()/;//得到手機最大允許記憶體的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,,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[];
            url = (String) params[];

            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();
            conn.setReadTimeout();
            conn.setRequestMethod("GET");

            int responseCode = conn.getResponseCode();
            if (responseCode == ) {
                //圖檔壓縮
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inSampleSize=;//寬高壓縮為原來的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);
    }
}
           

三、實作效果圖

Android網絡圖檔加載三級緩存