I have issue with Gridview in Android.
Context :
I have a gridview, with a list of images downloaded (around 100 images).
To do it more convenient for user, a first gridview is load, with inside 100 images on which is a logo Loading.
After that, I start an AsyncTask that :
In onProgressUpdate => Update image with gridview.getChildAt
In onPostExecute => change adapter of gridview with the list of bitmaps downloaded
My issue is in onProgressUpdate.
When using getChildAt(position), I realized that position means position of the item in the visible rect. So there is two issues :
=> First, hidden images are not updated (it's why I'm doing an setAdapter in PostExecute)
=> Second, if I scroll while downloading, it forget the first images, and some other issues while scrolling, but difficult to express with word ...
My question is a little easy, but I didn't find in Android Reference, and also after Google searches :
- How is it possible to update a view in a gridview by its real position, and not by visible position ?
Thanks a lot
Views that are not visible do not exist, so you can't update them. You can only update your backing model to have the correct information once the user scrolls to a particular item. So what you need to do is to retrieve the images and save them in a cache (or the model itself) that you can access when rendering a particular view.
However, I would suggest that there's no need to retrieve any images the user is not seeing yet.
Related
I have a class that extends BaseAdapter, which I use for a ListView. In the getView() method of that class I'm using an AsyncTask with a callback method to download an image (once downloaded, I store it, so I don't have to download it again). When the ListView loads the items first, only the first item displays an image an then starts to change the images (repeatedly displaying the images of the other items). Later also the other items start showing the same behaviour. After a while they stop cycling the images and each item shows the correct images. If I scroll the ListView the items are starting again to cycle the images.
This only happens, if I recycle the convertView parameter, that is passed to getView(). If I don't the images take very long to show up, and I'm afraid I'm creating too much new Views.
Thanks in advance for any advices, to get this working properly.
The simple way to get this going is to dump all your own image loading code and use something that already handles this, like Square's Picasso. There are plenty of alternatives if you do not like Picasso.
Otherwise, your tasks will need to be aware of the recycling, so they do not attempt to update an ImageView that now needs a different image. For example, you could use setTag() and getTag() on the ImageView to store (and retrieve) the URL the ImageView currently needs, and if the image downloaded by the task is some other URL, don't apply it.
But, again, please use an existing library for this. It's 2013: few people should be rolling their own download-the-images-for-use-in-ListView-rows code anymore.
I have an adapter that displays a grid of thumbnails with a text. These thumbnails are heavy to load, heavy to draw, etc.
The thumbnail gridview is constantly filled with new content, let's say, 1 new item every 2 seconds.
My adapter has a function that I call from outside to inject new items:
public void postNew(Item i) {
arrayStuff.put(i);
notifyDataSetChanged();
}
What happens is, with my current approach, when I insert a new element in the gridview, it refreshes everything, even if the added item is not going to be visible. The refresh process kind of breaks the experience, specially if the user is browsing the gridview and new content arrives.
How would you recommend improving this? is there a lighter 'notifyDataSetChanged()' or something like that?
I do not know of any lighter version of notify data set, but you can always use ListView.getFirstVisiblePosition and ListView.getLastVisiblePosition to determine whether your latest added position is visible, and only call notifyDataSetChanged if it is.
As for "heavy" bitmaps, as heavy as it is I think you should resample or scale it to the minimum size you need, using LruCache you can reduce the need of re-drawing on notify data set changed.
It sounds like you probably need to implement some form of caching, it's not very good memory management to have images which are not visible loaded into memory, ideally you would retrieve them from cache when they become (or are about to become) visible.
An alternative approach could be to add some form of visual indicator when new content arrives and then implement "pull down to refresh" or similar, then make a call to notifyDataSetChanged() on your adapter to refresh the content. I can imagine that refreshing every couple of seconds would not give a great UX because it would be hard to follow if the screen content is constantly changing.
You need create custom view(dynamic at runtime) that adds multiple imageview and appropriate textview, the container view should be LinearLayout, after that you can able to update a particular view or element.
I'm developing my first app and have been reading a LOT here.
I've been trying to find a solution for the following issue for over a week with no luck.
I have an Adapter that extends ArrayAdapter to show image and 3 lines of text in each row.
Inside the getView I assign relevant information for the TextViews and use ImageLoader class to download image and assign it to the ImageView.
Everything works great! I have 4.5 rows visible on my screen (out of total of 20). When I scroll down for the first time the images continue to download and be assigned in right order to the list.
BUT when I scroll back the list looses all the images and start redrawing them again (0.5-1 sec per image) in correct order. From what I've been reading it's the standard list performance but I want to change it.
I want that, once the image was downloaded, it will be "sticked" to the list for the whole session of the current window. Just like in Contacts list or in the Market. It is only 20 images (6-9kb each).
Hope I managed to explain myself.
you need to cache each image after download it, and each time the adapter need it check if its already downloaded get it from cache (disk or memory) otherwise download it.
at first i recommended you to read this tutorial from android dev site http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
or use an external lib like this one https://github.com/koush/UrlImageViewHelper
The problem here is that the ArrayAdapter is reusing the list view rows as you scroll, so as you scroll down, the top row will be reused and inserted at the bottom of the list (for performance reasons).
Your best bet here is to try to cache the images locally on your device to avoid calling the ImageLoader every time.
One pretty good library that solves this problem is ignition. It's open source and available here: https://github.com/kaeppler/ignition
Take a look at RemoteImageView for a good example of the caching mechanism.
I have a Gallery, which has an adapter connects to it. In the getView method, i have a custom layout, so that I can i have image and caption displayed together
The image is downloaded from an URL, which is done asynchously, and working as expected.
Currently i make each item to fill the screen, so i only have one item display at a time, basically i want to make it like a slide show.
let me be clear, currently i have an activity, and it only has one View, which is a Gallery.
problem occurs when I am swiping, the image bounces and stays at the same image. i need to swipe many times, hard, and long swipe, then i can get to next image.
i put a debug message in my custom adapter in the getView(), it seems getView is getting called many times (4 times), and position being passed is either the current position or the previous one, which explains why i am stuck at the same screen.
if i remove the remote downloading image part, or just use a static image form the phone, i don't have any more issues, in fact, the getView only gets called once, with correct position.
i am very frustrated, not sure what the problem is, could it be because i am downloading image asynchously, which will cause the image to update which causes getView to get called again to redraw itself?
i am not sure..
please help
Unfortunately this is a bug with gallery. Listviews will scroll nicely regardless of data being updated asynchronously. However, the gallery is just not coded up to par with the listview
When the gallery tries to update a visible view (due to your image loading callback) this view will "snap" back to the focused position. If you are changing the view in any way when it is scrolling it will snap. This is likely why you have to scroll hard to get away from the current view. It is trying to perform a callback on your view and only scrolling fast will prevent the callback from occurring before you move away from that view.
I've reported this bug a while ago here:
Android Issues
There are a few workarounds posted in there you can try if you are set on using a Gallery.
Unfortunately it hasn't gained attention from the Android developers.
It seems the issue is caused with views being set to "wrap_content" and the gallery having to remeasure/redraw its views
I have since migrated away from using the gallery and instead use a ViewPager. It is much easier to manage and you don't have to worry about this problem. This has been a known problem with the Gallery since the gallery was first introduced. I have no idea if this was fixed in any of the newer Android versions (3.x/4.x). As of 2.3.7 it is not fixed.
At first you should note: Any AdapterView (Gallery, ListView etc) doesn't guarantee that each time getView() method is called it will pass the same View instance parameter. It only guarantees that each view will have the same type (see Adapter.getIntemViewType() method docs)
So, when you start image downloading you should only specify position of the element. Then after the image has been downloaded you should bind specified ImageView with downloaded image in Adapter.getView() method call.
Take a look to the ImageDownloader from the Android samples here
The other approach is to use WeakHashMap in order to contain map of adapter views to its positions. I can provide you with code samples if you need.
Hi geeks!
Here is a problem using ListView.
When generating a single list item view, in the method of BaseAdapter.getView, some continuous async remote data request may be issued, like getting the photo of a person.
But when the response is back, the list item view might be reused, as the mechanism of ListView works. I cannot find the right view to put the response to.
How did you guys fix this problem?
As you say, there is a good chance that by the time you've loaded the image that the list item is no longer visible or even existing. So you can check what is on screen using ListView.getFirstVisiblePosition() and ListView.getLastVisiblePosition(), if it is onScreen get the item and set the image. Otherwise you have to cache the image (either memory or sd-card depending on how many images and the size of them) and next time getView() is called for that item just use the cached image.
I hope that helps.
I believe what your after is "lazy image loading" + caching. I got my implementation going via this answer. The package is called LazyList.
I hope this helps