0

長い時間の視聴者、ついにStackOverflowでのサインアップに取り掛かっています!

AndroidでViewGroupの背景をスクロールする方法を非常に長い間探していた後、私は次のことを開発しました。

public class SlidingDrawable extends Drawable implements Drawable.Callback {
private static final String TAG = "SlidingDraw";
private static float STEP_SIZE = 1.0f;

private BitmapDrawable mBitmap;
private Context mContext;

private float mPosX;
private int mBitmapWidth;

private Runnable mInvalidater;
private Handler mHandler;

public SlidingDrawable(Context c){
    mContext = c;

    // use this as the callback as we're implementing the interface
    setCallback(this);

    mHandler = new Handler();
    mInvalidater = new Runnable(){
        @Override
        public void run(){
            // decrement the drawables step size
            mPosX -= SlidingDrawable.STEP_SIZE;

            /*
             * Check to see if the current position is at point where it should 
             * loop.  If so, reset back to 0 to restart
             */
            if(Math.abs(mPosX) >= mBitmapWidth) mPosX = 0;
            // redraw
            invalidateDrawable(null);
        }
    };
}
public static void setStepSize(float newSize){
    SlidingDrawable.STEP_SIZE = newSize;
}
public void createBitmap(String path, ViewGroup parent){
    // height of the parent container
    int height = parent.getHeight();

    /* Initialize local variables
     *  bgBitmap    - the resulting bitmap to send into SlidingDrawable instance
     *  imageStream - raw bitmap data to be decoded into bgBitmap
     */     
    WindowManager wMgr = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
    int mScreenWidth = wMgr.getDefaultDisplay().getWidth();

    InputStream imageStream;
    Matrix imgMatrix = new Matrix();
    Bitmap bitmap = null;
    try {
        imageStream = mContext.getAssets().open(path);

        // create a temporary bitmap object for basic data
        Bitmap temp = BitmapFactory.decodeStream(imageStream);
        int width = temp.getWidth();

        // find the width difference as a percentage to apply to the 
        // transformation matrix
        float widthDifference = ((float)mScreenWidth) / (float)(width / 2);
        imgMatrix.postScale(widthDifference, 0, 0f, 0f);

        // create a copy of the bitmap, scaled correctly to maintain loop
        bitmap = Bitmap.createScaledBitmap(temp, (int)(width * widthDifference), height, true);

        // recycle the temp bitmap
        temp.recycle();
    } catch (IOException e) {
        e.printStackTrace();
    }   
    mBitmap = new BitmapDrawable(bitmap);

    // required
    mBitmapWidth = getIntrinsicWidth() / 2;
    Rect bounds = new Rect(0, 0, getIntrinsicWidth(), getIntrinsicHeight());        
    setBounds(bounds);
}
@Override
public void draw(Canvas canvas) {
    canvas.drawBitmap(mBitmap.getBitmap(), mPosX, 0f, null);
    scheduleDrawable(this, mInvalidater, SystemClock.uptimeMillis());
}
@Override
public int getOpacity() {
    return PixelFormat.OPAQUE;
}

@Override
public void scheduleDrawable(Drawable who, Runnable what, long when) {
    mHandler.postAtTime(what, who, when);
}

@Override
public void unscheduleDrawable(Drawable who, Runnable what) {
    mHandler.removeCallbacks(what, who);
}
@Override
public void invalidateDrawable(Drawable who) {
    invalidateSelf();
}
/* 
 * Methods not directly used or called omitted
 * 
 */

}

それは次のようにアクティビティで使用されます:

@Override
public void onWindowFocusChanged(boolean focus){
    // set the background of the root view of main.xml
    SlidingDrawable drawable = new SlidingDrawable(getApplicationContext());
    drawable.createBitmap("bgimg/basebg.jpg", mRoot);
    mRoot.setBackgroundDrawable(drawable);
}

簡単に言うと、basebg.jpg画像は約1600x480のタイル化可能な画像です。SlidingDrawableのコンストラクターは、スケーリングと移動、およびyaddayaddahです。できます。

さて、問題は、このようにそれを行うことは本当に非効率的であるように思われるということです。この種の実装に関する多くの情報を見つけることができないように思われるので、CPUサイクルを削減できる場所、またはメソッド呼び出しを正しく使用している場合でも、私は暗闇の中にいます。

私の質問は次のとおりです。

  • setTranslate()またはpostTranslateを使用して、Matrixを使用してビットマップを描画するのではなく、drawBitmapを使用する方がよいでしょうか。
  • drawBitmapを使用するか、translate()、save()、restore()などのキャンバス関数を使用する方が良いですか?
  • draw()メソッドはどのレートで呼び出されますか?たとえば、再描画を制限する24 FPSに制限する方法はありますか?
  • これらの種類のものの「いつ」パラメータは一体何ですか?SystemClock.uptimeMillis()を渡すことだけが機能し、「+ 100」などを追加して100ミリ秒ごとに起動することで遅延させようとすると、途切れてしまいました。

私はこれをできる限り研究しました...私は今それをStackOverflowに任せています:)

4

1 に答える 1

0

しばらくして製図板を使って、機能を単純化しました。基本的に、それはすべてにinvalidate()呼び出しを送信し、SystemClock.uptimeMillis()ステップの変更ごとに1回の再描画を実行していました。

そこで、Drawable.Callbackインターフェイスを削除し、ハンドラーから直接呼び出しを渡して、invalidateSelf()とにかく特別なことは何もしていないように見える中間インターフェイスメソッドを削除しました。

とを使用した場合のCPU使用率にわずかな違いがあった drawBitmap(Bitmap source, int X, int Y, Paint p)ため drawBitmap(Bitmap source, Matrix matrix, Paint p)、サイクルを節約するために後者を選択しました。

新しい方法は次のとおりです。

// Runnable
mInvalidater = new Runnable(){
    @Override
    public void run(){
        // decrement the drawables step size
        mPosX -= SlidingDrawable.STEP_SIZE;
        if(Math.abs(mPosX) >= mBitmapWidth){
            mPosX = 0;
            mImageMatrix.setTranslate(0, 0);
        }
        mImageMatrix.postTranslate(-STEP_SIZE, 0);
        SlidingDrawable.this.invalidateSelf();
    }
};
// Draw method
@Override
public void draw(Canvas canvas) {
    canvas.drawBitmap(mBitmap.getBitmap(), mImageMatrix, null);
    mHandler.postAtTime(mInvalidater, SystemClock.uptimeMillis() + 64); 
}

電話のプラグを抜き、アプリケーションを約1分間実行してから、MotoDroidでバッテリーの使用量を開いてバッテリーの結果をテストしました。以前は、バッテリーの使用量がディスプレイを上回りましたが、現在は快適に下に座っています。

Angry Birdsもベンチマークであり、オープニング画面(bgがスクロールし、鳥がいたるところに飛ぶ)を同じ時間実行しました。場合によっては、私のアプリがAngry Birdsの下に座っていましたが、常にそうとは限りませんでした。

2.2を実行しているデバイスでDDMSを介してCPU情報を表示dumpsys cpuinfoする際に問題があると思われるため、ADBシェルコマンドを使用してCPU使用率を確認しました。

私はまだこれについて他の考えを聞くつもりですが、今のところ、それは解決されています。

于 2011-10-05T06:32:35.127 に答える