Android 文件缓存方法

前言

我们经常遇到从网络获取图片,为了使图片查看流畅,我们肯定要使用缓存,大部分我们会使用内存缓存,但是android内存缓存毕竟是有限的,这样的话,我们必须使用文件来缓存部分图片。

思路

当我们把一张图片从网络下载成功以后,这个图片会被加入内存缓存和文件缓存,内存缓存来说请参考Android内存溢出大总结,对于文件缓存来说,这张图片将被以url的哈希值加cach后缀名的形式存储在SD卡上,这样,当下一次再需要同一个url的图片的时候,就不需要从网络下载了,而是直接通过url来进行查找。同时一张图片被访问时,它的最后修改时间将被更新,这样的意义在于:当SD卡空间不足的时候,将会按照最后修改时间来删除40%缓存的图片,确切来说,那些修改时间比较早的图片将会被删除。

代码

package com.ty.highway.highwaysystem.support.utils.cache;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.os.StatFs;
import android.util.Log;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Comparator;

/**
 * Created by fuweiwei on 2016/1/26.
 * 文件缓存
 * 内存缓存是有限的,其它的文件缓存,当文件缓存操作一定量时我们删除之前的缓存
 */
public class ImageFileCache
{
    private static final String TAG = "ImageFileCache";

    //图片缓存目录
    private static final String IMGCACHDIR = "/sdcard/ImgCach";

    //保存的cache文件宽展名
    private static final String CACHETAIL = ".cach";

    private static final int MB = 1024*1024;

    private static final int CACHE_SIZE = 1;

    //当SD卡剩余空间小于10M的时候会清理缓存
    private static final int FREE_SD_SPACE_NEEDED_TO_CACHE = 10;

    public ImageFileCache()
    {
        //清理部分文件缓存
        removeCache(IMGCACHDIR);
    }

    /**
     * 从缓存中获取图片
     */
    public Bitmap getImageFromFile(final String url)
    {
        final String path = IMGCACHDIR + "/" + convertUrlToFileName(url);
        File file = new File(path);
        if (file != null && file.exists())
        {
            Bitmap bmp = BitmapFactory.decodeFile(path);
            if (bmp == null)
            {
                file.delete();
            }
            else
            {
                updateFileTime(path);
                Log.d(TAG, "get bmp from FileCache,url=" + url);
                return bmp;
            }
        }
        return null;
    }

    /**
     * 将图片存入文件缓存
     */
    public void saveBitmapToFile(Bitmap bm, String url)
    {
        if (bm == null) {
            return;
        }
        //判断sdcard上的空间
        if (FREE_SD_SPACE_NEEDED_TO_CACHE > SdCardFreeSpace())
        {
            //SD空间不足
            return;
        }

        String filename = convertUrlToFileName(url);
        File dirFile = new File(IMGCACHDIR);
        if (!dirFile.exists())
            dirFile.mkdirs();
        File file = new File(IMGCACHDIR +"/" + filename);
        try
        {
            file.createNewFile();
            OutputStream outStream = new FileOutputStream(file);
            bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
            outStream.flush();
            outStream.close();
        }
        catch (FileNotFoundException e)
        {
            Log.d(TAG, "FileNotFoundException");
        }
        catch (IOException e)
        {
            Log.d(TAG, "IOException");
        }
    }

    /**
     * 计算存储目录下的文件大小,
     * 当文件总大小大于规定的CACHE_SIZE或者sdcard剩余空间小于FREE_SD_SPACE_NEEDED_TO_CACHE的规定
     * 那么删除40%最近没有被使用的文件
     */
    private boolean removeCache(String dirPath)
    {
        File dir = new File(dirPath);
        File[] files = dir.listFiles();

        if (files == null)
        {
            return true;
        }

        if (!android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
        {
            return false;
        }

        int dirSize = 0;
        for (int i = 0; i < files.length; i++)
        {
            if (files[i].getName().contains(CACHETAIL))
            {
                dirSize += files[i].length();
            }
        }

        if (dirSize > CACHE_SIZE * MB || FREE_SD_SPACE_NEEDED_TO_CACHE > SdCardFreeSpace())
        {
            int removeFactor = (int) (0.4 * files.length);
            Arrays.sort(files, new FileLastModifSort());
            for (int i = 0; i < removeFactor; i++)
            {
                if (files[i].getName().contains(CACHETAIL))
                {
                    files[i].delete();
                }
            }
        }

        if (SdCardFreeSpace() <= CACHE_SIZE)
        {
            return false;
        }

        return true;
    }

    /**
     * 修改文件的最后修改时间
     */
    public void updateFileTime(String path)
    {
        File file = new File(path);
        long newModifiedTime = System.currentTimeMillis();
        file.setLastModified(newModifiedTime);
    }

    /**
     * 计算SD卡上的剩余空间
     */
    private int SdCardFreeSpace()
    {
        StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
        double sdFreeMB = ((double)stat.getAvailableBlocks() * (double) stat.getBlockSize()) / MB;
        return (int) sdFreeMB;
    }

    /**
     * 将url转成文件名
     */
    private String convertUrlToFileName(String url)
    {
        return url.hashCode() + CACHETAIL;
    }

    /**
     * 根据文件的最后修改时间进行排序
     */
    private class FileLastModifSort implements Comparator<File>
    {
        public int compare(File file0, File file1)
        {
            if (file0.lastModified() > file1.lastModified())
            {
                return 1;
            }
            else if (file0.lastModified() == file1.lastModified())
            {
                return 0;
            }
            else
            {
                return -1;
            }
        }
    }

}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值