Потребление батареи с настраиваемым анимированным рисунком - PullRequest
0 голосов
/ 04 октября 2011

Просмотрщик времени Loooong, наконец-то пришло время зарегистрироваться здесь в StackOverflow!

После очень долгого поиска способа прокрутки фона для ViewGroup в Android я разработал следующее:

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 масштабов и перемещений и Yaddah Yaddah. Это работает.

Теперь проблема в том, что кажется, что это действительно неэффективно. Похоже, я не могу найти много информации о реализации такого рода, поэтому я не знаю, где можно сократить циклы ЦП или даже если я правильно использую вызовы методов.

Мои вопросы включают в себя:

  • Лучше ли рисовать BitBitmap, чем использовать setTranslate () или postTranslate, и рисовать растровое изображение с использованием матрицы?
  • Лучше ли использовать drawBitmap или функции Canvas, такие как translate (), save () и restore ()?
  • С какой скоростью вызывается метод draw (), и есть ли способ ограничить его, скажем, до 24 FPS или ограничить перерисовку?
  • Какого черта является параметром "когда" такого рода вещей? Передача SystemClock.uptimeMillis () - единственная, которая сработала, и попытка отложить ее, добавив «100» или что-то, чтобы выстрелить каждые 100 мс, только заикала.

Я исследовал это столько, сколько смогу ... Я оставляю это StackOverflow:)

1 Ответ

0 голосов
/ 05 октября 2011

Через некоторое время с чертежной доской я упростил функции.По сути, он отправлял вызов invalidate() на каждый SystemClock.uptimeMillis(), делая одну перерисовку для каждого изменения шага.

Итак, я удалил интерфейс Drawable.Callback и передал вызов invalidateSelf() непосредственно из обработчика, удалив методы промежуточного интерфейса, которые, похоже, ничего особенного не сделали.

Была небольшая разница в использовании процессора при использовании 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); 
}

Я проверил результаты работы батареи, отсоединив телефон от сети, запустив приложение примерно на минуту, затем открыв заряд батареи на моем Moto Droid.Раньше использование батареи превосходило дисплей, теперь оно удобно расположено ниже.

Angry Birds также был эталоном, запустив открывающий экран (где прокручиваются bg и птицы летают повсюду) в течение того же периода времениВ некоторых случаях мое приложение находилось ниже Angry Birds, но не всегда.

Использование ЦП было проверено с помощью команды оболочки ADB dumpsys cpuinfo, так как, похоже, возникла проблема Просмотр информации о ЦП вчерез DDMS на устройствах под управлением 2.2.

Я все еще хотел бы услышать другие мысли по этому поводу, но на данный момент это решено.

...