Carlos Tirado
Carlos Tirado

Reputation: 397

Getting memory leak error in android 2.3

I'm been having trouble with a memory leak error lately, what I'm trying to do is to create an Activity with a gallery that downloads pictures from a service and displays them, the first time that the error appeared, I did some investigation and turned out that it was either the referencing of the Context, or the way different versions of android manage the images in memory. I did some changes to the code and ended up with somethin like this:

public class GalleryView extends Activity {
private LinearLayout imageView;
private String GalleryId;
private ArrayList<Drawable> images = new ArrayList<Drawable>();
private ArrayList<Drawable> thumbs = new ArrayList<Drawable>();
private ArrayList<String> urls;
private AdvertiserDAO aDao = new AdvertiserDAO();


/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.galeria);

    setGallery();

    setThumbs();

    Button back = (Button) findViewById(R.id.Back);

    back.setOnClickListener(new View.OnClickListener() {

        public void onClick(View v) {
            finish();

        }
    });

    Gallery ga = (Gallery) findViewById(R.id.Gallery01);

    ga.setAdapter(new ImageAdapter(this));

    imageView = (LinearLayout) findViewById(R.id.ImageView01);
    ga.setOnItemClickListener(new OnItemClickListener() {
        public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                long arg3) {

            try {
                imageView.removeAllViews();

            } catch (Exception e) {
                e.getMessage();
            }
            TouchImageView touchImageView = new TouchImageView(
                    GalleryView.this);
            touchImageView.setImageDrawable(images.get(arg2));

            LayoutParams lp = new LayoutParams(LayoutParams.FILL_PARENT,
                    LayoutParams.FILL_PARENT);
            imageView.setGravity(Gravity.CENTER_HORIZONTAL
                    | Gravity.CENTER_VERTICAL);
            touchImageView.setLayoutParams(lp);
            imageView.addView(touchImageView);

        }

    });

}

private void setGallery()  {

    SharedPreferences sp = getSharedPreferences("galeriaId", 0);
    GalleryId = sp.getString("galeriaId", null);

    //retrieves urls of the pictures of the gallery
            urls = aDao.getUrls(GalleryId);

    for (int i = 0; i < urls.size(); i++) {

        Drawable d = ImageOperations(urls.get(i), "image" + i
                + ".jpg");
        images.add(d);
    }

}

private void setThumbs()  {

    SharedPreferences sp = getSharedPreferences("galeriaId", 0);
    GalleryId = sp.getString("galeriaId", null);

            //retrieves the urls of the thumbs of the gallery
    urls = aDao.getThumbs(GalleryId);

    for (int i = 0; i < urls.size(); i++) {

        Drawable d = ImageOperations( urls.get(i), "image" + i
                + ".jpg");
        thumbs.add(d);
    }
}

private Drawable ImageOperations(String url,
        String saveFilename)  {

    InputStream is = (InputStream) fetch(url);

    Drawable d = null;
    try {
        d = new ImageOperationsAsyncTask().execute(is).get();
    } catch (InterruptedException e) {
        Log.e(TAG, e.toString());
        e.printStackTrace();
    } catch (ExecutionException e) {
        Log.e(TAG, e.toString());
        e.printStackTrace();
    }

    return d;

}

public Object fetch(String address)  {

    Object content = null;
    try {
        content = new URLAsyncTAsk().execute(address).get();
    } catch (InterruptedException e) {
        Log.e(TAG, e.toString());
        e.printStackTrace();
    } catch (ExecutionException e) {
        Log.e(TAG, e.toString());
        e.printStackTrace();
    }

    return content;
}

private class ImageOperationsAsyncTask extends
        AsyncTask<InputStream, Integer, Drawable> {

    @Override
    protected Drawable doInBackground(InputStream... params) {

        InputStream is = null;

        for(InputStream i: params){

            is = i;
        }

        Drawable result = Drawable.createFromStream(is, "src");

        return result;
    }

}

private class URLAsyncTAsk extends AsyncTask<String, Integer, Object> {


    @Override
    protected Object doInBackground(String... params) {
        String address = "";
        for (String s : params) {
            address = s;
        }

        URL url;
        Object content = null;
        try {

            url = new URL(address);

            content = url.getContent();

        } catch (MalformedURLException e) {
            Log.e(TAG, e.toString());
            e.printStackTrace();
        } catch (IOException e) {
            Log.e(TAG, e.toString());
            e.printStackTrace();
        }

        return content;
    }

}

