Note that there are some explanatory texts on larger screens.

plurals
  1. POFedors Lazylist sometimes showing the same image
    primarykey
    data
    text
    <p>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:</p> <p>DEBUG/ImageLoader(6168): Bitmap: android.graphics.Bitmap@46363010 ImageView: android.widget.ImageView@463c1078</p> <p>DEBUG/ImageLoader(6168): Bitmap: android.graphics.Bitmap@463be868 ImageView: android.widget.ImageView@463c1078</p> <pre><code>public class AdapterPropertyFavouritesList extends ArrayAdapter&lt;Property&gt; { private final Activity activity; private final List&lt;Property&gt; events; public ImageLoader imageLoader; public AdapterPropertyFavouritesList(Activity activity, List&lt;Property&gt; 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.address2.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; } </code></pre> <p>}</p> <pre><code>public class ImageLoader{ private static final String TAG = ImageLoader.class.getSimpleName(); private boolean scaleImage = false; MemoryCache memoryCache = new MemoryCache(); FileCache fileCache; private Map&lt;ImageView, String&gt; imageViews = Collections.synchronizedMap(new WeakHashMap&lt;ImageView, String&gt;()); 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&lt;String&gt; urls) { boolean found = false; for(int i = 0; i &lt; urls.size() &amp;&amp; !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 &lt; REQUIRED_SIZE || height_tmp / 2 &lt; 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&lt;PhotoToLoad&gt; photosToLoad = new Stack&lt;PhotoToLoad&gt;(); // removes all instances of this ImageView public void Clean(ImageView image) { for (int j = 0; j &lt; 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 &amp;&amp; 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; } </code></pre> <p>}</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload