summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFawzi Mohamed <fawzi.mohamed@digia.com>2014-09-02 14:22:44 +0200
committerFawzi Mohamed <fawzi.mohamed@digia.com>2014-09-03 11:22:42 +0200
commitfd8217473be28dc714e0172420b32949d7e6b037 (patch)
tree86f8bc5abf3d6e7e5ff303124ae50a6ca7492c2a
parent053d10d6b4e226b2b1a4ddd5df1e462d656fb74d (diff)
downloadqtlocation-5.3.tar.gz
weatherinfo: improve update behavior of weatherinfo example5.3
Ensure that new data will get processed, and that error can be recovered, while avoiding an excessive load on the server. Change-Id: I1c3a0b17eb0cc31553013e953d7dcf46060daef1 Reviewed-by: Alex Blasche <alexander.blasche@digia.com>
-rw-r--r--examples/positioning/weatherinfo/appmodel.cpp81
-rw-r--r--examples/positioning/weatherinfo/appmodel.h2
-rw-r--r--examples/positioning/weatherinfo/main.cpp2
3 files changed, 75 insertions, 10 deletions
diff --git a/examples/positioning/weatherinfo/appmodel.cpp b/examples/positioning/weatherinfo/appmodel.cpp
index 30d990d4..f5d50c7e 100644
--- a/examples/positioning/weatherinfo/appmodel.cpp
+++ b/examples/positioning/weatherinfo/appmodel.cpp
@@ -52,8 +52,10 @@
#include <QJsonObject>
#include <QJsonArray>
#include <QStringList>
+#include <QTimer>
#include <QUrlQuery>
#include <QElapsedTimer>
+#include <QLoggingCategory>
/*
*This application uses http://openweathermap.org/api
@@ -61,6 +63,8 @@
#define ZERO_KELVIN 273.15
+Q_LOGGING_CATEGORY(requestsLog,"wapp.requests")
+
WeatherData::WeatherData(QObject *parent) :
QObject(parent)
{
@@ -131,8 +135,10 @@ void WeatherData::setTemperature(const QString &value)
class AppModelPrivate
{
public:
+ static const int baseMsBeforeNewRequest = 5 * 1000; // 5 s, increased after each missing answer up to 10x
QGeoPositionInfoSource *src;
QGeoCoordinate coord;
+ QString longitude, latitude;
QString city;
QNetworkAccessManager *nam;
QNetworkSession *ns;
@@ -144,6 +150,10 @@ public:
bool ready;
bool useGps;
QElapsedTimer throttle;
+ int nErrors;
+ int minMsBeforeNewRequest;
+ QTimer delayedCityRequestTimer;
+ QTimer requestNewWeatherTimer;
AppModelPrivate() :
src(NULL),
@@ -151,8 +161,16 @@ public:
ns(NULL),
fcProp(NULL),
ready(false),
- useGps(true)
- {}
+ useGps(true),
+ nErrors(0),
+ minMsBeforeNewRequest(baseMsBeforeNewRequest)
+ {
+ delayedCityRequestTimer.setSingleShot(true);
+ delayedCityRequestTimer.setInterval(1000); // 1 s
+ requestNewWeatherTimer.setSingleShot(false);
+ requestNewWeatherTimer.setInterval(20*60*1000); // 20 min
+ throttle.invalidate();
+ }
};
static void forecastAppend(QQmlListProperty<WeatherData> *prop, WeatherData *val)
@@ -200,6 +218,12 @@ AppModel::AppModel(QObject *parent) :
this, SLOT(handleWeatherNetworkData(QObject*)));
connect(d->forecastReplyMapper, SIGNAL(mapped(QObject*)),
this, SLOT(handleForecastNetworkData(QObject*)));
+ connect(&d->delayedCityRequestTimer, SIGNAL(timeout()),
+ this, SLOT(queryCity()));
+ connect(&d->requestNewWeatherTimer, SIGNAL(timeout()),
+ this, SLOT(refreshWeather()));
+ d->requestNewWeatherTimer.start();
+
//! [1]
// make sure we have an active network session
@@ -253,17 +277,27 @@ void AppModel::positionUpdated(QGeoPositionInfo gpsPos)
if (!(d->useGps))
return;
- QString latitude, longitude;
- longitude.setNum(d->coord.longitude());
- latitude.setNum(d->coord.latitude());
+ queryCity();
+}
//! [3]
+void AppModel::queryCity()
+{
//don't update more often then once a minute
//to keep load on server low
- if (d->throttle.isValid() && d->throttle.elapsed() < 1000*10 ) {
+ if (d->throttle.isValid() && d->throttle.elapsed() < d->minMsBeforeNewRequest ) {
+ qCDebug(requestsLog) << "delaying query of city";
+ if (!d->delayedCityRequestTimer.isActive())
+ d->delayedCityRequestTimer.start();
return;
}
- d->throttle.restart();
+ qDebug(requestsLog) << "requested query of city";
+ d->throttle.start();
+ d->minMsBeforeNewRequest = (d->nErrors + 1) * d->baseMsBeforeNewRequest;
+
+ QString latitude, longitude;
+ longitude.setNum(d->coord.longitude());
+ latitude.setNum(d->coord.latitude());
QUrl url("http://api.openweathermap.org/data/2.5/weather");
QUrlQuery query;
@@ -271,6 +305,7 @@ void AppModel::positionUpdated(QGeoPositionInfo gpsPos)
query.addQueryItem("lon", longitude);
query.addQueryItem("mode", "json");
url.setQuery(query);
+ qCDebug(requestsLog) << "submitting request";
QNetworkReply *rep = d->nam->get(QNetworkRequest(url));
// connect up the signal right away
@@ -281,6 +316,7 @@ void AppModel::positionUpdated(QGeoPositionInfo gpsPos)
void AppModel::positionError(QGeoPositionInfoSource::Error e)
{
+ Q_UNUSED(e);
qWarning() << "Position source error. Falling back to simulation mode.";
// cleanup insufficient QGeoPositionInfoSource instance
d->src->stopUpdates();
@@ -294,13 +330,30 @@ void AppModel::positionError(QGeoPositionInfoSource::Error e)
this->refreshWeather();
}
+void AppModel::hadError(bool tryAgain)
+{
+ qCDebug(requestsLog) << "hadError, will " << (tryAgain ? "" : "not ") << "rety";
+ d->throttle.start();
+ if (d->nErrors < 10)
+ ++d->nErrors;
+ d->minMsBeforeNewRequest = (d->nErrors + 1) * d->baseMsBeforeNewRequest;
+ if (tryAgain)
+ d->delayedCityRequestTimer.start();
+}
+
void AppModel::handleGeoNetworkData(QObject *replyObj)
{
QNetworkReply *networkReply = qobject_cast<QNetworkReply*>(replyObj);
- if (!networkReply)
+ if (!networkReply) {
+ hadError(false); // should retry?
return;
+ }
if (!networkReply->error()) {
+ d->nErrors = 0;
+ if (!d->throttle.isValid())
+ d->throttle.start();
+ d->minMsBeforeNewRequest = d->baseMsBeforeNewRequest;
//convert coordinates to city name
QJsonDocument document = QJsonDocument::fromJson(networkReply->readAll());
@@ -308,19 +361,25 @@ void AppModel::handleGeoNetworkData(QObject *replyObj)
QJsonValue jv = jo.value(QStringLiteral("name"));
const QString city = jv.toString();
+ qCDebug(requestsLog) << "got city: " << city;
if (city != d->city) {
- if (!d->throttle.isValid())
- d->throttle.start();
d->city = city;
emit cityChanged();
refreshWeather();
}
+ } else {
+ hadError(true);
}
networkReply->deleteLater();
}
void AppModel::refreshWeather()
{
+ if (d->city.isEmpty()) {
+ qCDebug(requestsLog) << "refreshing weather skipped (no city)";
+ return;
+ }
+ qCDebug(requestsLog) << "refreshing weather";
QUrl url("http://api.openweathermap.org/data/2.5/weather");
QUrlQuery query;
@@ -342,6 +401,7 @@ static QString niceTemperatureString(double t)
void AppModel::handleWeatherNetworkData(QObject *replyObj)
{
+ qCDebug(requestsLog) << "got weather network data";
QNetworkReply *networkReply = qobject_cast<QNetworkReply*>(replyObj);
if (!networkReply)
return;
@@ -393,6 +453,7 @@ void AppModel::handleWeatherNetworkData(QObject *replyObj)
void AppModel::handleForecastNetworkData(QObject *replyObj)
{
+ qCDebug(requestsLog) << "got forecast";
QNetworkReply *networkReply = qobject_cast<QNetworkReply*>(replyObj);
if (!networkReply)
return;
diff --git a/examples/positioning/weatherinfo/appmodel.h b/examples/positioning/weatherinfo/appmodel.h
index 16297236..caa8b7d4 100644
--- a/examples/positioning/weatherinfo/appmodel.h
+++ b/examples/positioning/weatherinfo/appmodel.h
@@ -132,6 +132,7 @@ public:
bool hasValidCity() const;
bool hasValidWeather() const;
void setUseGps(bool value);
+ void hadError(bool tryAgain);
QString city() const;
void setCity(const QString &value);
@@ -144,6 +145,7 @@ public slots:
//! [2]
private slots:
+ void queryCity();
void networkSessionOpened();
void positionUpdated(QGeoPositionInfo gpsPos);
void positionError(QGeoPositionInfoSource::Error e);
diff --git a/examples/positioning/weatherinfo/main.cpp b/examples/positioning/weatherinfo/main.cpp
index 6afcf1c4..95303934 100644
--- a/examples/positioning/weatherinfo/main.cpp
+++ b/examples/positioning/weatherinfo/main.cpp
@@ -43,12 +43,14 @@
#include <QtQml/QQmlEngine>
#include <QtQml/QQmlContext>
#include <QtQuick/QQuickItem>
+#include <QLoggingCategory>
//! [0]
#include "appmodel.h"
int main(int argc, char *argv[])
{
+ QLoggingCategory::setFilterRules("wapp.*.debug=false");
QGuiApplication application(argc, argv);
qmlRegisterType<WeatherData>("WeatherInfo", 1, 0, "WeatherData");