Android的三级缓存,其中主要的就是内存缓存和硬盘缓存,分别是LruCache和DisLruCache。

LruCache是Android 3.1所提供的一个缓存类,所以在Android中可以直接使用LruCache实现内存缓存。而DisLruCache目前在Android 还不是Android SDK的一部分,但Android官方文档推荐使用该算法来实现硬盘缓存。

简单使用

var listJob = ArrayList()KotlinCacheUtil.INSTANCE.init(application)val imageJob = KotlinCacheUtil.INSTANCE.setImageBitmap(            "https://img-my.csdn.net/uploads/201309/01/1378037235_7476.jpg",            imageView,            R.drawable.ic_launcher        )listJob.add(imageJob)

取消协程防止内存泄漏

override fun onDestroy() {    super.onDestroy()    for (job in listJob){        job.cancel()    }}

本文使用了Kotlin协程需要导入kotlinx-coroutines,网络请求框架okhttp

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.2.1'implementation 'com.squareup.okhttp3:okhttp:3.14.1'implementation 'com.squareup.okio:okio:2.2.2'

混淆代码

##okhttp3混淆-keep class okhttp3.** {*;}-dontwarn okhttp3.**##okio混淆-keep class okio.** {*;}-dontwarn okio.**

权限

6.0以上使用sd卡需要动态申请权限,自行百度

一、LruCache

不废话直接上工具类,初始化会在另一个管理缓存的工具类中使用,这里不需要操心

public class LruCacheUtil {    private static volatile LruCacheUtil instance;    private LruCacheUtil() {}    public static LruCacheUtil getInstance() {        if (instance == null) {            synchronized (LruCacheUtil.class) {                if (instance == null) {                    instance = new LruCacheUtil();                }            }        }        return instance;    }    private LruCache lruCache;    /**     * 初始化     */    public void init() {        long maxMemory = Runtime.getRuntime().maxMemory();        int cacheSize = (int) (maxMemory / 8);        lruCache = new LruCache(cacheSize) {            @Override            protected int sizeOf(@NotNull String key, @NotNull Bitmap value) {                return value.getByteCount();            }        };    }    /**     * 把Bitmap对象加入到缓存中     * @param imageUrl 图片url     * @param bitmap 加入缓存的图片     */    public void addBitmapToMemory(String imageUrl, Bitmap bitmap) {        String key = Md5Util.getInstance().MD5(imageUrl);        if (getBitmapFromMemCache(key) == null) {            lruCache.put(key, bitmap);        }    }    /**     * 从缓存中得到Bitmap对象     * @param imageUrl 图片url     * @return Bitmap     */    public Bitmap getBitmapFromMemCache(String imageUrl) {        String key = Md5Util.getInstance().MD5(imageUrl);        return lruCache.get(key);    }    /**     * 从缓存中删除指定的Bitmap     * @param imageUrl 图片url     */    public void removeBitmapFromMemory(String imageUrl) {        String key = Md5Util.getInstance().MD5(imageUrl);        lruCache.remove(key);    }    /**     * 清除所有缓存     */    public void evictAll(){        lruCache.evictAll();    }}

二、DisLruCache

今年Kotlin语言从安卓一等公民升级为第一等公民,是时候重新学习一波Kotlin了,DisLruCache工具类使用了新特性“协程”,没有了解的小伙伴可以先了解一下,用过后都说好;Kotlin的IO流值得吹一波,实在太好用了,inputStream.copyTo(outputStream)一行代码解决从一个流写到另一个流;最后吹一波Kotlin的单例模式,实在太好用了。

不要忘了这个

implementation 'com.jakewharton:disklrucache:2.0.2'

工具类

