iOS background thread slow down when UI is idle - c#

A bit of context first
I have a Xamarin app that essentially streams video from a remote server. I have a background thread that loops like this (pseudo-code):
private void UpdateMethod()
{
while (running)
{
bool success = WaitForUpdate();
if (!success)
{
break;
}
Update update = GetUpdate();
SendUpdateToConcurentQueue(update);
}
Disconnect();
}
I start the background thread like this:
Thread thread = new Thread(UpdateMethod);
thread.IsBackground = true;
thread.Start();
The issue
When I start the stream, everything is perfect. It's only after ~10 seconds of not interacting with the device that it becomes really slow. I've outputted the number of updates from the background thread, and they seem to come in a lot slower. I usually get around 2-6 updates to process per update (60fps). When it's super slow, I get 1 ever 6 update cycle.
One thing that puzzles me: When I pull down the iOS top bar menu, the updates go back up and the stream is suddenly back to normal speed. Update rate goes up for ~10 seconds and it goes back to lagging like crazy.
What I've tried
I tried to start a Dispatch queue with only this in it, like this:
DispatchQueue queue = new DispatchQueue("updateQueue");
queue.DispatchAsync(this.UpdateProcess);
It didn't seem to help at all.
I also tried to change the QualityOfService property in my update thread like this:
NSThread.Current.QualityOfService = NSQualityOfService.UserInitiated
Doesn't work either! It seems to me that iOS lowers my thread's priority for some reason. If I put a breakpoint in my UpdateMethod method, it's being hit when the app doesn't lag. But when there's lag, the breakpoint doesn't get hit. Now this really puzzles me, since the code still runs! I still receive the updates, it's just way slower...
Edit: I tested using Instruments and found that the network is being throttled... Investigating, but if anyone has knowledge of any kind of network throttle on iOS, let me know.

Try setting the IdleTimerDisabled to true, we do this all the time in iOS games to keep iOS from idling our games.
Note: We do this in a polite way only when the user is not touching the screen due to watching a replay, level changing multimedia segues, etc...
Note: Make sure that you do reset the idle when you do not need it (when you app does go in the background, etc...), as from killing battery and making users bummed out about your app to the real killer: Apple Store rejections
Apple: App Idle Timer info
Xamarin: UIKit.UIApplication.IdleTimerDisabled Property
The default value of this property is NO. When most apps have no touches as user input for a short period, the system puts the device into a "sleep” state where the screen dims. This is done for the purposes of conserving power. However, apps that don't have user input except for the accelerometer—games, for instance—can, by setting this property to YES, disable the “idle timer” to avert system sleep.
| IMPORTANT
You should set this property only if necessary and should be sure to reset it to NO when the need no longer exists. Most apps should let the system turn off the screen when the idle timer elapses. This includes audio apps. With appropriate use of Audio Session Services, playback and recording proceed uninterrupted when the screen turns off. The only apps that should disable the idle timer are mapping apps, games, or programs where the app needs to continue displaying content when user interaction is minimal.

Related

How to still have my app run when it is suspended because of lock screen and then wake the device

