Android优化RecyclerView图片展示:Glide成堆加载批量Bitmap在RecyclerView成片绘制Canvas,Kotlin(b)

本文主要是介绍Android优化RecyclerView图片展示:Glide成堆加载批量Bitmap在RecyclerView成片绘制Canvas,Kotlin(b),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Android优化RecyclerView图片展示:Glide成堆加载批量Bitmap在RecyclerView成片绘制Canvas,Kotlin(b)

对 Android GridLayoutManager Glide批量加载Bitmap绘制Canvas画在RecyclerView,Kotlin(a)-CSDN博客 改进,用Glide批量把Bitmap加载出来,然后在RecyclerView成片成堆的绘制Canvas,此种实现是RecyclerView加载多宫格图片展示,卡顿丢帧最低的一种实现,上下滑动流畅。

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

plugins {id 'org.jetbrains.kotlin.kapt'
}implementation 'com.github.bumptech.glide:glide:4.16.0'kapt 'com.github.bumptech.glide:compiler:4.16.0'

import android.content.Context
import android.util.Log
import com.bumptech.glide.GlideBuilder
import com.bumptech.glide.annotation.GlideModule
import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory
import com.bumptech.glide.load.engine.cache.MemorySizeCalculator
import com.bumptech.glide.load.engine.executor.GlideExecutor
import com.bumptech.glide.module.AppGlideModule@GlideModule
class MyGlideModule : AppGlideModule() {override fun applyOptions(context: Context, builder: GlideBuilder) {super.applyOptions(context, builder)builder.setLogLevel(Log.DEBUG)val memoryCacheScreens = 200Fval maxSizeMultiplier = 0.8Fval calculator = MemorySizeCalculator.Builder(context).setMemoryCacheScreens(memoryCacheScreens).setBitmapPoolScreens(memoryCacheScreens).setMaxSizeMultiplier(maxSizeMultiplier).setLowMemoryMaxSizeMultiplier(maxSizeMultiplier * 0.8F).setArrayPoolSize((1024 * 1024 * memoryCacheScreens).toInt()).build()builder.setMemorySizeCalculator(calculator)val diskCacheSize = 1024 * 1024 * 2000Lbuilder.setDiskCache(InternalCacheDiskCacheFactory(context, diskCacheSize))val mSourceExecutor = GlideExecutor.newSourceBuilder().setUncaughtThrowableStrategy(GlideExecutor.UncaughtThrowableStrategy.LOG).setThreadCount(4)//.setThreadTimeoutMillis(1000) //线程读写超时时间。.setName("fly-SourceExecutor").build()val mDiskCacheBuilder = GlideExecutor.newDiskCacheBuilder().setThreadCount(1)//.setThreadTimeoutMillis(1000) //线程读写超时时间。.setName("fly-DiskCacheBuilder").build()val mAnimationExecutor = GlideExecutor.newDiskCacheBuilder().setThreadCount(1)//.setThreadTimeoutMillis(1000) //线程读写超时时间。.setName("fly-AnimationExecutor").build()builder.setSourceExecutor(mSourceExecutor)builder.setDiskCacheExecutor(mDiskCacheBuilder)builder.setAnimationExecutor(mAnimationExecutor)}override fun isManifestParsingEnabled(): Boolean {return false}
}

import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.provider.MediaStore
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import com.google.android.material.imageview.ShapeableImageView
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.math.ceil
import kotlin.math.roundToIntconst val COLUMN_COUNT = 16 // 一行多少个图片。
const val CHUNKED_SIZE = 100 // 一批/一大片总共有多少张图片。class MainActivity : AppCompatActivity() {companion object {const val TAG = "fly"const val VIEW_TYPE = 0 //图片区域。const val GROUP_TYPE = 1 //分组标签。}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val rv = findViewById<RecyclerView>(R.id.rv)val layoutManager = LinearLayoutManager(this)layoutManager.orientation = LinearLayoutManager.VERTICALrv.layoutManager = layoutManagerval adapter = MyAdapter(this)rv.adapter = adapterrv.setHasFixedSize(true)lifecycleScope.launch(Dispatchers.IO) {val items = readAllImage(this@MainActivity)items.reverse()val lists: ArrayList<AdapterData> = sliceDataList(items)withContext(Dispatchers.Main) {adapter.dataChanged(lists)}}}class MyAdapter : RecyclerView.Adapter<MyVH> {private var mItems = arrayListOf<AdapterData>()private var mContext: Context? = nullconstructor(ctx: Context) {this.mContext = ctx}fun dataChanged(items: ArrayList<AdapterData>) {this.mItems = itemsnotifyDataSetChanged()}override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyVH {return when (viewType) {GROUP_TYPE -> {val view = LayoutInflater.from(mContext!!).inflate(android.R.layout.simple_list_item_1, parent, false)view.setBackgroundColor(ContextCompat.getColor(mContext!!, android.R.color.darker_gray))MyVH(view)}else -> {val view = BatchBitmapView(mContext!!)MyVH(view)}}}override fun getItemCount(): Int {return mItems.size}override fun getItemViewType(position: Int): Int {return mItems[position].type}override fun onBindViewHolder(holder: MyVH, position: Int) {Log.d(TAG, "onBindViewHolder $position")when (getItemViewType(position)) {GROUP_TYPE -> {holder.itemView.findViewById<TextView>(android.R.id.text1).text = "$position GROUP"}else -> {(holder.itemView as BatchBitmapView).setRowBitmapData(mItems[position].mediaData)}}}}class MyVH : RecyclerView.ViewHolder {constructor(itemView: View) : super(itemView) {}}class AdapterData(var type: Int = GROUP_TYPE, data: List<MediaData>? = null) {var mediaData: List<MediaData>? = data}class MediaData(var path: String, var index: Int)private fun sliceDataList(data: ArrayList<MediaData>): ArrayList<AdapterData> {val lists = ArrayList<AdapterData>()val chunks = data.chunked(CHUNKED_SIZE)chunks.forEach {lists.add(AdapterData(GROUP_TYPE))lists.add(AdapterData(VIEW_TYPE, it))}return lists}private fun readAllImage(context: Context): ArrayList<MediaData> {val photos = ArrayList<MediaData>()//读取所有图片val cursor = context.contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, null)var index = 0while (cursor!!.moveToNext()) {//路径 urival 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(MediaData(path, index++))}cursor.close()return photos}
}class BatchBitmapView : ShapeableImageView {private val mData = mutableListOf<DataBean>()private val mScreenWidth = resources.displayMetrics.widthPixelsprivate val mTargets = mutableListOf<CustomTarget<Bitmap>>()private var mContext: Context? = nullprivate var mImageSize = 0 //每个小格子图片的尺寸,动态计算而变化。companion object {const val TAG = "BatchBitmapView"}constructor(ctx: Context,attributeSet: AttributeSet? = null,defStyleAttr: Int = 0) : super(ctx, attributeSet, defStyleAttr) {mContext = ctxmImageSize = (mScreenWidth.toFloat() / COLUMN_COUNT.toFloat()).roundToInt()}fun setRowBitmapData(rows: List<MainActivity.MediaData>?) {mData.clear()Log.d(TAG, "mTargets.size=${mTargets.size}")mTargets.forEach {GlideApp.with(mContext!!).clear(it) //如果不清除,会发生有些图错放位置。}mTargets.clear() //mTargets上下滑动列表会越来越大,清空,一直保持ROW_SIZE.rows?.forEachIndexed { index, data ->val target = object : CustomTarget<Bitmap>() {override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {val bean = DataBean(resource)mData.add(bean)postInvalidate()}override fun onLoadCleared(placeholder: Drawable?) {}}GlideApp.with(mContext!!).asBitmap().centerCrop().override(mImageSize).load(data.path).into(target)mTargets.add(target)}}override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {super.onMeasure(widthMeasureSpec, heightMeasureSpec)val rows = ceil(CHUNKED_SIZE.toFloat() / COLUMN_COUNT.toFloat()).toInt()setMeasuredDimension(mScreenWidth, mImageSize * rows)}override fun onDraw(canvas: Canvas) {super.onDraw(canvas)mData.forEachIndexed { index, dataBean ->//canvas.save()val left = mImageSize * (index % COLUMN_COUNT)val top = (index / COLUMN_COUNT) * mImageSizecanvas.drawBitmap(dataBean.bitmap, left.toFloat(), top.toFloat(), null)//canvas.restore()}}data class DataBean(val bitmap: Bitmap)
}

