Android Glide预处理preload原始图片到成品resource & 预加载RecyclerViewPreloader,Kotlin
XML
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
XML
implementation 'com.github.bumptech.glide:glide:4.15.1'
kapt 'com.github.bumptech.glide:compiler:4.15.1'
implementation ("com.github.bumptech.glide:recyclerview-integration:4.15.1") {
// Excludes the support library because it's already included by Glide.
transitive = false
}
Kotlin
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.bitmap_recycle.LruBitmapPool
import com.bumptech.glide.load.engine.cache.LruResourceCache
import com.bumptech.glide.module.AppGlideModule
@GlideModule
class MyModule : AppGlideModule() {
companion object {
val mLruResourceCache = LruResourceCache(1024 * 1024 * 9999)
val mLruBitmapPool = LruBitmapPool(1024 * 1024 * 9999)
fun debug(msg: String) {
Log.d(
TAG,
"$msg"
)
}
}
override fun applyOptions(context: Context, builder: GlideBuilder) {
builder.setMemoryCache(mLruResourceCache)
builder.setBitmapPool(mLruBitmapPool)
builder.setLogLevel(Log.DEBUG)
Log.d(TAG, "自定义配置")
super.applyOptions(context, builder)
}
override fun isManifestParsingEnabled(): Boolean {
return false
}
}
XML
<?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"
tools:context=".MainActivity" />
</RelativeLayout>
Kotlin
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.ListPreloader
import com.bumptech.glide.integration.recyclerview.RecyclerViewPreloader
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.util.FixedPreloadSizeProvider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
const val PHOTO_SIZE = 80
const val TAG = "MyGlide"
const val preloadSize = 100
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
rvPreload()
}
private fun rvPreload() {
val spanCount = 13
var recyclerView: RecyclerView = findViewById(R.id.recycler_view)
recyclerView?.layoutManager = GridLayoutManager(this, spanCount).apply {
orientation = GridLayoutManager.VERTICAL
}
val adapter = MyAdapter(this)
recyclerView?.adapter = adapter
val heightCount = resources.displayMetrics.heightPixels / PHOTO_SIZE
val max = 10 * heightCount * spanCount
//如果没有句已加载且展示的格子再滑回去会出现残缺白块行。
recyclerView.recycledViewPool.setMaxRecycledViews(0, max)
CoroutineScope(Dispatchers.IO).launch {
val items = readAllImage(applicationContext)
//以len为长度值,将原始的列表切分为 [0-(len-1)],[len-列表结尾]两条。
//第一条较短,快速完成原始图片预处理,紧急为用户快速展示图片(此时Glide将从resource直接装入内存)
//第二条很长,适合在app冷启动后,后台静默加载。
val len = 600
val segment1 = items.subList(0, len)
val segment2 = items.subList(len, items.size - 1)
Log.d(TAG, "预处理 $len ...")
segment1.forEachIndexed { index, myData ->
glidePreload(myData)
}
Log.d(TAG, "预处理 $len")
// 这段时间是拍脑瓜拍出来的。
// Glide需要一定时间才能完成len个资源的预处理,把原始数据转换为resource成品。
// 如果不等待不延迟,直接通知adapter更新数据,绝大多数情况下,Glide此时还没来得及完成预处理,没有预处理快速显示的效果。
delay(10_000L)
withContext(Dispatchers.Main) {
Log.d(TAG, "预处理 $len done")
adapter.onChange(items)
}
Log.d(TAG, "预处理 第二批 ...")
segment2.forEachIndexed { index, myData ->
glidePreload(myData)
}
}
val preloadSizeProvider = FixedPreloadSizeProvider<MyData>(
PHOTO_SIZE,
PHOTO_SIZE
)
val preloadModelProvider = MyPreloadModelProvider(this, adapter)
val preloader: RecyclerViewPreloader<MyData> = RecyclerViewPreloader(
GlideApp.with(this),
preloadModelProvider,
preloadSizeProvider,
preloadSize
)
recyclerView?.addOnScrollListener(preloader)
}
private fun glidePreload(myData: MyData) {
//本身是线程化的,很快返回,不阻塞主线程。Glide将在后台线程中decode原始图片,加工成resource成品。
GlideApp.with(this)
.asBitmap()
.load(myData.path)
.centerCrop()
.override(PHOTO_SIZE)
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
.preload(PHOTO_SIZE, PHOTO_SIZE)
}
class MyPreloadModelProvider(
private val ctx: Context,
private val adapter: MyAdapter,
) : ListPreloader.PreloadModelProvider<MyData> {
override fun getPreloadItems(position: Int): MutableList<MyData> {
return mutableListOf(adapter.getItems()[position])
}
override fun getPreloadRequestBuilder(item: MyData): GlideRequest<Bitmap>? {
return GlideApp.with(ctx)
.asBitmap()
.load(item.path)
.centerCrop()
.override(PHOTO_SIZE)
}
}
class MyAdapter(private val ctx: Context) :
RecyclerView.Adapter<MyViewHolder>() {
private var items: MutableList<MyData>? = null
fun onChange(items: MutableList<MyData>) {
this.items = items
notifyDataSetChanged()
}
fun getItems(): MutableList<MyData> {
return items!!
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = LayoutInflater.from(ctx).inflate(R.layout.item, parent, false)
val params = view.layoutParams
params.width = PHOTO_SIZE
params.height = PHOTO_SIZE
return MyViewHolder(view)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
GlideApp.with(ctx)
.asBitmap()
.centerCrop()
.override(PHOTO_SIZE, PHOTO_SIZE)
.load(items?.get(position)?.path)
.into(holder.image)
holder.text.text = "$position"
}
override fun getItemCount(): Int {
return items?.size ?: 0
}
// override fun getItemId(position: Int): Long {
// return RecyclerView.NO_ID
// }
override fun getItemViewType(position: Int): Int {
return 0
}
}
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val image: AppCompatImageView = itemView.findViewById(R.id.image)
val text: TextView = itemView.findViewById(R.id.text)
}
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
)
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(MyData(path, index++))
}
cursor.close()
return photos
}
class MyData(var path: String, val index: Int)
}
XML
<?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:text="-.-"
android:textColor="@android:color/holo_red_dark"
android:textSize="8dp" />
</RelativeLayout>
Android GlideApp FixedPreloadSizeProvider RecyclerViewPreloader,mix Java&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/131905329Android GlideApp GlideRequest FixedPreloadSizeProvider 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/131813200