0

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 并使用 Matrix 绘制位图相比,drawBitmap 是否更好?
  • 是使用drawBitmap,还是使用translate()、save()、restore()等canvas函数更好?
  • draw() 方法的调用速率是多少,有没有办法将其限制为 24 FPS 或限制重绘?
  • 这类事情的“何时”参数到底是什么?传入 SystemClock.uptimeMillis() 是唯一有效的方法,并试图通过添加“+ 100”或每隔 100 毫秒触发一次的东西来延迟它,这只会让它结结巴巴。

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

4

1 回答 1

0

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

所以,我把Drawable.Callback接口去掉,直接从Handler传递invalidateSelf()调用,去掉中间的接口方法,反正好像也没什么特别的。

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

愤怒的小鸟也是一个基准,通过运行起始屏幕(背景滚动和小鸟到处飞)相同的时间,在某些情况下,我的应用程序位于愤怒的小鸟之下,但并非总是如此。

使用 ADB shell 命令检查 CPU 使用率,因为在运行 2.2 的设备上通过 DDMS查看 CPU 信息dumpsys cpuinfo似乎存在问题。

我仍然想听听对此的其他想法,但现在,它已经解决了。

于 2011-10-05T06:32:35.127 回答