2012-10-15 6 views
6

Ich experimentiere mit Zeichnen auf einer Leinwand mit einem Thread, um eine einfache Spiel-Engine zu erstellen, aber ich habe einige seltsame Probleme, die ich nicht erklären kann. Der Zweck dieses "Spiels" ist, jede Sekunde auf der Leinwand einen Kreis zu zeichnen. Das funktioniert, aber nicht so, wie ich es möchte. Es scheint, als würde die App zwischen zwei Leinwänden wechseln und jeder Leinwand einen Kreis hinzufügen, so dass Sie jede Sekunde mit der gleichen Anzahl von Kreisen wechseln können Platz auf der Leinwand.Android SurfaceView Leinwand Zeichnung mit einem Thread

Ich weiß nicht, was ich falsch mache, aber ich bin nicht vertraut mit Treading, hat es etwas damit zu tun, wie viele Kerne mein Android-Gerät hat oder so ähnlich?

Mein Code ist unten gezeigt, also verwende ich nur einen LaunchThread, der eine Layoutdatei verwendet, die mit dem Animationsfaden verknüpft, der einen Thread startet und jede Sekunde einen Kreis auf der Zeichenfläche zeichnet. (Sie können das touchevent ignorieren, es wird noch nicht verwendet).

Das Projekt besteht aus einem Haupt launchthread:

public class MainActivity extends Activity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 
    } 
} 

, die diese Layout-Datei verwendet:

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

Und meine Surface Klasse mit einem Innengewinde Klasse:

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

Sollte das in Ihrem Code AnimationView2 sein? Eine korrigierte Version würde geschätzt werden. – RichieHH

+0

(Wenn Sie den Code aus einem Samples Beispiel kopieren (dies ist ein leicht modifizierter LunarLander), ist es immer am besten, es zu sagen, da es die Fehlersuche erleichtert)). – RichieHH

Antwort

4

scheint die App zwischen zwei ca nvasses

Ja, so funktioniert es. Es ist die doppelte Pufferung genannt, und Sie müssen alle den Rahmen neu zu zeichnen each time:

Der Inhalt der Oberfläche nie zwischen unlockCanvas() und lockCanvas(), aus diesem Grunde erhält, muss jedes Pixel in der Fläche sein geschrieben.

Sie müssen also diese Zeile canvas.drawColor(Color.BLACK) in Ihrem Code unkommentiert sein.

Und Sie sollten Thread.sleep(1000) nicht aufrufen, während Canvas gesperrt ist, verursacht starvation Problem.

+0

Ok, danke für deine Antwort, also brauche ich eine Art ArrayList, wo ich alle meine Kreisobjekte aufbewahre und dann die ArrayList in der Draw-Methode schleife, um die Kreise zu zeichnen? – randomizer

+0

Wenn Sie jede Sekunde einen Kreis hinzufügen möchten und alle gleichzeitig zeichnen möchten, dann müssen Sie Informationen über alle in der Liste speichern, diese Liste durch die einzelnen Rahmen ziehen und alle Kreise zeichnen. –

+0

Ok thx, hab jetzt alles laufen :) – randomizer

0

Es klingt, als ob Sie das funktioniert haben, aber ich habe gerade einen kleinen Fehler bemerkt, auf den ich hinweisen sollte.

Sie haben canvas.restore() aufgerufen, ohne canvas.save() vorher aufzurufen. Aus der Android-Entwicklerreferenz für Canvas: "Es ist ein Fehler, restore() öfter aufzurufen als save() aufgerufen wurde."

Ich sehe keinen Grund für Sie, canvas.save() in Ihrem Fall aufzurufen, daher sollten Sie den Aufruf von canvas.restore() entfernen.

+0

Können Sie mir bitte dabei helfen? http://stackoverflow.com/questions/33909257/canvas-draw-functions-not-working-after-screen-locked-und-unlocked – Jas