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
}
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
}
}
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(
PHOTO_SIZE,
PHOTO_SIZE
)
val preloadModelProvider = MyPreloadModelProvider(this, adapter)
val preloader: RecyclerViewPreloader = 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 {
override fun getPreloadItems(position: Int): MutableList {
return mutableListOf(adapter.getItems()[position])
}
override fun getPreloadRequestBuilder(item: MyData): GlideRequest? {
return GlideApp.with(ctx)
.asBitmap()
.load(item.path)
.centerCrop()
.override(PHOTO_SIZE)
}
}
class MyAdapter(private val ctx: Context) :
RecyclerView.Adapter() {
private var items: MutableList? = null
fun onChange(items: MutableList) {
this.items = items
notifyDataSetChanged()
}
fun getItems(): MutableList {
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 {
val photos = ArrayList()
//读取手机图片
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)
}
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