Android Glide批量加载Bitmap,拼接组装大Bitmap,更新单个AppCompatImageView,Kotlin(2)
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
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
}
}
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) {
}
}
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