0

I have this android project, can not identify why it is eating up RAM ? Note there is no processing just RAM being filled in. I have read Android RAM issues and how to solve, but can't make out what to do. I am new to both android and java.

Noticed just now (in Android Monitor - RAM) my app is using only 4MB of memory. If anyone tries to run (please do - MainActivity is launcher and MyCanvas is just a class used as View) this, i can use speed variable as high as 100 (even more maybe), make thread call back in 10ms or even more frequent - it creates no problem. But as soon as I touch and move garbage collector comes pauses everything.

MyCanvas.java (used as view)

package com.abc.mygraphics;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;

import java.util.Random;
import android.os.Handler;

public class MyCanvas extends View {

public static Paint paint;
//public static int n = 5000;
public static int N = 100, particleSize = 3;
public static int height, width;
public static float[][] pos = new float[N][2];
public static float[][] pos0 = new float[N][2];
//public static float distX, distY, dist;
Handler handler = new Handler();
public static int speed = 1;
public static int gravityX, gravityY;
public static Random random = new Random();
public static int[] colorList = new int[10];
public static int sphereSize = 100, M = 10;
public static float[] distance = new float[N];
public static int[][] gravity = new int[N][2];
public static boolean[] direction = new boolean[N];
public static int[] moved = new int[N];

public MyCanvas(Context context) {
    super(context);

    width = MainActivity.sharedPreferences.getInt("screenX", 200);
    height = MainActivity.sharedPreferences.getInt("screenY", 200);
    colorList = new int[]{Color.RED, 0xffff4000, 0xffffff00, 0xff40ff00, 0xff00ff00, 0xff00ff80, 0xff0080ff, 0xff0000ff, 0xffbf00ff, 0xffff0040};

    paint = new Paint();
    paint.setColor(Color.GRAY);
    int i;
    for (i = 0; i < N; i++) {
        pos[i][0] = random.nextInt(width);
        pos[i][1] = random.nextInt(height);
        pos0[i][0] = pos[i][0];
        pos0[i][1] = pos[i][1];
        moved[i] = 0;
        direction[i] = true;
    }

    final Runnable r = new Runnable() {
        public void run() {
            invalidate();
            handler.postDelayed(this, 100);
        }
    };
    handler.postDelayed(r, 100);
}

public static void changeGravity(){
    gravityX = MainActivity.sharedPreferences.getInt("x",200);
    gravityY =   MainActivity.sharedPreferences.getInt("y",200);
    // gravityY -= 68;
    for(int i=0;i<N;i++){
        calcDist(i);
    }
}

@Override
public void onDraw(Canvas canvas){
    int i;
    int x;  //remove at some poitnt
    canvas.drawColor(Color.BLACK);
    //canvas.drawCircle(gravityX,gravityY, 50, paint);

    for(i=0;i<N;i++) {
        setPosition(i);
        x =  random.nextInt(10);
        paint.setColor(colorList[x]);
        canvas.drawCircle(pos[i][0], pos[i][1], particleSize, paint);
    }
}

public static void setPosition(int i){
    // this is wrong
    if(moved[i] >= (int)distance[i]/speed){
        direction[i] = !direction[i];
        setGravity(i);
    }
    else{
        pos[i][0] = pos0[i][0] + speed*moved[i]*(gravity[i][0]- pos0[i][0])/distance[i];
        pos[i][1] = pos0[i][1] + speed*moved[i]*(gravity[i][1]- pos0[i][1])/distance[i];
        moved[i]++;
    }
}

public static void calcDist(int i){
    setGravity(i);
    distance[i] = (float) Math.sqrt( Math.pow((gravity[i][0]-pos[i][0]),2) +  Math.pow((gravity[i][1]-pos[i][1]),2) );
}

public static void setGravity(int i){

    // do not forget to set pos0 in both cases
    if(direction[i]){
        gravity[i][0] = gravityX;
        gravity[i][1] = gravityY;
    }

    else{
        // make this biased on radius of sphere
        gravity[i][0] =  random.nextInt(width);
        gravity[i][1]  = random.nextInt(height);
    }
    pos0[i][0] = pos[i][0];
    pos0[i][1]  = pos[i][1];
    moved[i]=0;
}



}

Main Activity.java

package com.abc.mygraphics;

 import android.content.SharedPreferences;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.Window;
import android.view.WindowManager; 
import android.widget.EditText;
import android.widget.TextView;

import com.abc.mygraphics.MyCanvas;

import org.w3c.dom.Text;

public class MainActivity extends AppCompatActivity {

//DrawingView dr = new DrawingView(this);

public  static SharedPreferences sharedPreferences;

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


    DisplayMetrics displaymetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
    int height = displaymetrics.heightPixels;
    int width = displaymetrics.widthPixels;


    sharedPreferences = getSharedPreferences( getPackageName() + "_preferences", MODE_PRIVATE);

    SharedPreferences.Editor editor = sharedPreferences.edit();
    editor.putInt("screenX",width);
    editor.putInt("screenY", height);
    editor.putInt("x", 200);
    editor.putInt("y", 200);
    editor.commit();
    setContentView(new MyCanvas(this));
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    // int x = (int)event.getX();
    //int y = (int)event.getY();
    int x = (int) event.getRawX();
    int y = (int) event.getRawY();
    //sharedPreferences = getSharedPreferences("CheckSharing",Context.MODE_PRIVATE);
    SharedPreferences.Editor editor = sharedPreferences.edit();
    editor.putInt("x", x);
    editor.putInt("y", y);
    editor.apply();
    MyCanvas.changeGravity();

    return false;
}

}
  • Looks like your `Handler` in `MyView` might be leaking the `MyView` class which then also leaks the `Activity` it's associated with because of the way you are using `Handler.postDelayed`. Try temporarily commenting out the use of the `Handler` and see if the memory issue is still there (assuming this is the only leak in the code). If it isn't then we can discuss some possible fixes. – George Mulligan Jan 09 '17 at 19:15
  • Also, based on your edit if my guess is correct then the memory usage should continue to increase as you rotate the device back and forth between portrait and landscape mode causing a new instance of the activity hosting the custom view to be created each time. – George Mulligan Jan 09 '17 at 19:18
  • Than what do I do use instead of handler ??. See frankly I have no idea of working of thread I used it just beacause it does what I want. Because I need continuous refreshing of View. What I want is an app like Particle Flow (search on Play Store). – Vandan Kumbhat Jan 09 '17 at 19:30
  • You can try either using a static handler with a weak reference to the view as explained [here](http://stackoverflow.com/a/11408340/1435985). The question/answer is talking about a `Handler` in a `Service` but it still applies for one in a `View`. Alternatively move the `Handler` into the `Activity` or `Fragment` hosting the view and when the activity is paused [remove the callback](https://developer.android.com/reference/android/os/Handler.html#removeCallbacksAndMessages(java.lang.Object)). You can add the callback when the activity is resumed. – George Mulligan Jan 09 '17 at 19:37

1 Answers1

0

Got my problem. I was trying to call my methods every time a touch event happens, this is something we can't do because when you drag your mouse there are literally thousands(possibly more) touch events happening.

Try understanding from code. In main activity we have our onTouch event listener which calls changeGravity() method which in turn calls calcDist() and setGravity() (from calcDist() ) . So thats a lot of garbage being generated and hence the GC comes in to play, it pauses the application and everything seems like hanged.

Solution - Just place the calcDist() call inside thread, so whatever be the vakue of gravity will come in effect in 10ms. This is something our emulator and phone are capable of, compared to what happens if we call from changeGravity() method.