我一直在列表视图中使用Image loader类进行延迟加载。它工作正常,但我一直在处理将从Web服务下载的大量位图。所以现在我得到位图大小超过VM预算。将bitmapfactory大小增加到32 * 1024,但如果它再次达到32mb,则会抛出错误。过去一周它一直在打破我的脑袋。所以有人请帮我解决这个问题。我在这里发布了我的图像加载器类,请让我知道在哪里以及如何解决这个问题。
public class ImageLoader {
private HashMap<String, Bitmap> cache=new HashMap<String, Bitmap>();
Bitmap bitmap = null;
private Activity activity;
PhotosLoader photoLoaderThread=new PhotosLoader();
public ImageLoader(Activity activity){
this.activity = activity;
photoLoaderThread.setPriority(Thread.NORM_PRIORITY-1);
clearCache();
}
public void DisplayImage(String url, Activity activity, ImageView imageView, String[] imageUrl){
this.activity = activity;
if(cache.containsKey(url)){
imageView.setImageBitmap(cache.get(url));
}
else{
imageView.setImageResource(R.drawable.icon);
queuePhoto(url, activity, imageView);
}
}
private void queuePhoto(String url, Activity activity, ImageView imageView){
this.activity = activity;
photosQueue.Clean(imageView);
PhotoToLoad p=new PhotoToLoad(url, imageView);
synchronized(photosQueue.photosToLoad){
photosQueue.photosToLoad.push(p);
photosQueue.photosToLoad.notifyAll();
}
if(photoLoaderThread.getState()==Thread.State.NEW)
photoLoaderThread.start();
}
public Bitmap getBitmap(String url, int sampleSize) throws Exception{
Bitmap bm = null;
try {
URL request = new URL(url);
InputStream is = (InputStream) request.getContent();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inDither = true;
options.inPurgeable = true;
options.inInputShareable = true;
options.inSampleSize = sampleSize;
options.inTempStorage = new byte[32 * 1024];
bm = BitmapFactory.decodeStream(is, null, options);
if (bm!=null)
bm = Bitmap.createScaledBitmap(bm, 115,100, true);
is.close();
is = null;
} catch (IOException e) {
throw new Exception();
} catch (OutOfMemoryError e) {
bm.recycle();
bm = null;
System.gc();
throw new Exception();
}
return bm;
}
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();
}
static class PhotosQueue{
private Stack<PhotoToLoad> photosToLoad=new Stack<PhotoToLoad>();
public void Clean(ImageView image){
for(int j=0 ;j<photosToLoad.size();){
try{
if(photosToLoad.get(j).imageView==image)
photosToLoad.remove(j);
else
++j;
}catch (Exception e) {
}
}
}
}
class PhotosLoader extends Thread {
public void run() {
try {
while(true){
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 = null;
bmp = getBitmap(photoToLoad.url, 1);
cache.put(photoToLoad.url, bmp);
if(((String)photoToLoad.imageView.getTag()).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) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
class BitmapDisplayer implements Runnable{
ImageView imageView;
public BitmapDisplayer(Bitmap b, ImageView i){
bitmap = null;
bitmap=b;
imageView=i;
}
public void run(){
if(bitmap!=null){
imageView.setImageBitmap(bitmap);
imageView.setScaleType(ScaleType.FIT_XY);
}
else{
imageView.setImageResource(R.drawable.icon);
}
}
}
public void clearCache() {
try{
cache.clear();
cache = new HashMap<String, Bitmap>();
bitmap.recycle();
System.gc();
}catch (Exception e) {
}
}
答案 0 :(得分:1)
很简单,您尝试使用比Android VM更多的内存。所以你需要少用。
你要么:
(1)需要手动清除内存缓存 - 即一旦达到一定大小或数量的图像
或者
(2)使用类型为<String, SoftReference<Bitmap>>
的HashMap,以便垃圾收集器可以在不再显示图像时自动回收内存。
使用这些方法中的任何一种,您的内存缓存都不应该像以前一样大(这很好),因此您可能希望将文件保存到磁盘,以便在从中清除文件时不必再次下载它们内存缓存。
答案 1 :(得分:0)
试试这样..
try {
HttpURLConnection conn= (HttpURLConnection)myFileUrl.openConnection();
conn.setDoInput(true);
conn.connect();
int length = conn.getContentLength();
InputStream is = conn.getInputStream();
bmImg = BitmapFactory.decodeStream(is);
proImage.setImageBitmap(bmImg); // Bind image here on UI thread
clearBitMap(bmImg); // Call to clear cache
}
catch (IOException e) {
e.printStackTrace();
}
private void clearBitMap(Bitmap bitMap) {
bitMap = null;
System.gc();
}
答案 2 :(得分:0)
验证以下链接......我可以了解这个......
http://negativeprobability.blogspot.com/2011/08/lazy-loading-of-images-in-listview.html http://stackoverflow.com/questions/5082703/android-out-of-memory-error-with-lazy-load-images http://blog.jteam.nl/2009/09/17/exploring-the-world-of-android-part-2/ http://groups.google.com/group/android-developers/browse_thread/thread/bb3c57cab27e0d91?fwc=1