Android GridLayoutManager Glide批量加载Bitmap绘制Canvas画在RecyclerView,Kotlin(a)-CSDN博客【代码】Android Paging 3,kotlin(1)在实际的开发中,虽然Glide解决了快速加载图片的问题,但还有一个问题悬而未决:比如用户的头像,往往用户的头像是从服务器端读出的一个普通矩形图片,但是现在的设计一般要求在APP端的用户头像显示成圆形头像,那么此时虽然Glide可以加载,但加载出来的是一个矩形,如果要Glide_android 毛玻璃圆角。现在结合他人的代码加以修改,给出一个以原始图形中心为原点,修剪图片为头像的工具类,此类可以直接在布局文件中加载使用,比。文章浏览阅读670次。https://blog.csdn.net/zhangphil/article/details/137823405

Android RecyclerView性能优化及Glide流畅加载图片丢帧率低的一种8宫格实现,Kotlin-CSDN博客文章浏览阅读695次,点赞26次,收藏11次。【代码】Android Paging 3,kotlin(1)在实际的开发中,虽然Glide解决了快速加载图片的问题,但还有一个问题悬而未决:比如用户的头像,往往用户的头像是从服务器端读出的一个普通矩形图片,但是现在的设计一般要求在APP端的用户头像显示成圆形头像,那么此时虽然Glide可以加载,但加载出来的是一个矩形,如果要Glide_android 毛玻璃圆角。现在结合他人的代码加以修改,给出一个以原始图形中心为原点,修剪图片为头像的工具类,此类可以直接在布局文件中加载使用,比。文章浏览阅读670次。https://blog.csdn.net/zhangphil/article/details/137653692Android GridLayoutManager SpanSizeLookup dynamic set grid cell column count,Kotlin-CSDN博客文章浏览阅读584次,点赞6次,收藏7次。Android RecyclerView的StaggeredGridLayoutManager实现交错排列的子元素分组先看实现的结果如图:设计背景:现在的产品对设计的需求越来越多样化,如附录文章2是典型的联系人分组RecyclerView,子元素排列到一个相同的组,但是有些时候,UI要求把这些元素不是垂直方向的,而是像本文开头的图中所示样式排列,这就需要用StaggeredGridLayoutMa_staggeredgridlayoutmanager。https://blog.csdn.net/zhangphil/article/details/137694645Android Glide load grid RecyclerView scroll smooth, high performance and ,Kotlin-CSDN博客文章浏览阅读709次,点赞18次,收藏13次。【代码】Android Paging 3,kotlin(1)在实际的开发中,虽然Glide解决了快速加载图片的问题,但还有一个问题悬而未决:比如用户的头像,往往用户的头像是从服务器端读出的一个普通矩形图片,但是现在的设计一般要求在APP端的用户头像显示成圆形头像,那么此时虽然Glide可以加载,但加载出来的是一个矩形,如果要Glide_android 毛玻璃圆角。现在结合他人的代码加以修改,给出一个以原始图形中心为原点,修剪图片为头像的工具类,此类可以直接在布局文件中加载使用,比。文章浏览阅读670次。https://blog.csdn.net/zhangphil/article/details/137520793

