电池消耗与自定义动画drawable

时间:2011-10-04 08:09:20

标签: android custom-controls processing-efficiency

Loooong时间查看器,终于可以在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
 * 
 */

}

它在Activity中使用如下:

@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。它有效。

现在,问题是,这样做似乎效率很低。我似乎无法找到关于这种实现的大量信息,因此我对可以削减CPU周期的情况感到困惑,或者即使我正在使用方法调用。

我的问题包括:

  • 与使用setTranslate()或postTranslate并使用矩阵绘制位图相比,drawBitmap更好吗?
  • 使用drawBitmap或canvas(),save()和restore()等画布函数是否更好?
  • 调用draw()方法的速率是多少,是否有办法将其限制为24 FPS o限制重绘?
  • 这些东西的“什么时候”参数究竟是什么?传入SystemClock.uptimeMillis()是唯一有效的方法,并尝试通过添加“+ 100”或每隔100毫秒触发它来延迟它只会让它变得口吃。

我已尽可能多地研究这个...我现在将它留给StackOverflow:)

1 个答案:

答案 0 :(得分:0)

使用绘图板一段时间后,我简化了功能。基本上,它是在每个invalidate()上发送SystemClock.uptimeMillis()调用,为每个步骤更改执行一次重绘。

所以,我删除了Drawable.Callback接口并直接从处理程序传递了invalidateSelf()调用,删除了中间接口方法,这些方法似乎没有做任何特殊的事情。

使用的CPU使用率略有不同 drawBitmap(Bitmap source, int X, int Y, Paint p) vs. 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上的电池使用情况来测试电池结果。以前,电池的使用量超过了显示器,现在它可以舒适地低于显示器。

愤怒的小鸟也是一个基准,通过运行开启屏幕(bg卷轴和鸟飞到哪里)相同的时间,在某些情况下我的应用程序坐在愤怒的小鸟下面,但并不总是。

使用ADB shell命令dumpsys cpuinfo检查了CPU使用情况,因为运行2.2的设备上的DDMS似乎出现问题viewing CPU info

我仍然会听到关于此的其他想法,但就目前而言,它已经解决了。