I have a Windows UWP app, targeting Windows 10 Mobile for the most part. This application monitors the user's foot traffic and when they are in or out of defined geofences. I then have a web back end that uses SignalR to send position data to/from the device.
The issue is with the lock screen. Let's say that the app is started and running but the user locks the device OR the setting option for timeout to lock the screen expires and the device locks. You could hit power, swipe to unlock and see that the app is still running. However, during the time it is locked, I assume that the app is suspended?
So, I am wondering first of all, what happens to my location updates while suspended? I use these to send the position update via SignalR to my hub but also check if they are in/out of a geofence. I am doing something like this:
_geolocator = new Geolocator { ReportInterval = 0, DesiredAccuracyInMeters = 10, MovementThreshold = 4};
// Subscribe to PositionChanged event to get updated tracking positions
_geolocator.PositionChanged += OnPositionChanged;
// Subscribe to StatusChanged event to get updates of location status changes
_geolocator.StatusChanged += OnStatusChanged;
I assume that when the lock screen has taken over and my app is suspended, I will no longer get my OnPositionChanged events? How is this handled with other things like turn by turn navigation where it will still track your location even if the app is suspended or the lock screen is on?
Also, second question is what to do with the SignalR connection? I would love to still be able to push out my location updates when the OnPositionChanged event fires like I do when the app is not suspended. Can I also do that?
I have read about the background tasks but it seems these only run at 15 minute intervals (unless I misunderstood and this is configurable). For my application, 15 minutes is far too long. The most I would want is 30 seconds or 1 minute.
By the way, yes I understand that all of this has serious implications on battery life. Let's assume that I am not concerned about battery life for this.
Thanks!
The issue is with the lock screen. Let's say that the app is started and running but the user locks the device OR the setting option for timeout to lock the screen expires and the device locks. You could hit power, swipe to unlock and see that the app is still running. However, during the time it is locked, I assume that the app is suspended?
When you minimizes an app Windows waits a few seconds to see whether the user will switch back to it. If you do not switch back within this time window, and no extended execution, background task, or activity sponsored execution is active, Windows suspends the app. An app is also suspended when the lock screen appears as long as no extended execution session, etc. is active in that app. For more detail you could refer to Windows 10 universal Windows platform (UWP) app lifecycle.
I assume that when the lock screen has taken over and my app is suspended, I will no longer get my OnPositionChanged events? How is this handled with other things like turn by turn navigation where it will still track your location even if the app is suspended or the lock screen is on?
For your requirement, you could run your app while minimized with ExtendedExecutionReason.LocationTracking. For example, if you want to realize turn by turn navigation, you could refer to the following code.
Specify ExtendedExecutionReason.LocationTracking when you create an ExtendedExecutionSession if your app needs to regularly log the location from the GeoLocator. Apps for fitness tracking and navigation that need to regularly monitor the user's location and should use this reason.
For more detail you could refer to Track the user's location and App Lifecycle - Keep Apps Alive with Background Tasks and Extended Execution.
private async void StartTbTNavigationSession()
{
using (var session = new ExtendedExecutionSession())
{
session.Reason = ExtendedExecutionReason.LocationTracking;
session.Description = "Turn By Turn Navigation";
session.Revoked += session_Revoked;
var result = await session.RequestExtensionAsync();
if (result == ExtendedExecutionResult.Denied
{
ShowUserWarning("Background location tracking not available");
}
// Do Navigation
var completionTime = await DoNavigationSessionAsync(session);
}
}

Visual C# Drawing graphics based on data via. USB

I am trying to draw graphics on a form application based on data from an externally connected USB device to my PC. my goal is to continuously uploading the data from USB device and updating the graphics like every 20ms.
First, I made the below two codes and put them in button_click function. Each time the button is clicked, they work fine.
uploadData(); // this uploads 2KB data from USB device connected to my PC
drawGraphics(); // this draws graphics on a picture box
So as next step, I put them in while infinite loop like below. But drawing does not work while data uploading from the USB device keeps running. I was probing the USB device hardware and I confirmed it keeps sending new data to my PC.
while(true)
{
uploadData();
drawGraphics();
}
I put Thread.Sleep() between the above codes and put various delay values to see if the problem is solved, but no success.
Interesting thing is that each time when I move mouse's cursor over the form, the drawing starts a bit but stops at early point.
This could be related to very simple mistake. I am kind of new to Visual C# so just hit this wall and not able to overcome it.
Usually the way to handle an occasional-update requirement in a GUI app is to use a timer. The timer runs on a background thread and notifies the main thread occasionally that a "tick" has occurred. This way, other operations like processing mouse and keyboard input, drawing to the screen, etc. can continue. I'm not entirely sure why your solution isn't working, but I'm 99% sure you can fix it by replacing the while loop with a System.Windows.Forms.Timer that ticks on the desired interval.
So, I recommend: adding a Windows Forms Timer to your form via the Visual Studio designer, setting its Interval property to the desired number of milliseconds, registering an event handler for the timer tick, moving the uploadData() call to that event handler, and moving the content of the drawGraphics() method to the PictureBox's Paint event.
Instead of having an infinite loop, create a timer control. Set the Interval to 20 (thats 20 ms). In the OnTick create an Method that:
1) Send the Enabled property of your timer to 'False'
2) Calls your upLoadData and drawGraphics methods
3) Sets the Enabled property of your timer to 'True'
This way you won't simultaneously try to access the data on the USB more than once at a time if for some reason the 1st occurence takes a little longer than expected.

