SurfaceView同时显示两个动画
Simultaneous display of two animations in SurfaceView
我正在尝试让两个动画同时显示。应用程序构建成功但在模拟器中崩溃。
我在线程中创建了一个动画 class,该线程在 while 循环中处理动画。我认为我的绘制方法有问题,但我似乎无法弄清楚。
感谢您对此提供的任何帮助,谢谢
错误日志
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.myproject/com.example.myproject.MainActivity}: java.lang.IllegalArgumentException: Cannot add a null child view to a ViewGroup
和
java.lang.ArrayIndexOutOfBoundsException: length=2; index=2
at com.example.my_project.PlayActivity$surfaceView$Anim.run(PlayActivity.java:109)
代码
public class PlayActivity extends AppCompatActivity {
surfaceView view;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
view = new surfaceView(this);
setContentView(view);
public class surfaceView extends SurfaceView {
public surfaceView(Context context) {
super(context);
new Anim().start();
}
private class Anim extends Thread {
int counter = 0;
int counter2 = 0;
@Override
public void run() {
long last_updated_time = 0;
long delay = 250;
int[] purple_bird = {
R.drawable.bird1,
R.drawable.bird2
};
int[] red_bird = {
R.drawable.red1,
R.drawable.red2,
R.drawable.red3,
R.drawable.red4
};
while (true) {
boolean playing = true;
if (playing) {
long current_time = System.currentTimeMillis();
if (current_time > last_updated_time + delay) {
if ((counter >= 2) && (counter2 >= 4)) {
counter = 0;
counter2 = 0;
}
draw(purple_bird[counter], red_bird[counter2]);
last_updated_time = current_time;
counter++;
counter2++;
}
}
}
}
private void draw(int red_bird, int purple_bird) {
SurfaceHolder holder = getHolder();
Canvas canvas = holder.lockCanvas();
if (canvas != null) {
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
Bitmap purpleBird = BitmapFactory.decodeResource(getContext().getResources(), purple_bird);
Bitmap redBird = BitmapFactory.decodeResource(getContext().getResources(), red_bird);
Bitmap resizedRedBird = Bitmap.createScaledBitmap(redBird, (int) (redBird.getWidth() * 0.4), (int) (redBird.getHeight() * 0.4), true);
Bitmap resizedPurpleBird = Bitmap.createScaledBitmap(purpleBird, (int) (purpleBird.getWidth() * 0.2), (int) (purpleBird.getHeight() * 0.2), true);
canvas.drawBitmap(resizedRedBird, 500, 500, paint);
canvas.drawBitmap(resizedPurpleBird, 100, 100, paint);
holder.unlockCanvasAndPost(canvas);
}
}
}
}
}
因为访问 SurfaceView(使用 Canvas)是独占的,所以不能同时绘制它。
holder.lockCanvas();
(...) // the canvas is locked during this
holder.unlockCanvasAndPost(canvas);
因此,您可能的解决方案是在同一线程的同一绘制方法(在锁定和解锁之间)中操作和绘制红色小鸟和蓝色小鸟。
编辑
另一个错误2:
if ((counter >= 2) && (counter2 >= 4)) {
counter = 0;
counter2 = 0;
}
这个条件是错误的。因为只有当counter 和counter2 都超过时,它们才会被重置。它们应该分开:
if (counter >= 2) {
counter = 0;
}
if (counter2 >= 4) {
counter2 = 0;
}
通常一次只能从一个线程在 Surface 上绘图。
如果你想从不同的线程中绘制,那么你必须考虑到“lockCanvas()”需要在每次调用时上传所有表面像素,但你只是绘制每个动画像素而不考虑另一个。在这种行为中,“第二个”线程将仅用自己的像素“覆盖”整个表面像素,这就是您看到闪烁效果的原因。
我建议您使用一个公共位图来绘制(它将是唯一调用“unlockCanvasAndPost()”的位图),或者将这两个线程合并为一个并在那里处理两个动画。
我正在尝试让两个动画同时显示。应用程序构建成功但在模拟器中崩溃。
我在线程中创建了一个动画 class,该线程在 while 循环中处理动画。我认为我的绘制方法有问题,但我似乎无法弄清楚。
感谢您对此提供的任何帮助,谢谢
错误日志
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.myproject/com.example.myproject.MainActivity}: java.lang.IllegalArgumentException: Cannot add a null child view to a ViewGroup
和
java.lang.ArrayIndexOutOfBoundsException: length=2; index=2
at com.example.my_project.PlayActivity$surfaceView$Anim.run(PlayActivity.java:109)
代码
public class PlayActivity extends AppCompatActivity {
surfaceView view;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
view = new surfaceView(this);
setContentView(view);
public class surfaceView extends SurfaceView {
public surfaceView(Context context) {
super(context);
new Anim().start();
}
private class Anim extends Thread {
int counter = 0;
int counter2 = 0;
@Override
public void run() {
long last_updated_time = 0;
long delay = 250;
int[] purple_bird = {
R.drawable.bird1,
R.drawable.bird2
};
int[] red_bird = {
R.drawable.red1,
R.drawable.red2,
R.drawable.red3,
R.drawable.red4
};
while (true) {
boolean playing = true;
if (playing) {
long current_time = System.currentTimeMillis();
if (current_time > last_updated_time + delay) {
if ((counter >= 2) && (counter2 >= 4)) {
counter = 0;
counter2 = 0;
}
draw(purple_bird[counter], red_bird[counter2]);
last_updated_time = current_time;
counter++;
counter2++;
}
}
}
}
private void draw(int red_bird, int purple_bird) {
SurfaceHolder holder = getHolder();
Canvas canvas = holder.lockCanvas();
if (canvas != null) {
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
Bitmap purpleBird = BitmapFactory.decodeResource(getContext().getResources(), purple_bird);
Bitmap redBird = BitmapFactory.decodeResource(getContext().getResources(), red_bird);
Bitmap resizedRedBird = Bitmap.createScaledBitmap(redBird, (int) (redBird.getWidth() * 0.4), (int) (redBird.getHeight() * 0.4), true);
Bitmap resizedPurpleBird = Bitmap.createScaledBitmap(purpleBird, (int) (purpleBird.getWidth() * 0.2), (int) (purpleBird.getHeight() * 0.2), true);
canvas.drawBitmap(resizedRedBird, 500, 500, paint);
canvas.drawBitmap(resizedPurpleBird, 100, 100, paint);
holder.unlockCanvasAndPost(canvas);
}
}
}
}
}
因为访问 SurfaceView(使用 Canvas)是独占的,所以不能同时绘制它。
holder.lockCanvas();
(...) // the canvas is locked during this
holder.unlockCanvasAndPost(canvas);
因此,您可能的解决方案是在同一线程的同一绘制方法(在锁定和解锁之间)中操作和绘制红色小鸟和蓝色小鸟。
编辑
另一个错误2:
if ((counter >= 2) && (counter2 >= 4)) {
counter = 0;
counter2 = 0;
}
这个条件是错误的。因为只有当counter 和counter2 都超过时,它们才会被重置。它们应该分开:
if (counter >= 2) {
counter = 0;
}
if (counter2 >= 4) {
counter2 = 0;
}
通常一次只能从一个线程在 Surface 上绘图。
如果你想从不同的线程中绘制,那么你必须考虑到“lockCanvas()”需要在每次调用时上传所有表面像素,但你只是绘制每个动画像素而不考虑另一个。在这种行为中,“第二个”线程将仅用自己的像素“覆盖”整个表面像素,这就是您看到闪烁效果的原因。
我建议您使用一个公共位图来绘制(它将是唯一调用“unlockCanvasAndPost()”的位图),或者将这两个线程合并为一个并在那里处理两个动画。