2017-09-05 6 views
1

J'ai ma première application Qt en développement. C'est un client de bureau pour la messagerie de site.QNetworkAccessManager une instance et des slots de connexion

La documentation de Qt indique que je n'ai besoin que d'une seule instance de QNetworkAccessManager en regard de l'application. Mais j'ai aussi lu que l'utilisation de singletons avec Qt n'est pas une bonne idée. Comment puis-je faire une instance de QNetworkAccessManager à travers l'application?

Une autre question est de savoir comment connecter correctement les slots alors que j'appelle ApiHandler fonctions d'autres classes?

Par exemple, j'ai ExampleApi classe qui utilise les fonctions de ApiHandler, dans updateMessageList fente messagesListUpdated doit être connecté après demande terminé la mise à jour la liste des messages en vue, mais il n'a jamais appelé.

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; 
} 
+1

Votre gestionnaire est hors de portée avant que le résultat est reçu. – m7913d

+1

La solution peut être la même qu'avec 'QCoreApplication' et' qApp': oui, c'est un singleton, mais c'est un singleton dont vous contrôlez entièrement la durée de vie. –

Répondre

1

Une instance de QNetworkAccessManager snippet

QNetworkAccessManager* getManager() { 
    static QNetworkAccessManager* nam = new QNetworkAccessManager; 
    return nam; 
}