2011-06-28 9 views
5

私はthis tutorialに基づいてThreadからonDraw()メソッドを呼び出すSurfaceViewを実装しようとしています。以下のコードを実行した後、私のアプリはANRを出しています。なぜ私の実行可能ファイルはANRを与えていますか?

Threadの代わりにimplementing Runnableを試しましたが、それでもANRが得られました。

限り、ANRが発生したときに私はアプリでthere's nothing else runningを知っています。 (このコードを追加すると、ANRが発生し始めました:)

package com.thunderrabbit.run; 

import android.graphics.Canvas; 
import android.view.SurfaceHolder; 

public class MainThread extends Thread { 
    private final String TAG = this.getClass().getSimpleName(); 

    // desired fps 
    private final static int MAX_FPS = 50; 
    // maximum number of frames to be skipped 
    private final static int MAX_FRAME_SKIPS = 5; 
    // the frame period 
    private final static int FRAME_PERIOD = 1000/MAX_FPS; 

    private SurfaceHolder surfaceHolder; 
    private PageGLSurfaceView gamePanel; 
    private boolean running; // flag to hold game state 
    private Canvas canvas; 

    long beginTime;  // the time when the cycle begun 
    long timeDiff;  // the time it took for the cycle to execute 
    int sleepTime;  // ms to sleep (<0 if we're behind) 
    int framesSkipped; // number of frames being skipped 

    public MainThread(SurfaceHolder surfaceHolder, MySurfaceView gamePanel) { 
     super(); 
     this.surfaceHolder = surfaceHolder; 
     this.gamePanel = gamePanel; 
    } 

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

    @Override 
    public void run() { 
     sleepTime = 0; 
     while(running) 
     { 
      canvas = null; 
      try 
      { 
       synchronized (surfaceHolder) 
       { 
        canvas = surfaceHolder.lockCanvas(); 
        beginTime = System.currentTimeMillis(); 
            // resetting the frames skipped 
        framesSkipped = 0; 
        // update game state 
        this.gamePanel.update(); 
        // render state to the screen 
        // draws the canvas on the panel 
        this.gamePanel.render(canvas); 
        // calculate how long did the cycle take 
        timeDiff = System.currentTimeMillis() - beginTime; 
        // calculate sleep time 
        sleepTime = (int)(FRAME_PERIOD - timeDiff); 

        if (sleepTime > 0) { 
         // if sleepTime > 0 we're OK 
         try { 
          // send the thread to sleep for a short period 
          // very useful for battery saving 
          Thread.sleep(sleepTime); 
         } catch (InterruptedException e) {} 
        } 

        while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) { 
         // we need to catch up 
         // update without rendering 
         this.gamePanel.update(); 
         // add frame period to check if in next frame 
         sleepTime += FRAME_PERIOD; 
         framesSkipped++; 
        } 
        beginTime = System.currentTimeMillis(); 
        gamePanel.onDraw(canvas); 
       } 
      } 
      finally 
      { 
       if (canvas != null) 
       { 
        surfaceHolder.unlockCanvasAndPost(canvas); 
       } 
      } 
      // update game state 
      // render state to the screen 
     } 
     DebugLog.d(TAG, "Game loop executed "); 
    } 
} 

ANRの原因は何ですか?大幅に異なる方法でRunnableを実装するか、Threadを拡張する必要がありますか?

+0

を描画するための

  • 1( ANR)ダイアログ。 "Activity.runOnUiThread(Runnable)"について知りませんか?私はこれがあなたの解決策になると思います。 –

  • +0

    Logcatを投稿できますか? –

    +0

    @Balaji私はrunOnUiThreadを見たことがあるが、この場合は忘れてしまった。また、申し訳ありませんがLogCatの出力を投稿できませんでした。私は基本的に問題を再び引き起こす前にそれを解決しました。 :-) –

    答えて

    1

    gamePanelSurfaceViewになります(onTouchEvent())。つまり、あなたのUIスレッドです。 gamePanel.onDraw(canvas)を呼び出すときにブロックされています(ハードウェアがcanvasに描画されるのを待っています)ので、ANRを取得します。

    MainThreadはレンダリングスレッド(canvasをどのように所有しているかのように見える)のように見えます。あなたのゲームロジックは、MainGamePanelに入っているか、別スレッドになっているはずです。

    だから、理想的に、私は3つのスレッドだろう:ゲームロジックのための入力用

    • 1(何もしないそのほとんどの時間を費やしている主な活動)
    • 1を(すべての更新された別のスレッド時間)UIスレッドが数秒以上ブロックされている場合、ユーザは、悪名高い「アプリケーションが応答しません」と表示される)、キャンバスを所有し、すべての時間を描画している(
    +0

    同じ問題がありますが、UIスレッドがgamePanelではありません。私はxmlレイアウトを使用しています。http://stackoverflow.com/questions/13128232/surfaceview-disappear-onresume –

    1

    Thread.sleep(...)を使用するとスレッドがブロックされます。あなたがUIスレッドをブロックすると、あなたのアプリは本質的にフリーズし、OSはそれを無応答であるとみなします。代わりに、Timerを使用して調べる必要があります。例hereおよびhere

    基本的には、次回の実行までスレッドをスリープさせる代わりに、再度実行するときに呼び出すことができるようにタイマーを設定します。

    関連する問題