Android Glide preload RecyclerView切入后台不可见再切换可见只加载当前视野可见区域item图片,Kotlin

Android Glide preload RecyclerView切入后台不可见再切换可见只加载当前视野可见区域item图片,Kotlin

    <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.WeakReferenceconst val PHOTO_SIZE = 150const val EMPTY = 0
const val LOAD = 1class MainActivity : AppCompatActivity() {private val TAG = "Glide FLY"private var mItems = ArrayList<MyData>()private var mLayoutManager: GridLayoutManager? = nullprivate var mAdapter: MyAdapter? = nullprivate var mVisibleItemPosition: IntArray? = nulloverride 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,会进入onRestartoverride 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 = 8val rv = findViewById<RecyclerView>(R.id.recycler_view)mLayoutManager = GridLayoutManager(this, spanCount)rv.layoutManager = mLayoutManagerrv.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<MyData> {val photos = ArrayList<MyData>()//读取手机图片val cursor = context.contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,null,null,null,null)while (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(MyData(path))}cursor.close()return photos}
}class MyAdapter(private val context: Context) : RecyclerView.Adapter<MyVH>() {private var items = ArrayList<MyData>()fun onChange(items: ArrayList<MyData>) {this.items = itemsnotifyDataSetChanged()}override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyVH {val v = LayoutInflater.from(context).inflate(R.layout.item, parent, false)val params = v.layoutParamsparams.width = PHOTO_SIZEparams.height = PHOTO_SIZEreturn 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 = positionitems[position].status = LOADval target: Target<*> = GlideApp.with(holder.itemView.context).asBitmap().load(items[position].path).centerCrop().addListener(object : RequestListener<Bitmap> {override fun onLoadFailed(e: GlideException?,model: Any?,target: Target<Bitmap>,isFirstResource: Boolean): Boolean {items[position].status = EMPTYreturn 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: AppCompatImageViewvar text: TextViewinit {image = itemView.findViewById(R.id.image)text = itemView.findViewById(R.id.text)}
}class MyData(var path: String) {var targetRef: WeakReference<Target<*>>? = nullvar status = EMPTYvar pos = 0
}

<?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.RecyclerViewandroid: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.AppCompatImageViewandroid:id="@+id/image"android:layout_width="wrap_content"android:layout_height="wrap_content"android:scaleType="centerCrop"android:src="@drawable/ic_launcher_background" /><TextViewandroid: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

Android Glide自定义AppGlideModule,让Glide在app启动后基于定制化GlideModule加载,kotlin_zhangphil的博客-CSDN博客在实际的开发中,虽然Glide解决了快速加载图片的问题,但还有一个问题悬而未决:比如用户的头像,往往用户的头像是从服务器端读出的一个普通矩形图片,但是现在的设计一般要求在APP端的用户头像显示成圆形头像,那么此时虽然Glide可以加载,但加载出来的是一个矩形,如果要Glide_android 毛玻璃圆角。《Android图片加载与缓存开源框架:Android Glide》Android Glide是一个开源的图片加载和缓存处理的第三方框架。https://blog.csdn.net/zhangphil/article/details/131592226

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/59734.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go 数组

数组用于在单个变量中存储相同类型的多个值&#xff0c;而不是为每个值声明单独的变量。 声明数组 在Go中&#xff0c;有两种声明数组的方式&#xff1a; 使用var关键字&#xff1a; 语法 var array_name [length]datatype{values} // 这里定义了长度 或者 var array_n…

C++中的运算符总结(6):移位运算符

C中的运算符总结&#xff08;6&#xff09;&#xff1a;移位运算符 10、按位右移运算符&#xff08; >>&#xff09;和左移运算符&#xff08; <<&#xff09; 移位运算符将整个位序列向左或向右移动&#xff0c;其用途之一是将数据乘以或除以 2 n 2^n 2n。 下…

算法-图BFS/DFS-单词接龙

算法-图BFS/DFS-单词接龙 1 题目概述 1.1 题目出处 https://leetcode-cn.com/problems/number-of-islands 1.2 题目描述 给定两个单词&#xff08;beginWord 和 endWord&#xff09;和一个字典&#xff0c;找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如…

C++八股记录

C内存管理 C中&#xff0c;内存分成5个区。 栈&#xff1a;函数内局部变量&#xff1b;自动管理&#xff0c;效率高&#xff0c;但空间较小&#xff1b; 堆&#xff1a;new分配的内存块&#xff1b;手动管理&#xff0c;效率低&#xff0c;但空间大&#xff1b; 自由存储区&…

Linux 常用命令大全

一、基本操作命令 //------首先先来几个热键&#xff0c;非常方便&#xff0c;一定要记住------// Tab ------按键—命令补齐功能Ctrlc ------按键—停掉正在运行的程序Ctrld ------按键—相当于exit&#xff0c;退出Ctrll ------按键—清屏 1.1 关机和重启 1. 关机命令&am…

弯道超车必做好题集锦三(C语言选择题)

前言&#xff1a; 编程想要学的好&#xff0c;刷题少不了&#xff0c;我们不仅要多刷题&#xff0c;还要刷好题&#xff01;为此我开启了一个弯道超车必做好题锦集的系列&#xff0c;每篇大约10题左右。此为第三篇选择题篇&#xff0c;该系列会不定期更新&#xff0c;后续还会…

全面解析MES系统中的报工操作

一、报工操作的定义&#xff1a; 报工操作是指在生产过程中&#xff0c;操作员通过MES系统记录和提交生产工序的相关信息&#xff0c;如工时、产量、质量等。报工操作将生产过程中的实际情况反馈给MES系统&#xff0c;实现生产数据的实时采集和记录。 二、报工操作的流程&…

MacOS goland go1.21 debug问题

安装dlv brew install dlv 安装之后在终端会显示所在目录 类似/usr/local/Cellar/delve/1.21.0/bin 配置goland 在文件系统中找到goland 右击选择show package contents -> Contents -> plugins -> go 尝试替换 其中对应系统 的 dlv 结果还是不行 然后打开应用gol…

shell脚本:在curl命令中传递变量、单引号 ‘ 和双引号 “区别、时间戳获取、生成UUID

在curl命令中传递变量 在curl中引用变量时要加个转义 “” 如&#xff1a; #!/bin/sh timestamp$(($(date %s%N)/1000000)) curl http://xx -H "Content-Type:application/json" -X POST -d {"timestamp": ""${timestamp}""}单引…

常见前端面试之VUE面试题汇总七

20. 对 vue 设计原则的理解 1.渐进式 JavaScript 框架&#xff1a;与其它大型框架不同的是&#xff0c;Vue 被设计 为可以自底向上逐层应用。Vue 的核心库只关注视图层&#xff0c;不仅易于上 手&#xff0c;还便于与第三方库或既有项目整合。另一方面&#xff0c;当与现代化的…

universal robot 机械臂 官方基本教程

https://academy.universal-robots.cn/modules/e-Series-core-track/Chinese/module3/story_html5.html?courseId2166&languageChinese 教程1 控制箱内部 包含&#xff1a; 主机板&#xff0c;SD卡&#xff0c;和安全控制板 安全控制板负责所有控制信息&#xff0c;包括…

Ansible学习笔记(持续更新)

Ansible学习目录 1.自动化运维1.1 企业实际应用场景1.1.1 Dev开发环境1.1.2 测试环境1.1.3 发布环境1.1.4 生产环境1.1.5 灰度环境 1.2 程序发布1.3 自动化运维应用场景1.4 常用自动化运维工具 2.Ansible介绍和架构2.1 Ansible特性2.2 Ansible架构2.2.1 Ansible主要组成部分2.2…

LeetCode(力扣)617. 合并二叉树Python

LeetCode617. 合并二叉树 题目链接代码 题目链接 https://leetcode.cn/problems/merge-two-binary-trees/ 代码 递归 # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # self.val val # …

c# 使用了 await、asnync task.run 三者结合使用

在 C# 异步编程中&#xff0c;await 和 async 关键字结合使用可以让你更方便地编写异步代码&#xff0c;而无需直接使用 Task.Run。然而&#xff0c;有时候你可能仍然需要使用 Task.Run 来在后台线程上执行某些工作&#xff0c;这取决于你的代码逻辑和需求。 await 和 async 关…

【springboot】springboot定时任务:

文章目录 一、文档&#xff1a;二、案例&#xff1a; 一、文档&#xff1a; 【cron表达式在线生成器】https://cron.qqe2.com/ 二、案例&#xff1a; EnableScheduling //开启任务调度package com.sky.task;import com.sky.entity.Orders; import com.sky.mapper.OrderMapper; …

LeetCode1049. 最后一块石头的重量 II

1049. 最后一块石头的重量 II 文章目录 [1049. 最后一块石头的重量 II](https://leetcode.cn/problems/last-stone-weight-ii/)一、题目二、题解方法一&#xff1a;01背包二维数组算法思路具体实现 方法二&#xff1a;01背包一维数组 一、题目 有一堆石头&#xff0c;用整数数…

LeetCode-160. 相交链表

这是一道真的非常巧妙的题&#xff0c;题解思路如下&#xff1a; 如果让他们尾端队齐&#xff0c;那么从后面遍历就会很快找到第一个相交的点。但是逆序很麻烦。 于是有一个巧妙的思路诞生了&#xff0c;如果让短的先走完自己的再走长的&#xff0c;长的走完走短的&#xff0c;…

MyBatisx代码生成

MyBatisx代码生成 1.创建数据库表 CREATE TABLE sys_good (good_id int(11) NOT NULL,good_name varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,good_desc varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,PRIMARY KEY (good_id) ) ENGINEInnoDB DEFAULT CHA…

Multisim软件安装包分享(附安装教程)

目录 一、软件简介 二、软件下载 一、软件简介 Multisim软件是一款电路仿真和设计软件&#xff0c;由美国国家仪器公司&#xff08;National Instruments&#xff09;开发。它提供了一个交互式的图形界面&#xff0c;使用户能够轻松地构建和仿真电路。以下是Multisim软件的详…

Java中文件的创建(三种方式),文件常用的方法

文件的创建 方式1&#xff1a; new File(String pathName) 根据路径构建一个File对象方式2&#xff1a; new File(File parent,String child) 根据父目录文件子路径构建方式3&#xff1a; new File(String parent,String child) 根据父目录子路径构建 代码&#xff1a; //方…