Search code examples
javaandroidsurfaceview

Simultaneous display of two animations in SurfaceView


I'm trying to get two animations to show at the same time. The application builds successfully but crashes in the emulator.

I have created an Anim class in a thread that handles the Animations in a while loop. I think there is a problem with my draw method but I cant seem to figure it out.

I appreciate any help on this, thank you

Error Log

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

and

java.lang.ArrayIndexOutOfBoundsException: length=2; index=2
        at com.example.my_project.PlayActivity$surfaceView$Anim.run(PlayActivity.java:109)

CODE

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);




            }

        }
    }





}

}


Solution

  • Because accessing a SurfaceView (with Canvas) is exclusive, you cannot draw simultaneously to it.

    holder.lockCanvas();
    
    (...) // the canvas is locked during this
    
    holder.unlockCanvasAndPost(canvas);
    

    So, your possible solution is to manipulate and draw both of red bird and blue bird in the same draw method (in between lock and unlock) of the same thread.


    Edit

    For another error 2:

    if ((counter >= 2) && (counter2 >= 4)) {
        counter = 0;
        counter2 = 0;
    }
    

    This condition is wrong. Because only when both of counter and counter2 excessed, they are reset. They should be separated:

    if (counter >= 2) {
        counter = 0;
    }
    if (counter2 >= 4) {
        counter2 = 0;
    }