Android Coil ImageLoader MemoryCache设置Key与复用内存缓存,Kotlin

Android Coil ImageLoader MemoryCache设置Key与复用内存缓存,Kotlin

Kotlin 复制代码
import android.content.ContentUris
import android.content.Context
import android.net.Uri
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity() {
    companion object {
        const val TAG = "fly"
        const val SPAN_COUNT = 8
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.rv_layout)

        val rv = findViewById<RecyclerView>(R.id.rv)

        val layoutManager = GridLayoutManager(this, SPAN_COUNT)
        layoutManager.orientation = LinearLayoutManager.VERTICAL
        val adapter = ImageAdapter(this, 0)
        rv.adapter = adapter
        rv.layoutManager = layoutManager

        //rv.setHasFixedSize(true)
        //rv.setItemViewCacheSize(SPAN_COUNT * 20)
        //rv.recycledViewPool.setMaxRecycledViews(0, SPAN_COUNT * 20)

        val ctx = this
        lifecycleScope.launch(Dispatchers.IO) {
            val lists = readAllImage(ctx)
            Log.d(TAG, "readAllImage size=${lists.size}")

            lifecycleScope.launch(Dispatchers.Main) {
                adapter.dataChanged(lists)
            }
        }
    }

    class MyData(var path: String, var uri: Uri)

    private fun readAllImage(ctx: Context): ArrayList<MyData> {
        val photos = ArrayList<MyData>()

        //读取所有图
        val cursor = ctx.contentResolver.query(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, null
        )

        while (cursor!!.moveToNext()) {
            //路径
            val path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA))

            val id = cursor.getColumnIndex(MediaStore.Images.ImageColumns._ID)
            val imageUri: Uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, cursor.getLong(id))

            //名称
            //val name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME))

            //大小
            //val size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE))

            photos.add(MyData(path, imageUri))
        }
        cursor.close()

        return photos
    }
}
Kotlin 复制代码
import android.content.Context
import android.graphics.Bitmap
import android.util.Log
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.AppCompatImageView
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView
import coil.ImageLoader
import coil.memory.MemoryCache
import coil.request.CachePolicy
import coil.request.ImageRequest
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch


class ImageAdapter : RecyclerView.Adapter<ImageHolder> {
    private var mCtx: Context? = null
    private var mImageLoader: ImageLoader? = null
    private var mViewSize = 0

    constructor(ctx: Context, type: Int) : super() {
        mCtx = ctx

        mImageLoader = ImageLoader.Builder(mCtx!!)
            .memoryCachePolicy(CachePolicy.ENABLED)
            .availableMemoryPercentage(0.9999)
            .bitmapPoolingEnabled(true)
            .bitmapConfig(Bitmap.Config.RGB_565)
            .diskCachePolicy(CachePolicy.ENABLED)
            .build()

        Log.d(MainActivity.TAG, "memoryCache.maxSize=${mImageLoader?.memoryCache?.maxSize}")

        mViewSize = mCtx!!.resources.displayMetrics.widthPixels / MainActivity.SPAN_COUNT
    }

    private var mItems = ArrayList<MainActivity.MyData>()

    fun dataChanged(items: ArrayList<MainActivity.MyData>) {
        this.mItems = items
        notifyDataSetChanged()
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageHolder {
        val view = MyIV(mCtx!!, mViewSize)

        return ImageHolder(view)
    }

    override fun getItemCount(): Int {
        return mItems.size
    }

    override fun onBindViewHolder(holder: ImageHolder, position: Int) {
        bind(mItems[position], holder.image)
    }

    private fun bind(data: MainActivity.MyData, image: MyIV) {
        val key = MemoryCache.Key.invoke(data.path)

        val bmp = mImageLoader?.memoryCache?.get(key)

        if (bmp != null && bmp.byteCount > 0) {
            Log.d(
                MainActivity.TAG,
                "memory cache bmp=${bmp.byteCount} ${mImageLoader?.memoryCache?.size}/${mImageLoader?.memoryCache?.maxSize}"
            )
            image.setImageBitmap(bmp)
        } else {
            val t = System.currentTimeMillis()

            val request = ImageRequest.Builder(mCtx!!)
                .data(data.uri)
                .size(mViewSize)
                .target(image)
                .memoryCacheKey(key)
                .build()

            (mCtx as? MainActivity)?.lifecycleScope?.launch(Dispatchers.IO) {
                mImageLoader?.execute(request)
            }

            Log.d(MainActivity.TAG, "no memory cache time=${System.currentTimeMillis() - t}")
        }
    }
}

class ImageHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    var image = itemView as MyIV
}

class MyIV : AppCompatImageView {
    private var mSize = 0

    constructor(ctx: Context, size: Int) : super(ctx) {
        mSize = size
        scaleType = ScaleType.CENTER_CROP
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)

        setMeasuredDimension(mSize, mSize)
    }
}

1、已知问题,发现Coil在宫格多时候,如果直接:

Kotlin 复制代码
mImageLoader?.enqueue(request)

也有一定小的耗时。所以干脆用协程包装起来。

2、虽然通过设置内存系数

Kotlin 复制代码
availableMemoryPercentage

扩大了内存,但跑起来发现设置后内存还是比较小(约300mb),这是不够的,需要通过其他配置方式扩大内存空间。

3、app跑起来后,没有在当前app的硬盘缓存空间发现图片解码后的磁盘文件缓存痕迹。这需要再配置。

Android图片加载框架Coil,Kotlin-CSDN博客文章浏览阅读649次。Coil是专门针对Android平台上的Kotlin语言特性设计,这不像Glide,Glide的核心框架语言是Java。Coil实现看更细颗粒度的内存、磁盘缓存的客制化设置。https://blog.csdn.net/zhangphil/article/details/145558324

相关推荐
三少爷的鞋6 小时前
Android 架构七条铁律:架构师真正设计的不是代码,而是秩序
android
xiangxiongfly9157 小时前
Android GsonFactory总结
android·gson·gsonfactory
WythePlus9 小时前
Android 14 SELinux策略深度解析
android·安全策略·selinux策略
俩个逗号。。13 小时前
Kotlin flow 详解
android·开发语言·kotlin
灿飞15 小时前
Kotlin与Java虚拟机六:基础与类型系统:一切皆对象,但对象有代价
java·kotlin
橙光成长15 小时前
android-ad-cleaner:android免 Root 批量关闭系统开屏与营销推送
android·1024程序员节
深圳雨林凯AI15 小时前
图案裂变的底色衰减:alpha通道、亮度对比与白墨分色的量化拆解
android
mmsx15 小时前
Android 模块化收口:能力组合框架、手写 LifecycleOwner 与热修复共存
android
恋猫de小郭17 小时前
Flutter 可以更直接地调用原生 API 了,Dart Direct Native Interop
android·前端·flutter
2501_9160088918 小时前
iPhone 设备信息查看,用 KeyMob 看型号、序列号、电池健康和 UDID
android·ios·小程序·https·uni-app·iphone·webview