Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are advances of glide recyclerview integration?

I just tried to use glide recyclerview integration and read a document about it and it said: "The RecyclerView integration library makes the RecyclerViewPreloader available in your application. RecyclerViewPreloader can automatically load images just ahead of where a user is scrolling in a RecyclerView", but I don't realise any difference between glide recyclerview integration and only glide, please explain what are advances of glide recyclerview integration? And how can I see the difference?

Here's my code:

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)
    }
}

THERE ARE NO DIFFERENCES IF I COMMENT THIS LINE recycler_view.addOnScrollListener(preloader)

like image 745
vuhung3990 Avatar asked Dec 05 '17 22:12

vuhung3990


People also ask

How does glide work with RecyclerView?

First it collects and returns a list of Models (the items you pass in to Glide's load(Object) method, like URLs or file paths) for a given position. Second it takes a Model and produces a Glide RequestBuilder that will be used to preload the given Model into memory.


2 Answers

The RecyclerView integration library makes the RecyclerViewPreloader available in your application.
And RecyclerViewPreloader can automatically load images just ahead of where a user is scrolling in a RecyclerView.

Combined with the right image size and an effective disk cache strategy, this library can dramatically decrease the number of loading tiles/indicators users see when scrolling through lists of images by ensuring that the images the user is about to reach are already in memory.

To use the RecyclerView integration library, add a dependency on it in your build.gradle file:

compile ("com.github.bumptech.glide:recyclerview-integration:4.4.0") {
  /*Excludes the support library 
    because it's already included by Glide.*/
  transitive = false
}
like image 175
chandrakant sharma Avatar answered Oct 07 '22 00:10

chandrakant sharma


The issue in your code is that you create preloadSizeProvider of type ViewPreloadSizeProvider, but you never call preloadSizeProvider.setView(...) on it. So it doesn't know the size of your target view, so it can't preload images in correct size, so you see no improvement.

I recommend first trying to make it work with fixed size. So instead of using ViewPreloadSizeProvider create FixedPreloadSizeProvider(WIDTH, HEIGHT) and make sure to use same size when loading images via Glide as such Glide.with(this).load(imageUri).override(WIDTH, HEIGHT).into(imageView);

If you want to check if it works, enable logging for both Glide requests like this (I used Java code there for my simplicity):

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() }
    }
}

And in logcat you should see that PRELOAD requests have dataSource = [LOCAL] or [RESOURCE_DISK_CACHE] and LOAD requests have dataSource = [MEMORY_CACHE].

It if works, great. Then you can rewrite it to use ViewPreloadSizeProvider. In that case you remove the fixed image size (.override(250,250)) from Glide requests and then don't forget to call preloadSizeProvider.setView(holder.imageView) for example in onCreateViewHolder method.

like image 39
Robyer Avatar answered Oct 07 '22 01:10

Robyer