×
Namespaces

Variants
Actions

Why does QML require QDeclarativeNetworkAccessManagerFactory

From Nokia Developer Wiki
Jump to: navigation, search

This article explains why QML requires QDeclarativeNetworkAccessManagerFactory.

Introduction

Developers who study QML have seen and tried to understand why the QML engine requires the QDeclarativeNetworkAccessManagerFactory class. The reference manual says that this class is needed because it "creates QNetworkAccessManager instances for a QML engine with specialized caching, proxy and cookies support".

So the question is: "Why does QML need more than one QNetworkAccessManager instances"? In this article we will take a look a one example that will answer to this question, let's get started.

How many QNetworkAccessManager does my QML application needs?

Before to look for an answer, let's take a look at the QNetworkAccessManager documentation, in order to understand what QNetworkAccessManager does.

The documentation states that "The QNetworkAccessManager class allows the application to send network requests and receive replies." it even "holds the common configuration and settings for the requests it sends. It contains the proxy and cache configuration, as well as the signals related to such issues, and reply signals that can be used to monitor the progress of a network operation."

At the end the documentation says that "One QNetworkAccessManager should be enough for the whole Qt application". Okay it says "SHOULD". So the question is still up!

So, let's take a look at the following example to get an answer.

The QML application below shows an image (Qt logo fetched from internet) and a button. Clicking the button the javascript fetches IP address from a website (a text file) and displays it in the window. Basically this application performs two "GET" HTTP requests, which means that internally the QML engine calls two times QNetworkAccessManager::get().

import QtQuick 1.0
 
Rectangle {
width: 400; height: 250
 
WorkerScript {
id: myWorker
source: "worker.js"
 
onMessage: {
textbox.text = messageObject.response
}
}
 
Text {
id: textbox
text: "Click the rectangle to know your IP address"
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
}
 
Rectangle {
width: 100; height: 100
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: 50
color: "red"
MouseArea {
anchors.fill: parent
onClicked: myWorker.sendMessage( { url: "http://www.gnuton.org/ip.php" } );
}
 
Text {
text: "Click me"
}
}
 
Image {
width: 100
height: 100
anchors.left: parent.left
source: "http://qt.nokia.com/logo.png"
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 50
 
}
}
WorkerScript.onMessage = function(message) {
xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", message.url, true);
console.log("Fetching " + message.url)
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4) {
WorkerScript.sendMessage( {response: xmlhttp.responseText} );
}
}
xmlhttp.send(null)
}

The question now is: "Does the QML Engine use the same QNetworkAccessManager instance for both GET requests?" To understand that let's add to our application QDeclarativeNetworkAccessManagerFactory.

class MyNetworkAccessManagerFactory : public QDeclarativeNetworkAccessManagerFactory
{
public:
virtual QNetworkAccessManager *create(QObject *parent);
};
QNetworkAccessManager *MyNetworkAccessManagerFactory::create(QObject *parent)
{
QNetworkAccessManager *nam = new QNetworkAccessManager(parent);
qDebug() << nam;
if (!proxyHost.isEmpty()) {
qDebug() << "Created QNetworkAccessManager using proxy" << (proxyHost + ":" + QString::number(proxyPort));
QNetworkProxy proxy(QNetworkProxy::HttpCachingProxy, proxyHost, proxyPort);
nam->setProxy(proxy);
}
return nam;
}
 
int main(int argc, char **argv)
{
QUrl source("qrc:/main.qml");
QApplication app(argc, argv);
 
QDeclarativeView view;
view.engine()->setNetworkAccessManagerFactory(new MyNetworkAccessManagerFactory);
view.setSource(source);
view.show();
return app.exec();
}

As explained before the factory creates QNetworkManager instances; If we run again this application we see that the application makes use of two different access managers. In few words, a single instance is not enough. This happens because we have used a QML Worker script element that runs the JS code in WorkerScript.onMessage in another thread.

Conclusion

Each thread requires a QNetworkManager; The QML engine needs QDeclarativeNetworkAccessManagerFactory to create on demand these instances for various threads where JS can run.

Article Metadata
Compatibility
Platform(s): Symbian, Maemo, MeeGo
Symbian
Dependencies: Qt 4.8
Article
Keywords: Qt, QML, QNetworkAccessManager
Created: gnuton (29 Jun 2011)
Last edited: hamishwillee (11 Oct 2012)
This page was last modified on 11 October 2012, at 04:19.
66 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×