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、数据和元数据。