Android Glide批量加载Bitmap,拼接组装大Bitmap,更新单个AppCompatImageView,Kotlin(2)

Android Glide批量加载Bitmap,拼接组装大Bitmap,更新单个AppCompatImageView,Kotlin(2)

XML 复制代码
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
Kotlin 复制代码
import android.content.Context
import android.os.Bundle
import android.provider.MediaStore
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

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

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

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

        val layoutManager = LinearLayoutManager(this)
        layoutManager.orientation = LinearLayoutManager.VERTICAL
        val adapter = ImageAdapter(this, 0)
        rv1.adapter = adapter
        rv1.layoutManager = layoutManager

        rv1.setItemViewCacheSize(120)
        rv1.recycledViewPool.setMaxRecycledViews(0, 120)

        lifecycleScope.launch(Dispatchers.IO) {
            val items = readAllImage(this@MainActivity)
            items.reverse()

            val data = sliceDataList(items)
            withContext(Dispatchers.Main) {
                adapter.dataChanged(data)
            }
        }
    }

    private fun sliceDataList(data: ArrayList<MyData>): ArrayList<ArrayList<MyData>> {
        var k: Int
        val lists = ArrayList<ArrayList<MyData>>()
        for (i in data.indices step BatchBitmapView.ROW_SIZE) {
            val temp = ArrayList<MyData>()

            k = 0
            for (j in 0 until BatchBitmapView.ROW_SIZE) {
                k = i + j
                if (k >= data.size) {
                    break
                }
                temp.add(data[k])
            }

            lists.add(temp)
        }

        return lists
    }

    class MyData(var path: String, var index: Int)

    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
        )

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

            //图片名称
            //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, index++))
        }
        cursor.close()

        return photos
    }
}
Kotlin 复制代码
import android.content.Context
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView

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

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

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

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

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageHolder {
        val view = BatchBitmapView(mCtx!!)
        return ImageHolder(view)
    }

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

    override fun onBindViewHolder(holder: ImageHolder, position: Int) {
        val bbv = (holder.itemView as? BatchBitmapView)
        bbv?.setRowBitmapData(items[position], position)
    }
}

class ImageHolder : RecyclerView.ViewHolder {
    constructor(itemView: BatchBitmapView) : super(itemView) {

    }
}
Kotlin 复制代码
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Color
import android.util.AttributeSet
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatImageView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target

class BatchBitmapView @JvmOverloads constructor(
    val mCtx: Context,
    attributeSet: AttributeSet? = null,
    defStyleAttr: Int = 0
) : AppCompatImageView(mCtx, attributeSet, defStyleAttr) {
    private val mData = mutableListOf<DataBean>()
    private val mTargets = mutableListOf<Target<Bitmap>>()

    companion object {
        const val TAG = "fly/BatchBitmapView"
        const val ROW_SIZE = 16 //一行多少个bitmap
        const val IMAGE_SIZE = 200 //每个小格子图片的尺寸

        var mScreenWidth: Int = 0
        var mScreenHeight: Int = 0

        //整数相除,精度损失的平衡因子
        const val BALANCE_FACTOR = 1
    }

    init {
        //scaleType = ScaleType.FIT_CENTER

        if (mScreenWidth == 0) {
            mScreenWidth = resources.displayMetrics.widthPixels
        }

        if (mScreenHeight == 0) {
            mScreenHeight = resources.displayMetrics.widthPixels / ROW_SIZE + BALANCE_FACTOR
        }
    }

    fun setRowBitmapData(rows: ArrayList<MainActivity.MyData>?, position: Int) {
        mData.clear()

        mTargets.forEach {
            //如果不清除,会发生有些图错放位置。
            Glide.with(mCtx).clear(it)
        }
        mTargets.clear()

        var loadCount = 0
        rows?.forEachIndexed { _, myData ->
            val target = Glide.with(mCtx)
                .asBitmap()
                .centerCrop()
                .override(IMAGE_SIZE)
                .load(myData.path).addListener(object : RequestListener<Bitmap> {
                    override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Bitmap>, isFirstResource: Boolean): Boolean {
                        loadCount++

                        val errorBmp = BitmapFactory.decodeResource(mCtx.resources, android.R.drawable.stat_notify_error)

                        refresh(loadCount, errorBmp)

                        return false
                    }

                    override fun onResourceReady(
                        resource: Bitmap,
                        model: Any,
                        target: Target<Bitmap>?,
                        dataSource: DataSource,
                        isFirstResource: Boolean
                    ): Boolean {
                        loadCount++

                        refresh(loadCount, resource)

                        return false
                    }
                })
                .preload(IMAGE_SIZE, IMAGE_SIZE)

            mTargets.add(target)
        }
    }

    fun refresh(loadCount: Int, bmp: Bitmap) {
        val bean = DataBean(bmp)
        mData.add(bean)

        if (loadCount == ROW_SIZE) {
            val jBmp = joinBitmap()
            (mCtx as AppCompatActivity).runOnUiThread {
                this@BatchBitmapView.setImageBitmap(jBmp)
            }
        }
    }

    private fun joinBitmap(): Bitmap {
        val bmp = Bitmap.createBitmap(IMAGE_SIZE * ROW_SIZE, IMAGE_SIZE, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bmp)
        canvas.drawColor(Color.LTGRAY)

        mData.forEachIndexed { idx, dataBean ->
            canvas.drawBitmap(dataBean.bitmap, IMAGE_SIZE * idx.toFloat(), 0f, null)
        }

        return bmp
    }

    data class DataBean(val bitmap: Bitmap)

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        setMeasuredDimension(mScreenWidth, mScreenHeight)
    }
}

Android Glide自定义AppCompatImageView切分成若干小格子,每个小格子onDraw绘制Bitmap,Kotlin(1)_android appcompatimageview-CSDN博客文章浏览阅读1.3k次,点赞18次,收藏21次。本文介绍了如何在Android应用中使用Glide库将AppCompatImageView分割成小格子,并在每个格子上异步加载Bitmap并利用Canvas进行绘制,以提高性能。同时讨论了与直接添加ImageView相比,使用GlideCustomTarget和线性布局动态添加子View时的性能差异以及如何处理圆形头像的需求。https://blog.csdn.net/zhangphil/article/details/134519527

相关推荐
阿巴斯甜18 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker18 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952719 小时前
Andorid Google 登录接入文档
android
黄林晴20 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_2 天前
Android 启动优化方案
android
阿巴斯甜2 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇2 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_2 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android