Android SurfaceView canvas drawing with stream

I am experimenting with drawing on canvas using a stream to create a simple game engine, but I am having some strange problems that I cannot explain. The purpose of this β€œgame” is to draw a circle every second on the canvas. This works, but not the way I want it to work, it seems that the application switches between two stripes and adds a circle to each canvas, so that you switch between two stripes every second with the same number of circles, but in a different place on the canvas .

I don’t know what I am doing wrong, but I am not familiar with Treadding, is it somehow related to how many cores does my Android device have or something like that?

My code is shown below, so I just use startthread, which uses a layout file that refers to an animation that starts a thread and draws a circle on the canvas every second. (You can ignore touchhevent, it is not used yet).

The project exists from the main launch:

public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } } 

which uses this layout file:

 <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <com.androidtesting.AnimationView android:id="@+id/aview" android:layout_width="fill_parent" android:layout_height="fill_parent"/> </FrameLayout> 

And my Surfaceview class with inner Thread class:

 class AnimationView extends SurfaceView implements SurfaceHolder.Callback { private boolean touched = false; private float touched_x, touched_y = 0; private Paint paint; private Canvas c; private Random random; private AnimationThread thread; public AnimationView(Context context, AttributeSet attrs) { super(context, attrs); SurfaceHolder holder = getHolder(); holder.addCallback(this); thread = new AnimationThread(holder); } class AnimationThread extends Thread { private boolean mRun; private SurfaceHolder mSurfaceHolder; public AnimationThread(SurfaceHolder surfaceHolder) { mSurfaceHolder = surfaceHolder; paint = new Paint(); paint.setARGB(255,255,255,255); paint.setTextSize(32); } @Override public void run() { while (mRun) { c = null; try { c = mSurfaceHolder.lockCanvas(null); synchronized (mSurfaceHolder) { doDraw(c); sleep(1000); } } catch (Exception e) { e.printStackTrace(); }finally { if (c != null) { mSurfaceHolder.unlockCanvasAndPost(c); } } } } private void doDraw(Canvas canvas) { //clear the canvas //canvas.drawColor(Color.BLACK); random = new Random(); int w = canvas.getWidth(); int h = canvas.getHeight(); int x = random.nextInt(w-50); int y = random.nextInt(h-50); int r = random.nextInt(255); int g = random.nextInt(255); int b = random.nextInt(255); int size = 20; canvas.drawCircle(x,y,size,paint); canvas.restore(); } public void setRunning(boolean b) { mRun = b; } } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public boolean onTouchEvent(MotionEvent event) { touched_x = event.getX(); touched_y = event.getY(); int action = event.getAction(); switch(action){ case MotionEvent.ACTION_DOWN: touched = true; break; case MotionEvent.ACTION_MOVE: touched = true; break; default: touched = false; break; } return true; } public void surfaceCreated(SurfaceHolder holder) { thread.setRunning(true); thread.start(); } public void surfaceDestroyed(SurfaceHolder holder) { boolean retry = true; thread.setRunning(false); while (retry) { try { thread.join(); retry = false; } catch (InterruptedException e) { } } } } 
+6
source share
2 answers

it looks like the app is switching between two stripes

Yes, that’s how it works. It is called double buffering, and you need to redraw the entire frame every time:

The contents of the surface are never saved between unlockCanvas () and lockCanvas (), for this reason every pixel in the surface area must be recorded.

So you need this canvas.drawColor(Color.BLACK) to be uncommented in your code.

And you should not call Thread.sleep(1000) when the canvas is locked, this will cause a starvation problem.

+4
source

It looks like you have this work, but I just noticed a small error that I should point out.

You called canvas.restore () without calling canvas.save () in advance. From the Android developer link for Canvas: "This is an error caused by calling restore () more than the save () function is called."

I see no reason to call canvas.save () in your case, so you should remove the call to canvas.restore ().

0
source

Source: https://habr.com/ru/post/927744/


All Articles