简体   繁体   中英

Windows Phone Thread.Sleep preventing UI load while running in background

I'm writing a Windows Phone 8 app, which uses the Geolocator to track your location. I used the MS sample code as a base and have adapted it. I've got a problem, which is while the app is running in the background, I want to occasionally post a Toast message to notify the user of some information. I have this working fine, however the problem occurs when the user tries to open the app back up (and bring the app from 'RunningInBackground' back to the foreground. I have an 'infinite' loop, which does have a break out point, however it seems to lock out the Main thread and prevent the app from ever getting back to no longer being running in the background.

Here's a sample of the code that is running in my main xaml page:

    // The PositionChanged event is raised when new position data is available
    void geolocator_PositionChanged(Geolocator sender, PositionChangedEventArgs args)
    {
        CurrentPosition = args.Position;

        if (!App.RunningInBackground)
        {
            Dispatcher.BeginInvoke(() =>
            {
                // TODO: HANDLE POSITION CHANGES
                LatitudeTextBlock.Text = args.Position.Coordinate.Latitude.ToString("0.00");
                LongitudeTextBlock.Text = args.Position.Coordinate.Longitude.ToString("0.00");
            });
        }
        else
        {
            // ReadyToSend is a bool that is set further below, CheckingIfReadyToSend is a bool to prevent this bit of code from running more than once at a time
            if (!ReadyToSend && !CheckingIfReadyToSend )
            {
                CheckingIfReadyToSend = true;
                Dispatcher.BeginInvoke(() =>
                {

                    ReadyToSend = _viewModel.CheckIfNeedToStartNotifying();

                    if (ReadyToSend)
                    {
                        StartToastCycle(3);
                    }
                    CheckingIfReadyToSend = false;
                });

            }


        }
    }

private void StartToastCycle(int MaxNotifications)
    {
        while (App.RunningInBackground)
        {
            if (NotificationCount >= MaxNotifications || !App.RunningInBackground)
                break;
            if (NotificationCount < MaxNotifications && NotificationLastSent < DateTime.Now.AddMinutes(-2))
            {
                Microsoft.Phone.Shell.ShellToast toast = new Microsoft.Phone.Shell.ShellToast();
                toast.Content = "Test";
                toast.Title = "Test: ";
                toast.NavigationUri = new Uri("/Views/HomePage.xaml", UriKind.Relative);
                toast.Show();
                NotificationCount++;
                NotificationLastSent = DateTime.Now;
            }

            System.Threading.Thread.Sleep(10000);


        }
    }

So the above code works, it will fire off the StartToastCycle method when a certain condition is met and from then on it will send Toast Notifications every 2 minutes until it reaches MaxNotifications. The only problem is that if I tap the Toast notification to load the app from the background (before MaxNotifications condition is met), it stays stuck in that loop.

In the App.xaml.cs the Application_Activated event, where I set the bool IsRunningInBackground to false doesn't get hit.

Any ideas on how I can trigger the toast handler within the code but without locking out the main thread?

Any advice is greatly appreciated!

The answer is async !

You need to make StartToastCycle async , then have it await a Task.Delay for the amount of time.

private async void StartToastCycle(int MaxNotifications)
{
    while (App.RunningInBackground)
    {
        if (NotificationCount >= MaxNotifications || !App.RunningInBackground)
            break;
        if (NotificationCount < MaxNotifications && NotificationLastSent < DateTime.Now.AddMinutes(-2))
        {
            Microsoft.Phone.Shell.ShellToast toast = new Microsoft.Phone.Shell.ShellToast();
            toast.Content = "Test";
            toast.Title = "Test: ";
            toast.NavigationUri = new Uri("/Views/HomePage.xaml", UriKind.Relative);
            toast.Show();
            NotificationCount++;
            NotificationLastSent = DateTime.Now;
        }
        await Task.Delay(TimeSpan.FromSeconds(10));

    }
}

Now, I don't know if the toast needs to be sent on the UI thread. In the case that it does, you need to keep a copy of the Dispatcher object and invoke the toast on the UI thread (like you are doing in the top method). You may need to do some experimentation with this.

Hope that helps and happy coding!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM