图片缓存避免溢出

本文介绍了一个用于Android应用中的图片缓存工具类实现,该工具类可以有效地管理和维护应用程序内的图片资源缓存,包括缓存图片的获取、保存、清理等操作,并且考虑到了缓存大小限制及SD卡空间管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个类呢其实是我在慕课网上看的,当然了,我自己做了些改动,还是稍稍有点不同的。

class ImageFileCacheUtils(private var context: Context?) {

    constructor() : this(null){
        removeCache(cacheDirectory, 0.4f, false)
    }

    init {
        removeCache(cacheDirectory, 0.4f, false)
    }

    fun clearCache(): Boolean {
        return removeCache(cacheDirectory, 1.0f, true)
    }

    /**
     * 从文件缓存中获取图片
     * @param url
     * @return
     */
    fun getImage(url: String): Bitmap? {
        val path = cacheDirectory + "/" + convertUrlToFileName(url)
        val file = File(path)
        if (file.exists()) {
            val bitmap = BitmapFactory.decodeFile(path)
            if (bitmap == null) {
                file.delete()
                return null
            } else {
                updateFileTime(path)//更新文件最新访问时间
                return bitmap
            }
        } else {
            return null
        }
    }

    /**
     * 修改文件的最后修改时间
     * @param path
     */
    private fun updateFileTime(path: String) {
        val file = File(path)
        val newModeifyTime = System.currentTimeMillis()
        file.setLastModified(newModeifyTime)
    }

    fun saveBitmap(bitmap: Bitmap?, url: String) {
        if (bitmap == null) {
            return
        }
        //判断SD卡上的空间
        if (FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
            return
        }
        val fileName = convertUrlToFileName(url)
        val dir = cacheDirectory
        val dirFile = File(dir)
        if (!dirFile.exists()) {
            dirFile.mkdirs()
        }
        val file = File("$dir/$fileName")
        try {
            file.createNewFile()
            val outputStream = FileOutputStream(file)
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
            outputStream.flush()
            outputStream.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }

    }

    /**
     * 计算sd卡上的剩余空间
     * @return
     */
    fun freeSpaceOnSd(): Int {
        val statFs = StatFs(Environment.getExternalStorageDirectory().path)
        val sdFreeMB = statFs.availableBlocks.toDouble() * statFs.blockSize.toDouble() / MB
        Log.i("ImageFileCacheUtils:", "剩余空间为:$sdFreeMB")
        return sdFreeMB.toInt()
    }

    /**
     * 获取文件夹中缓存文件.cache占用存储空间大小
     * @return
     */
    fun cacheSizeOnSd(): Int {
        val dirFile = File(cacheDirectory)
        val files = dirFile.listFiles()
        if (files == null || files.size <= 0) {
            return 0
        }
        //如果sd卡没有挂载
        if (Environment.getExternalStorageState() != Environment.MEDIA_MOUNTED) {
            return 0
        }
        var dirSize = 0
        for (i in files.indices) {
            if (files[i].name.contains(WHOLESALE_CONV)) {
                dirSize += files[i].length().toInt()
            }
        }

        return dirSize
    }

    /**
     * 将url转成文件名
     * @param url
     * @return
     */
    private fun convertUrlToFileName(url: String): String {
        val strs = url.split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
        return strs[strs.size - 1] + WHOLESALE_CONV
    }

    /**
     * 计算存储目录下的文件大小
     * 当文件总大小大于规定的大小或者sd卡剩余空间小于FREE_SD_SPACE_NEEDED_TO_CACHE的规定时
     * ,那么删除removeSize * 100%最近没有被使用的文件
     * @param dirPath
     * @return
     */
    private fun removeCache(dirPath: String, removeSize: Float, isClearAll: Boolean): Boolean {
        val dirFile = File(dirPath)
        val files = dirFile.listFiles()
        if (files == null || files.size <= 0) {
            return true
        }
        //如果sd卡没有挂载
        if (Environment.getExternalStorageState() != Environment.MEDIA_MOUNTED) {
            if (context != null) {
                Toast.makeText(context, "检测不到外部存储空间,无法使用缓存!", Toast.LENGTH_SHORT).show()
            }
            return false
        }

        val dirSize = cacheSizeOnSd()
        if (isClearAll || dirSize > CACHE_SIZE * MB || FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
            val removeFactor: Int
            if (removeSize < 1) {
                removeFactor = (removeSize * files.size + 1).toInt()
            } else {
                removeFactor = files.size
            }

            Arrays.sort(files, FileLastModifySoft())
            for (i in 0 until removeFactor) {
                if (files[i].name.contains(WHOLESALE_CONV)) {
                    files[i].delete()
                }
            }
        }
        if (freeSpaceOnSd() <= CACHE_SIZE) {
            if (context != null) {
                Toast.makeText(context, "存储空间不足,请及时清理!", Toast.LENGTH_SHORT).show()
            }
            return false
        }
        return true
    }

    //比较器类
    private inner class FileLastModifySoft : Comparator<File> {
        override fun compare(arg0: File, arg1: File): Int {
            return if (arg0.lastModified() > arg1.lastModified()) {
                1
            } else if (arg0.lastModified() == arg1.lastModified()) {
                0
            } else {
                -1
            }
        }
    }

    companion object {
        private val CHCHEDIR = "ImageChace"//缓存目录
        val WHOLESALE_CONV = ".cache"//缓存文件后缀名
        private val MB = 1024 * 1024
        private val CACHE_SIZE = 80//缓存最大容量(超过就会利用lru算法删除最近最少使用的缓存文件)
        private val FREE_SD_SPACE_NEEDED_TO_CACHE = 100//缓存所需SD卡所剩的最小容量

        private var util: ImageFileCacheUtils = ImageFileCacheUtils()
        //单例模式

        fun getInstance(): ImageFileCacheUtils {
            if (util == null) {
                synchronized(ImageFileCacheUtils::class.java) {
                    if (util == null) {
                        util = ImageFileCacheUtils()
                    }
                }
            }
            return util
        }

        fun getInstance(context: Context): ImageFileCacheUtils {
            if (util == null) {
                synchronized(ImageFileCacheUtils::class.java) {
                    if (util == null) {
                        util = ImageFileCacheUtils(context)
                    }
                }
            }
            return util
        }

        /**
         * 获得缓存目录
         * @return
         */
        val cacheDirectory: String
            get() = "${sdPath}/${CHCHEDIR}"

        private//判断SD卡是否挂载
        //获取根目录
        val sdPath: String
            get() {
                var sdDir: File? = null
                val adCardExit = Environment.getExternalStorageState()
                        .endsWith(Environment.MEDIA_MOUNTED)
                if (adCardExit) {
                    sdDir = Environment.getExternalStorageDirectory()
                }
                return if (sdDir != null) {
                    sdDir.toString()
                } else {
                    ""
                }
            }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值