• 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

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

    1. plugins {
    2. id("org.jetbrains.kotlin.kapt")
    3. }
    1. implementation("com.github.bumptech.glide:glide:4.16.0")
    2. kapt("com.github.bumptech.glide:compiler:4.16.0")

    1. import android.content.Context
    2. import android.graphics.Bitmap
    3. import android.os.Bundle
    4. import android.provider.MediaStore
    5. import android.util.Log
    6. import android.view.LayoutInflater
    7. import android.view.View
    8. import android.view.ViewGroup
    9. import android.widget.TextView
    10. import androidx.appcompat.app.AppCompatActivity
    11. import androidx.appcompat.widget.AppCompatImageView
    12. import androidx.recyclerview.widget.GridLayoutManager
    13. import androidx.recyclerview.widget.RecyclerView
    14. import com.bumptech.glide.load.DataSource
    15. import com.bumptech.glide.load.engine.GlideException
    16. import com.bumptech.glide.request.RequestListener
    17. import com.bumptech.glide.request.target.Target
    18. const val PHOTO_SIZE = 150
    19. class MainActivity : AppCompatActivity() {
    20. private val TAG = "Glide Load"
    21. private var mItems = ArrayList()
    22. private var mLayoutManager: GridLayoutManager? = null
    23. private var mAdapter: MyAdapter? = null
    24. private var mGlideLoad: GlideLoad? = null
    25. override fun onCreate(savedInstanceState: Bundle?) {
    26. super.onCreate(savedInstanceState)
    27. setContentView(R.layout.recycler_view)
    28. init()
    29. }
    30. //当按了home键后,再次调出app,会进入onRestart
    31. override fun onRestart() {
    32. super.onRestart()
    33. Log.d(TAG, "onRestart")
    34. mGlideLoad?.clear()
    35. }
    36. override fun onStop() {
    37. super.onStop()
    38. Log.d(TAG,"onStop")
    39. }
    40. private fun init() {
    41. val spanCount = 8
    42. val rv = findViewById(R.id.recycler_view)
    43. mLayoutManager = GridLayoutManager(this, spanCount)
    44. rv.layoutManager = mLayoutManager
    45. mAdapter = MyAdapter(this)
    46. rv.adapter = mAdapter
    47. mItems = readAllImage(applicationContext)
    48. mAdapter?.onChange(mItems)
    49. mGlideLoad = GlideLoad(this, rv)
    50. }
    51. fun loadItem(holder: MyVH, position: Int) {
    52. val target: Target<*> = GlideApp.with(holder.itemView.context)
    53. .asBitmap()
    54. .load(mItems[position].path)
    55. .centerCrop()
    56. .addListener(object : RequestListener {
    57. override fun onLoadFailed(
    58. e: GlideException?,
    59. model: Any?,
    60. target: Target<Bitmap>,
    61. isFirstResource: Boolean
    62. ): Boolean {
    63. mGlideLoad?.setLoadStatus(position, GlideLoad.NONE, null)
    64. return false
    65. }
    66. override fun onResourceReady(
    67. resource: Bitmap,
    68. model: Any,
    69. target: Target<Bitmap>?,
    70. dataSource: DataSource,
    71. isFirstResource: Boolean
    72. ): Boolean {
    73. holder.image.setImageBitmap(resource)
    74. mGlideLoad?.setLoadStatus(position, GlideLoad.NONE, null)
    75. // 特别注意此处返回是true,而不能是false。
    76. // 因为如果返回false,当按home键把app切入后台后,再按app图标调出app切换到前台可见,反复切换,
    77. // 会造成Bitmap未回收的崩溃。
    78. return true
    79. }
    80. }).preload(
    81. PHOTO_SIZE,
    82. PHOTO_SIZE
    83. )
    84. mGlideLoad?.setLoadStatus(position, GlideLoad.LOAD, target)
    85. }
    86. inner class MyAdapter(private val context: Context) : RecyclerView.Adapter() {
    87. private var items = ArrayList()
    88. fun onChange(items: ArrayList<MyData>) {
    89. this.items = items
    90. notifyDataSetChanged()
    91. }
    92. override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyVH {
    93. val v = LayoutInflater.from(context).inflate(R.layout.item, parent, false)
    94. val params = v.layoutParams
    95. params.width = PHOTO_SIZE
    96. params.height = PHOTO_SIZE
    97. return MyVH(v)
    98. }
    99. override fun onBindViewHolder(holder: MyVH, position: Int) {
    100. loadItem(holder, position)
    101. holder.text.text = "$position"
    102. }
    103. override fun getItemCount(): Int {
    104. return items.size
    105. }
    106. }
    107. private fun readAllImage(context: Context): ArrayList {
    108. val photos = ArrayList()
    109. //读取手机图片
    110. val cursor = context.contentResolver.query(
    111. MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
    112. null,
    113. null,
    114. null,
    115. null
    116. )
    117. while (cursor!!.moveToNext()) {
    118. //图片路径 uri
    119. val path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA))
    120. //图片名称
    121. //val name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME))
    122. //图片大小
    123. //val size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE))
    124. photos.add(MyData(path))
    125. }
    126. cursor.close()
    127. return photos
    128. }
    129. }
    130. class MyVH(itemView: View) : RecyclerView.ViewHolder(itemView) {
    131. var image: AppCompatImageView
    132. var text: TextView
    133. init {
    134. image = itemView.findViewById(R.id.image)
    135. text = itemView.findViewById(R.id.text)
    136. }
    137. }
    138. class MyData(var path: String)

    1. "1.0" encoding="utf-8"?>
    2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    3. xmlns:tools="http://schemas.android.com/tools"
    4. android:layout_width="match_parent"
    5. android:layout_height="match_parent"
    6. tools:context=".MainActivity">
    7. <androidx.recyclerview.widget.RecyclerView
    8. android:id="@+id/recycler_view"
    9. android:layout_width="match_parent"
    10. android:layout_height="match_parent" />
    11. RelativeLayout>

    1. "1.0" encoding="utf-8"?>
    2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    3. android:layout_width="wrap_content"
    4. android:layout_height="wrap_content"
    5. android:padding="1px">
    6. <androidx.appcompat.widget.AppCompatImageView
    7. android:id="@+id/image"
    8. android:layout_width="wrap_content"
    9. android:layout_height="wrap_content"
    10. android:scaleType="centerCrop"
    11. android:src="@drawable/ic_launcher_background" />
    12. <TextView
    13. android:id="@+id/text"
    14. android:layout_width="wrap_content"
    15. android:layout_height="wrap_content"
    16. android:layout_centerInParent="true"
    17. android:background="@android:color/holo_green_light"
    18. android:paddingLeft="1dp"
    19. android:paddingRight="1dp"
    20. android:text="-.-"
    21. android:textColor="@android:color/holo_red_dark"
    22. android:textSize="5dp" />
    23. RelativeLayout>

    1. import android.content.Context
    2. import android.util.Log
    3. import androidx.recyclerview.widget.GridLayoutManager
    4. import androidx.recyclerview.widget.RecyclerView
    5. import com.bumptech.glide.request.target.Target
    6. import java.lang.ref.WeakReference
    7. class GlideLoad {
    8. private val TAG = "Glide Load"
    9. companion object {
    10. const val NONE: Int = 0
    11. const val LOAD: Int = 1
    12. }
    13. private var mLayoutManager: GridLayoutManager? = null
    14. private var mRecyclerView: RecyclerView? = null
    15. private var mVisibleItemPosition: IntArray? = null
    16. private var mContext: Context? = null
    17. private var mStatusItems: ArrayList? = ArrayList()
    18. constructor(ctx: Context?, rv: RecyclerView?) {
    19. mContext = ctx
    20. mRecyclerView = rv
    21. repeat(mRecyclerView?.adapter?.itemCount!!) {
    22. mStatusItems?.add(Status())
    23. }
    24. mLayoutManager = mRecyclerView?.layoutManager as? GridLayoutManager
    25. mRecyclerView?.addOnScrollListener(object : RecyclerView.OnScrollListener() {
    26. override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
    27. super.onScrolled(recyclerView, dx, dy)
    28. mVisibleItemPosition = getVisibleItemPosition()
    29. }
    30. })
    31. }
    32. fun setLoadStatus(pos: Int, status: Int, target: Target<*>?) {
    33. mStatusItems!![pos].position = pos
    34. mStatusItems!![pos].status = status
    35. if (target != null) {
    36. mStatusItems!![pos].targetRef = WeakReference(target)
    37. } else {
    38. mStatusItems!![pos].targetRef = null
    39. }
    40. }
    41. fun clear() {
    42. Log.d(TAG, "可见区域 ${mVisibleItemPosition!![0]}->${mVisibleItemPosition!![1]}")
    43. for (i in 0 until mStatusItems!!.size) {
    44. if (i !in mVisibleItemPosition!![0]..mVisibleItemPosition!![1]) {
    45. if (mStatusItems!![i].status == LOAD) {
    46. mStatusItems!![i].targetRef?.get()?.let {
    47. GlideApp.with(mContext!!).clear(it)
    48. }
    49. mStatusItems!![i].status = NONE
    50. mStatusItems!![i].targetRef = null
    51. }
    52. }
    53. }
    54. }
    55. private fun getVisibleItemPosition(): IntArray {
    56. val first = mLayoutManager?.findFirstVisibleItemPosition()
    57. val last = mLayoutManager?.findLastVisibleItemPosition()
    58. return intArrayOf(first!!, last!!)
    59. }
    60. class Status {
    61. var targetRef: WeakReference>? = null
    62. var status = NONE
    63. var position = 0
    64. }
    65. }

    1. import android.content.Context
    2. import android.util.Log
    3. import com.bumptech.glide.GlideBuilder
    4. import com.bumptech.glide.annotation.GlideModule
    5. import com.bumptech.glide.module.AppGlideModule
    6. @GlideModule
    7. class MyModule : AppGlideModule() {
    8. override fun applyOptions(context: Context, builder: GlideBuilder) {
    9. builder.setLogLevel(Log.DEBUG)
    10. }
    11. override fun isManifestParsingEnabled(): Boolean {
    12. return false
    13. }
    14. }

  • 相关阅读:
    打开转盘锁 -- BFS
    (附源码)计算机毕业设计ssmExcel 操作题自动评分系统
    Vim编辑器的使用
    3大主流分布式事务框架详解(图文总结)
    个人简历内容
    谷粒学苑_第四天
    什么是 CSRF 、原理及其解决方式
    Anaconda3使用Spark的正确方法
    python3 修行之基础篇(一)python 简介
    Kafka进阶
  • 原文地址:https://blog.csdn.net/zhangphil/article/details/132688141