WP8.1 Voice Recognition without rendering app

I have implemented voice commands in my Windows Phone 8.1 app, but I have run into 2 problems. The first problem, is that I would like to have the command execute without the app opening. I know it has to load the app to execute, but I'd like it to not be visible, or at least disappear when it is done. The voice command just causes a REST call to be executed and has no UI updating in the process. How can I make it not open/render the view?
Like you stated, it is not really possible.
You could instantly close the app and handle your request in the Suspension event handler using the referral.
But: You will still get the splash screen and is will probably be confusing for the user (why does that thing pop up?). Also, you cannot be sure how much time your suspension gets and if you are on a bad network connection, your rest call may fail.
It might be better to just show a confirmation/progress screen and have the user tab out himself.
Also: Be careful with sayings like just a REST call. If you are on a bad 2G connection or have some other network activity running, even a few kilobytes can take up some time.

How to show a scheduled dialog in a Windows Phone 8.1 Runtime app?

I'm trying to code a Timer-App with C# for Windows Phone 8.1 Runtime. My goal is to show a dialog and play a sound file when the timer is ended. If the user press "OK" the sound is stopped. Also a "Snooze" function would be great. Maybe not in this app, but I'm planning a personalized alarm clock too. Because I could add the TimeSpan for the timer to DateTime.Now it would be the easiest way to trigger at a specified time. Here are some ideas i had, but they don't do exactly what I want.
Register a background task. But there's no trigger for a specified
time. Only a TimeTrigger which fires at most every 30 min. A
solution, not very resource friendly, methinks, would be to look up
if the expected time is within the next 30 minutes and await the specified
time in the background task and use a ContantDialog. Not sure if this is possible at all.
Another possibility is to use a toast notification, but there is no
possibility of interaction and it is not very impressive, if you want
someone to notice the timer.
Alarms and Reminders are no longer available for RT apps...
Is there no other way? If there is a trigger for background tasks if internet connection is active, isn't there any trigger for a scheduled time? Or maybe a possibility to code something like the old Alarms and Reminders by myself?
Sorry that there is no code. But I don't have some useful code for this problem yet.
How would you solve this problem? Maybe for a timer, an alarm clock, a calender, a task reminder or something else that needs an interaction at a scheduled time. Thanks for your help.
The only real way to achieve this is with an Alarm, which (as you note) is Silverlight only.
For a runtime app a toast is closest, but isn't as alarmy. Once the user taps the toast (if at all) then it can launch the app for more detail. Toasts (especially when linked to a tile update) are good for calendar and task reminders, but if you want an alarm you really need the (Silverlight-only) Alarm API.
A Background Task cannot show any UI (other than raising a toast, which doesn't need the background task), so even if you could get the timing right it couldn't show the ContentDialog.

How to write AVI from a Callback, keep UI responsive and wait for completion

I have to use a camera SDK for a microscope that comes with a sample C# Windows Forms application.
The SDK functions are imported to the app via DLLImport.
In this sample application the single frames from the camera are read from RAM via a callback function.
This callback function then updates a PictureBox to show the live image.
For my useage however I want to not only show the frames, but also record them.
I think the easiest way to do this is by using SharpAvi.
However I don't know how to initialize the AviWriter (I obviously can't initialize it everytime the callback fires) and then add the single frames to the stream from the callback function.
At the moment I solved my problem by using another function that waits in a seperate thread for a public counter to go up - the counter itself is updated in the callback function.
Everytime the counter is updated this function then also reads the frame from RAM and adds it to the AviWriterStream.
To top it of I had to make the thread block my UI by using
var resetEvent = new ManualResetEvent(false);
System.Threading.ThreadPool.QueueUserWorkItem(delegate
{
WriteAVI()
resetEvent.Set();
}, null);
resetEvent.WaitOne();
This is due to the fact that I need to record several videos at different XY positions - so everytime my for loop arrives at a new XY position the recording is triggered and I have to make sure to only move to the next position once the recording is actually finished.
My way of doing this is obviously hackish and very bad practice (I already feel bad but just don't know better) and I am wondering what the correct solution would be.
So far it works - just the UI freeze is really annoying.
Edit: These are probably two questions:
1) How to correctly write frames to the AVI and
2) How to wait for the recording to be completed without making it freeze my UI

Categories