Чертеж холста Android SurfaceView с потоком

Я экспериментирую с рисованием на холсте с помощью потока для создания простого игрового движка, но у меня возникают некоторые странные проблемы, которые я не могу объяснить. Цель этой «игры» – рисовать круг каждую секунду на холсте. Это работает, но не так, как я хочу, чтобы он работал, кажется, что приложение переключается между двумя холстами и добавляет круг к каждому холсту, чтобы вы переключались между двумя полосками каждую секунду с тем же числом кругов, но в другом месте На холсте.

Я не знаю, что я делаю неправильно, но я не знаком с Treadding, это как-то связано с тем, сколько ядер у моего устройства Android или что-то в этом роде?

Мой код показан ниже, поэтому я просто использую startthread, который использует файл макета, который ссылается на анимацию, которая запускает поток и рисует круг на холсте каждую секунду. (Вы можете игнорировать touchhevent, он пока не используется).

Проект существует из основного запуска:

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

Который использует этот файл макета:

 <?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> 

И мой класс Surfaceview с внутренним классом Thread:

 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) { } } } } 

Кажется, приложение переключается между двумя полотнами

Да, так оно и работает. Он называется двойной буферизацией, и вам нужно каждый раз перерисовывать весь кадр:

Содержимое Поверхности никогда не сохраняется между unlockCanvas () и lockCanvas (), по этой причине каждый пиксель в области поверхности должен быть записан.

Таким образом, вам нужна эта строка canvas.drawColor(Color.BLACK) которая будет раскомментирована в вашем коде.

И вы не должны называть Thread.sleep(1000) то время как холст заблокирован, это вызовет проблему голода .

Похоже, у вас это работает, но я просто заметил небольшую ошибку, о которой я должен указать.

Вы вызывали canvas.restore () без вызова canvas.save () заранее. Из ссылки разработчика Android для Canvas: «Ошибка вызова функции« restore »() больше, чем вызывается функция save ()».

Я не вижу причин для вызова canvas.save () в вашем случае, поэтому вы должны удалить вызов canvas.restore ().