Android Glide in RecyclerView,only load visible item when page return,Kotlin

这篇具有很好参考价值的文章主要介绍了Android Glide in RecyclerView,only load visible item when page return,Kotlin。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Android Glide in RecyclerView,only load visible item when page return,Kotlin

base on this article:

Android Glide preload RecyclerView切入后台不可见再切换可见只加载当前视野可见区域item图片,Kotlin_zhangphil的博客-CSDN博客【代码】Android Paging 3,kotlin(1)在实际的开发中,虽然Glide解决了快速加载图片的问题,但还有一个问题悬而未决:比如用户的头像,往往用户的头像是从服务器端读出的一个普通矩形图片,但是现在的设计一般要求在APP端的用户头像显示成圆形头像,那么此时虽然Glide可以加载,但加载出来的是一个矩形,如果要Glide_android 毛玻璃圆角。《Android图片加载与缓存开源框架:Android Glide》Android Glide是一个开源的图片加载和缓存处理的第三方框架。https://blog.csdn.net/zhangphil/article/details/132592405文章来源地址https://www.toymoban.com/news/detail-703065.html

    <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.graphics.Bitmap
import android.os.Bundle
import android.provider.MediaStore
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.appcompat.widget.AppCompatImageView
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
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

const val PHOTO_SIZE = 150

class MainActivity : AppCompatActivity() {
    private val TAG = "Glide Load"

    private var mItems = ArrayList<MyData>()
    private var mLayoutManager: GridLayoutManager? = null
    private var mAdapter: MyAdapter? = null
    private var mGlideLoad: GlideLoad? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.recycler_view)
        init()
    }

    //当按了home键后,再次调出app,会进入onRestart
    override fun onRestart() {
        super.onRestart()
        Log.d(TAG, "onRestart")
        mGlideLoad?.clear()
    }

    override fun onStop() {
        super.onStop()
        Log.d(TAG,"onStop")
    }

    private fun init() {
        val spanCount = 8

        val rv = findViewById<RecyclerView>(R.id.recycler_view)

        mLayoutManager = GridLayoutManager(this, spanCount)
        rv.layoutManager = mLayoutManager

        mAdapter = MyAdapter(this)
        rv.adapter = mAdapter

        mItems = readAllImage(applicationContext)
        mAdapter?.onChange(mItems)

        mGlideLoad = GlideLoad(this, rv)
    }

    fun loadItem(holder: MyVH, position: Int) {
        val target: Target<*> = GlideApp.with(holder.itemView.context)
            .asBitmap()
            .load(mItems[position].path)
            .centerCrop()
            .addListener(object : RequestListener<Bitmap> {
                override fun onLoadFailed(
                    e: GlideException?,
                    model: Any?,
                    target: Target<Bitmap>,
                    isFirstResource: Boolean
                ): Boolean {
                    mGlideLoad?.setLoadStatus(position, GlideLoad.NONE, null)
                    return false
                }

                override fun onResourceReady(
                    resource: Bitmap,
                    model: Any,
                    target: Target<Bitmap>?,
                    dataSource: DataSource,
                    isFirstResource: Boolean
                ): Boolean {
                    holder.image.setImageBitmap(resource)
                    mGlideLoad?.setLoadStatus(position, GlideLoad.NONE, null)

                    // 特别注意此处返回是true,而不能是false。
                    // 因为如果返回false,当按home键把app切入后台后,再按app图标调出app切换到前台可见,反复切换,
                    // 会造成Bitmap未回收的崩溃。
                    return true
                }
            }).preload(
                PHOTO_SIZE,
                PHOTO_SIZE
            )

        mGlideLoad?.setLoadStatus(position, GlideLoad.LOAD, target)
    }

    inner class MyAdapter(private val context: Context) : RecyclerView.Adapter<MyVH>() {
        private var items = ArrayList<MyData>()

        fun onChange(items: ArrayList<MyData>) {
            this.items = items

            notifyDataSetChanged()
        }

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyVH {
            val v = LayoutInflater.from(context).inflate(R.layout.item, parent, false)
            val params = v.layoutParams
            params.width = PHOTO_SIZE
            params.height = PHOTO_SIZE
            return MyVH(v)
        }

        override fun onBindViewHolder(holder: MyVH, position: Int) {
            loadItem(holder, position)
            holder.text.text = "$position"
        }

        override fun getItemCount(): Int {
            return items.size
        }
    }

    private fun readAllImage(context: Context): ArrayList<MyData> {
        val photos = ArrayList<MyData>()

        //读取手机图片
        val cursor = context.contentResolver.query(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            null,
            null,
            null,
            null
        )

        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))
        }

        cursor.close()

        return photos
    }
}

