How to solve the vm budget memory heap error in lazy loading bitmaps?
I have been using Image loader class for lazy loading in list view. It works fine but I have been dealing with lots of bitmap that will be downloaded from web service. so now I get bitmap size exceeds VM budget. Increased bitmapfactory size to be 32*1024 but if it reaches 32mb again it will throw a the error. It being breaking my head for the past one week. so some one please help me out of this problem. I here by post my image loader class as well please let me know where and how should I solve this problem.
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) {
开发者_C百科}
}
Quite simply you're trying to use more memory than the Android VM gives you. So you need to use less.
You either:
(1) need to manually clear your in-memory cache - i.e. once you reach a certain size or number of images
or alternatively
(2) use a HashMap of type <String, SoftReference<Bitmap>>
so that the garbage collector can automatically reclaim the memory when the images are no longer being displayed.
With either of these methods your in-memory cache should not get as large as before (which is good), so you may want to save your files to disk so they do not have to be downloaded again should they be cleared from the in-memory cache.
verify below links..u can get idea about that...
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
Try like this..
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();
}
精彩评论