为什么我的可运行给ANR?

时间:2011-06-28 14:46:36

标签: android

我正在尝试实施SurfaceView,根据this tutorialonDraw()调用Thread方法。在我开始运行以下代码后,我的应用程序正在提供ANR。

我尝试了implementing Runnable,而不是扩展Thread,但它仍然提供了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吗?

2 个答案:

答案 0 :(得分:1)

使用Thread.sleep(...)阻止线程。如果您阻止UI线程,您的应用程序基本上被冻结,操作系统将认为它没有响应。相反,你应该考虑使用Timer。示例herehere

基本上不是在你的线程下次执行之前休眠,而是设置一个计时器,以便在需要再次执行时调用它。

答案 1 :(得分:1)

gamePanelSurfaceView延伸并接收您的输入(通过onTouchEvent())。换句话说,它是你的UI线程。当你打电话gamePanel.onDraw(canvas)它正在阻塞(等待硬件在canvas上绘制),所以你得到了ANR。

MainThread似乎是渲染线程(看看它如何拥有canvas),它应该是唯一一个渲染。您的游戏逻辑应该放在MainGamePanel或完全单独的线程中。

理想情况下,我会有三个主题:

  • 一个用于输入(主要活动花费大部分时间无所事事)
  • 一个用于游戏逻辑(一个单独的线程,它一直在更新)
  • 一个用于绘图(拥有画布并且一直在绘制)