class MyVH(itemView: View) : RecyclerView.ViewHolder(itemView) {
    var image: AppCompatImageView
    var text: TextView

    init {
        image = itemView.findViewById(R.id.image)
        text = itemView.findViewById(R.id.text)
    }
}

class MyData(var path: String)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="1px">

    <androidx.appcompat.widget.AppCompatImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:scaleType="centerCrop"
        android:src="@drawable/ic_launcher_background" />

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:background="@android:color/holo_green_light"
        android:paddingLeft="1dp"
        android:paddingRight="1dp"
        android:text="-.-"
        android:textColor="@android:color/holo_red_dark"
        android:textSize="5dp" />
</RelativeLayout>
import android.content.Context
import android.util.Log
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.request.target.Target
import java.lang.ref.WeakReference

class GlideLoad {
    private val TAG = "Glide Load"

    companion object {
        const val NONE: Int = 0
        const val LOAD: Int = 1
    }

    private var mLayoutManager: GridLayoutManager? = null
    private var mRecyclerView: RecyclerView? = null
    private var mVisibleItemPosition: IntArray? = null
    private var mContext: Context? = null

    private var mStatusItems: ArrayList<Status>? = ArrayList()

    constructor(ctx: Context?, rv: RecyclerView?) {
        mContext = ctx
        mRecyclerView = rv

        repeat(mRecyclerView?.adapter?.itemCount!!) {
            mStatusItems?.add(Status())
        }

        mLayoutManager = mRecyclerView?.layoutManager as? GridLayoutManager
        mRecyclerView?.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                mVisibleItemPosition = getVisibleItemPosition()
            }
        })
    }

    fun setLoadStatus(pos: Int, status: Int, target: Target<*>?) {
        mStatusItems!![pos].position = pos
        mStatusItems!![pos].status = status
        if (target != null) {
            mStatusItems!![pos].targetRef = WeakReference(target)
        } else {
            mStatusItems!![pos].targetRef = null
        }
    }

    fun clear() {
        Log.d(TAG, "可见区域 ${mVisibleItemPosition!![0]}->${mVisibleItemPosition!![1]}")

        for (i in 0 until mStatusItems!!.size) {
            if (i !in mVisibleItemPosition!![0]..mVisibleItemPosition!![1]) {
                if (mStatusItems!![i].status == LOAD) {
                    mStatusItems!![i].targetRef?.get()?.let {
                        GlideApp.with(mContext!!).clear(it)
                    }

                    mStatusItems!![i].status = NONE
                    mStatusItems!![i].targetRef = null
                }
            }
        }
    }

    private fun getVisibleItemPosition(): IntArray {
        val first = mLayoutManager?.findFirstVisibleItemPosition()
        val last = mLayoutManager?.findLastVisibleItemPosition()
        return intArrayOf(first!!, last!!)
    }

    class Status {
        var targetRef: WeakReference<Target<*>>? = null
        var status = NONE
        var position = 0
    }
}
import android.content.Context
import android.util.Log
import com.bumptech.glide.GlideBuilder
import com.bumptech.glide.annotation.GlideModule
import com.bumptech.glide.module.AppGlideModule

@GlideModule
class MyModule : AppGlideModule() {
    override fun applyOptions(context: Context, builder: GlideBuilder) {
        builder.setLogLevel(Log.DEBUG)
    }

    override fun isManifestParsingEnabled(): Boolean {
        return false
    }
}

