保存数据时出现android OutOfMemory问题

时间:2013-08-20 08:36:44

标签: android bitmap drawing byte out-of-memory

我正在做的是绘制应用程序,这个项目需要两个功能是撤消和重做..所以我需要在每次用户绘制并从屏幕上拉出他的手指后保存先前绘图的列表..

这是保存上一张图纸时的代码

    public void saveState() {

    State mUndoState = new State();
    saveState(mSurface.getBitmap(), mUndoState);
}

private void saveState(Bitmap bitmap, State state) {
    state.mBuffer = new byte[bitmap.getRowBytes() * bitmap.getHeight()];
    Buffer byteBuffer = ByteBuffer.wrap(state.mBuffer);
    bitmap.copyPixelsToBuffer(byteBuffer);
    mListUndoState.add(state);
    System.out.println("Size now: " + (mListUndoState.size() - 1));
    mListRedoState.clear();
    mListRedoState.add(state);
    // StylesFactory.saveState(state.stylesState);
}
    private static class State {
    byte[] mBuffer = null;
    // final HashMap<Integer, Object> stylesState = new HashMap<Integer,
    // Object>();
}

问题是android设备只有16 MB的堆内存..处理这个问题的最佳方法是什么? ..我只能将它保存到ListUndoState 7到10次,然后我的内存异常...我想获得无限制的撤消操作或至少不少于50次。

这是保存上一个图形以进行撤消和重做的完整类。

package com.appshouse.drawgram.utli;

import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

import android.graphics.Bitmap;

public class HistoryHelper {
    private final Surface mSurface;
    private List<State> mListUndoState = new ArrayList<State>();
    private List<State> mListRedoState = new ArrayList<State>();


public HistoryHelper(Surface surface) {
    mSurface = surface;

}

public void undo() {
    int length = mListUndoState.size() - 1;

    if (length <= 0) {
        System.out.println("no element is list");
        return;
    }
    System.out.println("history undo size: " + length);
    restoreState(mSurface.getBitmap(), mListUndoState.get(length - 1));

    mListRedoState.add(mListUndoState.get(length));
    mListUndoState.remove(length);
}

public void redo() {
    int length = mListRedoState.size() - 1;

    if (length <= 0) {
        System.out.println("no element is list");
        return;
    }
    System.out.println("history undo size: " + length);
    restoreState(mSurface.getBitmap(), mListRedoState.get(length));
    mListUndoState.add(mListRedoState.get(length));
    mListRedoState.remove(length);

}

private void restoreState(Bitmap bitmap, State state) {
    Buffer byteBuffer = ByteBuffer.wrap(state.mBuffer);
    bitmap.copyPixelsFromBuffer(byteBuffer);
    // StylesFactory.restoreState(state.stylesState);
}

public void saveState() {
    State mUndoState = new State();
    saveState(mSurface.getBitmap(), mUndoState);
}

private void saveState(Bitmap bitmap, State state) {
    state.mBuffer = new byte[bitmap.getRowBytes() * bitmap.getHeight()];
    Buffer byteBuffer = ByteBuffer.wrap(state.mBuffer);
    bitmap.copyPixelsToBuffer(byteBuffer);
    mListUndoState.add(state);
    System.out.println("Size now: " + (mListUndoState.size() - 1));
    mListRedoState.clear();
    mListRedoState.add(state);
    // StylesFactory.saveState(state.stylesState);
}

private static class State {
    byte[] mBuffer = null;
    // final HashMap<Integer, Object> stylesState = new HashMap<Integer,
    // Object>();
}

}

1 个答案:

答案 0 :(得分:0)

正如hieuxit建议我将位图保存在文件缓存中以解决这个问题,但我不知道这是否是最佳解决方案..所以如果有人有更好的解决方案,请提供给我。

这是我在上一课中所做的改变

package com.appshouse.drawgram.utli;

import java.nio.Buffer;
import java.nio.ByteBuffer;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.widget.Toast;

