0

Android アプリで、9x9 のフィールドを表示するビューを作成しました (簡略化されたスクリーンショットを参照)。

ここに画像の説明を入力

ビュー内の各フィールドは、ImageView (四角形ではなく画像を表示) で表されます。一部の ImageView は、それらをnullに設定し、可視性を に設定することによって削除されView.GONE、新しい要素がフィールドに追加されるたびに新しい ImageView が作成されます。これは、短時間で多数の ImageView を作成することを意味します。要点は、ゲームは私の HTC One でうまく動作しますが、しばらくすると (ガベージ コレクションが実行されているときだと思います) 遅れが生じ、その後遅れがなくなり、再びうまく動作するようになります。

これにより、 を使用してオブジェクトを管理するというアイデアがPool生まれます。たとえば、「削除された ImageViews」をリサイクルし、位置を設定して画像ソースを変更して再利用します。プレーンな Android 向けに開発していますが、LibGDX フレームワークを使用することを考えています。

私の質問は:プレーンな Java/Android でプールを実装する方法について何か提案はありますか? この投稿は興味深いもので、Apache Commons ObjectPool を使用できると思いました。Android または LibGDX でより良い方法はありますか?

注: ImageView は、各ラウンドで同じ位置にあるわけではありません。Tween Engine を使用してそれらを移動します。ただし、画像ビューの数は一種の一定です。ゲームのある時点で、81 個の ImageView (9*9) と、特別なイベントをアニメーション化するためのいくつかの ImageView (おそらく +10) があることを意味します。

アドバイス/推奨事項をいただければ幸いです。

よろしくお願いします、

ジミー

4

2 に答える 2

1

ジミーの提案によると、回答としてコメントを投稿しています

ある種のコレクションを利用することをお勧めしますList< ImageView >

  • 不要になったすべての画像ビューはそこに移動する必要があります

  • 新しい ImageView が必要な場合は、最初にリストに含まれていないかどうかを確認し、その背景と位置を更新する必要があります。

  • もちろん、使用する場合は、リストから削除する必要があります。
  • リストが空の場合にのみ、新しい ImageView を作成します。

これは最も単純なキャッシュ メカニズムの 1 つだと思いますが、たとえば ListView (行ビューの再利用) では適切に機能します。

于 2014-03-26T22:12:53.930 に答える
1

私は同様の問題を抱えていましたが、パフォーマンスに本当に満足することはありませんでした. すべてのヒントは、プレイフィールドを 30*30 に拡張して、900 の ImageView を取得したときでした。多くの最適化を試みましたが、パフォーマンスとメモリは高く、デバイス間で予測できませんでした。

だから私がしたことは、カスタムビューを作成することです. 一つだけです。次に、このビューはキャンバスに正方形を描きます。文字通り何万もの正方形 (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 <rlp@nebular.tv>
     */

    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();
        }
    }
于 2014-03-26T22:03:23.220 に答える