Implemented recyclerview with GridManager to display images from the Internet. To download using Picasso. The problem is that when there are a lot of pictures (> 100), when fast scrolling it slows down, trying to draw pictures right away, even if it is not required (for example, when scrolling upwards, I do not need to draw the entire list, but only where I’ll stop ). I heard, this is decided by the prohibition to upload images during scrolling. Who knows links to examples of such an implementation? or maybe some other solutions to this problem.
5 answers
On weak devices it was noticed:
If you have more than 15 grid elements, all loaded ones are manifested by fade-animation, if the loading time is very small or reading is coming from the disk and at that moment scroll occurs - logs are possible regardless of the library.
I worked deeply on Image Loading for android - and experimented with my own optimized solution, as well as with 3-rd part libraries.
In short, the following happens: when ready-made bitmaps (eg loading from disk + many grid cells + fast scrolling) too quickly and quickly arrive at the UI-stream, each bitmap starts the fade animation — each drawable / imageView is redrawn 30 times / sec . And all of them in inconsistency flood UI stream with events "invalidate drawable", "on Bitmap loaded" ...
It should not be forgotten that the ui-stream already has to rake a lot (sensor gestures, scroll list, and many others) ... as a rule, this is not a problem for most modern devices
but small weak devices do not have time to simultaneously and independently animate many elements on the stage, which also shifts itself. (by Canvas-API)
If everything is perfect with the boot logic - and the scrolling lags - try to reduce the duration of the fades - or turn them off altogether.
Something like this:
public class IdleRecyclerViewScrollListener extends RecyclerView.OnScrollListener { private final IdleHandler mIdleHandler; private final RecyclerView mRecyclerView; private final Runnable mIdleRunnable = new Runnable() { int mRepeatCount = 0; @Override public void run() { if (mRecyclerView != null && mIdleHandler != null && mRecyclerView.getLayoutManager() != null && mRecyclerView.getChildCount() > 0) { mRepeatCount = 0; mIdleHandler.onIdle( mRecyclerView.getLayoutManager().getPosition(mRecyclerView.getChildAt(0)), mRecyclerView.getChildCount()); } else if (mRecyclerView != null && ++mRepeatCount < 5) { mRecyclerView.postDelayed(mIdleRunnable, 200); } } }; private int mLastState = -1; public IdleRecyclerViewScrollListener(IdleHandler idleHandler, RecyclerView recyclerView) { mIdleHandler = idleHandler; mRecyclerView = recyclerView; } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if (dx == 0 && dy == 0) { onScrollStateChanged(recyclerView, RecyclerView.SCROLL_STATE_IDLE); } } @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState != mLastState) { if (newState == RecyclerView.SCROLL_STATE_IDLE) { recyclerView.postDelayed(mIdleRunnable, 200); } else { recyclerView.removeCallbacks(mIdleRunnable); } } mLastState = newState; } public interface IdleHandler { void onIdle(int firstVisibleItem, int visibleItemsCount); } } And add this class as a leaflet for recyclerview:
mRecyclerView.addOnScrollListener(new IdleRecyclerViewScrollListener( new IdleRecyclerViewScrollListener.IdleHandler() { @Override public void onIdle(int firstVisibleItem, int visibleItemsCount) { //TODO: начать загрузку картинок } }, mRecyclerView)); I can also advise using Glide instead of Picasso, it is faster, judging by the tests.
Glidein the list is not optimized. - Flippy
I have everything implemented through the Universal-Image-Loader , although it is necessary to sweat a little in order to properly scale the pictures before issuing, otherwise you can run into OutOfMemoryError .
In fact, Universal-Image-Downloader allows you to organize separate streams for each image download, and in many different ways: via the InputStream or through ContentProvider or something else. You can configure it to show a special dummy at the time of loading or, if an error is loaded, another stub
- Wow, I thought
UILis the last century :) - Flippy
Try replacing Picasso with Glide - the writing of the code is virtually identical, but the latter is much more productive, all other things being equal. And it seems to me that if you are downloading pictures that you scroll through - isn’t it a reason to use placeholder? Regarding the optimization of RecyclerView - it does not load everything at once, it loads what is on the screen + 1 position above and below.
- Glide on the list? He is not optimized for them, somewhere he saw that he did not work correctly, the person moved to Picasso - Flippy
Familiar problem. You need to crop the downloaded photo to the size of the ImageView . If you do not do this, then of course everything will hang. Why keep on screen more than necessary?
imageView.post(new Runnable(){ @Override public void run(){ Picasso.with(context). load(url). resize(imageView.getWidth(), imageView.getHeight()). into(imageView); } }