WSC
WSC

Reputation: 993

Android MonoGame application closing immediately after being resumed

Using MonoGame 3.7.1 I have a very basic game setup on Android. There is some weird behaviour with closing/reopening the app.

To exit the game, I use this logic:

if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
{
    Activity.MoveTaskToBack(true);
    //Exit(); //Originally was using this, neither seems to have changed much
}

However, when resuming the app it will occasionally (and seemingly at random) open and then immediately close (not crash). It doesn't always do this, sometimes it returns back to it's previous state without any issues. If I attempt to resume it again it will open as normal.

I have captured a video showing this behaviour here. It's worth noting that there's no crash happening. This is running in Debug via Visual Studio with the phone connected via USB so if it was a crash I'd know. This behaviour happens even when not in debug mode.

The debug output when the unexpected closing happens is this:

05-22 23:27:05.228 E/SensorManager(26381): registerListenerImpl sensorName:BMI160_ACCELEROMETER Accelerometer Non-wakeup,isWakeUpSensor:false,callingApp: TestGame.TestGame,callingPid:26381,callingUid:10569
05-22 23:27:05.245 D/DecorView(26381): onWindowFocusChangedFromViewRoot hasFocus: true, DecorView@8012b96[MainActivity]
05-22 23:27:05.265 W/monodroid-assembly(26381): typemap: unable to find mapping to a managed type from Java type 'com/google/android/gles_jni/EGLSurfaceImpl'
05-22 23:27:05.265 D/MonoGame(26381): GraphicsDeviceManager.ResetClientBounds: newClientBounds={X:0 Y:137 Width:1080 Height:1799}
05-22 23:27:05.265 D/AudioTrack(26381): ClientUid 10569 AudioTrack::start 
05-22 23:27:05.317 E/SensorManager(26381): unregisterListenerImpl callingApp: TestGame.TestGame,callingPid:26381,callingUid:10569
05-22 23:27:05.325 D/        (26381): PlayerBase::stop() from IPlayer
05-22 23:27:05.325 D/AudioTrack(26381): ClientUid 10569 AudioTrack::stop 
05-22 23:27:05.325 D/AudioTrack(26381): stop(1656): called with 1772 frames delivered
Thread finished: <Thread Pool> #17
Thread started: <Thread Pool> #28

The only things that stand out to me are the lines typemap: unable to find mapping..., GraphicsDeviceManager.ResetClientBounds, and Thread finished: <Thread Pool> #17.

That said, those could be completely unrelated as similar messages appear when it loads correctly.

Any ideas what's going on here?

Upvotes: 0

Views: 339

Answers (2)

derek schultz
derek schultz

Reputation: 1

I've run across this also. When I looked into it, it seems that the GamePad.Back button gets set to true, but doesn't get set back to false (at least not consistently - would need a OnKeyUp with a back button to set it back to false). As such, when you attempt to resume (OnActivate), the back button is still flagged as true, which, when the Update call is made, Re-Exits.

There are a few workarounds out there, but they didn't work for me.

Ultimately I tried the following (version 3.8.1) and it seems to work.

In the Android Project's Game1.cs file, I modified the Update method to call the OnKeyUp method to reset this value (side effect of the call). That way when you come back (re-activate) your app, it doesn't think the back button is still pressed, and then re-exit. I couldn't reset the Back value directly or call OnKeyUp directly, so I had to do a kludgy solution, but it seems to work.

private MonoGameAndroidGameView _monoGameAndroidGameView = null;
private KeyEvent _dummyKeyEvent = null;

protected override void Update(GameTime gameTime)
{
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
    {
        try
        {
            if (_monoGameAndroidGameView == null)
            {
                // NOTE: GamePad.Back is STATIC, so we can get away with separate instance referencing it
                _monoGameAndroidGameView = new MonoGameAndroidGameView(Game.Activity, (AndroidGameWindow)Window, this);
            }

            if (_dummyKeyEvent == null)
            {
                // create dummy keyevent so we can call OnKeyUp
                _dummyKeyEvent = new KeyEvent(0, "", 0, KeyEventFlags.Canceled);
            }

            if (_monoGameAndroidGameView != null)
            {
                try
                {
                    // Reset our BACK button flag so we can resume on activation, without re-BACKing out...
                    // NOTE: SIDE EFFECT of call is setting GamePad.Back = false - so it is NOT stuck on true, which causes exit loop on reactivate
                    _monoGameAndroidGameView.OnKeyUp(Keycode.Back, _dummyKeyEvent); 
                }
                catch
                {
                    // ignore error (if any) - side effect from above call will still take effect
                }

                Game.Activity.MoveTaskToBack(true);
                base.Update(gameTime);
            }
            else
            {
                throw new Exception("Unable to clear BACK button"); // below catch will do hard exit to prevent loop
            }
        }
        catch
        {
            // unable to close the way we want - just kill the process
            Game.Activity.MoveTaskToBack(true);
            Process.KillProcess(Process.MyPid());
        }
    }
    else
    {
        base.Update(gameTime);
    }
}

I hope this helps.

Upvotes: 0

nkast
nkast

Reputation: 16

I've never seen this but I've found a lot of issues with the handling of the backbuffer/clientWindow on Android involving ResetClientBounds().

You can try my modified build if you want and see if that fixed it. You can use the nuget or the installer.

It's required to to change ScreenOrientation = ScreenOrientation.FullSensor in the Activity1.cs, otherwise it will fail to load.

Upvotes: 0

Related Questions