到了这里,关于Android Glide in RecyclerView,only load visible item when page return,Kotlin的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • Android GridLayoutManager Glide批量加载Bitmap绘制Canvas画在RecyclerView,Kotlin(a)

    有一个遗留问题,每行加载16张图片,以行为原子单位。后面可以考虑另外一种实现,group分组标签单独占一行,图片可以一大片一大片的占据多行,每行16张。 Android Glide自定义AppCompatImageView切分成若干小格子,每个小格子onDraw绘制Bitmap,Kotlin(1)_android appcompatimageview-CSDN博

    2024年04月17日
    浏览(36)
  • Android开发:RecyclerView获取item位置的几种方法比较

            当使用 RecyclerView 来展示列表数据时,获取 item 的位置是一个常见的需求。RecyclerView 提供了多种获取 item 位置的方法,包括 getAdapterPosition() 、 getBindingAdapterPosition() 、 getAbsoluteAdapterPosition() 等等。这些方法的实现原理和返回值有所不同,因此在实际使用时需要根据

    2023年04月20日
    浏览(54)
  • Android NestedScrollView包裹RecyclerView高度撑满所有item,kotlin

    Android NestedScrollView包裹RecyclerView高度撑满所有item,kotlin 当用NestedScrollView包裹RecyclerView后,   然而设置: 会使得RecyclerView加载完成所有itemCount的数理,撑满整个RecyclerView高度,这深深改变了RecyclerView只加载显示当前屏幕可见区域的特性,此时RecyclerView一次性加载全部item。

    2024年02月16日
    浏览(35)
  • Android中实现RecyclerView,并对item及其多个子控件的点击事件监听

    目录 背景 实现RecyclerView 第一步、 新建item的xml 第二步、在activity的布局中引入 RecyclerView 第三步、新建一个adapter   第四步、在activity中初始化绑定adapter即可 实现item及其多个子组件点击事件监听 第一步、 适配器中创建监听对象 第二步、适配器中绑定监听item和子组件 第三

    2024年02月19日
    浏览(47)
  • 【Android】RecyclerView实现列表中的Item之间设置间距的一种方式

    RecyclerView 的 Item 默认没有间距是因为 RecyclerView 是一个高度自定义的控件,它的目标是提供一个高效灵活的列表展示,并且适应各种不同的布局需求。 为了让开发者能够充分自定义列表项的布局和样式,RecyclerView 没有默认设置项来添加 item 之间的间距。这样设计的好处是,

    2024年02月13日
    浏览(40)
  • 解决Android中使用RecyclerView滑动时底部item显示不全的问题

    感觉这个bug是不是因人而异啊,找了很多文章都没能解决我的问题,包括在RecyclerView上在嵌套上一层RelativeLayout,添加属性android:descendantFocusability=”blocksDescendants”,使用ConstraintLayout布局包裹RecyclerView,再设置layout_height=\\\"0dp\\\"和layout_constraintBottom_toBottomOf=\\\"parent\\\"(就是指定约束

    2024年02月16日
    浏览(34)
  • Android RecyclerView实现选中Item变色的最精简高效实现(绝不会出现点击时其它item偶尔也被选中现象)

    效果:  核心代码如下: 代码超精简,试一下您就知道了。跟网上其它的教程不同,绝不会出现点击时其它item偶尔也被同步选中改变颜色导致乱串的现象

    2024年02月11日
    浏览(31)
  • Android LinearLayout dynamic add child ImageView,Glide load,kotlin

    Android LinearLayout dynamic add child ImageView,Glide load,kotlin  images.xml image.xml Android Glide onlyRetrieveFromCache downloadOnly submit ,kotlin_zhangphil的博客-CSDN博客 【代码】Android Paging 3,kotlin(1)在实际的开发中,虽然Glide解决了快速加载图片的问题,但还有一个问题悬而未决:比如用户的头像,

    2024年02月14日
    浏览(32)
  • Wireshark报错 Info can only be sorted with 10000 or fewer visible rows——解决办法

    使用info筛选出Query和Response数据包时,报错: Info can only be sorted with 10000 or fewer visible rows; increase cache size in Layout preferences 。 这通常是因为Wireshark的缓存大小设置不够大,导致无法处理大量数据。  在菜单栏中选择“Edit”(编辑) - “Preferences”(首选项)。 选择外观,布局

    2024年03月19日
    浏览(39)
  • Android14之adb remount报错:Cannot use remount when a checkpoint is in progress(一百八十四)

    简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏: Audio工程师进阶系列 【 原创干货持续更新中…… 】🚀 优质专栏: 多媒体系统工程师系列 【 原创干货持续更新中…… 】🚀 人生格言: 人生从来没有捷径

    2024年04月28日
    浏览(41)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包