图像不延迟加载和缓存
我正在制作一个Android应用程序,我试图在列表视图中加载和缓存图像。我从here得到了代码。这个Github项目的例子对我来说工作得很好,但是当我尝试在我的应用程序中使用相同的例子时,它的dosnt工作。这是我的ImageManager类。图像不延迟加载和缓存
public class ImageManager {
private HashMap<String, SoftReference<Bitmap>> imageMap = new HashMap<String, SoftReference<Bitmap>>();
private File cacheDir;
private ImageQueue imageQueue = new ImageQueue();
private Thread imageLoaderThread = new Thread(new ImageQueueManager());
public ImageManager(Context context) {
// Make background thread low priority, to avoid affecting UI
// performance
imageLoaderThread.setPriority(Thread.NORM_PRIORITY - 1);
// Find the dir to save cached images
String sdState = android.os.Environment.getExternalStorageState();
if (sdState.equals(android.os.Environment.MEDIA_MOUNTED)) {
File sdDir = android.os.Environment.getExternalStorageDirectory();
cacheDir = new File(sdDir, "data/floapp");
System.out
.println("coming here in mounted media and created folder floapp");
} else
cacheDir = context.getCacheDir();
if (!cacheDir.exists())
cacheDir.mkdirs();
}
public void displayImage(String url, Activity activity, ImageView imageView) {
if (imageMap.containsKey(url)) {
imageView.setImageBitmap(imageMap.get(url).get());
} else {
queueImage(url, activity, imageView);
imageView.setImageResource(R.drawable.ic_launcher);
}
}
private void queueImage(String url, Activity activity, ImageView imageView) {
// This ImageView might have been used for other images, so we clear
// the queue of old tasks before starting.
imageQueue.Clean(imageView);
ImageRef p = new ImageRef(url, imageView);
synchronized (imageQueue.imageRefs) {
imageQueue.imageRefs.push(p);
imageQueue.imageRefs.notifyAll();
}
// Start thread if it's not started yet
if (imageLoaderThread.getState() == Thread.State.NEW)
imageLoaderThread.start();
}
private Bitmap getBitmap(String url) {
System.out.println("coming in getbitmap");
String filename = String.valueOf(url.hashCode());
File f = new File(cacheDir, filename);
System.out.println("cachedir=" + cacheDir.getPath());
System.out.println("filename=" + filename);
// Is the bitmap in our cache?
Bitmap bitmap = BitmapFactory.decodeFile(f.getPath());
System.out.println("bitmap after decoding the file thingy file path="
+ f.getPath());
if (bitmap != null)
return bitmap;
// Nope, have to download it
try {
bitmap = BitmapFactory.decodeStream(new URL(url).openConnection()
.getInputStream());
// save bitmap to cache for later
writeFile(bitmap, f);
return bitmap;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
private void writeFile(Bitmap bmp, File f) {
FileOutputStream out = null;
try {
out = new FileOutputStream(f);
bmp.compress(Bitmap.CompressFormat.PNG, 80, out);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null)
out.close();
} catch (Exception ex) {
}
}
}
/** Classes **/
private class ImageRef {
public String url;
public ImageView imageView;
public ImageRef(String u, ImageView i) {
url = u;
imageView = i;
}
}
// stores list of images to download
private class ImageQueue {
private Stack<ImageRef> imageRefs = new Stack<ImageRef>();
// removes all instances of this ImageView
public void Clean(ImageView view) {
for (int i = 0; i < imageRefs.size();) {
if (imageRefs.get(i).imageView == view)
imageRefs.remove(i);
else
++i;
}
}
}
private class ImageQueueManager implements Runnable {
// @Override
public void run() {
try {
while (true) {
// Thread waits until there are images in the
// queue to be retrieved
if (imageQueue.imageRefs.size() == 0) {
synchronized (imageQueue.imageRefs) {
imageQueue.imageRefs.wait();
}
}
// When we have images to be loaded
if (imageQueue.imageRefs.size() != 0) {
ImageRef imageToLoad;
synchronized (imageQueue.imageRefs) {
imageToLoad = imageQueue.imageRefs.pop();
}
Bitmap bmp = getBitmap(imageToLoad.url);
imageMap.put(imageToLoad.url,
new SoftReference<Bitmap>(bmp));
Object tag = imageToLoad.imageView.getTag();
// Make sure we have the right view - thread safety
// defender
if (tag != null
&& ((String) tag).equals(imageToLoad.url)) {
BitmapDisplayer bmpDisplayer = new BitmapDisplayer(
bmp, imageToLoad.imageView);
Activity a = (Activity) imageToLoad.imageView
.getContext();
a.runOnUiThread(bmpDisplayer);
}
}
if (Thread.interrupted())
break;
}
} catch (InterruptedException e) {
}
}
}
// Used to display bitmap in the UI thread
private 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(R.drawable.ic_launcher);
}
}
}
}
我得到FileNotFoundException,但文件正在我的SD卡上的文件夹中创建。谁能帮帮我吗??
- 预先感谢
更新: 我想这跟url有关。我从here得到了一个提示。我的网址是这样的 “http://graph.facebook.com/1519317701/picture”
我建议你去尝试一次这个例子:
我得到相同的错误。我正在使用第一个链接'lazy list with fedor'以及ImageLoader类中的decodeFile(),我正在将文件f.getpath()打印为“/ mnt/sdcard/LazyList/1534745000”并正确打印在BitmapFactory.decodeStream中(新的FileInputStream(f),null,o);我得到一个异常为“java.io.FileNotFoundException:/ mnt/sdcard/LazyList/1534745000(没有这样的文件或目录)”。 – Antrromet 2012-02-23 10:50:59
我想它的问题是相同的,代码很好,只是它不能从中解码流。我不知道为什么:(我已经浪费了很多时间在这...请帮助。 – Antrromet 2012-02-23 10:52:35
请看看我更新的问题,并抛出一些光,如果可以! – Antrromet 2012-02-23 11:05:56
我瞎猜这里.. 。我遇到了同样的问题,并且通过将“android.permission.WRITE_EXTERNAL_STORAGE”权限添加到我的应用程序清单中来修复它。虽然您可能已经添加了它...
是的......我已经添加了该权限。 – Antrromet 2012-02-29 04:19:21
另一个好的解决方案是ImageLoader(http://androidimageloader.com)。这提供了异步图像加载和透明的双级缓存。
where throw'FileNotFoundException','cacheDir = new File(sdDir,“data/floapp”);'here或where? – idiottiger 2012-02-23 09:56:50
对不起,我的坏。早些时候应该提到它。错误在位图bitmap = BitmapFactory.decodeFile(f.getPath()); – Antrromet 2012-02-23 09:59:09
打印语句工作得很好。 cachedir的输出是 cachedir =/mnt/sdcard/data/floapp – Antrromet 2012-02-23 10:01:33