Search code examples
uwp

UWP App Crashes on Resuming After Being Idle for a While


I am developing my UWP music player app for years. I've encountered an issue where the app crashes when it resumes after being idle for an uncertain period of time. However, if the music player keeps playing, the app functions perfectly fine. The crash occurs when the app is brought back into focus after being idle. I cannot steadily reproduce the crash, but it does come most of the time. I just don't know how long it takes.

I have attempted to diagnose the issue by attaching a debugger, but the crash doesn't occur when the debugger is attached. In the class App : Application, I have added try-catchs and logs to the Resuming, Suspending and UnhandledException method, but still couldn't pinpoint the cause of the crash.

I'm at a loss on how to further troubleshoot this problem. Any suggestions on what steps to take next or how to properly diagnose and avoid such crash would be greatly appreciated.

This is partially the code of my music player

public class MusicPlayer : IMusicEventListener
{
    public static MediaPlaybackState PlaybackState => Player.PlaybackSession.PlaybackState;
    public static bool IsPlaying => PlaybackState == MediaPlaybackState.Playing;
    public static Playlist NowPlaying => new Playlist(MenuFlyoutHelper.NowPlaying, CurrentPlaylist);
    private static MediaPlaybackList PlaybackList = new MediaPlaybackList() { MaxPlayedItemsToKeepOpen = 1 };
    public static MediaPlayer Player = new MediaPlayer() { Source = PlaybackList };
}

The is partially the code of my App class

sealed partial class App : Application
{
    public static bool Inited { get; private set; } = false;
    public static List<Action> LoadedListeners = new List<Action>();
    public App()
    {
        this.InitializeComponent();
        this.Suspending += OnSuspending;
        this.Resuming += App_Resuming;
        this.UnhandledException += App_UnhandledException;
    }

    private void App_Resuming(object sender, object e)
    {
        Debug.WriteLine($"sender {sender.GetType()} e {e}");
    }

    protected override void OnLaunched(LaunchActivatedEventArgs e)
    {
        OnLaunched(e, null);
    }

    private void OnSuspending(object sender, SuspendingEventArgs e)
    {
        var deferral = e.SuspendingOperation.GetDeferral();
        try
        {
            TileHelper.ResumeTile();
            ToastHelper.HideToast();
            Save();
            SQLHelper.ClearInactive();
        }
        catch (Exception ex)
        {
            Log.Warn($"OnSuspending exception {ex}");
        }
        deferral.Complete();
    }

    public static async void Save()
    {
        SettingsHelper.Save();
        MusicPlayer.Save();
        await Helper.ClearBackups(10);
    }

    protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args)
    {
        var deferral = args.TaskInstance.GetDeferral();
        switch (args.TaskInstance.Task.Name)
        {
            case ToastHelper.ToastTaskName:
                if (args.TaskInstance.TriggerDetails is Windows.UI.Notifications.ToastNotificationActionTriggerDetail details)
                {
                    // Perform tasks
                    if (Enum.TryParse(typeof(ToastButtonEnum), details.Argument, out object toastButton))
                    {
                        try
                        {
                            HandleBackgroundActivation((ToastButtonEnum)toastButton);
                        }
                        catch (Exception e)
                        {
                            Log.Warn($"HandleBackgroundActivation failed {e}");
                        }
                    }
                }
                break;
        }
        deferral.Complete();
    }

    private async void HandleBackgroundActivation(ToastButtonEnum toastButton)
    {
        switch (toastButton)
        {
            case ToastButtonEnum.Next:
                MusicPlayer.MoveNext();
                if (MusicPlayer.PlayMode == PlayMode.RepeatOne)
                {
                    ToastHelper.HideToast();
                    await ToastHelper.ShowToast(MusicPlayer.CurrentMusic, MusicPlayer.PlaybackState);
                }
                break;
            case ToastButtonEnum.Pause:
                MusicPlayer.Pause();
                break;
            case ToastButtonEnum.Play:
                MusicPlayer.Play();
                break;
            case ToastButtonEnum.SwitchLyricsSourceToMusic:
                await ToastHelper.SwitchLyricsSource(LyricsSource.Music);
                break;
            case ToastButtonEnum.SwitchLyricsSourceToLrcFile:
                await ToastHelper.SwitchLyricsSource(LyricsSource.LrcFile);
                break;
            case ToastButtonEnum.SwitchLyricsSourceToInternet:
                await ToastHelper.SwitchLyricsSource(LyricsSource.Internet);
                break;
        }
    }

    protected override async void OnFileActivated(FileActivatedEventArgs args)
    {
        base.OnFileActivated(args);
        Music music = await Music.LoadFromPathAsync(args.Files[0].Path);
        Log.Info("activate file " + args.Files[0].Path);
        if (music == null)
        {
            Helper.ShowButtonedNotification("CannotReadLocalMusicFile", "Authorize", async (n) =>
            {
                await StorageHelper.AuthorizeFolder();
            });
            return;
        }
        if (args.PreviousExecutionState == ApplicationExecutionState.Running)
        {
            MusicPlayer.AddNextAndPlay(music);
        }
        else
        {
            OnLaunched(null, music);
        }
    }

    private void App_UnhandledException(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e)
    {
        Log.Error("App_UnhandledException {0}", e.Exception);
    }

}

Solution

  • An exception was thrown in the Save() function, and the function is async void not async Task. Thus, its exception was thrown asynchronously and not caught in the OnSuspending. So the solution would simply catch the problem in the Save() function.

    private void OnSuspending(object sender, SuspendingEventArgs e)
    {
        var deferral = e.SuspendingOperation.GetDeferral();
        try
        {
            TileHelper.ResumeTile();
            ToastHelper.HideToast();
            Save();
            SQLHelper.ClearInactive();
        }
        catch (Exception ex)
        {
            Log.Warn($"OnSuspending exception {ex}");
        }
        deferral.Complete();
    }
    
    public static async void Save()
    {
        SettingsHelper.Save();
        MusicPlayer.Save();
        await Helper.ClearBackups(10);
    }