enum class DiskLruCacheUtil {    INSTANCE;    private lateinit var application: Application    private lateinit var diskLruCache: DiskLruCache    fun init(application: Application) {        this.application = application        try {            diskLruCache = DiskLruCache.open(directory("bitmap"), getAppVersion(), 1, (10 * 1024 * 1024).toLong())        } catch (e: IOException) {            e.printStackTrace()        } catch (e: PackageManager.NameNotFoundException) {            e.printStackTrace()        }    }    /**     * 把Bitmap对象加入到缓存中     * @param imageUrl 图片url,如https://img-my.csdn.net/uploads/201309/01/1378037235_7476.jpg     * @param bitmap 加入缓存的图片     */    fun addBitmapToMemory(imageUrl: String){        try {            val key = Md5Util.getInstance().MD5(imageUrl)            val editor = diskLruCache.edit(key)            if (editor != null) {                val outputStream = editor.newOutputStream(0)                if (downloadUrlStream(imageUrl, outputStream)){                    editor.commit()                }else{                    editor.abort()                }            }            diskLruCache.flush()        } catch (e: IOException) {            e.printStackTrace()        }    }    /**     * 网络下载     * @param imageUrl 图片url     * @param outputStream diskLruCache的IO流     * @return 是否下载成功     */    private fun downloadUrlStream(imageUrl: String, outputStream: OutputStream) :Boolean{        val request = Request.Builder()            .url(imageUrl)            .build()        try {            val response = HttpUtil.getInstance().client.newCall(request).execute()            if (response.isSuccessful) {                if (response.body()!= null){                    val bis = response.body()!!.byteStream().buffered()                    val bos = outputStream.buffered()                    try {                        bis.copyTo(bos)                        return true                    }catch (e: IOException) {                        e.printStackTrace()                    }finally {                        bis.close()                        bos.close()                    }                }            }        } catch (e: IOException) {            e.printStackTrace()        }        return false    }    /**     * 从缓存中得到Bitmap对象     * @param imageUrl 图片url     * @return Bitmap     */    fun getBitmapFromMemCache(imageUrl: String,maxWidth:Int,maxHeight:Int): Bitmap? {        val key = Md5Util.getInstance().MD5(imageUrl)        val snapShot = diskLruCache.get(key)        if (snapShot!=null){            val inputStream = snapShot.getInputStream(0)            return BitmapUtil.getInstance().getBitmap(inputStream,maxWidth,maxHeight,false)        }        return null    }    /**     * 从缓存中删除指定的Bitmap     * @param imageUrl 图片url     */    fun removeBitmapFromMemory(imageUrl: String) {        val key = Md5Util.getInstance().MD5(imageUrl)        diskLruCache.remove(key)    }    /**     * 所有缓存数据的总字节数     */    fun getSize():Long{        return diskLruCache.size()    }    /**     * 同步数据,在Activity的onPause()方法中去调用一次flush()方法     */    fun flush(){        diskLruCache.flush()    }    /**     * 在Activity的onDestroy()方法中去调用close()方法     */    fun close(){        diskLruCache.close()    }    /**     * 将所有的缓存数据全部删除     */    fun delete(){        diskLruCache.delete()    }    /**     * 缓存目录     */    private fun directory(fileName: String): File {        val path: String        //判断SD卡是否可用        if (Environment.MEDIA_MOUNTED == Environment.getExternalStorageState() || !Environment.isExternalStorageRemovable()) {            path = application.externalCacheDir!!.absolutePath        } else {            path = application.cacheDir.absolutePath        }        val file = File(path, fileName)        if (!file.exists()) {            file.mkdirs()        }        return file    }    /**     * app版本     */    @Throws(PackageManager.NameNotFoundException::class)    private fun getAppVersion(): Int {        val info = application.packageManager.getPackageInfo(application.packageName, 0)        return info.versionCode    }}

如果你有使用okhttp,那么也可以使用okhttp的DiskLruCache

enum class OKDiskLruCacheUtil {    INSTANCE;    private lateinit var application: Application    private lateinit var diskLruCache: DiskLruCache    fun init(application: Application) {        this.application = application        try {            diskLruCache = DiskLruCache.create(                FileSystem.SYSTEM,                directory("bitmap"),                getAppVersion(),                1,                10 * 1024 * 1024            )        } catch (e: IOException) {            e.printStackTrace()        } catch (e: PackageManager.NameNotFoundException) {            e.printStackTrace()        }    }    /**     * 把Bitmap对象加入到缓存中     * @param imageUrl 图片url,如https://img-my.csdn.net/uploads/201309/01/1378037235_7476.jpg     * @param bitmap 加入缓存的图片     */    fun addBitmapToMemory(imageUrl: String){        try {            val key = Md5Util.getInstance().MD5(imageUrl)            val editor = diskLruCache.edit(key)            if (editor != null) {                val outputStream= editor.newSink(0).buffer().outputStream()                if (downloadUrlStream(imageUrl, outputStream)){                    editor.commit()                }else{                    editor.abort()                }            }            diskLruCache.flush()        } catch (e: IOException) {            e.printStackTrace()        }    }    /**     * 网络下载     * @param imageUrl 图片url     * @param outputStream diskLruCache的IO流     * @return 是否下载成功     */    private fun downloadUrlStream(imageUrl: String, outputStream: OutputStream) :Boolean{        val request = Request.Builder()            .url(imageUrl)            .build()        try {            val response = HttpUtil.getInstance().client.newCall(request).execute()            if (response.isSuccessful) {                if (response.body()!= null){                    val bis = response.body()!!.byteStream().buffered()                    val bos = outputStream.buffered()                    try {                        bis.copyTo(bos)                        return true                    }catch (e: IOException) {                        e.printStackTrace()                    }finally {                        bis.close()                        bos.close()                    }                }            }        } catch (e: IOException) {            e.printStackTrace()        }        return false    }    /**     * 从缓存中得到Bitmap对象     * @param imageUrl 图片url     * @return Bitmap     */    fun getBitmapFromMemCache(imageUrl: String,maxWidth:Int,maxHeight:Int): Bitmap? {        val key = Md5Util.getInstance().MD5(imageUrl)        val snapShot = diskLruCache.get(key)        if (snapShot!=null){            val inputStream = snapShot.getSource(0).buffer().inputStream()            return BitmapUtil.getInstance().getBitmap(inputStream,maxWidth,maxHeight,false)        }        return null    }    /**     * 从缓存中删除指定的Bitmap     * @param imageUrl 图片url     */    fun removeBitmapFromMemory(imageUrl: String) {        val key = Md5Util.getInstance().MD5(imageUrl)        diskLruCache.remove(key)    }    /**     * 所有缓存数据的总字节数     */    fun getSize():Long{        return diskLruCache.size()    }    /**     * 同步数据,在Activity的onPause()方法中去调用一次flush()方法     */    fun flush(){        diskLruCache.flush()    }    /**     * 在Activity的onDestroy()方法中去调用close()方法     */    fun close(){        diskLruCache.close()    }    /**     * 将所有的缓存数据全部删除     */    fun delete(){        diskLruCache.delete()    }    /**     * 缓存目录     */    private fun directory(fileName: String): File {        val path: String        //判断SD卡是否可用        if (Environment.MEDIA_MOUNTED == Environment.getExternalStorageState() || !Environment.isExternalStorageRemovable()) {            path = application.externalCacheDir!!.absolutePath        } else {            path = application.cacheDir.absolutePath        }        val file = File(path, fileName)        if (!file.exists()) {            file.mkdirs()        }        return file    }    /**     * app版本     */    @Throws(PackageManager.NameNotFoundException::class)    private fun getAppVersion(): Int {        val info = application.packageManager.getPackageInfo(application.packageName, 0)        return info.versionCode    }}

三、三级缓存工具类

enum class KotlinCacheUtil {    INSTANCE;    private lateinit var application: Application    /**     * 初始化     * @param application     */    fun init(application: Application) {        this.application = application        screenWidth()        //内存缓存初始化        LruCacheUtil.getInstance().init()        //磁盘缓存初始化        OKDiskLruCacheUtil.INSTANCE.init(application)        //http初始化        HttpUtil.getInstance().init()    }    /**     * 三级缓存     * @param imageUrl 图片url     * @param imageView 显示控件     * @param placeholderBitmap 占位图     */    private fun setImageBitmap(imageUrl: String, imageView: ImageView, placeholderBitmap: Bitmap) :Job{        //设置占位图        imageView.setImageBitmap(placeholderBitmap)        return GlobalScope.launch {            //1.先从内存读取            var bitmap: Bitmap? = LruCacheUtil.getInstance().getBitmapFromMemCache(imageUrl)            if (bitmap == null) {                //2.如果没有则从磁盘读取                bitmap = OKDiskLruCacheUtil.INSTANCE.getBitmapFromMemCache(imageUrl,width,height)                if (bitmap == null) {                    if (isNetworkConnected()) {                        //3.从网络获取并加入磁盘缓存                        OKDiskLruCacheUtil.INSTANCE.addBitmapToMemory(imageUrl)                        //从磁盘缓存中获取bitmap                        bitmap = OKDiskLruCacheUtil.INSTANCE.getBitmapFromMemCache(imageUrl,width,height)                        if (bitmap == null) {                            launch (Dispatchers.Main){                                show("没有可用网络")                            }                            return@launch                        }                        //加入内存缓存                        LruCacheUtil.getInstance().addBitmapToMemory(imageUrl, bitmap)                    } else {                        //4.如果没有网络提示                        launch (Dispatchers.Main){                            show("没有可用网络")                        }                        return@launch                    }                } else {                    LruCacheUtil.getInstance().addBitmapToMemory(imageUrl, bitmap)                }            }            launch (Dispatchers.Main){                imageView.setImageBitmap(bitmap)            }        }    }    /**     * 三级缓存     * @param imageUrl 图片url     * @param imageView 显示控件     * @param resId 占位图的资源id     */    fun setImageBitmap(imageUrl: String, imageView: ImageView, resId: Int):Job {        //设置占位图        val bitmap = BitmapUtil.getInstance().getBitmapResources(application.resources,resId,width,height,false)        return setImageBitmap(imageUrl,imageView,bitmap)    }    /**     * 三级缓存     * @param imageUrl 图片url     * @param imageView 显示控件     * @param file sd卡占位图     */    fun setImageBitmap(imageUrl: String, imageView: ImageView, file: File):Job {        //设置占位图        val bitmap = BitmapUtil.getInstance().getBitmapFile(file,width,height,false)        return setImageBitmap(imageUrl,imageView,bitmap)    }    /**     * 三级缓存     * @param imageUrl 图片url     * @param imageView 显示控件     * @param path      占位图文件路径     * @param fileName  占位图文件名字     */    fun setImageBitmap(imageUrl: String, imageView: ImageView, path:String , fileName:String):Job {        //设置占位图        val bitmap = BitmapUtil.getInstance().getBitmapFile(path,fileName,width,height,false)        return setImageBitmap(imageUrl,imageView,bitmap)    }    /**     * 清除所有缓存     */    private fun delete() {        LruCacheUtil.getInstance().evictAll()        OKDiskLruCacheUtil.INSTANCE.delete()    }    /**    * 检测是否有网络连接    * @return 返回false无可用网络    */    private fun isNetworkConnected(): Boolean {        val mConnectivityManager = application.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager        val mNetworkInfo = mConnectivityManager.activeNetworkInfo        if (mNetworkInfo != null) {            return mNetworkInfo.isConnected        }        return false    }    private fun show(msg: String) {        Toast.makeText(application, msg, Toast.LENGTH_LONG).show()    }    private var width = 0    private var height = 0    /**     * 获取屏幕宽高     */    private fun screenWidth() {        val wm = application.getSystemService(Context.WINDOW_SERVICE) as WindowManager        val display = wm.defaultDisplay        val size = Point()        display.getSize(size)        width = size.x        height = size.y    }}

四、网络工具类

一个简单的小工具类,为懒癌患者准备

public class HttpUtil {    private static volatile HttpUtil instance;    private HttpUtil() {}    public static HttpUtil getInstance() {        if (instance == null) {            synchronized (HttpUtil.class) {                if (instance == null) {                    instance = new HttpUtil();                }            }        }        return instance;    }    private OkHttpClient client;    public void init(){        client  = new OkHttpClient.Builder()                //设置连接的连接超时的时间                .connectTimeout(10,TimeUnit.SECONDS)                //设置连接的读取超时时间                .readTimeout(30, TimeUnit.SECONDS)                //设置写入超时时间                .writeTimeout(10, TimeUnit.SECONDS)                .build();    }    public OkHttpClient getClient(){        return client;    }}

五、bitmap工具类

https://blog.csdn.net/a896159476/article/details/92996925

完整代码

https://github.com/a896159476/KotlinTest

更多相关文章

  1. android缓存框架ASimpleCache的使用 (网络请求数据并缓存)
  2. Android 定时器实现图片的变换
  3. android studio 小技巧之 图片预览
  4. android获取网络图片的用法 BitmapFactory.decodeByteArray
  5. Android 图片显示与屏幕适配的问题
  6. android获取手机上的图片和视频缩略图thumbnails
  7. android 引导用户指示操作 高亮显示 可以自定义文字或者图片来作
  8. Android 小項目之---Iphone拖动图片特效 (附源码)

随机推荐

  1. android Animation 动画效果介绍 续 .
  2. android EditText inputType 及 android:
  3. Android的建议
  4. Android(安卓)内核剖析
  5. 《Android编程入门很简单》PDF版电子书下
  6. android EditText inputType 及 android:
  7. shape的使用总结
  8. Android(安卓)GWES之Android消息系统
  9. 如何跟踪调试Android的源码
  10. android编译过程详解(一)