I have my first Qt application in development. It's a desktop client for site messaging.
Qt documentation says that i need to have only one instance of QNetworkAccessManager accross application. But i also read that using of singletons with Qt isn't a good idea. How i can make one instance of QNetworkAccessManager across app?
Another question is how to properly connect slots while i call ApiHandler functions from other classes?
For example i have ExampleApi class which uses functions of ApiHandler, in updateMessageList slot messagesListUpdated should be connected after request finished to update message list in view, but it never called.
ExampleApi.h
...
#include "apihandler.h"
class ExampleApi : public QObject
{
Q_OBJECT
public:
explicit ExampleApi(QObject *parent = 0);
void updateMessagesList();
signals:
public slots:
void messagesListUpdated(QNetworkReply* reply);
};
ExampleApi.cpp
ExampleApi::ExampleApi(QObject *parent) :
QObject(parent)
{
}
void ExampleApi::updateMessagesList()
{
QMap<QString, QString> m;
m["user_id"] = ConfigParser::settings.value(USER_ID).toString();
QNetworkAccessManager nam;
ApiHandler a(&nam);
// Connect a slot
connect(a.getManager(), SIGNAL(finished(QNetworkReply*)), this, SLOT(messagesListUpdated(QNetworkReply*)));
a.makeRequest("messages.get", m);
}
void ExampleApi::messagesListUpdated(QNetworkReply* reply)
{
QJsonDocument j = QJsonDocument::fromJson(reply->readAll());
QJsonObject getjson = j.object();
qDebug() << "ExampleApi::messagesListUpdated()" << getjson;
reply->deleteLater();
// ...
}
ApiHandler.h
class ApiHandler : public QObject
{
Q_OBJECT
public:
explicit ApiHandler(QNetworkAccessManager *nam, QObject *parent = 0);
~ApiHandler();
QNetworkReply* makeRequest(QString method, QMap<QString, QString> parameters);
QNetworkAccessManager* getManager();
private:
QUrl buildCall(QString method, QMap<QString, QString> parameters);
QNetworkAccessManager* manager;
signals:
public slots:
void replyFinished(QNetworkReply* reply);
void slotReadyRead();
void slotError(QNetworkReply::NetworkError error);
void slotSslErrors(QList<QSslError> errorList);
};
ApiHandler.cpp
#include "apihandler.h"
ApiHandler::ApiHandler(QNetworkAccessManager *nam, QObject *parent) :
QObject(parent), manager(nam)
{
Q_ASSERT(manager);
}
ApiHandler::~ApiHandler()
{
manager->deleteLater();
}
QUrl ApiHandler::buildCall(QString method, QMap<QString, QString> parameters)
{
QUrl url = QUrl(API_URL + method);
QUrlQuery query;
ConfigParser c;
// Append first access_token
query.addQueryItem("access_token", c.settings.value(ACCESS_TOKEN_KEY).toString());
if (!parameters.isEmpty()) {
QMapIterator<QString, QString> i(parameters);
while (i.hasNext()) {
i.next();
query.addQueryItem(i.key(), i.value());
}
}
url.setQuery(query.query());
return url;
}
QNetworkReply* ApiHandler::makeRequest(QString method, QMap<QString, QString> parameters)
{
QUrl url = this->buildCall(method, parameters);
//qDebug() << "ApiHandler::makeRequest: " << url;
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
QNetworkRequest request;
request.setUrl(url);
request.setRawHeader("User-Agent", "Site-Client");
QNetworkReply *reply = manager->get(request);
connect(reply, SIGNAL(readyRead()), this, SLOT(slotReadyRead()));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(slotError(QNetworkReply::NetworkError)));
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(slotSslErrors(QList<QSslError>)));
return reply;
}
void ApiHandler::replyFinished(QNetworkReply* reply)
{
qDebug() << "ApiHandler::replyFinished:" << reply->url();
QJsonDocument j = QJsonDocument::fromJson(reply->readAll());
if (j.isEmpty()) {
// throw error
qDebug("ApiHandler::replyFinished(...) j.isEmpty :(");
} else {
qDebug() << "ApiHandler::replyFinished(...)" << j;
}
reply->deleteLater();
}
void ApiHandler::slotReadyRead()
{
//qDebug("slotReadyRead");
}
void ApiHandler::slotError(QNetworkReply::NetworkError error)
{
qWarning() << "raised error:" << error;
}
void ApiHandler::slotSslErrors(QList<QSslError> errorList)
{
qWarning() << "raised sslErrors" << errorList;
}
QNetworkAccessManager* ApiHandler::getManager()
{
return this->manager;
}
QCoreApplication
andqApp
: yes, it's a singleton, but it's a singleton whose lifetime you fully control. – Stalinism