Android - Surface is not valid

11.1k views Asked by At

I'm trying to draw a red circle every 5 seconds. I have a draw and a run method, and the run method calls the draw method which draws the circles. However, when the draw method is called from the run method, the surface is not valid so I can't draw anything and the screen is black. How can I make the surface valid, or if I can't, how else can I do this? Here is the code and logcat.

public class RandomCircles extends Activity {

    MySurfaceView mySurfaceView;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mySurfaceView = new MySurfaceView(this);
        setContentView(mySurfaceView);
    }


    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
        mySurfaceView.onResumeMySurfaceView();
    }

    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        mySurfaceView.onPauseMySurfaceView();
    }

    class MySurfaceView extends SurfaceView implements Runnable {

        Thread thread = null;
        SurfaceHolder surfaceHolder;
        volatile boolean running = false;
        Handler handler = new Handler();

        private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        Random random;

        public MySurfaceView(Context context) {
            super(context);
            // TODO Auto-generated constructor stub
            surfaceHolder = getHolder();
            random = new Random();
        }

        public void onResumeMySurfaceView() {
            running = true;
            thread = new Thread(this);
            thread.start();
        }

        public void onPauseMySurfaceView() {
            boolean retry = true;
            running = false;
            while (retry) {
                try {
                    thread.join();
                    retry = false;
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void run() {
            System.out.println("The run method is running");
            // TODO Auto-generated method stub
            Draw();
        }

        public void Draw() {
            System.out.println("The draw method is running");
            if (surfaceHolder.getSurface().isValid()) {
                System.out.println("The surface is valid");
                Canvas canvas = surfaceHolder.lockCanvas();
                //... actual drawing on canvas

                int x = random.nextInt(getWidth());

                if (getWidth() - x < 100)
                    x -= 100;
                else if (getWidth() - x > getWidth() - 100)
                    x += 100;

                int y = random.nextInt(getHeight());

                if (getHeight() - y < 100)
                    y -= 100;
                else if (getHeight() - x > getHeight() - 100)
                    y += 100;

                int radius;
                radius = 100;
                Paint paint = new Paint();
                paint.setStyle(Paint.Style.FILL);
                paint.setColor(Color.WHITE);
                canvas.drawPaint(paint);
                // Use Color.parseColor to define HTML colors
                paint.setColor(Color.parseColor("#CD5C5C"));
                canvas.drawCircle(x, y, radius, paint);

                surfaceHolder.unlockCanvasAndPost(canvas);
            }
        }
    }
}

There are indicators when the run and draw methods are called, but the indicator after the check for if the screen is valid does not display.

1

There are 1 answers

10
MadEqua On BEST ANSWER

Implement SurfaceHolder.Callback and only render on the Surface when you receive the surfaceCreated(SurfaceHolder holder) callback. For example:

public MySurfaceView(Context context) {
  super(context);
  surfaceHolder = getHolder();
  surfaceHolder.addCallback(new SurfaceHolder.Callback() {
                @Override
                public void surfaceDestroyed(SurfaceHolder holder) {
                       //stop render thread here
                }

                @Override
                public void surfaceCreated(SurfaceHolder holder) {
                       //start render thread here
                }
                @Override
                public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}

         });
}