I am working on an app which requires an autocompletetextview for suggesting contacts in dropdown view. I am using a custom cursor adapter. My layout for one drop down item has imageview on the left (for showing image of the contact if available, else a default image).
I have used Asynctask to load images from the contacts. In my bindView method, I have following snippet to load images from the Async task.
contactImage = new conactImage(viewHolder, cursor);
contactImage.execute(new String[] {userId});
and in the Asynctask's onPostExecute method, I set the image bitmap.
mViewHolder.cImage.setImageBitmap(imageResultBitmap);
mViewHolder is the viewholder passed as argument in the previous snippet.
The problem I am facing is a bad UX. Suppose I entered two characters in the autocompletetextview. The images show up in a second. When I scroll, the images don't change unless I wait another 2 3 seconds to get the correct image loaded. And when I scroll fast, the views flicker a lot because of the random image bitmap changes.
I understand it is a view recycling thing, but this gets annoying. Please suggest any other possible way to do the same.
on scrolling
Thanks!
Related
I've a list of URLs, each corresponding to an image.
I need to display these images in a ListView.
Currently, my approach is pass this List<String> containing URLs to a CustomAdapter (extending BaseAdapater).
Each row item in the ListView will be inflated with an ImageView.
Then in the getView() method, if currentImageView == null, then I'll start an AsyncTask, which will download the bitmap for that imageList.get(position).
Then in the postExecute(), I'll set currentImageView.setBitmap(downloadedBitmap).
In this manner,from inside the adapter, I'll call AsyncTask one-by-one for each image.
If you think, there is something wrong in this approach then please let me know. Also, please suggest the correct approach.
One pitfall with approach I've found in when AsyncTask for a certain list element is in progress & user scrolls down then back up, the same async task will be called again.
How can I prevent this?
When your views get recycled, the currentImageView will not be null and it will keep displaying the same images. I would suggest using Universal Image Loader. It takes care of all of that for you, with TONS of extra features like caching and what not.
Try this library
Then in getView method, simply add this code
UrlImageViewHelper.setUrlDrawable(holder.image, model.getimageURL(), R.drawable.placeholder);
parameter one is your ImageView, second parameter is Image URL, and the last is placeholder image.
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 am new to Android and Java. I am building an app that allows users to push a button which launches an image chooser where they can select from images on the sd card. The app loads with a grid view with 2 cells. One cell has an image view that has a default image. The other is the button. Once, the image is chosen, the image view needs to be displayed in the Image View of the Grid View.
I am using a string path that is being decoded from the images uri to create a bitmap. I then am calling imageView.setImageBitmap(bitmap). This is doing nothing. I have tried updating the image resource with a different image in the drawable folders and still nothing. I added a seperate image view just under the grid in my activity, and that image is updating fine which leads me to believe that this has to do with the grid view (this is my first grid view).
Any help is very much appreciated.
Thank you.
GridView is maybe not the right choice if you've only got two cells. You will probably have an easier time with a simple LinearLayout that has the two items you're dealing with.
But, here's how you do it with a GridView:
Create your adapter by extending BaseAdapter. The most important method is getView(), but it's where you should be doing the least amount of work.
When the GridView goes to redraw itself, it'll go through for each visible position and call getView() for each one. You'll be supplied a View. If the view is null, inflate a new one from your XML resources, populate it, and return it. If the view is NOT null, populate the existing one with the appropriate data. The widget is being efficient by recycling views.
The trick you need is that when you want the image to change, you need to call notifyDataSetChanged() on your adapter in order to trigger the redraw (which is when you'll populate the new image in the view for the appropriate cell).
That's the two-minute version. At Google I/O a year or two back, they did a talk on The World of ListView and posted it on YouTube. It was a good talk and pretty much everything there applies to GridView as well.
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.
Let's assume i got a list of ImageView and TextView with LinearLayout.
Now i'm using simple ArrayAdapter extension that gets Strig[][] as items which is an array of double strings (each entry contains String[2] where the first string is a uri to the image and the second one is the text. i override getView to display the image and text , recyling views, of course :-).
However since image loading, even from resources may be slow, i'm doing it in an async task, that means that i have a default image loaded and i use: startLoading (it's my method) that stakes the ImageView and the Uri and once the image is ready it places it in the image view.
However sometimes, since it's a list if the image is not loaded yet and I'm in the middle of the process it's worth while stopping the loading, and that's in case that the line i'm loading image for is no longer visible.
Since the views are recycled i can't check if ImageView is visible since it may be visible but with a different Drawable... is there a way for me to know at some point that my line in invalidated and not visible ? is there a simple way or shell i need to start using flags and tag pattern and stuff like that to discover that my line is no longer valid ?
What I do is based on how the ListView manages it's views.
As there is a limited set of Views really used by the ListView and that might be passed to our Adapter through the convertView argument of the getView() method, I implemented the following:
I have a LinkedList class member where I store the Uris to be loaded. These Uris are consumed in an AsyncTask member to retrieve the pics.
Before returning the item view in getView(), my Adapter places the Urin of the item pic in the View.setTag(Object).
When I reuse a convertView, before reusing it's content I get the Uri it was previously linked to using View.getTag() and remove the corresponding element from the pending Uris LinkedList.