Consider the following piece of code, which fetches an RSS feed and then displays the images within as a slideshow which loops forever:
import QtQuick 2.2
import QtQuick.XmlListModel 2.0
Rectangle {
id: window
color: "black"
width: 800
height: 480
PathView {
anchors.fill: parent
highlightRangeMode: PathView.StrictlyEnforceRange
preferredHighlightBegin: 0.5
preferredHighlightEnd: 0.5
highlightMoveDuration: 500
snapMode: PathView.SnapOneItem
pathItemCount: 3 // only show previous, current, next
path: Path { // horizontal
startX: -width; startY: height/2
PathLine{x: width*2; y: height/2}
}
model: XmlListModel {
source: "http://feeds.bbci.co.uk/news/business/rss.xml"
query: "/rss/channel/item"
namespaceDeclarations: "declare namespace media = 'http://search.yahoo.com/mrss/';"
XmlRole { name: "image"; query: "media:thumbnail/@url/string()" }
}
delegate: Image {
width: PathView.view.width
height: PathView.view.height
source: image
fillMode: Image.PreserveAspectCrop
}
Timer { // automatically loop through the images
interval: 1000; running: true; repeat: true;
onTriggered: {
parent.incrementCurrentIndex()
}
}
Timer {
interval: 600000; running: true; repeat: true;
onTriggered: parent.model.reload()
}
}
}
This code loads the images from the web as it needs them. However, once an image is no longer displayed it discards the data. The next time the slideshow loops around the image will be reloaded from the web. As a result, the code hits the remote image server once per second for as long as it is running, downloading 50-300KB each time.
The code runs on an embedded system with not much RAM, so caching the decoded image data by keeping the delegate when it is not on the path is not an option.
Instead the caching should be done at the HTTP level, storing the original downloaded files. It should therefore obey the HTTP cache control headers.
The caching should be done in memory only as the system has only a small flash disk.
How can I implement this in Qt? I assume it will involve C++ code, that is fine.
To control the caching behaviour when QML fetches a network resource you would subclass QQmlNetworkAccessManagerFactory and have it create QNetworkAccessManagers with a cache attached. Then you attach the factory to your QQmlEngine:
class MyNAMFactory : public QQmlNetworkAccessManagerFactory
{
public:
virtual QNetworkAccessManager *create(QObject *parent);
};
QNetworkAccessManager *MyNAMFactory::create(QObject *parent)
{
QNetworkAccessManager *nam = new QNetworkAccessManager(parent);
nam->setCache(new QNetworkDiskCache(parent));
return nam;
}
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
QQuickView view;
view.engine()->setNetworkAccessManagerFactory(new MyNAMFactory);
view.setSource(QUrl("qrc:///main.qml"));
view.show();
return app.exec();
}
Caches must implement the QAbstractNetworkCache interface. Qt has one built in cache type, QNetworkDiskCache which, as the name implies, saves the cache to disk. There is no built-in class for in-memory caching, but it would be fairly easy to implement one by using a QHash to store the URLs, data, and metadata.