Work with the timer in Sailfish OS on long time intervals
Introduction
Quite often, with the implementation of any logic in the application, there is a need to trigger some function after a certain period of time. The most obvious example of this need is the timer application. For example, cooktimer or Saildoro .
As mentioned in a previous article, you can use a standard element
Timer
or its C ++ equivalent to add a timer to an application on Sailfish OS QTimer
. However, by default, the operation of these timers is suspended for long periods of time due to the fact that the device can go into "sleep". The developers of the two applications mentioned above have just encountered this problem.This article presents a standard for the system, but unfortunately an undocumented way to handle this behavior of Sailfish OS.
starting point
As a starting point, an “abstract” application for Sailfish OS will be considered, in which some functionality needs to be triggered after a long period of time. At the same time, the timer operation is described not in the QML code, but in a class in C ++:
Header
classTimerWrapper :public QObject
{
Q_OBJECT
public:
// Конструктор и деструкторexplicitTimerWrapper(QObject *parent = 0);
~TimerWrapper();
Q_INVOKABLE voidstart(int interval); // Метод для запуска таймераQ_INVOKABLE voidstop(); // Метод для остановки таймера
signals:
voidpomodoroFinished(int start, int end); // Сигнал остановки таймераvoidactiveChanged(); // Сигнал смены состояния таймераprivate:
QTimer *_timer; // Объект таймераint _startTime; // Время запуска таймера
};
Source
#include"timerwrapper.h"/**
* Конструктор таймера.
*/
TimerWrapper::TimerWrapper(QObject *parent) : QObject(parent) {
_timer = new QTimer(this); // Создание объекта таймера
_timer->setSingleShot(true); // Отключение автоматического возобновления таймера// После остановки таймера посылаются сигналы смены состояния и завершения работы
connect(_timer, &QTimer::timeout, [=]() {
emit activeChanged();
eemit pomodoroFinished(_startTime, QDateTime::currentDateTime().toMSecsSinceEpoch());
});
}
/**
* Деструктор таймера.
*/
TimerWrapper::~TimerWrapper() {
delete _timer;
_timer = nullptr;
}
/**
* Метод для начала работы таймера.
* @:param: interval - длительность работы таймера в миллисекундах
*/void TimerWrapper::start(int interval) {
_startTime = QDateTime::currentMSecsSinceEpoch(); // Сохранение времени начала
_timer->start(interval); // Запуск таймераemit activeChanged(); // Сигнал о смене состояния таймера
}
/**
* Метод для остановки таймера.
*/void TimerWrapper::stop() {
_timer->stop(); // Остановка таймераemit activeChanged(); // Сигнал о смене состояния
}
An object of this class must be registered in QML:
main.cpp
#ifdef QT_QML_DEBUG#include<QtQuick>#endif#include<QGuiApplication>#include<QQmlContext>#include<QQuickView>#include<QScopedPointer>#include<sailfishapp.h>#include"timerwrapper.h"intmain(int argc, char *argv[]){
// Создание объекта приложения
QScopedPointer<QGuiApplication> application(SailfishApp::application(argc, argv));
// Создание объекта для отображения интерфейса
QScopedPointer<QQuickView> view(SailfishApp::createView());
// Создание объекта таймера
QScopedPointer<TimerWrapper> timer(new TimerWrapper(view.data()));
// Регистрация объекта таймера
view->rootContext()->setContextProperty("timer", timer.data());
// Объявление пути к стартовому QML-файлу
view->setSource(SailfishApp::pathTo("qml/harbour-application.qml"));
// Отображение интерфейса
view->show();
// Запуск приложенияreturn application->exec();
}
With this approach, as mentioned in the introduction, there can be a suspension of the timer operation over long time intervals.
Decision
The first option to prevent the timer from falling asleep was proposed in the developer mailing list and caught on in the cooktimer application. Here it is proposed to explicitly start an additional timer, which calls the D-Bus method once a minute
req_display_cancel_blanking_pause
to prevent the device from falling asleep. It is obvious that such an implementation is not optimal and cumbersome. First, when using this approach, the device battery discharges faster. Secondly, a minor code appears in the project that can be avoided. And you can avoid the use of secondary code because Sailfish OS already provides two possible solutions to the problem posed: the elements
ScreenBlank
and KeepAlive
.Using the first approach involves a constantly active screen. This is a working but straightforward approach that actively consumes the device’s battery. Thus, it can be used, but in a limited circle of situations.
import QtQuick 2.0// Подключение модуля для поддержки стандартных элементов QMLimport Sailfish.Silica 1.0// Подключение модуля для поддержки Sailfish OS UIimport Sailfish.Media 1.0// Подключение модуля для поддержки элемента ScreenBlank
ApplicationWindow // Объявление главного окна приложения
{
initialPage: Component { FirstPage { } } // Объявление главной страницы приложения
cover: Qt.resolvedUrl("cover/CoverPage.qml") // Объявление обложки приложения
ScreenBlank { // Объявление элемента для предотвращения засыпания устройства
id: screenBlank // Идентификатор для обращения
suspend: true// Экран постоянно активирован
}
}
In turn, the use of the element
KeepAlive
is a more democratic approach. It consumes less battery power, as it does not keep the device screen constantly on, and at the same time, either does not allow the device to go into a deep sleep, or “wakes” it at a certain point in time, thanks to which the timer will continue to work and long periods of time.import QtQuick 2.0// Подключение модуля для поддержки стандартных элементов QMLimport Sailfish.Silica 1.0// Подключение модуля для поддержки Sailfish OS UIimport org.nemomobile.keepalive 1.1// Подключение модуля для поддержки элемента KeepAlive
ApplicationWindow // Объявление главного окна приложения
{
initialPage: Component { FirstPage { } } // Объявление главной страницы приложения
cover: Qt.resolvedUrl("cover/CoverPage.qml") // Объявление обложки приложения
KeepAlive { // Объявление элемента для предотвращения засыпания устройства
id: keepAlive // Идентификатор для обращения
enabled: true// Устройство не уходит в глубокий сон
}
}
It is worth noting that, in principle, the work of all three of these methods is a regular appeal to the system methods of D-Bus, which was discussed in a previous article.
Conclusion
As part of this short note, three possible ways to prevent the device from deep falling asleep are described. It can be concluded that for background tasks (for example, a timer) it is optimal to use an element
KeepAlive
, and if there is a need to constantly display information to the user, then ScreenBlank
.