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

相关文章

shell脚本批量导出redis key-value方式

《shell脚本批量导出rediskey-value方式》为避免keys全量扫描导致Redis卡顿,可先通过dump.rdb备份文件在本地恢复,再使用scan命令渐进导出key-value,通过CN... 目录1 背景2 详细步骤2.1 本地docker启动Redis2.2 shell批量导出脚本3 附录总

批量导入txt数据到的redis过程

《批量导入txt数据到的redis过程》用户通过将Redis命令逐行写入txt文件,利用管道模式运行客户端,成功执行批量删除以Product*匹配的Key操作,提高了数据清理效率... 目录批量导入txt数据到Redisjs把redis命令按一条 一行写到txt中管道命令运行redis客户端成功了批量删除k

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Android Paging 分页加载库使用实践

《AndroidPaging分页加载库使用实践》AndroidPaging库是Jetpack组件的一部分,它提供了一套完整的解决方案来处理大型数据集的分页加载,本文将深入探讨Paging库... 目录前言一、Paging 库概述二、Paging 3 核心组件1. PagingSource2. Pager3.

Python实现批量提取BLF文件时间戳

《Python实现批量提取BLF文件时间戳》BLF(BinaryLoggingFormat)作为Vector公司推出的CAN总线数据记录格式,被广泛用于存储车辆通信数据,本文将使用Python轻松提取... 目录一、为什么需要批量处理 BLF 文件二、核心代码解析:从文件遍历到数据导出1. 环境准备与依赖库

小白也能轻松上手! 路由器设置优化指南

《小白也能轻松上手!路由器设置优化指南》在日常生活中,我们常常会遇到WiFi网速慢的问题,这主要受到三个方面的影响,首要原因是WiFi产品的配置优化不合理,其次是硬件性能的不足,以及宽带线路本身的质... 在数字化时代,网络已成为生活必需品,追剧、游戏、办公、学习都离不开稳定高速的网络。但很多人面对新路由器

linux批量替换文件内容的实现方式

《linux批量替换文件内容的实现方式》本文总结了Linux中批量替换文件内容的几种方法,包括使用sed替换文件夹内所有文件、单个文件内容及逐行字符串,强调使用反引号和绝对路径,并分享个人经验供参考... 目录一、linux批量替换文件内容 二、替换文件内所有匹配的字符串 三、替换每一行中全部str1为st

从入门到精通详解LangChain加载HTML内容的全攻略

《从入门到精通详解LangChain加载HTML内容的全攻略》这篇文章主要为大家详细介绍了如何用LangChain优雅地处理HTML内容,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录引言:当大语言模型遇见html一、HTML加载器为什么需要专门的HTML加载器核心加载器对比表二

基于Python开发一个图像水印批量添加工具

《基于Python开发一个图像水印批量添加工具》在当今数字化内容爆炸式增长的时代,图像版权保护已成为创作者和企业的核心需求,本方案将详细介绍一个基于PythonPIL库的工业级图像水印解决方案,有需要... 目录一、系统架构设计1.1 整体处理流程1.2 类结构设计(扩展版本)二、核心算法深入解析2.1 自

Python自动化批量重命名与整理文件系统

《Python自动化批量重命名与整理文件系统》这篇文章主要为大家详细介绍了如何使用Python实现一个强大的文件批量重命名与整理工具,帮助开发者自动化这一繁琐过程,有需要的小伙伴可以了解下... 目录简介环境准备项目功能概述代码详细解析1. 导入必要的库2. 配置参数设置3. 创建日志系统4. 安全文件名处