QNetworkAccessManager doesn't emit finished without blocking current thread
-
in some of my methods:
@connect(nwam, SIGNAL(finished(QNetworkReply*)) , this, SLOT(processReply(QNetworkReply*)) );@processReply is @QByteArray ba = r->readAll();
qDebug() << ba;@finished signal emits only if i do
@
QEventLoop eventLoop;
connect(nwam, SIGNAL(finished(QNetworkReply *)), &eventLoop, SLOT(quit()));
eventLoop.exec();
@
But it will block main thread.So, what I am doing wrong? -
Hi, and welcome to the Qt Dev Net!
Which thread does your QNAM live in?
Which thread runs processReply?
How did you create + start your threads?
-
i don't use my own threads, i do all the things inside main thread because , as i can see, QNAM is async by design
[quote author="JKSH" date="1396218189"]Hi, and welcome to the Qt Dev Net!Which thread does your QNAM live in?
Which thread runs processReply?
How did you create + start your threads?[/quote]
-
QNAM itself is async, but signal delivery relies on a working event loop.
Qt is event driven, so you should be running all your code inside an event loop, especially if you want to receive events and fire slots.
Don't think in terms "my program runs code from top to bottom but hangs at exec(). You should rather think "my program spins inside exec() and notifies me via slots and event handlers when something happens". -
To add to Chris: Your main thread needs a running event loop in order for QNAM to work. That means you must call QCoreApplication::exec() -- or else no signals and slots will be processed.
-
So, do you mean that i have to write something like this?
@
nwam->get(request);
connect(nwam, SIGNAL(finished(QNetworkReply)) , this, SLOT(processTaskListsReply(QNetworkReply*)) );QEventLoop eventLoop;
connect(nwam, SIGNAL(finished(QNetworkReply *)), &eventLoop, SLOT(quit()));
eventLoop.exec();
@ -
then you should not need a second QEventLoop (QApplication already has a QEventLoop internally), that might be the problem why your signals and slots are not working as they should.
The QApplication is usually a global object in your application, you can access it with the global pointer qApp from anywhere if you need to.So it should not matter if you create the QNAM from your Dialog or in the main.cpp or whatever, you don't need to create a QEventLoop yourself for it to work.
-
Hard to tell with the information you gave. Maybe you're deleting the receiving object before the finish signal fires? And since you put additional blocking exec() it works.
Some more context and code would be helpful. -
@
QNetworkAccessManager *nwam = new QNetworkAccessManager();
QNetworkRequest request = new QNetworkRequest(QUrl(listUrl));
request->setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
nwam->get(request);
connect(nwam, SIGNAL(finished(QNetworkReply)) , this, SLOT(processTaskListsReply(QNetworkReply)) );@
@
processTaskListsReply(QNetworkReply *r)
{
qDebug() << "processTaskListsReply();";
QByteArray ba = r->readAll();
qDebug() << ba;
}
@ -
I meant the context of it. Where is it created. What is the lifetime of the object it holds these. Where is the nwam deleted etc.
-
it almost looks like you create a new QNetworkAccessManager for every request? hard to tell from your snippet but that is not a very good idea.
If you read the doc of QNAM it says one object per app should be sufficient in most cases, so usually you have one global QNAM and there is no need to create it on the heap (with new).
What I would do, if you onyl have one Dialog in your app then just create an object in there:
@
class Dialog : public QDialog
{
Q_OBJECT
private:
QNetworkAccessManager m_networkManager;
};
@
and then connect the signals of m_networkManager in the constructor of the Dialog only once and reuse the QNAM for all requests. Unless you only need the QNAM in rare cases this would be a better way I think. -
You don't have to use only one instance, but it would be considered best practice to only have one, because the QNAM initialization might be expensive and it also caches many things like DNS resolution etc, if you create a new one every time that cache will be lost and network requests take longer.
There was a nice talk about it, if you want take a look I found it very interesting. "QtDD13 - Peter Hartmann - Speeding up your Qt app with new QtNetwork features":https://www.youtube.com/watch?v=OM9BgcXr9ys&list=LLa69qk-_WIRna0JNQf8Md0w. -
Singleton may be not so good idea, i found this
@
DbHandler* dbHandler = new DbHandler;// Make your DbHandler* globally accessible by settings it as a // dynamic property of the application object. application.setProperty("dbHandler", QVariant::fromValue<DbHandler*>(dbHandler)); ....
}
void SomeObject::someMethod()
{
DbHandler* dbHandler = qApp->property("dbHandler").value<DbHandler*>();
}
@But... what if i wand to split a part of my app as library later, then i will get dependency injection: users will have to give QNAM instance to my constructor, is it right way?