简体   繁体   English

Android:有效管理位图arraylist而不引起OutOfMemory异常

[英]Android: Managing bitmap arraylist efficiently without causing OutOfMemory exception

I am implementing a sketch-book in android. 我正在用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. 为了显示用户有多个页面,当用户单击下一页时,我将当前在画布上的位图保存到Bitmap ArrayList并清除画布以获取新的位图。 I am saving whole ArrayList at the end together into image files(Which is working fine). 我将整个ArrayList最后保存到图像文件中(哪个工作正常)。

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 . 问题是,在我的应用程序中,用户可以使用“ 下一个”和“上一个”按钮移动到先前绘制的位图,在这里,我从Bitmap ArrayList重新绘制了位 That's why I used Bitmap ArrayList . 这就是为什么我使用Bitmap ArrayList的原因。 The problem is that after few pages are created like say, 30 pages my app crashes, saying OutOfMemory exception . 问题是,在创建了几页(例如说30页)后,我的应用程序崩溃了,并显示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 这是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));


        }

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. 您应该使用诸如ViewPager之类的组件来根据需要管理加载/卸载页面的过程,因此您在内存中将仅包含将要显示的页面。

Otherwise you could implement that same logic yourself. 否则,您可以自己实现相同的逻辑。

Hope this helps. 希望这可以帮助。

Do not save your Bitmap in ArrayList . 不要将您的Bitmap保存在ArrayList Save them in your sandbox internal memory or the cache ( via getCacheDir() ). 将它们保存在沙箱内部存储器或缓存中(通过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() . 当您按下下一个或上一个时,您需要通过以下解码方法之一从文件中解码位图并将其加载: BitmapFactory.decode()

What you can do is save the file path in the ArrayList , so that you can keep track of Next and Previous . 您可以做的是将文件路径保存在ArrayList ,以便跟踪NextPrevious

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. 另外, BitmapFactory.decode()可能会占用一些时间,并且如果您希望用户交互良好,则可以继续进行解码,提前(可能是异步)解码几个(仅几个) Bitmap Make sure that you call Bitmap.recycle() once you are done with the bitmap and moving on to the next one. 完成bitmap并转到下一个bitmap ,请确保调用Bitmap.recycle()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM