I have a list which I use recyclerView to display. Each row in the list displays an image that is downloaded from a remote server. In order to speedup the display of the list I am downloading the images in the background. Each time the bind() wants to display the image I call a method that starts an asynchronous task that download the image and in the onPostExecute() method I call setImageBitmap() of the image to display the bit-mapped downloaded.
The problem is as follows
As I scroll down, the recyclerView loads more images that fits the screen and when the setImageBitmap() is called the list jumps up, so that the last 1 or 2 items in the list almost never displayed.
When I disable the call to setImageBitmap() there is no problem in displaying the last items (the list now is without images), and scrolling up and down the list.
The problem also shows up when I scroll down very slow. I limited the screen to show only 4 items, and as I scroll down to the 6th or 7th item suddenly the display jumps and displays again from item 2 to 5.
What is going on there and how can I make the display to scroll smoothly and without jumping all over?
There problem here comes to the fact your recycler view at the time it is inflated has size X, when you load your image the size changes but the LayoutManager is not aware of this change, hence it won't update your view.
You should post a snippet of your code, it will help to clarify.
Related
Having read a lot of questions answering "how to update one single row of ListView or RecyclerView (which would be notifyItemChanged(position)), i have a more "nested" question:
My custom RecyclerView ImageRecycler holds a couple of CardViews. In these cardviews, we can find a ProgressBar and an ImageView.
Logic: I open a file chooser elsewhere, choose an image, starts displaying / fading it in for 2 seconds in the newly added CardView, while i am also uploading it to a server. So during my image animation, i want to be updated for the upload progress as well. For the last said, i use a LocalBroadcastReciever calling notifyItemChanged(position).
To load the ImageView, i use Glide for asynchronous image loading in my adapter:
File f = new File(entries.get(position).getFilePath());
Glide
.with(main)
.load(f)
.diskCacheStrategy(DiskCacheStrategy.RESULT)
.crossFade(2000)
.into(holder.iv1);
Which leads to my problem:
Image is uploading, notify-method called a few times, which uploads the ProgressBar (yay!), but also makes Glide reloading the image again and again, so the screen starts flickering.
I already tried to animate the image only for the first time, after that, i only call my view holder to just set the already loaded image:
holder.iv1.setImageBitmap(entries.get(position).getBitmap());
But this makes the scrolling of my RecyclerView very faltering.
So how can i refresh only the ProgressBar as a part of CardView, but allowing the "old" image to stay?
So our android app uses recyclerview with a cursor adaptor and then we are using https://github.com/codepath/android_guides/wiki/Endless-Scrolling-with-AdapterViews for endless scrolling with a loader reset event (that will on the next create loader increase the limit for the amount of data we load) that will then update the view.
But the issue is, every time this happens, the recyclerview is at the bottom. So to solve that we are recording the last visible item with findFirstVisibleItemPosition and then using scrollToPosition when the view is ready.
But we have found that if the user scrolls past that point, they will get this jump / jitter as the load finishes because it loads them to that exact item when in fact they are sometimes partly thru it. We try to use scrollTo with exact X and Y (that we record beforehand) but that is not working with recyclerviews as I guess they won't know the exact dimensions of the items.
I know that we can for example only trigger this at the end of the scroll (IE have the buffer size to be 0 or 1) so we know we are at the exact end of the list and can then begin there, but we would like this to be as smooth as possible.
If there is any suggestion I would love to know.
Two questions:
a) is there any way to stop views from getting "thrown out" when you scroll? I'm fetching images from the web using the YouTubeAPI (YouTubeThumbnailView) and it takes some time to fetch these - when scrolling the images are loaded in a couple seconds after scrolling has stopped.
and b) can I withhold elements of the listview until they are completely loaded? I'd prefer the elements to render when their thumbnails have loaded.
It seems like you're going about this the wrong way. You should be fetching the images and storing them in some sort of cache (there are numerous topics on this, so I'll leave that part as an exercise) and then notifying when the data has loaded and updating the thumbnail if it's still on screen. It shouldn't matter whether the View was "thrown out"; on the next time you try to View that particular thumbnail it should already be in the cache and should be able to be loaded near-instantly.
As for the second question, you could initially set the visibility of the View that you return in your Adapter's getView() to INVISIBLE, then when you display the thumbnail, set the thumbnail and then set the View to VISIBLE.
Hi I want to show the images in listview when user scroll the list.
I retrieved the image from database(blob) not from web service.
for example
I have an 40 items in the list view and in my mobile screen 10 item is visible. when i scroll the list it load the next images. i don't want to load the 40 images concurrently.
list will show images between Fisrt Visible Position and Last Visible Position.
Like in a twitter app the images first blank when user scroll then it load in the listview
Thanks in advance.
The solution you finding is called Lazy Loading Adapter, this tutorial will work as you want check this link, this loads images in lazy manner.
I am new Android developer. I want to achieve the following: On a particular screen (Activity) I have a grid view with images being set onto it. I have hundreds of thumbnail images coming from a server via http request. Now I don't want the gridview (with 4 columns in one row) to load the images in one go. Instead I want images to be loaded one row at a time (4 images), with other tiles of the grid view showing progess bar. Also when only few images are displayed the user should still be able to scroll the gridview vertically and thereby displaying empty gridview frames or tiles but if the scrolling is paused the frames or tiles of gridview are again loaded one row at a time.
I am looking for ideas to achieve this.
Thanks in advance for your responses.
In your Adapter's getView method set the image with a indefinite progress spinner.
After that start an AsyncTask to download the image if its not present in the object returned by getItem. Pass the item's position to the asynctask.
In AsyncTask's onPostExecute set the image to the view at position and hide the progress spinner.
Downloading the image in AsyncTask will ensure that your gridview is filled with items(empty) and responds to scrolling.