0

I am implementing a sketch-book in android. In this I have added a canvas. To show that users have multiple pages, when user clicks on next page I save the bitmap currently on canvas to a Bitmap ArrayList and clear the canvas for new bitmap. I am saving whole ArrayList at the end together into image files(Which is working fine).

The problem is, In my app user is able to move to previously drawn bitmaps using Next and Previous buttons, here i did it my redrawing bitmaps from Bitmap ArrayList. That's why I used Bitmap ArrayList. The problem is that after few pages are created like say, 30 pages my app crashes, saying OutOfMemory exception.

Could anyone suggest an efficient way to implement what I am trying to achieve, so that users can create as many pages as they want and still navigate back and forth??

Here is code for saving into bitmap arraylist

public void bitArrayStore(int k) {

        if (drawView.canvasBitmap.sameAs(drawView.emptyBitmap)) {
            flag = true;
        } else {

            try {
                if (flag1 == false) {
                    drawView.buildDrawingCache();
                    drawView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
                    bitmaps.set(k, Bitmap.createBitmap(drawView.getDrawingCache()));

                } else {
                    bitmaps.add(k, Bitmap.createBitmap(drawView.getDrawingCache()));
                    flag1 = false;
                }
            } catch (IndexOutOfBoundsException e) {
                bitmaps.add(k, Bitmap.createBitmap(drawView.getDrawingCache()));

            }
            drawView.destroyDrawingCache();

        }

This is the code I use for redrawing into canvas when user clicks previous or next button

public void redraw(ArrayList<Bitmap> bits, int i) {
        try {

                drawCanvas.drawBitmap(bits.get(i), 0, 0, canvasPaint);
                invalidate();


        }catch (NullPointerException e){
            Log.w("DrawingApp","Exception");
        }
    }

Here is the code for next and previous button inside onClickListeners

if (v.getId() == R.id.previousbtn) {
            PageNoLayout.setVisibility(View.VISIBLE);
            hideDrawer(colorNsize);
            hideDrawer(eraserDrawer);
            try {
                bitArrayStore(j);
                drawView.startNew();
                j--;
                if (bitmaps.size() > j) {
                    drawView.redraw(bitmaps, j);
                }
            } catch (IndexOutOfBoundsException e) {
                j = 0;
                try {
                    drawView.redraw(bitmaps, j);
                } catch (IndexOutOfBoundsException e1) {
                    drawView.startNew();
                }
            }
            pageNo.setText(String.valueOf(j+1));
            flag = false;
        } else if (v.getId() == R.id.nextbtn) {
            PageNoLayout.setVisibility(View.VISIBLE);
            hideDrawer(colorNsize);
            hideDrawer(eraserDrawer);
            if (j < 50) {
                bitArrayStore(j);
                if (flag == false) {
                    j++;
                }
                if (bitmaps.size() > j) {
                    drawView.startNew();
                    drawView.redraw(bitmaps, j);
                } else {
                    drawView.startNew();
                }
                flag = false;
            } else {
                Snackbar.make(v, "Reached page limit. Please save and start new note", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
            pageNo.setText(String.valueOf(j+1));


        }
Henry
  • 17,490
  • 7
  • 63
  • 98
JCoder
  • 113
  • 1
  • 2
  • 9
  • 1
    The only way to do it is by saving the bitmaps in disk (PNG or JPG) and then reloading then. Bitmaps use a lot of memory and if you try to have too many of them in memory you will run out of memory, it's simple math. – Budius Oct 28 '15 at 10:42
  • That I figured out. But I couldnt come up with an alternative. That's why I asked. Thanks for the response. Like you said if I save into disk how will i know what the previous file was or what the next file is? could you help me out with this confusion? @Budius – JCoder Oct 28 '15 at 10:46
  • You just have to remember the correlation between `pager number` and `file path`. You could have a standard naming convention, `page_X.png`, or put in an SQLite DB, have an `ArrayList`, write to shared preferences. – Budius Oct 28 '15 at 10:51
  • @Budius ... Thanks for the solution.... I tried it out.. works just like I wanted. Please write your solution as Answer so that i could mark it as accepted answer..:) – JCoder Oct 28 '15 at 18:21

2 Answers2

0

You should use a component like a ViewPager that manages the process of load/unload pages as its needed, so you will only have in memory the pages that are going to be shown.

Otherwise you could implement that same logic yourself.

Hope this helps.

Nanoc
  • 2,381
  • 1
  • 20
  • 35
0

Do not save your Bitmap in ArrayList. Save them in your sandbox internal memory or the cache ( via getCacheDir()). When you press next or previous, you need to decode the bitmap from the file and load it, via one of the decode methods: BitmapFactory.decode().

What you can do is save the file path in the ArrayList, so that you can keep track of Next and Previous.

Also, BitmapFactory.decode() can take up sometime and if you want the user interaction to be good, you might go ahead and decode a couple (just a couple) of Bitmap in advance, probably asynchronously. Make sure that you call Bitmap.recycle() once you are done with the bitmap and moving on to the next one.

Henry
  • 17,490
  • 7
  • 63
  • 98