user1129820
user1129820

Reputation: 51

How to avoid memory leaked called java.lang.OutOfMemoryError: bitmap size exceeds VM budget in android

I have tried develop an apps. This is ok for a small 101KB image file but when i use this apps for 307KB image instead of this image then it doesn't run and shows : java.lang.OutOfMemoryError: bitmap size exceeds VM budget.

Following is my code:

    Resources rs = getResources();
    Drawable dw = rs.getDrawable(R.drawable.chart);
    width =  dw.getIntrinsicWidth();
    height = dw.getIntrinsicHeight();
    DisplayMetrics dm = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(dm);

    fitScaleX = (float)dm.widthPixels / (float)width;
    fitScaleY = fitScaleX;

and at line, Drawable dw = rs.getDrawable(R.drawable.chart); The error occurs. How can i avoid this probleme?

This is my full code:

public class ZoomActivity extends Activity implements OnTouchListener { 

ImageView view;
Matrix  matrix = new Matrix();
Matrix  savedMatrix = new Matrix();
PointF  start = new PointF();
PointF  mid = new PointF();
float   oldDist = 0;
int     width = 0;
int     height = 0;
float   fitScaleX = 1.0f;
float   fitScaleY = 1.0f;

static final int STATE_NONE = 0;
static final int STATE_DRAG = 1;
static final int STATE_ZOOM = 2;
int mode = STATE_NONE;
long doubleClickStartTime = 0;
boolean doubleClickFlag = false;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);        
    requestWindowFeature(Window.FEATURE_NO_TITLE);

    setContentView(R.layout.chart);        

    view = (ImageView) findViewById(R.id.imageViewChart);
    view.setOnTouchListener(this);

    getFitScale();      

    matrix.postScale(fitScaleX, fitScaleY, 0, 0);
    view.setImageMatrix(matrix);
}

public void onStart() {
    super.onStart();


}

private void getFitScale() {        
    Resources rs = getResources();
    Drawable dw = rs.getDrawable(R.drawable.chart);
    width =  dw.getIntrinsicWidth();
    height = dw.getIntrinsicHeight();
    DisplayMetrics dm = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(dm);

    fitScaleX = (float)dm.widthPixels / (float)width;
    fitScaleY = fitScaleX;
}   

public boolean onTouch(View v, MotionEvent event)
{       
    // Handle touch events here...
    switch (event.getAction() & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN:
         savedMatrix.set(matrix);
         start.set(event.getX(), event.getY());
         mode = STATE_DRAG; 
         break;
    case MotionEvent.ACTION_UP:
        mode = STATE_NONE;
         // for Auto Fitting
         if(doubleClickFlag == false)
             doubleClickStartTime = SystemClock.uptimeMillis();

         if(doubleClickFlag) { 
             if(SystemClock.uptimeMillis() - doubleClickStartTime < 500) {
                matrix.reset();
                matrix.postScale(fitScaleX, fitScaleY, 0, 0);
             } else {
                doubleClickStartTime = SystemClock.uptimeMillis();
                doubleClickFlag = false;
             }
         }

         if(doubleClickFlag == false)
             doubleClickFlag = true;
         else
             doubleClickFlag = false;
         break;
    case MotionEvent.ACTION_POINTER_UP:
         mode = STATE_NONE;  
         break;
    case MotionEvent.ACTION_MOVE:
         if (mode == STATE_DRAG) {
             float dx = event.getX() - start.x;
             float dy = event.getY() - start.y;
             float[] values = new float[9];              

             matrix.set(savedMatrix);
             matrix.getValues(values);

             if(values[Matrix.MTRANS_X]+ dx < view.getWidth() - width * values[Matrix.MSCALE_X]) {                  
                dx = view.getWidth()  - values[Matrix.MTRANS_X] - width * values[Matrix.MSCALE_X];
             }               
             else if(values[Matrix.MTRANS_X]+ dx > 0) {
                 dx = 0 - values[Matrix.MTRANS_X];
             }

             if(values[Matrix.MTRANS_Y] + dy  < view.getHeight() - height*values[Matrix.MSCALE_Y]) {                     
                dy = view.getHeight() - height * values[Matrix.MSCALE_Y] - values[Matrix.MTRANS_Y];
             }
             else if(values[Matrix.MTRANS_Y] + dy > 0) {
                 dy = 0 - values[Matrix.MTRANS_Y];
             }

             matrix.postTranslate(dx, dy);
         }
         else if (mode == STATE_ZOOM) {
              float newDist = spacing(event);
              matrix.set(savedMatrix);

              if (newDist > 10f) {
                 float[] values = new float[9];              

                 matrix.set(savedMatrix);
                 matrix.getValues(values);

                 float scale = newDist / oldDist;

                 if(values[Matrix.MSCALE_X] * scale > 3.0f ||
                    values[Matrix.MSCALE_Y] * scale > 3.0f   ) {
                    matrix.reset();
                    matrix.postScale(3.0f, 3.0f, 0, 0);
                 }
                 else if(values[Matrix.MSCALE_X] * scale < fitScaleX ||
                         values[Matrix.MSCALE_Y] * scale < fitScaleY) {
                    matrix.reset();
                    matrix.postScale(fitScaleX, fitScaleY, 0, 0);
                 }
                 else {
                     matrix.postScale(scale, scale, 0, 0);
                 }
              }
           }
         break;

    case MotionEvent.ACTION_POINTER_DOWN:
         oldDist = spacing(event);

         if (oldDist > 10f) {
             savedMatrix.set(matrix);
             midPoint(mid, event);
             mode = STATE_ZOOM;            
         }
         break;
    }

    // Perform the transformation
    view.setImageMatrix(matrix);

    return true; // indicate event was handled
}

private float spacing(MotionEvent event) {
    float x = event.getX(0) - event.getX(1);
    float y = event.getY(0) - event.getY(1);

    return FloatMath.sqrt(x * x + y * y);
}

private void midPoint(PointF point, MotionEvent event) {
    float x = event.getX(0) + event.getX(1);
    float y = event.getY(0) + event.getY(1);
    point.set(x / 2, y / 2);
}
}

Upvotes: 2

Views: 968

Answers (1)

kosa
kosa

Reputation: 66637

Bitmap images consume lot of memory, it is better to reduce their resolution. Here is a link with couple of workarounds with this issue. Bitmap images exceed VM budget work arounds

Upvotes: 1

Related Questions