这篇关于Android优化RecyclerView图片展示:Glide成堆加载批量Bitmap在RecyclerView成片绘制Canvas,Kotlin(b)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/917363

相关文章

MyBatisPlus如何优化千万级数据的CRUD

《MyBatisPlus如何优化千万级数据的CRUD》最近负责的一个项目,数据库表量级破千万,每次执行CRUD都像走钢丝,稍有不慎就引起数据库报警,本文就结合这个项目的实战经验,聊聊MyBatisPl... 目录背景一、MyBATis Plus 简介二、千万级数据的挑战三、优化 CRUD 的关键策略1. 查

使用Python绘制3D堆叠条形图全解析

《使用Python绘制3D堆叠条形图全解析》在数据可视化的工具箱里,3D图表总能带来眼前一亮的效果,本文就来和大家聊聊如何使用Python实现绘制3D堆叠条形图,感兴趣的小伙伴可以了解下... 目录为什么选择 3D 堆叠条形图代码实现:从数据到 3D 世界的搭建核心代码逐行解析细节优化应用场景:3D 堆叠图

利用Python脚本实现批量将图片转换为WebP格式

《利用Python脚本实现批量将图片转换为WebP格式》Python语言的简洁语法和库支持使其成为图像处理的理想选择,本文将介绍如何利用Python实现批量将图片转换为WebP格式的脚本,WebP作为... 目录简介1. python在图像处理中的应用2. WebP格式的原理和优势2.1 WebP格式与传统