public class HistoryHelper {
    private final Surface mSurface;
    int undoAvailable = 0;
    int redoAvailable = 0;
    Context context;

    public HistoryHelper(Context c, Surface surface) {
        mSurface = surface;
        context = c;
    }

    public void undo() {

        if (undoAvailable > 1) {
            undoAvailable--;
            new LoadRestoreState().execute();
            redoAvailable ++;
        } else {
            Toast.makeText(context, "End of Undo Data", Toast.LENGTH_LONG)
                    .show();
        }
    }
public void redo() {
    if(redoAvailable >= 1)
    {
        undoAvailable ++;
        new LoadRestoreState().execute();
        redoAvailable --;
    }else
    {
        Toast.makeText(context, "End of Redo Data", Toast.LENGTH_LONG)
        .show();
    }
}


public void saveState() {
    new LoadSaveState().execute(mSurface.getBitmap());
}


private class LoadSaveState extends AsyncTask<Bitmap, Void, Void>
{
    @Override
    protected Void doInBackground(Bitmap... params) {
        undoAvailable++;
        FileCache fileCache = new FileCache(context, String.valueOf(undoAvailable));
        String str_buffer = Common.getStringDrawing(params[0]);
        fileCache.writeFile(str_buffer);
        redoAvailable = 0;
        return null;
    }
}

private class LoadRestoreState extends AsyncTask<Void , Void, Void>
{

    @Override
    protected Void doInBackground(Void... params) {
        FileCache getFileChach = new FileCache(context,
                String.valueOf(undoAvailable));
        String image_str = getFileChach.readFile();
        Bitmap drawing = Common.getBitmapFromString(image_str);
        byte[] buffer = new byte[drawing.getRowBytes()
                * drawing.getHeight()];
        Buffer byteBuffer = ByteBuffer.wrap(buffer);
        drawing.copyPixelsToBuffer(byteBuffer);
        byteBuffer = ByteBuffer.wrap(buffer);
        mSurface.getBitmap().copyPixelsFromBuffer(byteBuffer);
        return null;
    }
}
}

FileCache类的位置是:

    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;

    import android.content.Context;

    public class FileCache {

        private File cacheDir;
        private File TempFile;

        public FileCache(Context context, String Filename) {

            cacheDir = context.getCacheDir();
            if (!cacheDir.exists())
                cacheDir.mkdirs();
            TempFile = new File(cacheDir.getPath(), Filename);
        }

        public void writeFile(String buffer)

 {
        FileWriter writer = null;
        try {
            writer = new FileWriter(TempFile);
            writer.write(buffer);
            System.out.println(TempFile + " File - data: " + buffer.toString()
                    );
            writer.close();
        } catch (IOException e) {

        }
    }

    public String readFile() {
        String strLine = "";
        StringBuilder text = new StringBuilder();
        try {
            FileReader fileReader = new FileReader(TempFile);
            BufferedReader bufferReader = new BufferedReader(fileReader);
            while ((strLine = bufferReader.readLine()) != null) {
                text.append(strLine + "\n");
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("get text String: "+text.toString());
        return text.toString();
    }

    public void clear() {
        File[] files = cacheDir.listFiles();
        if (files == null)
            return;
        for (File f : files)
            f.delete();
    }

}

这是我在Common类中创建的两个函数:

public static String getStringDrawing(Bitmap bm) {
    String image_str = "";
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    byte[] byte_arr;
    bm.compress(Bitmap.CompressFormat.PNG, 90, stream);
    byte_arr = stream.toByteArray();
    image_str = Base64.encodeBytes(byte_arr);
    return image_str;
}

public static Bitmap getBitmapFromString(String img_str)
{
    Bitmap bmImg = null;
    try {
        byte[] encodeByte = null;
        encodeByte = Base64.decode(img_str);
        bmImg = BitmapFactory.decodeByteArray(encodeByte, 0,
                encodeByte.length);
        bmImg = Bitmap.createBitmap(bmImg);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return bmImg;
}

当然你需要下载base64类来将图像转换为字符串,反之亦然