緩存的使用之單張圖片 + 二級(jí)緩存

本文為單張圖片做二級(jí)緩存的實(shí)例

1坯约、LruCache工具類

/**
 * 圖片的內(nèi)存緩存工具類
 */
class CacheUtils {

    companion object{

        lateinit var mMemoryCache : LruCache<String, Bitmap>
        private var  maxMemory by Delegates.notNull<Int>()
        private var  cacheSize by Delegates.notNull<Int>()

        fun  initCacheAbout(){
            // 獲得虛擬機(jī)能提供的最大內(nèi)存熊咽,超過(guò)這個(gè)大小會(huì)拋出OutOfMemory的異常
            maxMemory = (Runtime.getRuntime().maxMemory() / 1024).toInt()
            cacheSize = maxMemory / 8
            mMemoryCache = ImageCache(cacheSize)
        }

        fun addBitmapToMemoryCache(key: String?, bitmap: Bitmap?) {
            if (getBitmapFromMemCache(key) == null) {
                Log.d("Neo","addBitmapToMemoryCache(存之前),長(zhǎng)度="+mMemoryCache.size())
                mMemoryCache.put(key, bitmap)
                Log.d("Neo","addBitmapToMemoryCache(存完之后)闹丐,長(zhǎng)度="+mMemoryCache.size())
            }
        }

        fun getBitmapFromMemCache(key: String?): Bitmap? {
            Log.d("Neo","getBitmapFromMemCache() temp=$mMemoryCache")
            Log.d("Neo","getBitmapFromMemCache() 長(zhǎng)度="+mMemoryCache.size())
            Log.d("Neo","getBitmapFromMemCache() temp[key]="+mMemoryCache[key])
            return mMemoryCache[key]
        }

        class ImageCache(cacheSize: Int) : LruCache<String, Bitmap>(cacheSize) {
            override fun sizeOf(key: String?, value: Bitmap?): Int {
                return value!!.byteCount / 1024
            }
        }

    }
}

2横殴、DiskLruCache工具類

/**
 * 圖片的磁盤緩存工具類
 */
class DiskLruCacheUtils {

    companion object{

        lateinit var mDiskLruCache: DiskLruCache

        /**
        * 初始化磁盤緩存
        */
        fun initDisk(context : Context){
            try {
                val cacheDir = getDiskCacheDir(context, "bitmap")
                if (!cacheDir.exists()) {
                    cacheDir.mkdirs()
                }
                mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersion(context), 1, 10 * 1024 * 1024)
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }

        /**
         * 獲取磁盤緩存路徑地址
         */
        fun getDiskCacheDir(context: Context, uniqueName: String): File {
            val cachePath: String = if (Environment.MEDIA_MOUNTED == Environment.getExternalStorageState()
                || !Environment.isExternalStorageRemovable()
            ) {
                context.externalCacheDir!!.path
            } else {
                context.cacheDir.path
            }
            return File(cachePath + File.separator + uniqueName)
        }

        /**
         * 獲取系統(tǒng)版本號(hào)
         */
        private fun getAppVersion(context: Context): Int {
            try {
                val info = context.packageManager.getPackageInfo(context.packageName, 0)
                return info.versionCode
            } catch (e: PackageManager.NameNotFoundException) {
                e.printStackTrace()
            }
            return 1
        }

        /**
         * 將圖片地址進(jìn)行MD5編碼
         */
        fun hashKeyForDisk(key: String): String? {
            return try {
                val mDigest: MessageDigest = MessageDigest.getInstance("MD5")
                mDigest.update(key.toByteArray())
                bytesToHexString(mDigest.digest())
            } catch (e: NoSuchAlgorithmException) {
                key.hashCode().toString()
            }
        }

        private fun bytesToHexString(bytes: ByteArray): String? {
            val sb = StringBuilder()
            for (i in bytes.indices) {
                val hex = Integer.toHexString(0xFF and bytes[i].toInt())
                if (hex.length == 1) {
                    sb.append('0')
                }
                sb.append(hex)
            }
            return sb.toString()
        }

        /**
         * 下載圖片并寫入磁盤緩存
         */
        fun downloadUrlToStream(urlString: String, outputStream: OutputStream): Boolean {
            var urlConnection: HttpURLConnection? = null
            var out: BufferedOutputStream? = null
            var `in`: BufferedInputStream? = null
            try {
                val url = URL(urlString)
                urlConnection = url.openConnection() as HttpURLConnection
                `in` = BufferedInputStream(urlConnection.inputStream, 8 * 1024)
                out = BufferedOutputStream(outputStream, 8 * 1024)
                var b: Int
                while (`in`.read().also { b = it } != -1) {
                    out.write(b)
                }
                return true
            } catch (e: IOException) {
                e.printStackTrace()
            } finally {
                urlConnection?.disconnect()
                try {
                    out?.close()
                    `in`?.close()
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
            return false
        }

        /**
         * 把byte字節(jié)寫入緩存DiskLruCache
         */
        @Throws(java.lang.Exception::class)
        fun writeToDiskLruCache(url: String, buf: ByteArray) {
            Log.d("TAG", "$url : 開(kāi)始寫入緩存...")

            //DiskLruCache緩存需要一個(gè)key,我先把url轉(zhuǎn)換成md5字符串卿拴,
            //然后以md5字符串作為key鍵
            val key: String? = hashKeyForDisk(url)
            val editor: DiskLruCache.Editor = mDiskLruCache.edit(key)
            val os: OutputStream = editor.newOutputStream(0)
            os.write(buf)
            os.flush()
            editor.commit()
            mDiskLruCache.flush()
            Log.d("TAG", "$url : 寫入緩存完成.")
        }

    }
}

3衫仑、單張圖片二級(jí)緩存的使用

  • 首先查看內(nèi)存緩存中是否有此圖片,如果有直接顯示堕花;
  • 如果內(nèi)存中沒(méi)有此圖文狱,則查看磁盤中是否有緩存,如果有則直接顯示缘挽,同時(shí)瞄崇,將內(nèi)存緩存的數(shù)據(jù)覆蓋;
  • 如果磁盤緩存也沒(méi)有數(shù)據(jù)壕曼,則需要請(qǐng)求網(wǎng)絡(luò)苏研,下載成功后,調(diào)用第一步的方法腮郊,重新將圖片寫入二級(jí)緩存摹蘑,然后顯示出來(lái);
/**
 * 單張圖片的 內(nèi)存緩存 + 磁盤緩存
 */
class SingleImageMemoryAndDiskCacheActivity : AppCompatActivity() {

    lateinit var imageView : ImageView
    private val oriUrl : String = "https://t7.baidu.com/it/u=2168645659,3174029352&fm=193&f=GIF"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_single_image_memory_and_disk_cache)
        imageView = findViewById(R.id.image_id)
        loadImage()
    }

