QNetworkAccessManager 一个实例和连接槽

Posted

技术标签:

【中文标题】QNetworkAccessManager 一个实例和连接槽【英文标题】:QNetworkAccessManager one instance and connecting slots 【发布时间】:2017-09-05 13:55:48 【问题描述】:

我的第一个 Qt 应用程序正在开发中。它是用于站点消息传递的桌面客户端。

Qt 文档说我只需要一个 QNetworkAccessManager 跨应用程序的实例。但我也读到在 Qt 中使用单例并不是一个好主意。我如何在应用程序中创建一个 QNetworkAccessManager 实例?

另一个问题是,当我从其他类调用 ApiHandler 函数时,如何正确连接插槽?

例如,我有 ExampleApi 类,它使用 ApiHandler 的功能,在 updateMessageList 插槽中 messagesListUpdated 应该被连接请求完成后更新视图中的消息列表,但它从未调用过。

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;

【问题讨论】:

您的经理在收到结果之前就超出了范围。 解决方案可以与QCoreApplicationqApp 相同:是的,它是一个单例,但它是一个您完全控制其生命周期的单例。 【参考方案1】:

QNetworkAccessManager sn-p的一个实例

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

【讨论】:

以上是关于QNetworkAccessManager 一个实例和连接槽的主要内容,如果未能解决你的问题,请参考以下文章

使用 QNetworkAccessManager 请求

如何恢复 QNetworkAccessManager

QNetworkAccessManager 一个实例和连接槽

离线使用 QNetworkAccessManager

QNetworkAccessManager 可以从不同的线程获取/发布吗?

错误:没有用于调用“QNetworkAccessManager::QNetworkAccessManager(Networking* const)”的匹配函数