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);
    }
}

三、实现效果图

这里写图片描述

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值