Resume Android App running in the background

What’s the ConfigurationChanges in your activity1.cs file?
That’s the CC from one of my projects
, ConfigurationChanges =
ConfigChanges.Orientation |
ConfigChanges.Keyboard |
ConfigChanges.KeyboardHidden |
ConfigChanges.ScreenSize |
ConfigChanges.ScreenLayout |
ConfigChanges.UiMode |
ConfigChanges.SmallestScreenSize

Also add a breakpoint in OnCreate() and OnDestroy() in there to see if your App is getting recreated.

Before suspending the app, clean the output in VS to see if you are getting any suspicious errors when the app is getting suspended.

Those are mine:

ConfigurationChanges = 
ConfigChanges.Orientation | 
ConfigChanges.Keyboard | 
ConfigChanges.KeyboardHidden | 
ConfigChanges.ScreenSize

I left the ConfigChanges like they were by default as far as I remember. My plan so far is to get a foundation where I can debug the app and also get some info about what happened when the app crashes on a user device. Catching unhandled exceptions, logging and writing them out seems like a good practice.

So far it is a pretty basic app, I am just getting started with Android app dev too. So any advice and links where or what I should read to get the basic concepts about it are welcome too, if anyone has suggestions.

I added the breakpoints but they did not get triggered when I suspended the app with the triangle button. I did the test pretty quick though. I will retry it later to double check.

Are there any differences which I should be aware of in this case when I debug on emulator vs real device?

On mobile right now. My idea now is to remove my superficial Exception (which I put in to be able to catch something and testing if writing the log works, which does not at the moment for some reason) and check if I can find out what happens when resume fails.

This is what I see in the output window when resume fails. Also I checked and no breakpoint gets hit (OnCreate, OnDestroy). Also no breakpoint gets hit inside the Handle_UnhandledException method (I set breakpoints at the beginning of try and catch).

02-03 21:24:23.703 D/EGL_emulation(17813): eglMakeCurrent: 0xe0b1a360: ver 3 0 (tinfo 0xe0b0f040)
02-03 21:24:23.800 D/EGL_emulation(17813): eglMakeCurrent: 0xebc2c700: ver 3 0 (tinfo 0xc444f010)
02-03 21:24:23.801 D/MonoGame(17813): GraphicsDeviceManager.ResetClientBounds: newClientBounds={X:35 Y:0 Width:1009 Height:1794}
02-03 21:24:23.878 D/EGL_emulation(17813): eglMakeCurrent: 0xebc2c700: ver 3 0 (tinfo 0xc444f010)
02-03 21:24:23.878 D/MonoGame(17813): GraphicsDeviceManager.ResetClientBounds: newClientBounds={X:35 Y:0 Width:1009 Height:1794}
02-03 21:24:24.467 D/EGL_emulation(17813): eglMakeCurrent: 0xe0b1a360: ver 3 0 (tinfo 0xe0b0f040)

If I throw an exception and leave it unhandled I hit the breakpoints in the Handle_UnhandledException method. So the setup seems to be fine. Also it may be that the code for writing out the text file is now working fine. I want to verify this now by checking the filesystem from the emulator. I can get access to the filesystem using adb shell. Now there I can cd my way along the path where I expect the CrashLog to be. But at some point I don’t have read access, I get Permission denied errors.

generic_x86:/data/user/0 $ ls
ls: .: Permission denied
1|generic_x86:/data/user/0 $

Out of time to further investigate right now. But found out some things. No Exception is thrown when resume fails! The app is just being put to the background immediately when I click the app icon in the launcher or try to resume the app by clicking the square button to view the apps and then tapping / selecting the app to bring it to the foreground / resume it again.

On the other hand writing the CrashLog works. I could verify this by throwing an Exception myself which got caught and written to the CrashLog. I checked that with breakpoints which all got hit and also by looking if the CrashLog file had been written (it was on the filesystem). The content contained my custom Exception text.

So not sure what to do with the initial issue now of the failed resume… But nice that I can write CrashLogs now, thanks @Trinith for that :slight_smile:

Thanks for the useful ideas to @nkast which got me in the right direction to be able to check what was happening.

I found some other thread for older MG versions where there is the same thing described to happen. There is also a workaround described which I can try when I get to it again. I will try to find it again and see if this can fix the issue.

Hmm, looks like it was closed because it was fixed in the develop version… But then again the .NET Core version should have that fix already, or not? The MG nugets show me version 3.8.0.1641 in the project properties (the Android nuget displays nothing in the properties window though but it was created using the dotnet new command at the same time as the other projects and should match the version then I guess?). How can I check / verify if the Android project should have the fix or not? I think it should but then again I see the issue happening?

Found the thread with the fix from @tunkio . Just putting it here again but I did not yet test if myself yet.

So the workaround did not resolve / fix the issue for me. I just created a blank new Android App from scratch. I tried with the emulator and real device. The issue is still there. To reproduce should be easy. Just start the App inside an emulator or on a real device. Put the app to the background by using the triangle (important, since e.g. using the square everything seems to works fine). Then either resume the app by clicking the android app symbol in the launcher which should resume the app which has been put to the background. Alternatively show all running tasks by clicking the square button. Then select the app to bring it to the foreground / resume the app. It should become visible / come to the foreground for a very short moment and immediately go to the background again.

