2

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

这是保存先前绘图时的代码

    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>();
}

}
4

1 回答 1

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 类来将图像转换为字符串,反之亦然

于 2013-08-23T19:13:17.517 回答