Activity and View are created almost at the same time. Surface is created later, and what SufaceHolder designed for callbacks for.
You cannot render on the Surface before it exists or after it is destroyed, so it makes no sense to start the rendering stream before or after it is complete. The tricky part is that the callbacks occur in the main UI thread (since you configured it), so the surfaceDestroyed() can be called while the rendering thread is running.
EDIT:
Below are some notes on the SurfaceView / Activity lifecycle. Now they are part of the official documentation on Android; see Appendix B at System Graphics Level . The original post is available below for historical purposes.
You can see examples of both approaches at Grafika . Approach No. 1 (creating / destroying a stream in onResume / onPause) can be seen in TextureFromCameraActivity , approach # 2 (creating / destroying a thread in surfaceCreated / surfaceDestroyed) can be in HardwareScalerActivity and RecordFBOActivity .
A few thoughts on the application life cycle and
SurfaceView .
There are two somewhat independent things:
- App onCreate / onResume / onPause
- Surface created / modified / destroyed
When the action begins, you receive callbacks in the following order:
- Oncreate
- onResume
- surfaceCreated
- surfaceChanged
If you press back, you will get:
- Onpause
- surfaceDestroyed (called just before the surface leaves)
If you rotate the screen, the Activity breaks down and recreates, so you get a complete loop. (You can say a βquickβ restart by checking isFinishing() .) Perhaps you can start / stop the action so fast that surfaceCreated() can happen after onPause() , but I'm not sure about that.
If you press the power button to clear the screen, you will only get onPause() - no surfaceDestroyed() . Surface remains alive, and the rendering can go on (you even keep getting Choreographer events if you keep asking for them). If you have a lock screen that forces a certain orientation of your Activity to get hit, but if not, you can exit the screen with the same Surface as before.
This raises a fundamental question when using a separate rendering stream with SurfaceView : if thread life should be tied to Surface or Activity ? Answer: it depends on what you want when the screen goes blank. There are two main approaches: (1) start / stop a thread on an Activity start / stop; (2) start / stop the thread on Surface create / destroy.
# 1 interacts well with the application life cycle. We start the rendering stream in onResume() and stop it in onPause() . When creating and adjusting the flow, it becomes a little inconvenient because sometimes the surface already exists, and sometimes it will not. We cannot simply forward Surface callbacks to the stream, as they will not start again if Surface already exists. Therefore, we need to query or cache the state of Surface and forward it to the rendering stream. Please note that we have to be a little careful when passing objects between threads - itβs better to send a Surface or SurfaceHolder message through a Handler message, rather than just inserting it into a stream to avoid problems with multi-core systems (see Android SMP Primer ).
# 2 has some appeal because Surface and rendering are logically intertwined. We start the thread after creating the Surface , which avoids cross-thread communication problems. Surface created / modified messages are simply redirected. We need to make sure that the rendering stops when the screen is blank, and resumes when it is blank; this can be a simple matter, saying that the choreographer stops referring to the frame callback. Our onResume() will need to resume callbacks if and only if the rendering stream is running. This may not be so trivial - if we live on the basis of the elapsed time between frames, we could have a very big gap when the next event, so an explicit pause / resume message may be required.
The above applies primarily to how the visualization stream is configured, and it performs. A related issue is onPause() state from the thread when Activity killed (in onPause() or onSaveInstanceState() ). Approach # 1 will work better for this, because once the rendering stream has been attached, its state can be accessed without synchronization primitives.