2013-08-20 45 views
2

我在做什麼是繪製應用程序,並且這個項目需要兩個功能是撤消和重做..所以我需要在每次用戶繪製和拉出後保存先前繪圖的列表他的手指從屏幕..保存數據時出現android OutOfMemory問題

這是以前保存圖形時的代碼

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

如果將所有狀態保存在內存中,則不能存儲太多狀態。我有2個建議給你: 1.如果你開發一個繪圖應用程序,我認爲你不應該將位圖保存爲一個狀態。你可以保存用戶動作,比如:什麼樣的動作:繪製,擦除......和座標列表用戶反應,... 這個基礎你可以撤消2.或者如果你必須保存位圖,我建議你應該將位圖保存爲文件,不要在內存中保留很多位圖,它們會讓您的應用程序出現內存不足錯誤。 – hieuxit

回答

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

} 

,這裏是我在通用類創建了兩個功能:

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類將圖像轉換爲字符串,反之亦然