Maybe the MoveToBackground / Exit method works fine and has really been fixed and the issue is related to the GamePad somehow? The template just tests the GamePadState. And with the debugger it looks like after the resume it gets the same state again (Buttons.Pressed(Buttons.Back)). This only happens now and then, so not everytime though. Also when I put a breakpoint in, it “helps” that the GamePadState gets it right after the resume! So I can put a breakpoint in. And then it hits it. I click resume the app oes to the background. After that the resume works most of the time. If I don’t have the breakpoint active it makes a difference and the resume fails. Again this is for the empty project now from the Android template.

Hmmm, maybe I didn’t understand the original problem (though glad you’ve got crash logging now :D). Does this happen after you exit the game, or after you just task switch away? Now that I re-read your post, you said it happens when you press the triangle button, but that’s the back button and you have to write specific code to handle that case.

What are you doing in that case?

I went over my own game’s code and a couple other things jump out…

  • I remember having some issues that might be similar to this when full screen ads were shown. It put my game into the background and it wouldn’t come back. I fixed it by changing the LaunchMode to LaunchMode.SingleInstance. I had some code to detect the case, but there was no recovery… all I could do was show a screen saying, “Hey, sorry, please task kill the app and restart.” Changing the LaunchMode resolved the issue. You could try that?
  • I remember having some issues where my process, on Android, wouldn’t exit cleanly. I hooked my back button up to exit the game, throwing a GameFinished event when that happened. Just allowing my MonoGame class to exit wasn’t enough, and so I had to hook that event up to run Process.KillProcess(Process.MyPid()) to make it actually quit.

Anyway, maybe give the LaunchMode thing a try to see if it makes any difference. Past that, I’m not sure :frowning:

Like described in the post before, I tried with a fresh Android App created from the MonoGame template in Visual Studio and left everything like it was. I am using the back button / triangle. The Update method from the Android template has Game.Exit(); but if I read / understood the MG source good enough, on Android, this will result in Game.Activity.MoveTaskToBack(true); anyway at some state.

Maybe I could try that. Do you have the implementation at hand or available somewhere? Do I have to call this Process.KillProcess(Process.MyPid()) at a specific place? Inside the Activity or the Game class?
In principle I would prefer to just let the Framwork handle Game.Exit(); but as a temporary workaround…

Again it would help if somebody could quickly test if they have the same issue with a fresh Android App. Either on a real device or in the emulator. Both test cases have that issue here. The steps to reproduce are in my last post. They are pretty simple. A test could be done pretty quick.

As a workaround, this kills the process if the back button is pressed on Android. So the app will just start from scratch / restart after the back button is used.

        protected override void Update(GameTime gameTime)
        {
            GamePadState gamePadState = GamePad.GetState(PlayerIndex.One);

            bool isBackButtonPressed = gamePadState.Buttons.Back == ButtonState.Pressed;

            if (isBackButtonPressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
            {
                Exit();
                HandleAndroid();
            }

            // TODO: Add your update logic here

            base.Update(gameTime);
        }

        private static void HandleAndroid()
        {
#if ANDROID
            Process.KillProcess(Process.MyPid());
#endif
        }

What you did here is similar to what I did :slight_smile: If you want to avoid the #if ANDROID line though, you can just add an event to your main game’s class, Exited, and then from your android activity, handle the event and do the kill process call there. This keeps Android specific logic out of your game class.

1 Like

Ok just a moment, will post it as example for others.

// Game1.cs...
        public event EventHandler ExitedEventHandler;
        protected virtual void OnExitedEventHandler(EventArgs e)
        {
            EventHandler handler = ExitedEventHandler;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        protected override void Update(GameTime gameTime)
        {
            GamePadState gamePadState = GamePad.GetState(PlayerIndex.One);

            bool isBackButtonPressed = gamePadState.Buttons.Back == ButtonState.Pressed;

            if (isBackButtonPressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
            {
                Exit();
                OnExitedEventHandler(EventArgs.Empty);
            }

            // TODO: Add your update logic here

            base.Update(gameTime);
        }
//Activity1.cs...
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            _game = new Game1();
            _view = _game.Services.GetService(typeof(View)) as View;

            SetContentView(_view);

            _game.ExitedEventHandler += HandleExitedEventByKillingTheAndroidProcessWorkaround;
            _game.Run();
        }

        static void HandleExitedEventByKillingTheAndroidProcessWorkaround(object sender, EventArgs e)
        {
            Console.WriteLine("Killing the process now...");
            Process.KillProcess(Process.MyPid());
        }

Should I mark this as Solution…?

1 Like

Just tested can’t resume after Exit(); using backbutton (monogame 3.8.0.1641).

Cloned monogame source and find this, in AndroidGameActivity.cs

protected override void OnPause()
{
       base.OnPause();
       //EventHelpers.Raise(this, Paused, EventArgs.Empty);

        if (_orientationListener.CanDetectOrientation())
             _orientationListener.Disable();
}

If that EventHelpers.Raise is commented out, I can resume after Exit() via backbutton…

1 Like

Trying this out now myself…

So since I don’t use the source normally. Clone, Build, Build Tools, Create Android App with template, delete nuget refs, Add projects as references to the Android project are the steps right?

Ok trying out right now…

Works for me too on the emulator so far…

Now testing on a device…

Worked on the device too.

@tunkio Good work! I marked this as Solution! :slight_smile:
@Trinith Good workaround! I leave it here too for others using the current version provided by the nugets.

1 Like

I reported issue to github Android not resuming to app after using Exit(); via backbutton · Issue #7458 · MonoGame/MonoGame · GitHub

Created a pull request here which applies the change described by @tunkio which fixes the issue but probably it needs more work because the commented source may be necessary for other platforms or something which I don’t know and did not check at this point. Further discussion can be done on GitHub of course.