Resume Android App running in the background

When I try to resume an Android App which has been put to the background it becomes visible for a short moment and goes back to the background. This happens if I use the Android Triangle from within the App only. Circle and Square work fine as far as I can tell.

Is there something I have to do to make it resume again after the app has been put to the background?!

I am talking about the gesture buttons, so these one here

Screenshot_20210202_212906

Nope, it should just work!

If it’s not, I suspect you’ve actually crashed. You can add a event handler to your AppDomain.CurrentDomain.UnhandledException event, then log the exception to a file you can check later. Here’s an example…

        private string _appStorageDir;

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            _appStorageDir = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.ToString(), "ArbitraryPixel", "CodeLogic");
            AppDomain.CurrentDomain.UnhandledException += Handle_UnhandledException;
            ...
        }

        private void Handle_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            try
            {
                string baseFile = "CrashLog";

                string fileName = string.Format("{0}_{1}.txt", baseFile, DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss-fff"));
                string dir = Path.Combine(_appStorageDir, "Log");
                if (!Directory.Exists(dir))
                    Directory.CreateDirectory(dir);
                string path = Path.Combine(dir, fileName);

                File.WriteAllText(path, e.ExceptionObject.ToString());
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("Unable to log dump file.");
                System.Diagnostics.Debug.WriteLine(ex.ToString());
                System.Diagnostics.Debug.WriteLine("Unhandled exception:");
                System.Diagnostics.Debug.WriteLine(e.ToString());
            }
        }

You can change the directory structure in the _appStorageDir assignment call. Anyway, when the app crashes, it will write a file with the exception to your device’s storage directory. Then you can just navigate there and see what the heck happened.

Hopefully that helps. I seem to recall experiencing this same issue when I was developing CodeLogic and it occurred when the game crashed. Good luck!

1 Like

I just ran a test to see if I can catch any unhandled exceptions with the code above. It seems to work just fine but there are some things which I need more help with.

  1. The method Android.OS.Environment.ExternalStorageDirectory is displayed as deprecated, see the screenshot. Is there an up-to-date method which we could use to replace it?

  2. What do I have to configure to get the CrashLog written out on the emulator too? Do I need to configure the emulator or do I have to change something in the code to get write access or something? Because the write of the CrashLog itself fails at the moment. And where can I access it when it got written from within the emulator?

  3. Testing with a real device in a moment… Does not seem to work. I guess I need to request / configure write access or something? How or where can I do this, if this is the case? Or what do I have to do to make it work on a real device?

Hmmm, I wrote this a few years back, it looks like they’ve deprecated it. You’ll have to google to find out what the alternative is… usually they tell you in the doc, but apparently they didn’t feel like it this time :stuck_out_tongue:

The crash log should write out on emulator just the same as the real device, you just have to find the correct folder. I think it’s different for every device… for me, I actually go to internal storage and then there’s an ArbitraryPixel folder there. For me, I was able to just write to it, but I did have to request permissions when I was trying to actually ship it. If you’re just in development territory and trying to figure out why your app crashes, you probably don’t need to worry about this yet.

Again, this is all based off of knowledge from a few years back. You might have to do some googling, sorry! The core premise should be the same, it just looks like the APIs have changed a bit.

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