连续缓存示例
连续缓存示例展示了如何使用 QContiguousCache 来管理非常大的模型的内存使用。在某些环境下内存是有限的,即使内存不是有限的,用户也不喜欢应用使用过多的内存。使用 QContiguousCache 来管理列表,而不是将整个列表加载到内存中,允许应用限制其使用的内存量,无论访问的数据集有多大。
使用 QContiguousCache 最简单的方法是在请求项目时进行缓存。当一个视图请求第N行的项目时,它也可能请求与N行接近的行。
QVariant RandomListModel::data(const QModelIndex &index, int role) const { if (role != Qt::DisplayRole) return QVariant(); int row = index.row(); if (row > m_rows.lastIndex()) { if (row - m_rows.lastIndex() > lookAhead) cacheRows(row - halfLookAhead, qMin(m_count, row + halfLookAhead)); else while (row > m_rows.lastIndex()) m_rows.append(fetchRow(m_rows.lastIndex() + 1)); } else if (row < m_rows.firstIndex()) { if (m_rows.firstIndex() - row > lookAhead) cacheRows(qMax(0, row - halfLookAhead), row + halfLookAhead); else while (row < m_rows.firstIndex()) m_rows.prepend(fetchRow(m_rows.firstIndex() - 1)); } return m_rows.at(row); } void RandomListModel::cacheRows(int from, int to) const { for (int i = from; i <= to; ++i) m_rows.insert(i, fetchRow(i)); }
获取行后,该类确定该行是否在连续缓存的当前范围内。也可以简单地使用以下代码。
while (row > m_rows.lastIndex()) m_rows.append(fetchWord(m_rows.lastIndex()+1); while (row < m_rows.firstIndex()) m_rows.prepend(fetchWord(m_rows.firstIndex()-1);
然而,如果直接使用滚动条,列表通常会跳跃行,因此上述代码会导致获取旧行与新行之间的每一行。
使用 QContiguousCache::lastIndex() 和 QContiguousCache::firstIndex() 允许示例确定缓存当前缓存的列表的哪一部分。这些值并不代表缓存自身内存中的索引,而是一个缓存表示的虚拟无限数组。
通过使用 QContiguousCache::append() 和 QContiguousCache::prepend() 代码确保当请求的行没有远离当前缓存范围时,仍然不会丢失可能仍在屏幕上的项。 QContiguousCache::insert() 可能会从缓存中删除一个以上项,因为 QContiguousCache 不允许有间隙。如果您需要快速在具有显著间隙的行之间跳转,请考虑使用 QCache。
这就完成了。一个完美的缓存,对于非常大的列表,使用最少的内存。在这种情况下,获取词到缓存的操作生成随机信息而不是固定信息,这允许您在运行示例时看到缓存范围是如何保持本地行数的。
QString RandomListModel::fetchRow(int position) const { return QString::number(QRandomGenerator::global()->bounded(++position)); }
还可以考虑在应用程序的绘图例程之外将项预取到缓存中。这可以通过单独的线程或使用 QTimer 以增量方式扩展缓存范围来完成,在超出当前缓存范围的行请求之前进行。
版权所有© 2024 Qt公司有限公司。此处包含的文档贡献的版权属于各自所有者。本提供的文档受《由自由软件基金会发布的GNU自由文档许可证版本1.3》的条款许可http://www.gnu.org/licenses/fdl.html。Qt及其相关标志是芬兰以及全球其他国家的Qt公司有限责任公司的商标。商标。所有其他商标均为各自所有者的财产。