为什么我的SurfaceView对其动画如此“跳跃”?

时间:2013-05-22 23:05:15

标签: android animation rotation surfaceview

我正在制作一个简单的2个图像旋转动画,一个在另一个上面(每个都有不同的速度)。我知道已经有一个动画API,但我需要使用这个。

效果很好,但有时,动画停止很短的时间然后继续,使其“跳跃”(在某些帧上保持比其他帧更多)。

为什么会发生?因为GC?我该怎么做才能避免它?我打算做一些后台操作,所以它可能会变得更慢。

我知道使用sleep()并不意味着线程会在给定时间后立即唤醒,但这太过分了,而且非常明显。

有什么技巧可以让它更顺畅吗?也许使用更好的选择?

这是代码(执行它的视图):

public class AnimView extends SurfaceView implements SurfaceHolder.Callback
  {
  int                     _angle;
  private final Bitmap    _bitmap;
  private final Paint     _paint =new Paint();
  private AnimationThread _animationThread;
  private Matrix          _matrix;
  private int             _width;
  private int             _height;

  public AnimView(final Context context)
    {
    super(context);
    _bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
    _paint.setAntiAlias(true);
    getHolder().addCallback(this);
    }

  public AnimView(final Context context,final AttributeSet attrs)
    {
    super(context,attrs);
    _bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
    _paint.setAntiAlias(true);
    getHolder().addCallback(this);
    }

  public AnimView(final Context context,final AttributeSet attrs,final int defStyle)
    {
    super(context,attrs,defStyle);
    _bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
    _paint.setAntiAlias(true);
    getHolder().addCallback(this);
    }

  @Override
  public void surfaceChanged(final SurfaceHolder holder,final int format,final int width,final int height)
    {
    _width=width;
    _height=height;
    }

  @Override
  public void surfaceCreated(final SurfaceHolder holder)
    {
    if(isInEditMode())
      return;
    _matrix=new Matrix();
    setWillNotDraw(false);
    _animationThread=new AnimationThread();
    _animationThread.start();
    }

  @Override
  public void surfaceDestroyed(final SurfaceHolder holder)
    {
    _animationThread.cancelAnimation();
    }

  @Override
  protected void onDraw(final Canvas canvas)
    {
    if(isInEditMode())
      {
      canvas.drawColor(0xffff0000);
      return;
      }
    _paint.setAntiAlias(true);
    _matrix.reset();
    _matrix.postScale(_width/_bitmap.getWidth(),_height/_bitmap.getHeight());
    _matrix.postRotate(_angle,_width/2,_height/2);
    canvas.drawBitmap(_bitmap,_matrix,_paint);
    _matrix.reset();
    _matrix.postScale(_width/_bitmap.getWidth(),_height/_bitmap.getHeight());
    _matrix.postRotate(_angle*2,_width/2,_height/2);
    canvas.drawBitmap(_bitmap,_matrix,_paint);
    }

  private class AnimationThread extends Thread
    {
    private boolean _isRunning =true;

    public AnimationThread()
      {}

    public void cancelAnimation()
      {
      _isRunning=false;
      }

    @Override
    public void run()
      {
      while(_isRunning)
        {
        postInvalidate();
        refreshDrawableState();
        try
          {
          sleep(5);
          }
        catch(final InterruptedException e)
          {
          e.printStackTrace();
          }
        _angle=(_angle+1)%360;
        }
      }
    }
  }

1 个答案:

答案 0 :(得分:0)

尝试这样的事情

@Override
public void run()
  {
    long last = System.currentTimeMillis();
    long currentTime = last;
    long frameTime = 40;
  while(_isRunning)
    {
      currentTime = System.currentTimeMillis();
      if(currentTime - last > frameTime){
        postInvalidate();
        refreshDrawableState();
       //I FORGOT THIS
          last = currentTime;
      }
    try
      {
        sleep(5);  
      }
    catch(final InterruptedException e)
      {
      e.printStackTrace();
      }
    _angle=(_angle+1)%360;
    }
  }
}

