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

相关推荐
andr_gale27 分钟前
04_rc文件语法规则
android·framework·aosp
祖国的好青年1 小时前
VS Code 搭建 React Native 开发环境(Windows 实战指南)
android·windows·react native·react.js
黄林晴2 小时前
警惕!AGP 9.2 别只改版本号,R8 规则与构建链路全线收紧
android·gradle
小米渣的逆袭2 小时前
Android ADB 完全使用指南
android·adb
儿歌八万首2 小时前
Jetpack Compose Canvas 进阶:结合 animateFloatAsState 让自定义图形动起来
android·动画·compose
zhangphil3 小时前
Android Page 3 Flow读sql数据库媒体文件,Kotlin
android·kotlin
神探小白牙4 小时前
echarts,3d堆叠图
android·3d·echarts
李白的天不白4 小时前
如何项目发布到github上
android·vue.js
summerkissyou19874 小时前
Android-RTC、NTP 和 System Time(系统时间)
android