Spring如何使用注解@DependsOn控制Bean加载顺序

《Spring如何使用注解@DependsOn控制Bean加载顺序》:本文主要介绍Spring如何使用注解@DependsOn控制Bean加载顺序,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录1.javascript 前言2. 代码实现总结1. 前言默认情况下,Spring加载Bean的顺

Android DataBinding 与 MVVM使用详解

《AndroidDataBinding与MVVM使用详解》本文介绍AndroidDataBinding库,其通过绑定UI组件与数据源实现自动更新,支持双向绑定和逻辑运算,减少模板代码,结合MV... 目录一、DataBinding 核心概念二、配置与基础使用1. 启用 DataBinding 2. 基础布局

Android ViewBinding使用流程

《AndroidViewBinding使用流程》AndroidViewBinding是Jetpack组件,替代findViewById,提供类型安全、空安全和编译时检查,代码简洁且性能优化,相比Da... 目录一、核心概念二、ViewBinding优点三、使用流程1. 启用 ViewBinding (模块级

基于 HTML5 Canvas 实现图片旋转与下载功能(完整代码展示)

《基于HTML5Canvas实现图片旋转与下载功能(完整代码展示)》本文将深入剖析一段基于HTML5Canvas的代码,该代码实现了图片的旋转(90度和180度)以及旋转后图片的下载... 目录一、引言二、html 结构分析三、css 样式分析四、JavaScript 功能实现一、引言在 Web 开发中,

Python如何去除图片干扰代码示例

《Python如何去除图片干扰代码示例》图片降噪是一个广泛应用于图像处理的技术,可以提高图像质量和相关应用的效果,:本文主要介绍Python如何去除图片干扰的相关资料,文中通过代码介绍的非常详细,... 目录一、噪声去除1. 高斯噪声(像素值正态分布扰动)2. 椒盐噪声(随机黑白像素点)3. 复杂噪声(如伪

Python中图片与PDF识别文本(OCR)的全面指南

《Python中图片与PDF识别文本(OCR)的全面指南》在数据爆炸时代,80%的企业数据以非结构化形式存在,其中PDF和图像是最主要的载体,本文将深入探索Python中OCR技术如何将这些数字纸张转... 目录一、OCR技术核心原理二、python图像识别四大工具库1. Pytesseract - 经典O

Python实现精准提取 PDF中的文本,表格与图片

《Python实现精准提取PDF中的文本,表格与图片》在实际的系统开发中,处理PDF文件不仅限于读取整页文本,还有提取文档中的表格数据,图片或特定区域的内容,下面我们来看看如何使用Python实... 目录安装 python 库提取 PDF 文本内容:获取整页文本与指定区域内容获取页面上的所有文本内容获取