如何暂停和恢复surfaceView线程

时间:2010-08-20 01:41:28

标签: android multithreading surfaceview

我有一个surfaceView设置并运行,但是当我恢复它时,我收到一个错误,该线程已经启动。当应用程序进入后台然后返回前台时,处理的正确方法是什么?我已经修好了并且设法让应用程序无法崩溃而返回......但是SurfaceView不再绘制任何东西了。我的代码:

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
           Log.e("sys","surfaceCreated was called.");
           if(systemState==BACKGROUND){
                  thread.setRunning(true);

           }
           else {
        thread.setRunning(true);
               thread.start();
               Log.e("sys","started thread");
               systemState=READY;
           }



    }
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
           Log.e("sys","surfaceDestroyed was called.");
           thread.setRunning(false);
           systemState=BACKGROUND;
    }

8 个答案:

答案 0 :(得分:11)

简单的解决方案是简单地杀死并重新启动线程。创建方法resume() - 创建线程对象并启动它 - 并暂停() - 杀死线程(参见Lunarlander示例) - 在SurfaceView类中,从surfaceCreated和surfaceDestroyed中调用它们来启动和停止线程。

现在在运行SurfaceView的Activity中,您还需要从Activity(或片段)onResume()和onPause()调用SurfaceView中的resume()和pause()方法。这不是一个优雅的解决方案,但它会起作用。

答案 1 :(得分:4)

此错误似乎与月球着陆器错误有关,这个错误非常有名(在Google上进行搜索)。经过所有这段时间,并在几个Android版本发布后,该bug仍然存在 没人打扰更新它。我发现这可以解决最少的代码混乱:

  public void surfaceCreated(SurfaceHolder holder) {     
          if (thread.getState==Thread.State.TERMINATED) { 
               thread = new MainThread(getHolder(),this);
          }
          thread.setRunning(true);
          thread.start();
  }

答案 2 :(得分:2)

public void surfaceCreated(SurfaceHolder holder) {
        if (!_thread.isAlive()) {
            _thread = new MyThread(this, contxt);
        }

public void surfaceDestroyed(SurfaceHolder holder) {            
        boolean retry = true;
        _thread.setRunning(false);
        while (retry) {
            try {
                _thread.join();
                retry = false;
            } catch (InterruptedException e) {
                // we will try it again and again...
            }
        }
    }

答案 3 :(得分:2)

我发现的最好方法是覆盖控制表面视图的活动的onResume方法,以便使用该方法重新实例化SurfaceView,然后使用setContentView设置它。这种方法的问题是你需要重新加载SurfaceView正在处理的任何状态。

public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(new MyCustomSurfaceView(this));
    }

    @Override
    protected void onResume() {
        super.onResume();
        setContentView(new MyCustomSurfaceView(this));
    }

答案 4 :(得分:1)

试图对上面接受的答案发表评论,但不能,对此不熟悉。我不认为你应该从SurfaceView和Activity调用你的启动/停止线程方法。这将导致双重启动/停止线程,并且您不能多次启动线程。只需从Activity的onPause和onResume中调用您的方法即可。退出并重新进入应用程序时会调用它们,这样可以确保您的状态得到妥善处理。 surfaceDestroyed并不总是被调用,这让我搞砸了一段时间。

如果使用此方法,请确保在使用画布之前检查运行代码中的有效曲面,因为Activity将在曲面可用之前在onResume中启动线程。

        while (_run) {
            if (_surfaceHolder.getSurface().isValid()) {
                ...
            }
        } //end _run

答案 5 :(得分:1)

这就是我用过的东西。该应用程序现在不会崩溃。

查看课程:

holder.addCallback(new Callback() {

        public void surfaceDestroyed(SurfaceHolder holder) {
            gameLoopThread.setRunning(false);
            gameLoopThread.stop();
        }

        public void surfaceCreated(SurfaceHolder holder) {
            gameLoopThread.setRunning(true);
            gameLoopThread.start();

        }

在GameLoopThread中:

private boolean running = false;

public void setRunning(boolean run) {
    running = run;
}
@Override
public void run() {
    long ticksPs=1000/FPS;
    long startTime;
    long sleepTime;

while(running){
        Canvas c = null;
        startTime=System.currentTimeMillis();
        try {
            c = view.getHolder().lockCanvas();
            synchronized (view.getHolder()) {

                view.onDraw(c);

            }

        } finally {

            if (c != null) {
                view.getHolder().unlockCanvasAndPost(c);
            }

        }
        sleepTime=ticksPs-(System.currentTimeMillis()-startTime);
        try{

            if(sleepTime>0){
                sleep(sleepTime);
            }
            else
                sleep(10);
        } catch(Exception e){}
}

}

我希望它会有所帮助。

答案 6 :(得分:0)

您应该使用Activities onPause()和onResume()方法。

首先,在surfaceCreated()中,启动线程。另外,在onResume()中,确保线程尚未启动(在线程内部保留一个变量或其他内容)。然后,如果它没有运行,请将其再次设置为运行。在onPause()中,暂停线程。在surfaceDestroyed中,再次暂停线程。

答案 7 :(得分:0)

这个众所周知的问题的另一个解决方案。可悲的是,我不明白它为什么会起作用 - 它意外地出现了。但它对我有用并且易于实现:不会覆盖Activity的{​​{1}},onPause()onResume()onStart(),也不会写出特殊的内容线程方法(如onStop()resume())是必需的。

特殊要求是将所有变化的变量放在除渲染线程类之外的其他变量中。

要添加到渲染线程类的要点:

pause()

现在,有关class RefresherThread extends Thread { static SurfaceHolder threadSurfaceHolder; static YourAppViewClass threadView; static boolean running; public void run (){ while(running){ //your amazing draw/logic cycle goes here } } } 的重要事项:

YourAppViewClass

上面的两个代码块不是完整编写的类,而仅仅是需要哪些方法的命令的概念。另请注意,每次返回应用都会调用class YourAppViewClass extends SurfaceView implements SurfaceHolder.Callback { static RefresherThread surfaceThread; public YourAppViewClass(Activity inpParentActivity) { getHolder().addCallback(this); RefresherThread.threadSurfaceHolder = getHolder(); RefresherThread.threadView = this; } @Override public void surfaceCreated(SurfaceHolder holder) { surfaceThread = new RefresherThread(); surfaceThread.running=true; surfaceThread.start(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { surfaceThread.running=false; try { surfaceThread.join(); } catch (InterruptedException e) { } } }

很抱歉这样费用太高的答案。我希望它能正常运作并有所帮助。