Android 如何解决延迟加载位图时的vm预算内存堆错误?
我一直在使用图像加载器类在列表视图中进行延迟加载。它工作得很好,但我一直在处理大量将从web服务下载的位图。所以现在我得到的位图大小超过了虚拟机预算。将bitmapfactory大小增加为32*1024,但如果它再次达到32mb,则会抛出错误提示。在过去的一个星期里,我的头都碎了。所以请有人帮我解决这个问题。我在这里张贴我的图像加载器类以及请让我知道我应该在哪里和如何解决这个问题Android 如何解决延迟加载位图时的vm预算内存堆错误?,android,android-image,Android,Android Image,我一直在使用图像加载器类在列表视图中进行延迟加载。它工作得很好,但我一直在处理大量将从web服务下载的位图。所以现在我得到的位图大小超过了虚拟机预算。将bitmapfactory大小增加为32*1024,但如果它再次达到32mb,则会抛出错误提示。在过去的一个星期里,我的头都碎了。所以请有人帮我解决这个问题。我在这里张贴我的图像加载器类以及请让我知道我应该在哪里和如何解决这个问题 public class ImageLoader { private HashMap<String, Bit
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) {
}
}
公共类ImageLoader{
私有HashMap缓存=新建HashMap();
位图=空;
私人活动;
PhotoLoader photoLoaderThread=新的PhotoLoader();
公共图像加载器(活动){
这个。活动=活动;
photoLoaderThread.setPriority(Thread.NORM_PRIORITY-1);
clearCache();
}
public void DisplayImage(字符串url、活动活动、ImageView ImageView、字符串[]imageUrl){
这个。活动=活动;
if(cache.containsKey(url)){
setImageBitmap(cache.get(url));
}
否则{
setImageResource(R.drawable.icon);
队列照片(url、活动、图像视图);
}
}
私有void queuePhoto(字符串url、活动活动、ImageView ImageView){
这个。活动=活动;
Photosque.Clean(imageView);
PhotoToLoad p=新的PhotoToLoad(url,imageView);
已同步(PhotoQueue.photosToLoad){
photoqueue.photoload.push(p);
photoqueue.phototoload.notifyAll();
}
if(photoLoaderThread.getState()==Thread.State.NEW)
photoLoaderThread.start();
}
公共位图getBitmap(字符串url,int-sampleSize)引发异常{
位图bm=null;
试一试{
URL请求=新URL(URL);
InputStream为=(InputStream)请求。getContent();
BitmapFactory.Options=new-BitmapFactory.Options();
options.inDither=true;
options.inpurgable=true;
options.inInputShareable=true;
options.inSampleSize=样本大小;
options.inTempStorage=新字节[32*1024];
bm=BitmapFactory.decodeStream(is,null,options);
如果(bm!=null)
bm=Bitmap.createScaledBitmap(bm,115100,true);
is.close();
is=null;
}捕获(IOE异常){
抛出新异常();
}捕获(OutOfMemory错误){
bm.recycle();
bm=null;
gc();
抛出新异常();
}
返回bm;
}
私有类光电负载{
公共字符串url;
公共影像视图;
公共PhotoToLoad(字符串u,图像视图i){
url=u;
imageView=i;
}
}
PhotosQueue PhotosQueue=新的PhotosQueue();
公共void stopThread(){
photoLoaderThread.interrupt();
}
静态类队列{
私有堆栈photoload=新堆栈();
公共空间清理(图像视图图像){
对于(intj=0;j来说,很简单,你试图使用比Android虚拟机更多的内存,所以你需要使用更少的内存
你可以:
(1) 需要手动清除内存缓存-即,一旦达到一定大小或数量的图像
或者
(2) 使用类型为
的哈希映射,以便当图像不再显示时,垃圾收集器可以自动回收内存
使用这两种方法中的任何一种,您的内存缓存都不会像以前那样大(这很好),因此您可能希望将文件保存到磁盘,以便在从内存缓存中清除文件时,不必再次下载它们。请这样尝试
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();
}
验证以下链接..你可以得到关于这个的想法
http://stackoverflow.com/questions/5082703/android-out-of-memory-error-with-lazy-load-images
http://groups.google.com/group/android-developers/browse_thread/thread/bb3c57cab27e0d91?fwc=1简单地看一下你的代码,你真的在回收所有位图吗?我想你不会,但只有在抛出异常时,你才会偶尔回收一个。也就是说,PhotoLoader线程中的bmp不会回收,是吗?clearCache()它本身只在ImageLoader本身的构造函数中被调用,对吗?S,我在项目中的每个列表视图中都使用了这个类。列表视图有来自apter get view方法的适配器。这个完整的类将被每个列表调用,所以我不知道从何处清除或回收()。你能帮我使用类型的HashMap吗?因为如果用软引用更改位图,它会在HashMap中给我空指针异常,get();因此,你能给我一些例子来使用它吗?提前感谢你在地图中放置图像。put(url,new SoftReference(bitmap));要获得图像,你有SoftReference ref=map.get(url);如果(ref!=null&&ref.get()!=null){Bitmap Bitmap=ref.get();}感谢您的回复。我将测试这些方法并让您知道。