PDA

View Full Version : QNetworkAccessManager doesn't call finished signal



Swiftie
13th November 2014, 19:41
Howdy!
Trying to make GET request with Qt5 and get the response.
But slots never called and no network activity from application.
connect returns true.
Perhaps QNetworkAccessManager get destroyed after calling get method.

Give me explanation how it's works.

Thanks!

appapi.h


#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>

class AppApi : public QObject
{
Q_OBJECT
public:
explicit AppApi(QObject *parent = 0);
void makeRequest();
QNetworkAccessManager* manager;

signals:

public slots:
void replyFinished(QNetworkReply* reply);
void slotError(QNetworkReply::NetworkError error);
};

appapi.cpp


AppApi::AppApi(QObject *parent) :
QObject(parent)
{
this->manager = new QNetworkAccessManager(this);
}

void AppApi::makeRequest()
{
connect(this->manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));

QNetworkRequest request;
request.setUrl(QUrl("http://google.com"));

QNetworkReply *reply = this->manager->get(request);
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(slotError(QNetworkReply::NetworkError)));
}

void AppApi::replyFinished(QNetworkReply* reply)
{
qDebug("replyFinished");
}

void AppApi::slotError(QNetworkReply::NetworkError error)
{
qDebug("slotError");
}

anda_skoa
13th November 2014, 21:55
What does the rest of the program look like?
Where do you create an instance of AppApi and how long does it live?

Cheers,
_

Swiftie
13th November 2014, 23:08
anda_skoa, thanks for reply!

Oh it's my fault, 12 hours with PC is a bad thing :(

I forgot to create a new instance:


AppApi a;
a.makeRequest();

Here the "solution".


AppApi *a = new AppApi;
a->makeRequest();


Some questions.
- How i can make async requests and return response without creating new instances for AppApi? (static functions?)
For example, i have a class UserApi which inherits AppApi and i need able to use makeRequest().

- Should i use deleteLater() after i process request response?

Thanks

anda_skoa
14th November 2014, 09:36
Some questions.
- How i can make async requests and return response without creating new instances for AppApi? (static functions?)

You will always need an instance of the network access manager.
And you will need some object instance for the slots.

So a static method could create a network access manager, initiate the request, return both the manager and the reply and the caller could connect to its own slot.
But the only thing you "safe" is the line that creates the manager, the two lines that create the request and the get() call.

Why is creating an object of the Api class something you don't want to do?
Sounds like common delegation to me.



For example, i have a class UserApi which inherits AppApi and i need able to use makeRequest().

Well, in this case the UserApi object is an instance of AppApi.



- Should i use deleteLater() after i process request response?

Yes.

Cheers,
_

Swiftie
14th November 2014, 12:26
Thanks for reply,
Here the some changes i made

void AppApi::replyFinished(QNetworkReply* reply)
{
qDebug() << "replyFinished" << reply;
reply->deleteLater();
}
Here the UserApi class:

#include "../appapi.h"

class UserApi : public AppApi
{
public:
UserApi();
void sendMessage();
};



#include "userapi.h"

UserApi::UserApi()
{
}

QString UserApi::sendMessage()
{
// Processing content, etc
AppApi api;
api.makeRequest();
}

Somewhere in code


UserApi *c = new UserApi;
c->sendMessage();

Raises Segmentation fault.
I know it's a lame code, but after 2 years of Python i forgot even a basics of C++ and it's my first project in Qt.

Can you explain how properly i make request from UserApi (for example) and return response.

Best regards

anda_skoa
14th November 2014, 13:53
UserApi is derived from AppApi, it is an instance of AppApi, just like in Python.

So just call the implementation of the base class


QString UserApi::sendMessage()
{
makeRequest(); // method of base class AppApi.

// return missing here. this is not a void method
}


Also make sure you connect the manager's finished() signal only once, e.g. right after you create the manager.

Cheers,
_

Swiftie
14th November 2014, 16:53
Thanks, i figured out.

And the last question, it's how to properly return the response?
I know how to "return" response in synchronous mode (using QEventLoop), but i need to implement returning response from async requests.
Here the "example"


UserApi *c = new UserApi;
QJsonDocument j = QJsonDocument::fromJson(c->sendMessage(..parameters here..)); // c->sendMessage needs to return response from GET request


Best regards

anda_skoa
14th November 2014, 17:29
You get the data in replyFinished() from the QNetworkReply object.

Then you send it in a signal of your class if you want to handle it outside that object or call a virtual method that you implement in UserApi.

Returning is inherently synchronous.

Cheers,
_