    private fun loadImage(){
        try {

            //根據(jù)圖片地址拿到MD5之后的字符串
            val key = DiskLruCacheUtils.hashKeyForDisk(oriUrl)

            //先查看內(nèi)存緩存
            val bitmap = CacheUtils.getBitmapFromMemCache(key)

            //內(nèi)存緩存有數(shù)據(jù)轧飞,直接讀取并加載
            if (bitmap != null) {
                imageView.setImageBitmap(bitmap)
            }
            else { //內(nèi)存緩存無(wú)數(shù)據(jù)衅鹿,則查看磁盤緩存
                val snapShot = DiskLruCacheUtils.mDiskLruCache[key]

                //磁盤緩存有數(shù)據(jù),直接讀取并加載
                if (snapShot != null) {
                    val `is` = snapShot.getInputStream(0)
                    val bitmapFromDiskCache = BitmapFactory.decodeStream(`is`)
                    //如果磁盤有數(shù)據(jù)踪少,則將內(nèi)存緩存的數(shù)據(jù)覆蓋
                    CacheUtils.addBitmapToMemoryCache(key, bitmapFromDiskCache)
                    imageView.setImageBitmap(bitmapFromDiskCache)
                }
                //磁盤緩存也沒(méi)有數(shù)據(jù)塘安,則需要請(qǐng)求網(wǎng)絡(luò)
                else{
                    startDownload()
                }
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    /**
     * 下載網(wǎng)絡(luò)圖片并緩存到磁盤,完成后讀緩存
     */
    private fun startDownload(){
        Thread {
            try {
                val key = DiskLruCacheUtils.hashKeyForDisk(oriUrl)
                val editor = DiskLruCacheUtils.mDiskLruCache.edit(key)
                if (editor != null) {
                    val outputStream: OutputStream = editor.newOutputStream(0)
                    if (DiskLruCacheUtils.downloadUrlToStream(oriUrl, outputStream)) {
                        runOnUiThread {
                            loadImage()
                        }
                        editor.commit()
                    } else {
                        editor.abort()
                    }
                }
                DiskLruCacheUtils.mDiskLruCache.flush()
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }.start()
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末援奢,一起剝皮案震驚了整個(gè)濱河市兼犯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌集漾,老刑警劉巖切黔,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異具篇,居然都是意外死亡纬霞,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門驱显,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)诗芜,“玉大人瞳抓,你說(shuō)我怎么就攤上這事》郑” “怎么了孩哑?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)翠桦。 經(jīng)常有香客問(wèn)我横蜒,道長(zhǎng),這世上最難降的妖魔是什么销凑? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任丛晌,我火速辦了婚禮,結(jié)果婚禮上斗幼,老公的妹妹穿的比我還像新娘澎蛛。我一直安慰自己,他們只是感情好蜕窿,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布瓶竭。 她就那樣靜靜地躺著,像睡著了一般渠羞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上智哀,一...
    開(kāi)封第一講書(shū)人閱讀 49,950評(píng)論 1 291
  • 那天次询,我揣著相機(jī)與錄音,去河邊找鬼瓷叫。 笑死屯吊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的摹菠。 我是一名探鬼主播盒卸,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼次氨!你這毒婦竟也來(lái)了蔽介?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤煮寡,失蹤者是張志新(化名)和其女友劉穎虹蓄,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體幸撕,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡薇组,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了坐儿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片律胀。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡宋光,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出炭菌,到底是詐尸還是另有隱情罪佳,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布娃兽,位于F島的核電站菇民,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏投储。R本人自食惡果不足惜第练,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望玛荞。 院中可真熱鬧娇掏,春花似錦、人聲如沸勋眯。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)客蹋。三九已至塞蹭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間讶坯,已是汗流浹背番电。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留辆琅,地道東北人漱办。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像婉烟,于是被迫代替她去往敵國(guó)和親娩井。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容