QML中如何控制HTTP资源的缓存?
How to control caching of HTTP resources in QML?
考虑以下代码,它获取 RSS 提要,然后将其中的图像显示为永远循环播放的幻灯片:
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()
}
}
}
此代码根据需要从 Web 加载图像。但是,一旦图像不再显示,它就会丢弃数据。下次幻灯片循环播放时,将从网络重新加载图像。结果,只要是运行,代码就每秒访问一次远程图像服务器,每次下载50-300KB。
该代码在 RAM 不多的嵌入式系统上运行,因此当委托不在路径上时通过保留委托来缓存解码的图像数据不是一种选择。
相反,缓存应该在 HTTP 级别完成,存储原始下载的文件。因此它应该服从 HTTP 缓存控制 headers.
缓存应该只在内存中完成,因为系统只有一个小闪存盘。
如何在 Qt 中实现它?我假设它会涉及 C++ 代码,那很好。
要在 QML 获取网络资源时控制缓存行为,您可以子类化 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();
}
缓存必须实现 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 来存储 URL、数据和元数据。
考虑以下代码,它获取 RSS 提要,然后将其中的图像显示为永远循环播放的幻灯片:
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()
}
}
}
此代码根据需要从 Web 加载图像。但是,一旦图像不再显示,它就会丢弃数据。下次幻灯片循环播放时,将从网络重新加载图像。结果,只要是运行,代码就每秒访问一次远程图像服务器,每次下载50-300KB。
该代码在 RAM 不多的嵌入式系统上运行,因此当委托不在路径上时通过保留委托来缓存解码的图像数据不是一种选择。
相反,缓存应该在 HTTP 级别完成,存储原始下载的文件。因此它应该服从 HTTP 缓存控制 headers.
缓存应该只在内存中完成,因为系统只有一个小闪存盘。
如何在 Qt 中实现它?我假设它会涉及 C++ 代码,那很好。
要在 QML 获取网络资源时控制缓存行为,您可以子类化 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();
}
缓存必须实现 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 来存储 URL、数据和元数据。