public class ImageAdapter extends BaseAdapter {

    private Context ctx;
    int imageBackground;

    public ImageAdapter(Context c) {

        ctx = c;
        TypedArray ta = obtainStyledAttributes(R.styleable.Gallery1);
        imageBackground = ta.getResourceId(
                R.styleable.Gallery1_android_galleryItemBackground, 1);

        ta.recycle();
    }

    public int getCount() {

        return images.size();
    }

    public Object getItem(int arg0) {

        return arg0;
    }

    public long getItemId(int arg0) {

        return arg0;
    }

    public View getView(int arg0, View arg1, ViewGroup arg2) {
        ImageView iv = new ImageView(ctx);
        iv.setImageDrawable(thumbs.get(arg0));

        iv.setScaleType(ImageView.ScaleType.FIT_XY);
        iv.setLayoutParams(new Gallery.LayoutParams(150, 120));
        iv.setBackgroundResource(imageBackground);
        return iv;
    }
}}

This code works on my android 4.1 phone, and in the android 2.2 emulator, but on android 2.3 emulator and phone it is still displaying a memory leak error in the log cat.

Any idea why is it not working only in android 2.3???

EDIT: Here's the log that the LogCat is posting:

06-17 14:41:45.050: W/System.err(305): java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
06-17 14:41:45.060: W/System.err(305):  at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:224)
06-17 14:41:45.060: W/System.err(305):  at java.util.concurrent.FutureTask.get(FutureTask.java:83)
06-17 14:41:45.060: W/System.err(305):  at android.os.AsyncTask.get(AsyncTask.java:340)
06-17 14:41:45.060: W/System.err(305):  at directorio.actividades.GalleryView.ImageOperations(GalleryView.java:140)
06-17 14:41:45.060: W/System.err(305):  at directorio.actividades.GalleryView.setGallery(GalleryView.java:107)
06-17 14:41:45.060: W/System.err(305):  at directorio.actividades.GalleryView.onCreate(GalleryView.java:50)
06-17 14:41:45.060: W/System.err(305):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
06-17 14:41:45.060: W/System.err(305):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)
06-17 14:41:45.060: W/System.err(305):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
06-17 14:41:45.060: W/System.err(305):  at android.app.ActivityThread.access$1500(ActivityThread.java:117)
06-17 14:41:45.060: W/System.err(305):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
06-17 14:41:45.060: W/System.err(305):  at android.os.Handler.dispatchMessage(Handler.java:99)
06-17 14:41:45.060: W/System.err(305):  at android.os.Looper.loop(Looper.java:130)
06-17 14:41:45.060: W/System.err(305):  at android.app.ActivityThread.main(ActivityThread.java:3683)
06-17 14:41:45.060: W/System.err(305):  at java.lang.reflect.Method.invokeNative(Native Method)
06-17 14:41:45.060: W/System.err(305):  at java.lang.reflect.Method.invoke(Method.java:507)
06-17 14:41:45.060: W/System.err(305):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
06-17 14:41:45.060: W/System.err(305):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
06-17 14:41:45.060: W/System.err(305):  at dalvik.system.NativeStart.main(Native Method)
06-17 14:41:45.060: W/System.err(305): Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
06-17 14:41:45.060: W/System.err(305):  at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
06-17 14:41:45.060: W/System.err(305):  at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:470)
06-17 14:41:45.060: W/System.err(305):  at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:336)
06-17 14:41:45.060: W/System.err(305):  at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
06-17 14:41:45.060: W/System.err(305):  at android.graphics.drawable.Drawable.createFromStream(Drawable.java:657)
06-17 14:41:45.060: W/System.err(305):  at directorio.actividades.GalleryView$ImageOperationsAsyncTask.doInBackground(GalleryView.java:195)

Upvotes: 0

Views: 302

Answers (1)

Fritz
Fritz

Reputation: 10045

The problem here is not a memory leak per se, the real problem is the one that the exception points at:

OutOfMemoryError: bitmap size exceeds VM budget

Check the line where the exception is being thrown and you'll notice it is related to an image being loaded. That image is way too big and the memory consumed to process it is not enough to complete the task.

You can find a good reference on this other answer. A good approach is to play with the options of the BitmapFactory class and decode the image only when you find the correct sampling that will prevent the OutOfMemory issue from happening.

Upvotes: 1

Related Questions