0

編集:報奨金を追加しました。うまくいけば、これは目前の問題にいくらかの注意を引くでしょう。

私は現在、眠っている赤ちゃんをアニメーション化するアプリケーションのメイン画面でアニメーションが継続的に実行されるという問題を解決しようとしています。これは、imageViewを作成し、アニメーション内の現在の画像を次の行に置き換えることによって行われます。500を超える画像があるため、画像が置き換えられるたびにView Hierachy全体が再計算されるため、CPUに非常に負荷がかかります。このアニメーション中にビュー階層全体を再計算しない方法はありますか?

runメソッドは次のようになります。

        @Override
    public void run() {
        if (bitmap != null) {
            bitmap.recycle();
        }
        final String name = String.format(Locale.ENGLISH, pattern, current);
        final int id = getResources().getIdentifier(name, "drawable", getPackageName());
        if (id != 0) {
            bitmap = BitmapFactory.decodeResource(getResources(), id);
            view.setImageBitmap(bitmap);
        }
        current++;
        if (runAgain()) {
            frameCounter++;
            long nextAt = firstFrameAt + (frameCounter * interval);
            long delay = nextAt - SystemClock.elapsedRealtime() - 1;
            if (delay > 0) {
                handler.postDelayed(this, delay);
            } else {
                this.run();
            }
        }
    }

編集:私は独自のカスタムImageViewを作成し、問題の原因となるメソッドをオーバーライドすることを考えていました。これは実行可能な解決策でしょうか?

4

4 に答える 4

0

次の2つのメソッドをオーバーライドする独自のカスタムImageViewを実装することで、問題を解決しました。

@Override
public void setImageBitmap(final Bitmap bitmap) {
    if (VERSION.SDK_INT < VERSION_CODES.ICE_CREAM_SANDWICH) {

        // The currently set Drawable
        Bitmap oldBitmap = null;
        try
        {
            oldBitmap = ((BitmapDrawable)this.getDrawable()).getBitmap();   
        }catch(NullPointerException e)
        {
            Log.d("setImageBitmap", "oldBitmap is null");
        }

        if (null != oldBitmap && oldBitmap != bitmap) {
            final int oldWidth = oldBitmap.getWidth();
            final int oldHeight = oldBitmap.getHeight();

            /**
             * Ignore the next requestLayout call if the new Bitmap is the
             * same size as the currently displayed one.
             * */
            mIgnoreNextRequestLayout = oldHeight == bitmap.getHeight()
                    && oldWidth == bitmap.getWidth();
        }
    }

    super.setImageBitmap(bitmap);
}

@Override
public void requestLayout() {
    if (!mIgnoreNextRequestLayout) {
        super.requestLayout();
        Log.d("RequestLayout", "Requesting new layout");
    }
    else
        Log.d("RequestLayout", "Ignoring next requestLayout");

    // Reset Flag so that the requestLayout() will work again
    mIgnoreNextRequestLayout = false;
}
于 2013-02-03T12:11:33.267 に答える
0

Canvas.drawBitmapを使用してビットマップを描画し、ImageViewと(少なくとも)そのonDraw()メソッドをオーバーライドします。

バックグラウンドスレッドを使用すると、画像をプリフェッチしてビットマップの小さなFIFOキューを作成し、タイマーメカニズムを使用して、キュー内の次のビットマップの次の描画をトリガーできます。

于 2013-01-28T13:26:52.783 に答える
0

ええ、レイアウトリクエストをブロックするだけです。onRequestLayoutをオーバーライドし、スーパーを呼び出さないでください。適切なサイズを設定するには、親で手動のonLayoutを実行する必要があります(または、ICSの場合はレイアウトメソッドをオーバーライドします... 2.xではfinalとしてマークされています)。わかる?

私のコンテナビューの例:

@Override
public void requestLayout() {

}

// i'm ignoring the widths/heights here an manually setting it to what i know it should be. The children DO need a layout initially or their widths will be 0 and not show. 
 // 

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    super.onLayout(changed, l, t, r, b);
    int count = getChildCount();
    for (int i=0; i<count; i++) {
        ImageView iv = (ImageView)getChildAt(i);
        iv.layout(0, 0, width, height);
    }
}

そのため、子に変更が発生するたびに、ディメンションが変更されていないことがわかっているため、ビュー階層全体を再検証する必要はありません。これにより、デバイスのCPUを大幅に節約できます。次のようなことも検討してください。最適化された画像ビュー

于 2013-01-31T02:45:08.097 に答える
0

のソースコードによるとImageView

/**
 * Sets a drawable as the content of this ImageView.
 * 
 * @param drawable The drawable to set
 */
public void setImageDrawable(Drawable drawable) {
    if (mDrawable != drawable) {
        mResource = 0;
        mUri = null;

        int oldWidth = mDrawableWidth;
        int oldHeight = mDrawableHeight;

        updateDrawable(drawable);

        if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
            requestLayout();
        }
        invalidate();
    }
}

/**
 * Sets a Bitmap as the content of this ImageView.
 * 
 * @param bm The bitmap to set
 */
@android.view.RemotableViewMethod
public void setImageBitmap(Bitmap bm) {
    // if this is used frequently, may handle bitmaps explicitly
    // to reduce the intermediate drawable object
    setImageDrawable(new BitmapDrawable(mContext.getResources(), bm));
}

レイアウトを要求するかどうかを決定するために、提供する新しいビットマップの境界がチェックされていることは明らかです。

        if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
            requestLayout();
        }

あなたの説明によると、あなたはほとんど映画の効果を作成しているので、あなたの画像はまったく同じサイズでなければならないと思います。だから、それらのサイズを確認してください。すでに同じサイズの場合は、本当に確認する必要がありますthe entire View Hierachy is re-calculate

サイドノート:

  • おそらく画像のサイズを確認する必要があります。大きな画像のデコードもCPUに負荷がかかります。
  • 別のスレッドで次の画像をデコードし、50ミリ秒が経過した場合はそれを設定するか、通過するまで待つことをお勧めします。つまり、ハンドラーを待たずに次の画像をデコードし、デコードが完了したときに通知します。
  • あなたはビットマップを呼び出しrecycleています!ドキュメントを確認してください。This is an advanced call, and normally need not be called, since the normal GC process will free up this memory when there are no more references to this bitmap.リサイクルが非常に集中的かどうかはわかりませんが、この場合はドキュメントに従い、電話をかけないでください。
于 2013-01-31T15:31:13.217 に答える