且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Surfaceview ANR onResume

更新时间:2022-10-15 23:38:05

THX这个职位的为什么我的可运行给ANR?我可以解决这个问题,我从UI线程中分离出的MainThread进一步的细节检查***的答案。

I'm working on a Android game using SurfaceView, the game works fine, so I want to pause it when the user hits HOME key but when getting back the SurfaceView disappears(black background Edit: sometimes the drawing appears) and buttons are inactive in both cases then I get ANR.

public class MainActivity extends Activity {
    private Game game;
    MainPanel mp;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        game = new Game();
        LoadLevel();
        Init();
        setContentView(R.layout.main);//contains surfaceview and buttons
        mp = (MainPanel) findViewById(R.id.SurfaceView01);
        mp.Init(game,this);
        Button btnTop = (Button) findViewById(R.id.buttonTop);
        Button btnBottom = (Button) findViewById(R.id.buttonBottom);
        Button btnLeft = (Button) findViewById(R.id.buttonLeft);
        Button btnRight = (Button) findViewById(R.id.buttonRight);
        btnTop.setOnClickListener...
    }

    private void Init() {
        ...
    }

    public void LoadLevel() {
        ...
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d("Tag","Resume");
    }

    @Override
    protected void onPause() {
            super.onPause();
        Log.d("Tag","Pause");
    }
}

public class MainPanel extends SurfaceView implements SurfaceHolder.Callback {

    private MainThread thread;
    private Game game;
    private MainActivity act;

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

    public MainThread getThread() {
        return thread;
    }

    public void Init(Game game, MainActivity act){
        this.game = game;
        this.act = act;
    }

    public void Move(int dir) {
        ...
    }

    public void update() {
        ...
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {}
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        if (thread == null) {
            thread = new MainThread(getHolder(), this);
            thread.Start();
            thread.start();
        }
    }
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        thread.Stop();
        boolean retry = true;
        while (retry) {
            try {
                thread.join();
                retry = false;
            } catch (InterruptedException e) {}
        }
        thread = null;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(Color.BLACK);
        //drawing...
    }
}

public class MainThread extends Thread {
    private final static int MAX_FPS = 30;
    private final static int MAX_FRAME_SKIPS = 3;
    private final static int FRAME_PERIOD = 1000 / MAX_FPS;

    private SurfaceHolder surfaceHolder;
    private MainPanel gamePanel;
    private boolean run = false;
    private boolean start = false;

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

    public void Start() {
        this.run = true;
        this.start = true;
    }

    public void Pause() {
        this.start = false;
    }

    public void Resume() {
        this.start = true;
    }
    public void Stop() {
        this.run = false;
    }

    @Override
    public void run() {
        Canvas c = null;
        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 

        while(run) {
            while(start) {
                try {
                    c = surfaceHolder.lockCanvas(null);
                    synchronized (surfaceHolder) {
                        beginTime = System.currentTimeMillis();
                        framesSkipped = 0;  // resetting the frames skipped
                        // update game state
                        gamePanel.update();
                        // render state to the screen draws the canvas on the panel
                        if(c!=null) gamePanel.onDraw(c);
                        // 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
                            gamePanel.update();
                            // add frame period to check if in next frame
                            sleepTime += FRAME_PERIOD;
                            framesSkipped++;
                        }
                    }
                } finally {
                    if (c != null) surfaceHolder.unlockCanvasAndPost(c);
                }
            }
        }
    }
}

Thx to this post why is my runnable giving ANR? I could solve the problem, I isolated the MainThread from the UI thread for further details check the best answer.