2014-03-26 25 views
0

以我的Android應用我創建表示9×9的視野中的視圖(參見簡化屏幕截圖):在Android中處理ImageViews的對象池?

enter image description here

在視圖中每個字段由一個ImageView的表示(示出圖片代替矩形)。一些ImageViews將被刪除,將其設置爲null並將可見性設置爲View.GONE,並且每次將新元素添加到該字段時都會創建新的ImageView。這意味着我可以在很短的時間內創建大量的ImageView。關鍵是,遊戲在我的HTC One上運行良好,但在一段時間後(我認爲垃圾收集正在運行時)滯後,然後停止滯後並再次運行得很好。

這讓我想到使用Pool來管理我的對象,例如,通過回收「刪除的ImageViews」並通過設置位置和更改圖像源來重複使用它們。我正在開發純Android,但我想使用LibGDX框架。

我的問題是:關於如何在普通Java/Android中實現Pool的問題,您有什麼建議嗎?我發現this後感興趣,以爲我可以去與Apache Commons ObjectPool。 Android或LibGDX有更好的方法嗎?

注意: ImageView的每一輪都不在同一位置。我使用吐溫引擎移動它們。但是,圖像視圖的數量是不變的。意思是在遊戲的某些時候,我有81個ImageView(9 * 9)加上幾個ImageView用於動畫特殊事件(也許是+10)。

我會很感激任何意見/建議。

最好的問候,

吉米

+0

如果我理解你在正確的方式比賽的想法,與imageviews網格是靜態 - 這意味着圖像視圖的數量總是相同的,對嗎?爲什麼不更新imageView背景或圖像而不是重新創建它們?在我看來,游泳池的想法並不好 - 如果你需要實現某種方式滾動的列表或網格視圖,可能會有用 – MP23

+0

對不起,我還沒有提到它,但我正在移動ImageViews周圍(使用Tween引擎進行動畫處理),因此它們在每一輪中都沒有相同的位置。否則,我完全同意你的觀點,只有改變圖像源纔是明智之舉。此外,我還有更多ImageView用於動畫化兩張牌的合併。希望對你有意義。 –

+0

好的,那麼我建議使用某種集合,例如列表,每一個沒有更多必要的圖像視圖應該去那裏,如果需要一些新的ImageView,那麼你應該首先檢查你的列表是否不包含一個,並更新其背景和位置。當然,如果你使用它,你應該從列表中刪除它。僅當列表爲空時才創建新的ImageView。我認爲它是簡單的緩存機制之一,但它在例如ListView中正常工作(重用行視圖) – MP23

回答

1

據吉米的建議,我張貼我的意見作爲答案

我建議使用一些集合類如List<ImageView>的,

  • 每個圖像認爲是不更有必要的應該去那裏

  • 如果一些新的ImageView是必要的,那麼你應該首先檢查你的列表是否包含一個,並更新其背景和位置。

  • 當然,如果你使用它,你應該從列表中刪除它。
  • 僅當列表爲空時才創建新的ImageView。

我認爲這是最簡單的緩存機制之一,但它工作正常在如ListView控件(行觀的再利用)

+0

或者我會使用兩個列表..一個用於可見的ImageView,一個用於不可見的ImageView。正如我告訴你的,明天我會讓你知道的。等不及要實現:) –

+0

它使用兩個列表視圖很好用:'列表 cacheViews'和'列表 currentViews'。當'cacheViews'爲空時,我創建一個新的ImageView,並將引用存儲在'currentViews'中,如果它不是空的,我通過將'cacheViews'的視圖移動到另一個列表,設置位置和可見性來重用視圖。回收很簡單,只需將'View.GONE'的可見性設置爲cacheViews即可。感謝您的想法/提醒:-D –

+0

很好聽,rupps的答案也很好,但它是完全不同的方法 – MP23

1

我也有類似的問題,絕不是真正的表現感到滿意。這一切都是當我將我的比賽場地擴大到30 * 30時,我獲得了900個ImageViews。我嘗試了很多優化,但是性能和內存在設備上很高且不可預測。

所以我做的是創建一個自定義視圖。只有一個。這個視圖然後在畫布上繪製正方形。我很驚訝,現在我可以成千上萬的正方形(100x100),並且性能非常流暢。

我在這裏發佈我的觀點的骨架與所有廢話刪除的靈感,我強烈建議你按照這種方法。

