Fedors Lazylist sometimes showing the same image
I am using Fedors implementation of lazy loading images. But sometimes the first item in the listview gets the same image as the last visible item in the list. All other items gets the correct image. If I start scrolling in my list, then the first item gets updated with the correct image. In my log i can see that the ImageView has the same toString output, so that must be the problem I guess:
DEBUG/ImageLoader(6168): Bitmap: android.graphics.Bitmap@46363010 ImageView: android.widget.ImageView@463c1078
DEBUG/ImageLoader(6168): Bitmap: android.graphics.Bitmap@463be868 ImageView: android.widget.ImageView@463c1078
public class AdapterPropertyFavouritesList extends ArrayAdapter<Property> {
private final Activity activity;
private final List<Property> events;
public ImageLoader imageLoader;
public AdapterPropertyFavouritesList(Activity activity, List<Property> objects) {
super(activity, R.layout.favourite_item , objects);
this.activity = activity;
this.events = objects;
App app = (App)activity.getApplication();
imageLoader = app.getImageLoader();
}
public static class ViewHolder{
public TextView address1;
public TextView address2;
public TextView price;
public ImageView image;
public RatingBar ratingBar;
public View event;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = convertView;
ViewHolder holder;
if(rowView == null)
{
LayoutInflater inflater = activity.getLayoutInflater();
rowView = inflater.inflate(R.layout.favourite_item, null);
holder = new ViewHolder();
holder.address1 = (TextView)rowView.findViewById(R.id.address1);
holder.address2 = (TextView)rowView.findViewById(R.id.address2);
holder.price = (TextView)rowView.findViewById(R.id.price);
holder.image = (ImageView)rowView.findViewById(R.id.propertyThumbImg);
holder.ratingBar = (RatingBar)rowView.findViewById(R.id.ratingbar_1);
holder.event = (View)rowView.findViewById(R.id.event);
}
else
holder=(ViewHolder)rowView.getTag();
final Property p = events.get(position);
if (p != null)
{
holder.address1.setText(p.getStreetName());
holder.addr开发者_C百科ess2.setText(p.getZipcodeCountry());
holder.price.setText(ViewHelper.getFormatedMoneyValue(p.price));
holder.ratingBar.setRating(p.getTotalRating());
String url = p.getImage(0);
if(url!=null)
{
imageLoader.DisplayImage(url, activity, holder.image);
}
else
{
holder.image.setImageResource(R.drawable.no_photo_available);
}
rowView.setTag(holder);
}
if(p.hasEvents())
{
holder.event.setVisibility(View.VISIBLE);
}
else
{
holder.event.setVisibility(View.GONE);
}
return rowView;
}
}
public class ImageLoader{
private static final String TAG = ImageLoader.class.getSimpleName();
private boolean scaleImage = false;
MemoryCache memoryCache = new MemoryCache();
FileCache fileCache;
private Map<ImageView, String> imageViews = Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
public ImageLoader(Context context)
{
// Make the background thead low priority. This way it will not affect
// the UI performance
photoLoaderThread.setPriority(Thread.NORM_PRIORITY - 1);
fileCache = new FileCache(context);
}
private final int stub_id = R.drawable.loading_1;
public void DisplayImage(String url, Activity activity, ImageView imageView)
{
imageViews.put(imageView, url);
Bitmap bitmap = memoryCache.get(url);
if (bitmap != null)
{
imageView.setImageBitmap(bitmap);
if(App.LOG_ON)
{
App.log(TAG, "Bitmap: "+bitmap+" ImageView: "+imageView);
}
}
else
{
queuePhoto(url, activity, imageView);
imageView.setImageResource(stub_id);
if(App.LOG_ON)
{
App.log(TAG, "------------------------");
App.log(TAG, "queuePhoto. Set default image on ImageView: "+imageView);
App.log(TAG, "queuePhoto. url: "+url);
App.log(TAG, "------------------------");
}
}
}
public boolean hasAllImagesCached(List<String> urls)
{
boolean found = false;
for(int i = 0; i < urls.size() && !found; i++)
{
String url = urls.get(i);
if(!memoryCache.containsImage(url))
{
found = true;
}
}
return !found;
}
private void queuePhoto(String url, Activity activity, ImageView imageView)
{
// This ImageView may be used for other images before. So there may be
// some old tasks in the queue. We need to discard them.
photosQueue.Clean(imageView);
PhotoToLoad p = new PhotoToLoad(url, imageView);
synchronized (photosQueue.photosToLoad)
{
photosQueue.photosToLoad.push(p);
photosQueue.photosToLoad.notifyAll();
}
// start thread if it's not started yet
if (photoLoaderThread.getState() == Thread.State.NEW)
photoLoaderThread.start();
}
private Bitmap getBitmap(String url)
{
File f = fileCache.getFile(url);
// from SD cache
Bitmap b = decodeFile(f);
if (b != null)
return b;
// from web
try
{
Bitmap bitmap = null;
URL imageUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
conn.setConnectTimeout(8000);
conn.setReadTimeout(8000);
InputStream is = conn.getInputStream();
OutputStream os = new FileOutputStream(f);
Utils.CopyStream(is, os);
os.close();
bitmap = decodeFile(f);
return bitmap;
} catch (Exception ex)
{
ex.printStackTrace();
return null;
}
}
// decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f)
{
try
{
// decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
BitmapFactory.Options o2 = null;
// decode with inSampleSize
if (scaleImage)
{
// Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE = 70;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true)
{
if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
}
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e)
{
}
return null;
}
// Task for the queue
private class PhotoToLoad
{
public String url;
public ImageView imageView;
public PhotoToLoad(String u, ImageView i)
{
url = u;
imageView = i;
}
}
PhotosQueue photosQueue = new PhotosQueue();
public void stopThread()
{
photoLoaderThread.interrupt();
}
// stores list of photos to download
class PhotosQueue
{
private Stack<PhotoToLoad> photosToLoad = new Stack<PhotoToLoad>();
// removes all instances of this ImageView
public void Clean(ImageView image)
{
for (int j = 0; j < photosToLoad.size();)
{
if (photosToLoad.get(j).imageView == image)
{
photosToLoad.remove(j);
if(App.LOG_ON)
{
App.log(TAG, "photo removed");
}
}
else
{
++j;
}
}
}
}
class PhotosLoader extends Thread
{
public void run()
{
try
{
while (true)
{
// thread waits until there are any images to load in the
// queue
if (photosQueue.photosToLoad.size() == 0)
synchronized (photosQueue.photosToLoad)
{
photosQueue.photosToLoad.wait();
}
if (photosQueue.photosToLoad.size() != 0)
{
PhotoToLoad photoToLoad;
synchronized (photosQueue.photosToLoad)
{
photoToLoad = photosQueue.photosToLoad.pop();
}
Bitmap bmp = getBitmap(photoToLoad.url);
memoryCache.put(photoToLoad.url, bmp);
String tag = imageViews.get(photoToLoad.imageView);
if (tag != null && tag.equals(photoToLoad.url))
{
BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad.imageView);
Activity a = (Activity) photoToLoad.imageView.getContext();
a.runOnUiThread(bd);
}
}
if (Thread.interrupted())
break;
}
} catch (InterruptedException e)
{
// allow thread to exit
}
}
}
PhotosLoader photoLoaderThread = new PhotosLoader();
// Used to display bitmap in the UI thread
class BitmapDisplayer implements Runnable
{
Bitmap bitmap;
ImageView imageView;
public BitmapDisplayer(Bitmap b, ImageView i)
{
bitmap = b;
imageView = i;
}
public void run()
{
if (bitmap != null)
imageView.setImageBitmap(bitmap);
else
imageView.setImageResource(stub_id);
}
}
public void clearCache()
{
memoryCache.clear();
fileCache.clear();
}
public synchronized boolean isScaleImage()
{
return scaleImage;
}
public synchronized void setScaleImage(boolean scaleImage)
{
this.scaleImage = scaleImage;
}
}
one of my apps had alot of pictures, however i used the gallery as opposed to this method for viewing them. however i had very strange issues on some pictures. i looked and those images where much larger then the rest. i would say to take a look at your pictures and if some are larger then the rest and see if those correspond to the items in the list getting corrupt. if some are larger resize them down and see if the problem still happens
Actually here is a link of an Lazy Loading image implementation which I think it's better than Fedor's : Image Download.Maybe it can help you.
The problem seems to be solved. My listview was placed in a custom dialog. The getview method was called 6 times, even though that there were only 2 items in the list. I changed the height parameter from "wrap_content" to 80*(listitems.size()) and the problem was solved.
精彩评论