androidcroppuzzleandroid-bitmapporter-duff

How do I make a puzzle app in droid without running out of memory?


I notice that other puzzle apps from the google play store can go up to as many as 400 separate movable puzzle pieces

I have been attempting to learn how to at least take an image that will represent my puzzle, Crop certain sections and mask the image space that is left with a puzzle piece design in order to create my individual puzzle pieces

I want to max out with 20 pieces for my app but so far according to my android studio memory log once bitmap factory is done creating one puzzle piece I’m using up around 18mb of memory, after 20 pieces are created along with all the other functions of the app I’m using up 400+mb of memory which I must use “largeHeap=true” to keep from running out of memory, but I’m so close to exceeding those higher limits that the app is super sluggish and enough animated activity will inevitably crash the app

I would love to know what those other play store puzzle apps are doing that I’m not

any input is greatly appreciated

FYI I’m using PNG24 for my images and the dimension on my test image is 556x720

Here is an example if I were to just create one animated-able puzzle piece image

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    this.requestWindowFeature(Window.FEATURE_NO_TITLE);//Remove title bar
    this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);//Hides notification bar
    this.setContentView(R.layout.activity_main);//set content view AFTER ABOVE sequence (to avoid crash)

    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

    mainDisplay = getWindowManager().getDefaultDisplay();
    mainLayout = (ViewGroup) findViewById(R.id.id_layout);

    DisplayMetrics m = new DisplayMetrics();
    this.getWindowManager().getDefaultDisplay().getMetrics(m);
    int windowHeight = m.heightPixels;
    int windowWidth = m.widthPixels;

    offsetX = (windowWidth / 1440.0f);
    offsetY = (windowHeight / 2560.0f);

    ourContext = this;

    xpos = new float[2];
    ypos = new float[2];

    iv_PuzzleOne();

    bkgdbm = BitmapFactory.decodeResource(getResources(), R.drawable.puzzleimage); 

    paintObject = new Paint();
    paintObject.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR)); 

    bm_PuzzleOne();

    thisTimerTask = new ThisClass();
    thisTimer = new Timer();
    thisTimer.scheduleAtFixedRate(thisTimerTask, 16, 16);

    touchpad = new ImageButton(this);
    SetPos(0, 0, 1440, 2560);
    touchpad.setLayoutParams(layoutPositioner);
    touchpad.getBackground().setAlpha(1);
    mainLayout.addView(touchpad);

    touchpad.setOnTouchListener(new View.OnTouchListener() {

        //@SuppressLint("NewApi")
        @Override
        public boolean onTouch(View v, MotionEvent event) {

            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                xpos[0] = event.getX(); //storing my finger's position coordinates when I first touch the screen into the 1st element
                ypos[0] = event.getY();

                if ((event.getX() > imgx1) && (event.getX() < imgx1 + imagewidth1)
                        && (event.getY() > imgy1) && (event.getY() < imgy1 + imageheight1)) {
                    touching1Puzzle = true;
                    img1.bringToFront();
                }

            }

            if (event.getAction() == MotionEvent.ACTION_MOVE) {

                xpos[1] = event.getX(); //add my finger's new current coordinates into the 2nd element
                ypos[1] = event.getY();

                if (touching1Puzzle) {
                    adjustImg();
                }
            }

            if (event.getAction() == MotionEvent.ACTION_UP) {
                if (touching1Puzzle) {
                    touching1Puzzle = false;
                }

            }

            return false;
        }

    });
}


void bm_PuzzleOne()
{
    //start of 1st puzzle

    foregdimg1 = BitmapFactory.decodeResource(getResources(), R.drawable.puzzlepieceprac);//puzzle cut out (42.48MB) +6.15
    mutableforegdimg1 = foregdimg1.copy(Bitmap.Config.ARGB_8888, true); //(48.32MB) +5.84

    compositeImage1 = Bitmap.createBitmap(mutableforegdimg1);//cuts out foreground info into bkgdimage (54.43MB) +6.11

    imgCanvas1 = new Canvas(compositeImage1); //canvas references puzzle cut out image (54.43MB) +0
    imgCanvas1.drawBitmap(croppedBmp, null, new Rect(0, 0, 1500, 2000), paintObject);//places puzzle image on canvas (54.43MB) +0

    img1.setImageBitmap(compositeImage1);

}


void iv_PuzzleOne()
{
    img1 = new ImageView(ourContext);
    SetPos(imgx1, imgy1, imagewidth1, imageheight1);
    //bkgdimg.setImageResource(R.drawable.c);
    //img1.setBackgroundColor(0xffF07305); //Orange
    img1.setLayoutParams(layoutPositioner);
    mainLayout.addView(img1);

}

void adjustImg()
{
    if (touching1Puzzle)
    {
        if (xpos[1] > xpos[0]) //if the image had slid to the right
        {
            xPositionDifference = xpos[1] - xpos[0]; // find the difference in coordinate value between where my finger was and where it currently is
            imgx1 += xPositionDifference; //add that difference to the current image position ...

            xpos[0] += xPositionDifference; // ... store that difference for the next shift in finger postion

        } else if (xpos[1] < xpos[0]) //if the image had slid to the left
        {
            xPositionDifference = xpos[0] - xpos[1]; // find the difference in coordinate value between where my finger was and where it currently is
            imgx1 -= xPositionDifference; //subtract that difference to the current image position ...

            xpos[0] -= xPositionDifference; // ... store that difference for the next shift in finger postion
        }

        if (ypos[1] > ypos[0]) //if the image had slid to the right
        {
            yPositionDifference = ypos[1] - ypos[0]; // find the difference in coordinate value between where my finger was and where it currently is
            imgy1 += yPositionDifference; //add that difference to the current image position ...

            ypos[0] += yPositionDifference; // ... store that difference for the next shift in finger postion

        } else if (ypos[1] < ypos[0]) //if the image had slid to the left
        {
            yPositionDifference = ypos[0] - ypos[1]; // find the difference in coordinate value between where my finger was and where it currently is
            imgy1 -= yPositionDifference; //subtract that difference to the current image position ...

            ypos[0] -= yPositionDifference; // ... store that difference for the next shift in finger postion

        }
    }

}

class ThisClass extends TimerTask {

    @Override
    public void run() {
        MainActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {

                if(touching1Puzzle)
                {SetPos(imgx1, imgy1, imagewidth1, imageheight1);
                    img1.setLayoutParams(layoutPositioner);}

            }
        });
    }
}

public void SetPos(float x, float y, float width, float height) {
    layoutPositioner = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
    layoutPositioner.topMargin = (int) (offsetY * y);
    layoutPositioner.leftMargin = (int) (offsetX * x);
    layoutPositioner.width = (int) (width * offsetX);
    layoutPositioner.height = (int) (height * offsetY);
}

}

This is what it looks like when I load 5 images

http://s15.postimg.org/ymqspk77v/Screenshot_2016_02_29_07_19_26.png


Solution

  • Simply just use vectors instead of images.. you will save much memory for running app and storage. Its supported very well. and you can use SVG resources