Android: Regaining focus using SurfaceView

2019-04-29 15:06发布

问题:

I'm currently getting to grips with Android, playing around with the Lunar Lander sample.

I've found that if you navigate away from the app (eg, hit the call button) it will destroy the underlying surface (calling surfaceDestroyed).

Navigating back (which will trigger onWindowVisibilityChanged) the app will crash, as it will try to draw to the surface without recreating it.

Is there some code I can put in onWindowVisibilityChanged (or anywhere else) that will regenerate the SurfaceView's underlying surface and resume execution nicely?

It feels like this should be a simple function call but I can't find anything in the API docs.

Thanks!

回答1:

This solution for "mSurfaceExists = true" isn't working for me either. It looks like surfaceCreated() is not getting called because super.onWindowVisibilityChanged() is not called. So there is no surface created and it doesn't crash because threas.start is not called.

I believe the problem is: Calling thread.start() causes the error because the thread was already started. But in surfaceDestroyed(), thread.join causes the thread to complete and die. And a thread can not be restarted once dead.

I am guessing the trick is to create a new thread in surfacecreated or to only cause the thread to complete when user is calling the application to finish(back key) and not pausing(home key). This can be checked by calling isFinishing() on the activity.

Not sure if this will work. I will be trying this soon.



回答2:

Mis-diagnosis! The app re-creates the surface automatically, but there's a call in there that tries to draw to it before it's created.

Fixing the problem:

boolean mSurfaceExists;
...
public void surfaceDestroyed(SurfaceHolder holder) {
    mSurfaceExists = false;
    ...
}

public void surfaceCreated(SurfaceHolder holder) {
    mSurfaceExists = true;
    ...
}

protected void onWindowVisibilityChanged(int visibility) {
    // only call base if there's a surface
    if(mSurfaceExists)
        super.onWindowVisibilityChanged(visibility);
}

Now it's all swell. (as far as I'm aware, anyway - Java/Android experts feel free to comment if this is bad practise!)