我正在使用Fedors实现延迟加载图像。但有时列表视图中的第一个项目与列表中最后一个可见项目的图像相同。所有其他项目都获得正确的图像。如果我开始在列表中滚动,那么第一个项目将使用正确的图像进行更新。在我的日志中,我可以看到ImageView具有相同的toString输出,所以这一定是我猜的问题:
DEBUG / ImageLoader(6168):位图:android.graphics.Bitmap@46363010 ImageView:android.widget.ImageView@463c1078
DEBUG / ImageLoader(6168):位图: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.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;
}
}
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;
}
}
答案 0 :(得分:0)
我的一个应用程序有很多图片,但是我使用了图库而不是这种方法来查看它们。但是我在一些照片上遇到了很奇怪的问题。我看起来和那些比其他更大的图像。我会说看看你的照片,如果有些比较大,那么剩下的,看看那些是否与列表中的项目相对应。如果有些人调整大小,请查看问题是否仍然存在
答案 1 :(得分:0)
这个问题似乎已经解决了。我的列表视图放在自定义对话框中。 getview方法被调用了6次,即使列表中只有2个项目。我将height参数从“wrap_content”更改为80 *(listitems.size()),问题解决了。
答案 2 :(得分:0)
实际上这里是一个延迟加载图像实现的链接,我认为它比Fedor更好:Image Download。也许它可以帮助你。