Android如何優雅的緩存網絡圖片

Android如何優雅的緩存網絡圖片

在Android開發中,基本上都會有與網絡握手,如果沒實現這個功能,那也就只能是在開發一個“單機遊戲”咯。既然從網絡獲取數據,那就避免不了加載網絡數據,那麼問題來了,流量怎麼辦?大家都知道,加載網絡圖片比加載網絡文本耗費的流量多得多。不用擔心,今天來分享以下如何緩存網絡圖片到本地來:

  • 根據圖片的url去加載,本地有就加載本地,沒有則請求網絡
  • 圖片壓縮,降低內存使用
  • 圖片鏈接和圖片上傳

主要思路

在我們我實現圖片顯示的時候,一般都是在Adapter裏面,或者其他地方,先調用我們工具類的主方法,主方法重載了兩個,傳入的參數不一樣,一個是傳ImageView加圖片的url,一個是隻傳url,這個根據你的需求來。調用主方法後,工具類先會從內存中去加載,如果沒有就去本地加載,本地也沒有,就就只能去網絡請求了,所以會有三個類是去做對應地方的操作。

不羅嗦,上代碼

這是主方法,都有註釋的,扯那麼多理論也還是抵不過一行代碼

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

import com.example.smilefood.R;

/**
 * 自定義圖片加載工具類
 * 
 * @author Kevin
 * 
 */
public class MyBitmapUtils {

    private NetCacheUtils mNetCacheUtils;
    private LocalCacheUtils mLocalCacheUtils;
    private MemoryCacheUtils mMemoryCacheUtils;

    public MyBitmapUtils() {

        mMemoryCacheUtils = new MemoryCacheUtils();
        mLocalCacheUtils = new LocalCacheUtils();
        mNetCacheUtils = new NetCacheUtils(mLocalCacheUtils, mMemoryCacheUtils);

    }

    /**
     * 加載圖片的核心api
     * 
     * @param ivPic
     *            ImageView對象
     * @param url
     *            圖片鏈接
     */
    public void display(ImageView ivPic, String url) {
        // 從內存緩存讀
        Bitmap bitmap = mMemoryCacheUtils.getBitmapFromMemory(url);
        if(bitmap!=null) {//如果內存存在,就直接設置並返回
            ivPic.setImageBitmap(bitmap);
            System.out.println("從內存讀取圖片");
            return;
        }

        // 從本地緩存讀
        bitmap = mLocalCacheUtils.getBitmapFromLocal(url);
        if (bitmap != null) {//如果本地文件存在,就直接設置並返回
            ivPic.setImageBitmap(bitmap);
            System.out.println("從本地讀取圖片");
            mMemoryCacheUtils.putBitmapToMemory(url, bitmap);//設置內存圖片
            return;
        }

        // 從網絡緩存下載
        mNetCacheUtils.getBitmapFromNet(ivPic, url);
    }
    public Bitmap display( String url) {
        // 從內存緩存讀
        Bitmap bitmap = mMemoryCacheUtils.getBitmapFromMemory(url);
        if(bitmap!=null) {//如果內存存在,就直接設置並返回

            System.out.println("從內存讀取圖片");
            return bitmap;
        }

        // 從本地緩存讀
        bitmap = mLocalCacheUtils.getBitmapFromLocal(url);
        if (bitmap != null) {//如果本地文件存在,就直接設置並返回

            System.out.println("從本地讀取圖片");
            mMemoryCacheUtils.putBitmapToMemory(url, bitmap);//設置內存圖片
            return bitmap;
        }

        // 從網絡緩存下載
        //mNetCacheUtils.getBitmapFromNet(ivPic, url);
        return null;
    }
}

本地緩存工具類

public class LocalCacheUtils {

    private static final String LOCAL_PATH = Environment
            .getExternalStorageDirectory().getAbsolutePath() + "/smile_cache";

