- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
build.gradle文件:
- plugins {
- id("org.jetbrains.kotlin.kapt")
- }
-
-
- implementation("com.github.bumptech.glide:glide:4.16.0")
- kapt("com.github.bumptech.glide:compiler:4.16.0")
如果手机图片很多,假设已经将全部图片装入宫格的列表,在快速上下滑动过程中,由于glide会累积每一个图片的加载任务,如果图片比较大,上下滑动时间又很长,那么累积任务会很严重,导致异常发生,实现在RecyclerView切入后台(或不可见)时候,然后再次切换回来,只加载当前RecyclerView可见区域的item,非可见区域的图片加载任务,全部清除掉。
注意这里是利用onRestart生命周期模拟当RecyclerView不可见又切换回来的场景,这里可以换成其他场景,只要捕捉到RecyclerView已经消失在视野可见区域,比如利用fragment或者activity的可见性判断等等。
- 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 androidx.recyclerview.widget.RecyclerView.OnScrollListener
- 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
- import java.lang.ref.WeakReference
-
- const val PHOTO_SIZE = 150
-
- const val EMPTY = 0
- const val LOAD = 1
-
- class MainActivity : AppCompatActivity() {
- private val TAG = "Glide FLY"
-
- private var mItems = ArrayList
() - private var mLayoutManager: GridLayoutManager? = null
- private var mAdapter: MyAdapter? = null
- private var mVisibleItemPosition: IntArray? = null
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
-
- init()
-
- mItems = readAllImage(applicationContext)
- mAdapter?.onChange(mItems)
- }
-
- override fun onResume() {
- super.onResume()
- Log.d(TAG, "onResume")
- }
-
- //当按了home键后,再次调出app,会进入onRestart
- override fun onRestart() {
- super.onRestart()
- Log.d(TAG, "onRestart")
-
- loadOnlyVisibleItem()
- }
-
- private fun loadOnlyVisibleItem() {
- Log.d(TAG, "可见区域 ${mVisibleItemPosition!![0]}->${mVisibleItemPosition!![1]}")
- for (i in mVisibleItemPosition!![0]..mVisibleItemPosition!![1]) {
- Log.d(TAG, "可见区域 ${mItems[i].pos} -- ${mItems[i].path}")
- }
-
- for (i in 0 until mItems.size) {
- if (i !in mVisibleItemPosition!![0]..mVisibleItemPosition!![1]) {
- if (mItems[i].status == LOAD) {
- mItems[i].targetRef?.get()?.let {
- GlideApp.with(this).clear(it)
- }
- mItems[i].status = EMPTY
- }
- }
- }
- }
-
- private fun getVisibleItemPosition(): IntArray {
- val first = mLayoutManager?.findFirstVisibleItemPosition()
- val last = mLayoutManager?.findLastVisibleItemPosition()
- return intArrayOf(first!!, last!!)
- }
-
- private fun init() {
- val spanCount = 8
-
- val rv = findViewById
(R.id.recycler_view) -
- mLayoutManager = GridLayoutManager(this, spanCount)
- rv.layoutManager = mLayoutManager
-
- rv.addOnScrollListener(object : OnScrollListener() {
- override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
- super.onScrolled(recyclerView, dx, dy)
- mVisibleItemPosition = getVisibleItemPosition()
- }
- })
-
- mAdapter = MyAdapter(this)
- rv.adapter = mAdapter
- }
-
- private fun readAllImage(context: Context): ArrayList
{ - val photos = ArrayList
() -
- //读取手机图片
- 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 MyAdapter(private val context: Context) : RecyclerView.Adapter
() { - private var items = ArrayList
() -
- 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) {
- load(holder, position)
- holder.text.text = "$position"
- }
-
- override fun getItemCount(): Int {
- return items.size
- }
-
- private fun load(holder: MyVH, position: Int) {
- items[position].pos = position
- items[position].status = LOAD
-
- val target: Target<*> = GlideApp.with(holder.itemView.context)
- .asBitmap()
- .load(items[position].path)
- .centerCrop()
- .addListener(object : RequestListener
{ - override fun onLoadFailed(
- e: GlideException?,
- model: Any?,
- target: Target<Bitmap>,
- isFirstResource: Boolean
- ): Boolean {
- items[position].status = EMPTY
- return false
- }
-
- override fun onResourceReady(
- resource: Bitmap,
- model: Any,
- target: Target<Bitmap>?,
- dataSource: DataSource,
- isFirstResource: Boolean
- ): Boolean {
- holder.image.setImageBitmap(resource)
- items[position].status = EMPTY
-
- // 特别注意此处返回是true,而不能是false。
- // 因为如果返回false,当按home键把app切入后台后,再按app图标调出app切换到前台可见,反复切换,
- // 会造成Bitmap未回收的崩溃。
- return true
- }
- }).preload(
- PHOTO_SIZE,
- PHOTO_SIZE
- )
-
- items[position].targetRef = WeakReference(target)
- }
- }
-
- 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) {
- var targetRef: WeakReference
>? = null - var status = EMPTY
- var pos = 0
- }
- "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>
- "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 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预加载preload ,kotlin_zhangphil的博客-CSDN博客【代码】Android Paging 3,kotlin(1)在实际的开发中,虽然Glide解决了快速加载图片的问题,但还有一个问题悬而未决:比如用户的头像,往往用户的头像是从服务器端读出的一个普通矩形图片,但是现在的设计一般要求在APP端的用户头像显示成圆形头像,那么此时虽然Glide可以加载,但加载出来的是一个矩形,如果要Glide_android 毛玻璃圆角。《Android图片加载与缓存开源框架:Android Glide》Android Glide是一个开源的图片加载和缓存处理的第三方框架。_glide预加载https://blog.csdn.net/zhangphil/article/details/131635804Android Glide预处理preload原始图片到成品resource & 预加载RecyclerViewPreloader,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/132000010