Recycler View – pre cache views

Prerequisites :

  1. RecyclerView

Recently I had to “optimize” a RecyclerView to make it load images before they are displayed (render views, before they become visible). The problem was as seen below, that for a few milliseconds the preview or a blank image is displayed before the Bitmap is placed. I had to get rid of this effect, and make the images load before they become visible to the user. Obviously for loading images I am using Picasso .

And here is the code for the initial implementation, which obviously loads a list of cat images.


CatsRecyclerAdapter adapter = new CatsRecyclerAdapter(getActivity(), cats);

//Setup layout manager
PreCachingLayoutManager layoutManager = new PreCachingLayoutManager(getActivity());
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
layoutManager.setExtraLayoutSpace(DeviceUtils.getScreenHeight(getActivity()));

recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);

First thing I tried was to tell Picasso to  pre-fetch some of the images, before they are displayed. Inside the bindViewHolder() method I was using :


Picasso.with(context).load(url).fetch();

to load the images for the next few items. This will download the images before they are needed, and improves things, but there is still a delay while the Bitmap is loaded from disk / memory and resized properly.

My second temptation was to “hack” the RecyclerView, and set the width to be higher than the screen height, forcing the rendering of a few items that are not yet visible to the user. This did not work with RecyclerView, although it might work with ListView.

Finally I digged more inside the RecyclerView and found out that the LinearLayoutManager has a protected method :

protected int getExtraLayoutSpace(RecyclerView.State> state)

So I extended this class and override the method, to return an additional number of pixels to be drawn, and solve our problem in an elegant way.

public class PreCachingLayoutManager extends LinearLayoutManager {
    private static final int DEFAULT_EXTRA_LAYOUT_SPACE = 600;
    private int extraLayoutSpace = -1;
    private Context context;

    public PreCachingLayoutManager(Context context) {
        super(context);
        this.context = context;
    }

    public PreCachingLayoutManager(Context context, int extraLayoutSpace) {
        super(context);
        this.context = context;
        this.extraLayoutSpace = extraLayoutSpace;
    }

    public PreCachingLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
        this.context = context;
    }

    public void setExtraLayoutSpace(int extraLayoutSpace) {
        this.extraLayoutSpace = extraLayoutSpace;
    }

    @Override
    protected int getExtraLayoutSpace(RecyclerView.State state) {
        if (extraLayoutSpace > 0) {
            return extraLayoutSpace;
        }
        return DEFAULT_EXTRA_LAYOUT_SPACE;
    }
}

And just use this as LayoutManager for our RecyclerAdapter, and as it can be seen below, the problem is solved.

If anyone needs it, the code is available on GitHub.

Advertisements

About Ovidiu

Passionate Android Developer. What else? Snowboarding. Football. Stuff like that.
This entry was posted in Android, Google and tagged , , , , , , , . Bookmark the permalink.

7 Responses to Recycler View – pre cache views

  1. Sourabh says:

    Is something like this possible for GridLayoutManager?

    • hey i find same staggeredlayout or grid layout , actucally its very important point to discuss , i tried with linearlayoutmanager work ok , but cant find anything for staggered or grid have u found solution ?

  2. Rob says:

    This worked wonderfully for my project. Thank you!

  3. teja says:

    awesome bud. Really helpful.

  4. Nixy says:

    Thank you, greate solution!

  5. babilon1210 . says:

    How do I work with the DeviceUtils?

  6. what about staggered or grid layout ? .. nothign for it i tried many things ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s