how to pause and resume a surfaceView thread

前端 未结 8 1184
野趣味
野趣味 2020-12-02 08:21

I have a surfaceView setup and running, but when I resume it I get an error that the thread has already been started. What\'s the proper way to handle when the app goes to t

相关标签:
8条回答
  • 2020-12-02 08:30

    Tried to comment on the accepted answer above but couldn't, new to this. I don't think you should be calling your start/stop thread methods from both your SurfaceView and Activity. This will result in starting/stopping the thread doubly, and you can't start a thread more than once. Just call your methods from the Activity's onPause and onResume. They're called when exiting and re-entering the app so this will make sure your states are handled properly. surfaceDestroyed isn't always called, which messed me up for a while.

    If you use this method make sure to check for a valid surface in your run code before working with your canvas, because the Activity will start the thread in onResume before the surface is available.

            while (_run) {
                if (_surfaceHolder.getSurface().isValid()) {
                    ...
                }
            } //end _run
    
    0 讨论(0)
  • 2020-12-02 08:30

    Another solution for this good-known problem. Sadly, I don't understand why it works -- it came out accidentally. But it works good for me and it's easy to implement: no overriding of Activity's onPause(), onResume(), onStart(), onStop(), nor writing of special thread methods (like resume(), pause()) are required.

    Special requirement is to put all changing variables in something other than rendering thread class.

    Main points to add to render-thread class:

    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
            }
        }
    }
    

    Now, important things about 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) {  
            }               
        }
    }
    

    Two code blocks above are not full-written classes, but mere notion of which commands in which methods are needed. Also note that each return to app invokes surfaceChanged().

    Sorry for such space-consuming answer. I hope it will work properly and will help.

    0 讨论(0)
  • 2020-12-02 08:41

    The best way I have found is to override the onResume method of the activity controlling the surface view so that with the method it re-instantiates the SurfaceView and then sets it with setContentView. The problem with this approach is that you need to reload any state that your SurfaceView was taking care of.

    public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            setContentView(new MyCustomSurfaceView(this));
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            setContentView(new MyCustomSurfaceView(this));
        }
    
    0 讨论(0)
  • 2020-12-02 08:42

    This is what I have used. The app does not crashes now.

    View Class:

    holder.addCallback(new Callback() {
    
            public void surfaceDestroyed(SurfaceHolder holder) {
                gameLoopThread.setRunning(false);
                gameLoopThread.stop();
            }
    
            public void surfaceCreated(SurfaceHolder holder) {
                gameLoopThread.setRunning(true);
                gameLoopThread.start();
    
            }
    

    In the 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){}
    }
    
    }
    

    I hope it will help.

    0 讨论(0)
  • 2020-12-02 08:43

    This bug appears to relate to the lunar lander bug, which is quite famous (do a Google search on it). After all this time, and after several android version releases, the bug still exists and no one has bothered to update it. i have found this to work with the least code clutter:

      public void surfaceCreated(SurfaceHolder holder) {     
              if (thread.getState==Thread.State.TERMINATED) { 
                   thread = new MainThread(getHolder(),this);
              }
              thread.setRunning(true);
              thread.start();
      }
    
    0 讨论(0)
  • 2020-12-02 08:43
    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...
                }
            }
        }
    
    0 讨论(0)
提交回复
热议问题