2016-02-22 21 views
0

我正在研究android中的繪畫應用程序。 目前我正在處理撤銷功能 - 我的想法是存儲更改的像素的座標和顏色。Android內存異常存儲大量的字節

我正在處理性能問題的RGB - 因此它們存儲在一個字節數組中。

currentRGBPixelArray是包含舊ARGB值的數組。 updatedRGBPixelArray是包含新ARGB值的數組。

如果總是3個字段中的值不同,我知道我必須存儲這些值。這是在Integer,Byte []對上完成的,其中Integer是RGBPixelArray中像素的索引。

但是,使用此代碼時,當存儲大量數據時(例如,如果背景或像1920 * 1080的屏幕那樣的巨大區域被改變,可能多次),我會發生內存不足異常。

這裏是我的代碼:

List<Pair<Integer, Byte[]>> changeTupelHolder = new ArrayList<>(); 
for (int index = 0; index < width; index += 4) 
{ 
    if (currentRGBPixelArray[index] != updatedRGBPixelArray[index] || 
     currentRGBPixelArray[index+1] != updatedRGBPixelArray[index+1] || 
     currentRGBPixelArray[index+2] != updatedRGBPixelArray[index+2]) 
    { 
      Pair<Integer, Byte[]> changeTupel = 
       new Pair<>(index, 
          new Byte[]{currentRGBPixelArray[index], 
            currentRGBPixelArray[index+1], 
            currentRGBPixelArray[index+2]}); 
      changeTupelHolder.add(changeTupel); 
    } 
} 

然後changeTupelHolder再次存儲在堆棧和撤消時,被稱爲彈出。

如何處理內存不足異常? 存儲changeTupelHolder是一個好主意(性能?)? 如果是這樣,當應用程序傾向於內存不足時該如何做?

或者你對我的問題有一個完全不同的想法?

感謝您的幫助!

+0

你能解釋更多的在什麼時候,你應該存儲的變化?什麼情況會觸發你的代碼? 另外,你可以使用類似SVG的東西嗎? – Mussa

+0

這只是一個簡單的繪畫活動 - 如果我畫一個圓形,填充一個區域或任何我想存儲舊像素。 – Agyss

+0

如果它只是一個簡單的繪畫活動,那麼你應該能夠使用矢量並將它們作爲路徑存儲在堆棧中。 – Mussa

回答

2

這是持有圖像數據非常低效的方式。保存圖像數據的正確方法是一個字節數組byte byte [] = new byte [4 * NUM_PIXELS]。獲得像素的顏色將會是數據[pixelnum * 4 + COLOR_INDEX],其中alpha的顏色索引爲0,紅色爲1,綠色爲2,藍色爲3。

你這樣做的方式 - 你正在創建數百萬個小對象,每個小對象都有自己的大量開銷,每個小對象都要存儲一個字節。這會殺死一臺PC。和手機做可怕的與分配,高性能的android代碼的關鍵是最大限度地減少分配的對象的數量。

我知道現代學派不是去思考性能,除非你知道存在問題,但有一個巨大的星號 - 你仍然需要使用常識。常識應該告訴你,每個像素1個對象是一個壞主意。

+0

我不確定你是否正確。我將圖像存儲在currentRGBPixelArray中,它是byte [4 * NUM_PIXELS],更新後的RGBPixelArray只是暫時的,只是將這些更改存儲爲Pairs,因爲在大多數情況下,可能只有2.000.000像素中的2.000會發生更改,例如,如果您只是畫一個圓或一條線。 – Agyss

+1

分配2000個對象 - 不計算列表將在內部分配的小對象 - 數量巨大,絕不應該這樣做。 –

0

我會用矢量做到這一點。

其實我已經做了類似於撤消/重做與載體,並從未遇到過內存異常。

我用android.graphics.Pathandroid.graphics.Paint來創建一個矢量對象。

下面是示例代碼爲SVG轉換爲路徑和油漆:

public VectorPathObject(final List<List<Object>> actions, final float left, final float top, final String color, final float strokeWidth) { 
    mPath = new Path(); 
    for (List<Object> action : actions) { 
     switch (action.get(0).toString()) { 
      case M: 
       mPath.moveTo(left + Float.parseFloat(action.get(1).toString()), top + Float.parseFloat(action.get(2).toString())); 
       break; 
      case Q: 
       mPath.quadTo(left + Float.parseFloat(action.get(1).toString()), top + Float.parseFloat(action.get(2).toString()), left + Float.parseFloat(action.get(3).toString()), top + Float.parseFloat(action.get(4).toString())); 
       break; 
      case L: 
       mPath.lineTo(left + Float.parseFloat(action.get(1).toString()), top + Float.parseFloat(action.get(2).toString())); 
       break; 
     } 
    } 
    mPaint = new Paint(); 
    mPaint.setAntiAlias(true); 
    mPaint.setStyle(this.paintStyle); 
    mPaint.setStrokeCap(this.lineCap); 
    mPaint.setStrokeJoin(Paint.Join.MITER); 
    mPaint.setColor(Color.parseColor(color)); 
    mPaint.setStrokeWidth(strokeWidth); 
    mPaint.setAlpha(this.opacity); 
} 
+0

這看起來不錯,但我確實有填充所有形式的填充工具,並且我無法想象使用此方法處理此問題的方法。 – Agyss