/** 
    * ChequeredView is a view that displays a 2D square matrix, where each square can be individually selected. 
    * For high performance, It only uses one view regardless of the matrix size (everything is drawn in a canvas) 
    * @author rodo 13 march 2014 <[email protected]> 
    */ 

    public class ChequeredView extends View { 

     private final String TAG="ChequeredView"; 

     private static final int 
      DEFAULT_MATRIX_SIZE_COLS=20, 
      DEFAULT_MATRIX_SIZE_COLS=20, 
      DEFAULT_SQUARE_SIZE=100; 

     private int mCols=DEFAULT_MATRIX_SIZE_COLS, 
        mRows=DEFAULT_MATRIX_SIZE_ROWS; 

     /* Save touch press */ 
     private int mTouchX=0, mTouchY=0; 

     ///////////////// VIEW CODE 

     public ChequeredView(Context context, AttributeSet attrs) { super(context, attrs); } 
     public ChequeredView(Context context) { super(context); } 

     /** 
     * Report a size of your view that is: SquareSize * NUM_COLS x SquareSize * NUM_ROWS. You will paint it later. 
     */ 

     @Override 
     protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
      super.onMeasure(widthMeasureSpec, heightMeasureSpec); 

      // calculate optimum square size 
      mStyleSquareSize=MeasureSpec.getSize(widthMeasureSpec)/mSquaresPerCanvas; 

      // report total size 
      setMeasuredDimension(DEFAULT_MATRIX_SIZE_COLS * mStyleSquareSize, DEFAULT_MATRIX_SIZE_ROWS * mStyleSquareSize); 
     } 

     @Override 
     public void onDraw(Canvas canvas) { 
      render(canvas); 
     } 


     @Override 
     public boolean onTouchEvent(android.view.MotionEvent event) { 

      switch (event.getAction()) { 
      case MotionEvent.ACTION_DOWN: 
       // I execute the action in ACTION_UP so I can put this inside a scrollview and touch doesn't interferre the scroll. 
       mTouchX=(int) event.getX(); 
       mTouchY=(int) event.getY(); 
       return true; 

      case MotionEvent.ACTION_UP: 

       // only process touch if finger has not moved very much (if it has, it's a fling on parent) 

       if (isApprox(event.getX(), mTouchX, 5) && (isApprox(event.getY(), mTouchY, 5))) 
         processTouch((int)event.getX(), (int)event.getY()); 

       break; 

      } 
      return false; 
     }; 

     /** 
     * Check if a value is close to another one 
     * @param value Value to check 
     * @param ref Reference value 
     * @param threshold Threshold 
     * @return true if |val-ref|<threshold 
     */ 

     private boolean isApprox(float value, int ref, int threshold) { 
      float result=Math.abs(value-ref); 
      return (result<threshold); 
     } 

     ///////////////// VIEW METHODS 


     public void setMatrixSize(int numx, int numy) { 
      mRows=numx; 
      mCols=numy; 
      invalidate(); 
     } 

     ///////////////// VIEW INTERNALS 


     /** 
     * Renders the whole squaremap 
     * @param canvas 
     */ 

     private void render(Canvas canvas) { 
      if (canvas==null) return; 
      for (int x=0; x<mCols; x++) { 
       for (int y=0; y<mRows; y++) { 
        render_square(canvas, x, y); 
       } 
      } 
     } 

     /** 
     * Renders one of the squares 
     * @param canvas Canvas where to draw 
     * @param nCol The column 
     * @param nRow The row 
     */ 

     private void render_square(Canvas canvas, int nCol, int nRow) { 


      String text=null, transition=null; 
      int delay=0; 
      Paint paint=null; 

      int cx=nCol*mStyleSquareSize, cy=nRow*mStyleSquareSize; 

      canvas.save(); 
      canvas.translate(cx, cy); 
      canvas.drawRect(mStyleSquareMargin, mStyleSquareMargin, mStyleSquareSize-2*mStyleSquareMargin, mStyleSquareSize-2*mStyleSquareMargin, paint); 

      // this draws an square (I use vectorial squares with text rather than images, but just change drawRect to drawBitmap) 
      // just change it for drawBitmap() to draw one bitmap 

      canvas.restore(); 
     } 

     /** 
     * Process a touch on the map area 
     * @param x raw x coordinate 
     * @param y raw y coordinate 
     */ 

     private void processTouch(int x, int y) { 
      int nx=x/mStyleSquareSize, ny=y/mStyleSquareSize; 
      mSelectedX=nx; 
      mSelectedY=ny; 
      if (mSquareListener!=null) { 
       mSquareListener.onSquareSelected(nx, ny, data); 
      } 
      invalidate(); 
     } 
    } 
+0

你有什麼建議,我可以如何使用ImageView的這個骨架?我不繪製矩形 - 每個ImageView代表另一個圖像源(但有些將相同)。不過,我可以想象,一次又一次的繪畫可能會更快。 –

+1

忘記ImageView,只是在我指出的地方使用drawBitmap。 drawBitmap可以在畫布上繪製任何位圖。 ImageView內部正在做這個!看看函數render_square! – rupps

+0

好點,明天我會試一試。 –