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 = 200F
        val maxSizeMultiplier = 0.8F

        val 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 * 2000L
        builder.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.roundToInt

const 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.VERTICAL
        rv.layoutManager = layoutManager

        val adapter = MyAdapter(this)
        rv.adapter = adapter

        rv.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? = null

        constructor(ctx: Context) {
            this.mContext = ctx
        }

        fun dataChanged(items: ArrayList<AdapterData>) {
            this.mItems = items
            notifyDataSetChanged()
        }

        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 = 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(MediaData(path, index++))
        }
        cursor.close()

        return photos
    }
}

class BatchBitmapView : ShapeableImageView {
    private val mData = mutableListOf<DataBean>()
    private val mScreenWidth = resources.displayMetrics.widthPixels
    private val mTargets = mutableListOf<CustomTarget<Bitmap>>()
    private var mContext: Context? = null
    private var mImageSize = 0 //每个小格子图片的尺寸,动态计算而变化。

    companion object {
        const val TAG = "BatchBitmapView"
    }

    constructor(
        ctx: Context,
        attributeSet: AttributeSet? = null,
        defStyleAttr: Int = 0
    ) : super(ctx, attributeSet, defStyleAttr) {
        mContext = ctx
        mImageSize = (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) * mImageSize
            canvas.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文章来源地址https://www.toymoban.com/news/detail-858050.html

到了这里,关于Android优化RecyclerView图片展示:Glide成堆加载批量Bitmap在RecyclerView成片绘制Canvas,Kotlin(b)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 前端JS 展示上传图片缩略图(本地图片读取)

    需求: 点击上传图片按钮,选择图片以后,不请求后端接口,直接将图片展示在缩略图中。 解决方案: 使用 FileReader 和 FileReader 中的 readAsDataURL 方法。 第一步 从 input[type=“file”] (上传文件标签) 里面拿到 file 数据,类似下图 第二步 拿到file数据后,执行下面代码 效果展示

    2024年02月15日
    浏览(35)
  • element UI多图片展示

    图片展示效果如下: 【使用for循环展示图片和对应图片名称,鼠标选中图片有阴影效果,可以自动换行】 对应图片上使用鼠标点击或鼠标悬浮,图片变大,展示如下: 完整代码

    2024年02月15日
    浏览(28)
  • iOS 展示网络GIF 图片

    请求(下载成功之后执行)成功回调 使用 FLAnimatedImage 展示沙盒中的gif 资源

    2024年02月09日
    浏览(29)
  • 基于html+css的图片展示18

    项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目结构 index.html代码如下 总结 此代码可以实现图片的无限重复向下移动展示效果

    2023年04月20日
    浏览(31)
  • 【uniapp 图片展示自适应,等比例缩放】

    在uniapp页面展示中会遇到图片展示问题,等比缩放或者自适应view大小。 只固定调整图片的宽度(或者高度)而图片的高度(或者宽度)可以自动根据图片原始比例调节的情况,这种情况下我们可以通过使用image标签的mode属性控制。 组件默认宽度 320px、高度 240px; 注意uniap

    2024年02月12日
    浏览(41)
  • 在layui弹出层遍历展示图片和文章详情里面点击放大图片

     借鉴:在layui弹出层遍历展示图片_layui弹出图片_其实不会敲代码的博客-CSDN博客 二、文章详情

    2024年02月12日
    浏览(48)
  • 前端Vue页面中如何展示本地图片

    我们使用img标签展示图片,src属性设置成图片请求路径 \\\"http://localhost:8888/image/img.jpg\\\" 的格式,也就是会向后端发送这个请求获取图片。 但是图片是存放在本地的某个文件里,那如何才能找到呢? 这就需要对这个请求的路径进行映射,以找到真正的存放图片的地址。

    2024年02月04日
    浏览(31)
  • Spring Boot实现图片上传和展示

    本文将介绍如何使用Spring Boot框架搭建后端服务,实现接收前端上传的图片并保存到 resources/images 目录下。同时,我们还将展示如何在前端编写一个HTML页面,实现上传图片和从 resources/images 目录下获取图片并展示的功能。 使用Spring Boot来快速搭建后端服务,以下是实现步骤:

    2024年01月19日
    浏览(46)
  • windows 电脑图片/视频不展示预览图

    描述 Windows电脑上的图片和视频没有预览图 解决后效果: 可能原因及解决办法 1. Windows的缩略图预览功能被禁用 处理步骤: 【控制面板】 【系统和安全】 【系统】 在左侧导航栏中选择【高级系统设置】 然后在【性能】栏中打开【设置】 在【视觉效果】选项卡中,打开【始

    2024年02月06日
    浏览(97)
  • Three.js--》实现图片转3D效果展示

    目录 项目搭建 初始化three.js基础代码 加载图片纹理 设置着色器 今天简单实现一个three.js的小Demo,加强自己对three知识的掌握与学习,只有在项目中才能灵活将所学知识运用起来,话不多说直接开始。 项目搭建 本案例还是借助框架书写three项目,借用vite构建工具搭建vue项目

    2024年02月08日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包