【问题标题】:What are advances of glide recyclerview integration?glide recyclerview 集成有哪些进展?
【发布时间】:2018-05-19 17:25:31
【问题描述】:

我刚刚尝试使用 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)
    }

}

MyAdapter.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)

【问题讨论】:

    标签: android android-recyclerview kotlin android-glide recyclerview-layout


    【解决方案1】:

    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
    }
    

    【讨论】:

    • 感谢您的回答,我怎样才能看到差异?
    • 请在慢速网络连接或 2G 网络上使用您的应用程序,而不是看到差异
    • 我理解你所说的,但这并不取决于网络类型,因为当打开 glide setLogLevel(Log.VERBOSE) 的日志时,会看到它加载了相同数量的请求。感谢您的回答,但这还不够。
    • 添加依赖还不够
    • 这是来自 Glide 文档的复制粘贴,没有任何解释。
    【解决方案2】:

    您的代码中的问题是您创建了ViewPreloadSizeProvider 类型的preloadSizeProvider,但您从不调用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)
        }
    
    }
    

    MyAdapter.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 方法中。

    【讨论】:

      【解决方案3】:

      假设用户正在滚动加载大图像的 RecyclerView,那么,用户应该等待加载图像的延迟,然后才能在相应的列表项中看到它。 RecyclerViewPreloader 预先加载图片,所以当用户滚动时,已经加载并立即显示。

      在您的代码中,您使用了一个小列表和一个小的 maxPreload 值,因此您不会注意到使用 RecyclerViewPreloader 的区别。要查看它的实际效果,您应该使用包含许多不同图像的长列表,并在使用和不使用预加载器的情况下快速滚动。如果没有预加载器,您将在加载之前看到空图像,并且使用它,图像应该可以快速流畅地显示。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多