2016-05-18 3 views
0

У меня есть следующий класс:Android Canvas SurfaceView черный экран

public class GameView extends SurfaceView implements SurfaceHolder.Callback { 

public static final int WIDTH = 860; 
public static final int HEIGHT = 480; 

int x = 0; 

GameLoop gameLoop; 

public GameView(Context context) { 
    super(context); 
    getHolder().addCallback(this); 
    setFocusable(true); 
} 

public GameView(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    getHolder().addCallback(this); 
    setFocusable(true); 
} 

public GameView(Context context, AttributeSet attrs, int defStyleAttr) { 
    super(context, attrs, defStyleAttr); 
    getHolder().addCallback(this); 
    setFocusable(true); 
} 

@Override 
public void surfaceCreated(SurfaceHolder holder) { 
    //setWillNotDraw(false); 

    gameLoop = new GameLoop(this); 

    gameLoop.start(); 
} 

@Override 
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 

} 

@Override 
public void surfaceDestroyed(SurfaceHolder holder) { 

} 

@Override 
protected void onDraw(Canvas canvas) { 
    super.onDraw(canvas); 

    if(canvas != null) { 
     Paint paint = new Paint(); 
     paint.setColor(Color.WHITE); 
     canvas.drawRect(x, 0, 200, 200, paint); 
     canvas.drawRect(200, 200, 400, 400, paint); 
     Log.v("TEST", "Drawing into canvas"); 
     Log.v("TEST", "x := " + x); 
    } 
} 

public void update() { 
    x += 5; 
} 

и игровой цикл, который выглядит следующим образом:

public class GameLoop extends Thread { 
public static final int REFRESH_TIME = 2; 
private static final int LOG_FPS_AFTER_FRAMES = 30; 

public static Canvas canvas; 

private double averageFPS; 

private GameView gameView; 

private boolean running; 

public GameLoop(GameView gamePanel) { 
    this.gameView = gamePanel; 
} 

@Override 
public void run() { 
    super.run(); 

    running = true; 

    long startTime; 
    long timeMillis; 
    long waitTime; 
    long totalTime = 0; 
    int frameCount = 0; 
    long targetTime = 1000*REFRESH_TIME; 

    while(running) { 
     startTime = System.nanoTime(); 
     canvas = null; 

     try { 
      canvas = gameView.getHolder().lockCanvas(); 

      synchronized (gameView.getHolder()) { 
       gameView.update(); 
       gameView.draw(canvas); 
      } 


     } catch(Exception e) {} 
     finally { 
      if(canvas != null) { 
       try { 
        gameView.getHolder().unlockCanvasAndPost(canvas); 
       } catch(Exception e) {} 
      } 
     } 


     timeMillis = (System.nanoTime() - startTime)/1000000; 
     waitTime = targetTime - timeMillis; 

     try { 
      this.sleep(waitTime); 
     } catch(Exception e) {} 

     totalTime += System.nanoTime() - startTime; 
     frameCount++; 

     if(frameCount == LOG_FPS_AFTER_FRAMES) { 
      averageFPS = 1000/((totalTime/frameCount)/1000000); 
      frameCount = 0; 
      totalTime = 0; 
      Log.v("FPS", Double.toString(averageFPS)); 
     } 

    } 

} 

@Override 
public void interrupt() { 
    super.interrupt(); 

    running = false; 
} 

public boolean isRunning() { 
    return running; 
} 

public void setRunning(boolean value) { 
    this.running = value; 
} 

}

метод OnDraw вызывается каждые две секунды но экран остается черным. Любые идеи, что может быть проблемой? (кстати, если я раскомментировать линии setWillNotDraw (ложные) прямоугольники рисуются один раз, но не движется) ...

ответ

1

Я просто переопределил функцию onDraw (холст-холст) нарисовать (холст-холст), и он работает!

4

У вас есть обычная проблема: вы перекрывая onDraw(), который втягивает наПредставление части. Таким образом, у вас очень дорогой пользовательский вид, который работает неправильно. Если вы разрешите рисовать «Просмотр», он будет рисовать один раз, но вы не вызываете invalidate(), чтобы он никогда не повторился. Я предполагаю, что вы задали цвет фона в своем макете, делая вид непрозрачным, поэтому вы не можете видеть, что нарисовано на поверхности.

Для рендеринга холста часто лучше использовать custom View, а не SurfaceView. Я бы рекомендовал этот подход.

Если вы действительно хотите использовать SurfaceView, измените onDraw() на что-нибудь еще (например, doDraw()) и назовите его из потока рендеринга. Поскольку вы будете рисовать поверх поверхности, а не в части «Просмотр», вам не нужно подклассифицировать SurfaceView (и не следует, поскольку создание независимого класса позволит избежать распространенных ошибок, например, вы упали). Удостоверьтесь, что вы понимаете, как SurfaceView and Activity interact, так как есть различные способы попасть в неприятности.

Вы должны также прочитать рекомендуемый способ структурирования game loop.