(Android) Event loop stops on display sleep/screensaver
-
I'm working on a control application for an industrial device using a SBC platform (ODroid C4) running Android 9
The application communicates with the device over the network using a message queue (ZeroMQ) and uses a QTimer to poll the queue for incoming events, but the problem is that as soon as the display either goes to sleep/screen saver due to inactivity, that seems to cause Qt's event loop to stop running. Connecting to the
QApplication::applicationStateChanged
signal shows me that the application first goes to theApplicationInactive
state but then immediately goes to theApplicationSuspended
state which I'm guessing is the reason that the event loop stops. The device itself continues sending updates which get queued on the receiving end because ZeroMQ sockets run in a separate background thread that doesn't stop running, so when the screen then wakes up and the Qt event loop restarts, and it goes back to polling the receiver for incoming events, it receives all of them at once, which can cause anything from a few seconds of lag to freezing/crashing the app entirely depending on how long the screen was inactive and how many events have backed up in the queue.Is there any way to tell Qt or the OS to not pause the event loop when the display goes to sleep/screensaver - Is there any way in the Android app manifest or permissions API to tell the Android OS that the application should be allowed to continue running in the background? Alternatively is there any signal I can send back to the QApplication when it reaches the Inactive state that will prevent it from going to Suspended, or any way to send input to the application that will wake it back up?
I could potentially rework the device manager class which handles commands and events so that it could be spun off onto a separate thread. I'd prefer not to go this route if possible, since we've tried for simplicity's sake to keep the app single threaded, with the exception of a few long-running operations. All the classes managing the GUI objects invoke the methods on the device manager class directly to send device commands, and then when the poll timer listening for command responses/events gets incoming data, it passes that back to the GUI classes via Qt signals and/or lambda objects for success/error callbacks
- I know that QThreads run their own event loops - do those loops also stop when the screen is inactive or is that behavior specific to the main/GUI event loop? I'm assuming because the app is being flagged as 'Suspended' that means all QThreads will stop their event loops in which case this wouldn't solve the problem
- The examples for QThread primarily deal with using a thread to handle a single long-running or asynchronous operation as opposed to starting up a thread for a specific object which needs to handle multiple input/output commands over the life of the application - I know that Qt handles signal/slot connections across different threads transparently, but there are a LOT of possible outgoing commands to the device and many of them are used from multiple places within the GUI, so I'd prefer not to have to turn every one of those into a signal/slot connection, so it could turn into a messy multi-layer abstraction to allow the GUI classes to continue using direct method calls to invoke device commands but have those commands actually invoked via a different object on another thread