我只是尝试使用 glide recyclerview 集成并阅读了有关它的文档,它说:“RecyclerView 集成库使 RecyclerViewPreloader 在您的应用程序中可用。RecyclerViewPreloader 可以在用户在 RecyclerView 中滚动的位置之前自动加载图像 ”,但我没有意识到 glide recyclerview 集成和仅 glide 有什么区别,请解释一下 glide recyclerview 集成有哪些优点?我怎样才能看到差异?
这是我的代码:
GlideModule.kt
@GlideModule
class GlideModule : AppGlideModule() {
override fun applyOptions(context: Context?, builder: GlideBuilder?) {
val requestOp = RequestOptions.noAnimation()
.priority(Priority.LOW)
builder?.setDefaultRequestOptions(requestOp)
?.setLogLevel(Log.VERBOSE)
super.applyOptions(context, builder)
}
// Disable manifest parsing to avoid adding similar modules twice.
override fun isManifestParsingEnabled(): Boolean {
return false
}
}
MyPreloadModelProvide.kt
class MyPreloadModelProvide(val listUrls: List<String>, val context: Context) : PreloadModelProvider<Any> {
override fun getPreloadItems(position: Int): MutableList<Any> {
val url = listUrls.get(position)
if (TextUtils.isEmpty(url)) {
return Collections.emptyList();
}
return Collections.singletonList(url);
}
override fun getPreloadRequestBuilder(url: Any?): RequestBuilder<*>? {
return GlideApp.with(context)
.load(url)
}
}
我的适配器.kt
class MyAdapter(val listUrl: List<String>, val context: Context) : RecyclerView.Adapter<MyViewHolder>() {
override fun getItemCount(): Int = listUrl.size
@SuppressLint("CheckResult")
override fun onBindViewHolder(holder: MyViewHolder?, position: Int) {
GlideApp.with(context)
.load(listUrl[position])
.into(holder?.imageView)
holder?.imageView?.setOnClickListener { Toast.makeText(context, listUrl[position], Toast.LENGTH_LONG).show() }
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): MyViewHolder = MyViewHolder(LayoutInflater.from(parent?.context).inflate(R.layout.item, parent, false))
}
class MyViewHolder(view: View?) : RecyclerView.ViewHolder(view) {
var imageView: ImageView
init {
imageView = view!!.findViewById(R.id.img)
}
}
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var preloadSizeProvider: ViewPreloadSizeProvider<Any>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// glide
var listUrls = listOf(
"https://img.pokemondb.net/artwork/bulbasaur.jpg",
"https://img.pokemondb.net/artwork/ivysaur.jpg",
"https://img.pokemondb.net/artwork/komala.jpg",
"https://img.pokemondb.net/artwork/turtonator.jpg",
"https://img.pokemondb.net/artwork/togedemaru.jpg",
"https://img.pokemondb.net/artwork/mimikyu.jpg",
"https://img.pokemondb.net/artwork/nihilego.jpg",
"https://img.pokemondb.net/artwork/buzzwole.jpg",
"https://img.pokemondb.net/artwork/pheromosa.jpg",
"https://img.pokemondb.net/artwork/xurkitree.jpg",
"https://img.pokemondb.net/artwork/celesteela.jpg",
"https://img.pokemondb.net/artwork/kartana.jpg",
"https://img.pokemondb.net/artwork/guzzlord.jpg",
"https://img.pokemondb.net/artwork/necrozma.jpg",
"https://img.pokemondb.net/artwork/magearna.jpg",
"https://img.pokemondb.net/artwork/marshadow.jpg"
)
preloadSizeProvider = ViewPreloadSizeProvider<Any>()
val modelProvider = MyPreloadModelProvide(listUrls, this)
val preloader = RecyclerViewPreloader(GlideApp.with(this), modelProvider, preloadSizeProvider, 2 /*maxPreload*/)
// recycler view
recycler_view.layoutManager = LinearLayoutManager(this)
recycler_view.setHasFixedSize(true)
recycler_view.adapter = MyAdapter(listUrls, this)
// THERE ARE NO DIFFERENCES IF I COMMENT THIS LINE
recycler_view.addOnScrollListener(preloader)
}
}
如果我评论这一行,没有任何区别
recycler_view.addOnScrollListener(preloader)
RecyclerView
集成库使RecyclerViewPreloader
在您的应用程序中可用。RecyclerViewPreloader
可以自动加载用户在 RecyclerView
中滚动的位置之前的图像。
结合正确的图像大小和有效的磁盘缓存策略,该库可以通过确保用户即将到达的图像已经在内存中来显着减少用户在滚动图像列表时看到的加载图块/指示器的数量。
要使用
RecyclerView
集成库,请在 build.gradle
文件中添加对其的依赖项:
compile ("com.github.bumptech.glide:recyclerview-integration:4.4.0") {
/*Excludes the support library
because it's already included by Glide.*/
transitive = false
}
代码中的问题是您创建了
preloadSizeProvider
类型的 ViewPreloadSizeProvider
,但从未在其上调用 preloadSizeProvider.setView(...)
。因此它不知道目标视图的大小,因此无法预加载正确大小的图像,因此您看不到任何改进。
我建议首先尝试使其以固定大小工作。因此,不要使用
ViewPreloadSizeProvider
创建 FixedPreloadSizeProvider(WIDTH, HEIGHT)
并确保在通过 Glide 加载图像时使用相同的尺寸,例如 Glide.with(this).load(imageUri).override(WIDTH, HEIGHT).into(imageView);
如果你想检查它是否有效,请像这样启用两个 Glide 请求的日志记录(为了简单起见,我在那里使用了 Java 代码):
MyPreloadModelProvide.kt
class MyPreloadModelProvide(val listUrls: List<String>, val context: Context) : PreloadModelProvider<Any> {
override fun getPreloadRequestBuilder(url: Any?): RequestBuilder<*>? {
return GlideApp.with(context)
.override(250, 250)
.dontTransform()
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
Log.d("IMAGE PRELOAD", "onResourceReady() called with: model = [" + model + "], target = [" + target + "], dataSource = [" + dataSource + "]");
return false;
}
})
.load(url)
}
}
我的适配器.kt
class MyAdapter(val listUrl: List<String>, val context: Context) : RecyclerView.Adapter<MyViewHolder>() {
override fun getItemCount(): Int = listUrl.size
@SuppressLint("CheckResult")
override fun onBindViewHolder(holder: MyViewHolder?, position: Int) {
GlideApp.with(context)
.load(listUrl[position])
.override(250, 250)
.dontTransform()
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
Log.d("IMAGE LOAD", "onResourceReady() called with: model = [" + model + "], target = [" + target + "], dataSource = [" + dataSource + "]");
return false;
}
})
.into(holder?.imageView)
holder?.imageView?.setOnClickListener { Toast.makeText(context, listUrl[position], Toast.LENGTH_LONG).show() }
}
}
在 logcat 中,您应该看到 PRELOAD 请求具有 dataSource = [LOCAL] 或 [RESOURCE_DISK_CACHE] 并且 LOAD 请求具有 dataSource = [MEMORY_CACHE]。
如果有效,那就太好了。然后你可以重写它以使用
ViewPreloadSizeProvider
。在这种情况下,您可以从 Glide 请求中删除固定图像大小 (.override(250,250)
),然后不要忘记在 preloadSizeProvider.setView(holder.imageView)
方法中调用 onCreateViewHolder
。
假设用户正在滚动加载大图像的RecyclerView,那么用户应该等待加载图像的延迟,然后才能在相应的列表项中看到它。 RecyclerViewPreloader 提前加载图像,因此当用户滚动时,已经加载并立即显示。
在您的代码中,您使用了一个小列表和一个小的 maxPreload 值,因此您不会注意到使用 RecyclerViewPreloader 的差异。要查看它的实际效果,您应该使用包含许多不同图像的长列表,并在使用或不使用预加载器的情况下快速滚动。如果没有预加载器,您将在加载之前看到空图像,有了它,图像应该可以快速流畅地显示。
Glide 有一个 RecyclerView 集成 页面,您可能会认为这是让 Glide 与 Android RecycerView 一起工作的必需方法。但它实际上只是添加了一个内存缓存预加载器,实现起来有点复杂;只需将
Glide.with(view.context).load(url)
添加到 RecyclerView onBindViewHolder
的简单方法也同样有效,不会导致任何内存泄漏。默认情况下,Glide 有一个内置的磁盘缓存,效果很好。
所以OP的问题是这个内存预加载器有什么优点。所述优点是显而易见的,在用户滚动到图像之前预加载图像。
但更好的问题是,这些优势是否值得付出额外的努力来使其发挥作用。这是一个主观问题。只有互联网连接速度较慢的用户才会注意到这一点,即使如此,我也不确定是否值得这么麻烦。您不知道用户将滚动到哪里,您可以预加载图像,然后用户将滚动到最底部,并且无论如何都需要加载新图像。所以在我看来,这不值得这么麻烦。