    /**
     * 從本地讀取圖片
     * 
     * @param url
     * @return
     */
    public Bitmap getBitmapFromLocal(String url) {

        try {
            String fileName = url;
            File file = new File(LOCAL_PATH, fileName);

            if (file.exists()) {
                // 圖片壓縮
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inSampleSize = 2;// 表示壓縮比例,2表示寬高都壓縮爲原來的二分之一, 面積爲四分之一
                options.inPreferredConfig = Config.RGB_565;// 設置bitmap的格式,565可以降低內存佔用

                Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(
                        file), null, options);
                return bitmap;
            } else {
                return null;
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 向本地存圖片
     * 
     * @param url
     * @param bitmap
     */
    public void putBitmapToLocal(String url, Bitmap bitmap) {
        try {
            String fileName =url;
            File file = new File(LOCAL_PATH, fileName);
            File parent = file.getParentFile();

            // 創建父文件夾
            if (!parent.exists()) {
                parent.mkdirs();
            }

            bitmap.compress(CompressFormat.JPEG, 100,
                    new FileOutputStream(file));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

內存緩存工具類

public class MemoryCacheUtils {

    // HashMap<String, SoftReference<Bitmap>> mMemoryCache = new HashMap<String,
    // SoftReference<Bitmap>>();
    LruCache<String, Bitmap> mMemoryCache;

    public MemoryCacheUtils() {
        int maxMemory = (int) Runtime.getRuntime().maxMemory();// 當前手機分配給app進程的最大內存,虛擬機默認16M

        System.out.println("maxMemory:" + maxMemory);
        mMemoryCache = new LruCache<String, Bitmap>(maxMemory / 8) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                int size = value.getRowBytes() * value.getHeight();// 返回bitmap佔用的內存大小
                System.out.println("sizeof:" + size);
                return size;
            }
        };
    }

    /**
     * 從內存讀取圖片
     * 
     * @param url
     * @return
     */
    public Bitmap getBitmapFromMemory(String url) {
        // SoftReference<Bitmap> softBitmap = mMemoryCache.get(url);
        // System.out.println("讀取內存圖片。。。" + softBitmap);
        // if (softBitmap != null) {
        // Bitmap bitmap = softBitmap.get();
        // System.out.println("讀取內存圖片成功。。。" + bitmap);
        // return bitmap;
        // }

        Bitmap bitmap = mMemoryCache.get(url);
        return bitmap;
    }

    /**
     * 向內存存圖片
     * 
     * @param url
     * @param bitmap
     */
    public void putBitmapToMemory(String url, Bitmap bitmap) {
        // System.out.println("設置內存圖片。。。");
        // SoftReference<Bitmap> softBitmap = new
        // SoftReference<Bitmap>(bitmap);// 通過軟引用對對象包裝
        // mMemoryCache.put(url, softBitmap);
        mMemoryCache.put(url, bitmap);
    }

}

網絡緩存工具類

public class NetCacheUtils {

    LocalCacheUtils mLocalCacheUtils;
    MemoryCacheUtils mMemoryCacheUtils;

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

    public void getBitmapFromNet(ImageView ivPic, String url) {
        BitmapTask task = new BitmapTask();
        task.execute(new Object[] { ivPic, url });
    }

    class BitmapTask extends AsyncTask<Object, Void, Bitmap> {

        private ImageView imageView;
        private String url;

        /**
         * 返回的對象會自動回傳到onPostExecute裏面
         */
        @Override
        protected Bitmap doInBackground(Object... params) {
            imageView = (ImageView) params[0];
            url = (String) params[1];
            imageView.setTag(url);
            Bitmap bitmap = downloadBitmap(url);
            return bitmap;
        }

        @Override
        protected void onPostExecute(Bitmap result) {
            // 這裏的result就是doInBackground返回回來的對象
            if (result != null) {
                String ivUrl = (String) imageView.getTag();
                if (url.equals(ivUrl)) {// 確保imageview設置的是正確的圖片(因爲有時候listview有重用機制,多個item會公用一個imageview對象,從而導致圖片錯亂)
                    imageView.setImageBitmap(result);
                    System.out.println("從網絡緩存讀取圖片");

                    // 向本地保存圖片文件
                    mLocalCacheUtils.putBitmapToLocal(url, result);
                    // 向內存保存圖片對象
                    mMemoryCacheUtils.putBitmapToMemory(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");
            conn.connect();

            int responseCode = conn.getResponseCode();
            if (responseCode == 200) {
                InputStream inputStream = conn.getInputStream();

                //圖片壓縮
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inSampleSize = 2;//表示壓縮比例,2表示寬高都壓縮爲原來的二分之一, 面積爲四分之一
                options.inPreferredConfig = Config.RGB_565;//設置bitmap的格式,565可以降低內存佔用

                Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options);
                return bitmap;
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            conn.disconnect();
        }

        return null;
    }

}

最後說兩句,想要加載圖片的時候直接看下面

new MyBitmapUtils().display(holder.foodImg_img,mFoodList.get(position).getFoodUrl());

這裏我是在Adapter裏面要實現item裏面一個ImageView顯示圖片

瀏覽器兼容

  1. 目前,本編輯器對Chrome瀏覽器支持最爲完整。建議大家使用較新版本的Chrome。
  2. IE9以下不支持
  3. IE9,10,11存在以下問題
    1. 不支持離線功能
    2. IE9不支持文件導入導出
    3. IE10不支持拖拽文件導入

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章