RecyclerView: How to load items only when the user has stopped scrolling?

advertisements

Currently, I'm developing a launcher app. The app has to load all icons into memory. In some older devices, when I load the app icons through the PackageManager, the app crashes. That's why I'm currently loading icons in the onBindViewHolder(...) method of RecyclerView in a background thread:

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    // ...

    Thread t = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                handler.postAtFrontOfQueue(new Runnable() {
                    Drawable drawable = activity.getPackageManager().getApplicationIcon(app.name.toString());

                    @Override
                    public void run() {
                        viewHolder.appIconIv.setImageDrawable(drawable);
                    }
                });
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
        }
    });
    t.start();

    // ...
}

But, the problem here is, the RecyclerView stutters/lags while scrolling even though the icons are being loaded in the background. Plus, if I scroll to the bottom, all the icons are loaded into memory causing the app to crash on older devices (with less RAM). Besides, I don't think this is a good solution as it has to create a new thread for every single binding of the views. So, my question is, whether it is possible to know if the user has stopped scrolling (and only load icons then).

Any help regarding any of the issues I mentioned apart from the main question is really really appreciated and I'll be really grateful. [ specially all those performance/RAM issues :( ]

Thanks in advance. :D


First of all, I would heavily advise against ever using postAtFrontOfQueue for fear of pushing other things back. If you push things to the front, there's events that have the possibility of never getting executed resulting in strange behavior.

In an app I'm currently developing I'm waiting to load images with picasso until the user is done scrolling / flinging using this current implementation.

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                mPicasso.resumeTag(FeedViewHolder.SEARCH_IMAGE_TAG);
            }
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            if (Math.abs(dy) > SCROLL_THRESHOLD) {
                mPicasso.pauseTag(FeedViewHolder.SEARCH_IMAGE_TAG);
            } else {
                mPicasso.resumeTag(FeedViewHolder.SEARCH_IMAGE_TAG);
            }
        }
    });

You can use picasso to load drawable resources and set the tag like this

mPicasso.load(R.drawable.image_resource_name)
                .fit()
                .centerCrop()
                .tag(SEARCH_IMAGE_TAG)
                .into(imageView);