这样您每40毫秒刷新一次屏幕并每隔5毫秒更新一次您的位置。这只是一个部分,您可以设置矩阵更新和计算也不在绘图部分,这也将提高您的速度。你对实际绘制时间的计算越少,它就越快。

编辑:看看这个

public class AnimView extends SurfaceView implements SurfaceHolder.Callback {
int _angle;
private final Bitmap _bitmap;
private final Paint _paint = new Paint();
private AnimationThread _animationThread;
private Matrix _matrix;
private int _width = 100;
private int _height = 100;
private Bitmap backBitmap;
private Canvas backCanvas;

public AnimView(final Context context) {
    super(context);
    _bitmap = BitmapFactory.decodeResource(getResources(),
            R.drawable.ic_launcher);
    _paint.setAntiAlias(true);
    getHolder().addCallback(this);      
}

public AnimView(final Context context, final AttributeSet attrs) {
    super(context, attrs);
    _bitmap = BitmapFactory.decodeResource(getResources(),
            R.drawable.ic_launcher);
    _paint.setAntiAlias(true);
    getHolder().addCallback(this);      
}

public AnimView(final Context context, final AttributeSet attrs,
        final int defStyle) {
    super(context, attrs, defStyle);
    _bitmap = BitmapFactory.decodeResource(getResources(),
            R.drawable.ic_launcher);
    _paint.setAntiAlias(true);
    getHolder().addCallback(this);
}

@Override
public void surfaceChanged(final SurfaceHolder holder, final int format,
        final int width, final int height) {
    _width = width;
    _height = height;
    createImage();
}

@Override
public void surfaceCreated(final SurfaceHolder holder) {
    if (isInEditMode())
        return;
    _matrix = new Matrix();
    setWillNotDraw(false);
    _animationThread = new AnimationThread();
    _animationThread.start();
}

@Override
public void surfaceDestroyed(final SurfaceHolder holder) {
    _animationThread.cancelAnimation();
}

@Override
protected void onDraw(final Canvas canvas) {
    if (isInEditMode() || backBitmap == null) {
        canvas.drawColor(0xffff0000);
        return;
    }

    canvas.drawBitmap(backBitmap, 0, 0, _paint);
}

private class AnimationThread extends Thread {
    private boolean _isRunning = true;

    public AnimationThread() {
    }

    public void cancelAnimation() {
        _isRunning = false;
    }

    @Override
    public void run() {
        long last = System.currentTimeMillis();
        long currentTime = last;
        long frameTime = 40;
        long updateTime = 20;
                    boolean updated = false;
        while (_isRunning) {
            currentTime = System.currentTimeMillis();
            if (currentTime - last > frameTime) {
                postInvalidate();
                refreshDrawableState();
                last = currentTime;
                                    updated = false;
            }
            else if(currentTime - last > updateTime){
                                if(!updated){
                drawImage();
                                    updated = true;
                                }
            }
            try {
                sleep(5);
            } catch (final InterruptedException e) {
                e.printStackTrace();
            }
            _angle = (_angle + 1) % 360;
        }
    }
}

private void createImage(){
    backBitmap = Bitmap.createBitmap(_width, _height, Config.ARGB_8888);
    backCanvas = new Canvas();
    backCanvas.setBitmap(backBitmap);
}

private void drawImage(){
    backCanvas.drawRGB(0, 0, 0);
    _paint.setAntiAlias(true);
    _matrix.reset();
    _matrix.postScale(_width / _bitmap.getWidth(),
            _height / _bitmap.getHeight());
    _matrix.postRotate(_angle, _width / 2, _height / 2);
    backCanvas.drawBitmap(_bitmap, _matrix, _paint);
    _matrix.reset();
    _matrix.postScale(_width / _bitmap.getWidth(),
            _height / _bitmap.getHeight());
    _matrix.postRotate(_angle * 2, _width / 2, _height / 2);
    backCanvas.drawBitmap(_bitmap, _matrix, _paint);
}
}

希望这有助于并享受您的工作