diff options
author | Richard Moe Gustavsen <[email protected]> | 2019-09-12 14:14:05 +0200 |
---|---|---|
committer | Richard Moe Gustavsen <[email protected]> | 2019-12-04 01:34:07 +0100 |
commit | 4b58d69d56c5876a1b1d71ce6a96b4c6c81a833f (patch) | |
tree | 094a0240be7462a2768084985d49f2f58a294ab1 /src/qmlmodels/qqmltableinstancemodel.cpp | |
parent | af9a96ca10e72517a7e8aa1ada7ec2d635e2a9ff (diff) |
QQmlTableInstanceModel: factor out reuse pool
Factor out the reuse pool logic in TableInstanceModel into a
separate class, so that we can share it with the upcoming implementation
for recycling items in QQmlDelegateModel.
Change-Id: If8f700b7a0208bac7d1cb1de087792e2c3a9b512
Reviewed-by: Shawn Rutledge <[email protected]>
Diffstat (limited to 'src/qmlmodels/qqmltableinstancemodel.cpp')
-rw-r--r-- | src/qmlmodels/qqmltableinstancemodel.cpp | 93 |
1 files changed, 11 insertions, 82 deletions
diff --git a/src/qmlmodels/qqmltableinstancemodel.cpp b/src/qmlmodels/qqmltableinstancemodel.cpp index 1af93e87d8..b4d1e61e31 100644 --- a/src/qmlmodels/qqmltableinstancemodel.cpp +++ b/src/qmlmodels/qqmltableinstancemodel.cpp @@ -141,7 +141,7 @@ QQmlDelegateModelItem *QQmlTableInstanceModel::resolveModelItem(int index) return nullptr; // Check if the pool contains an item that can be reused - modelItem = takeFromReusableItemsPool(delegate); + modelItem = m_reusableItemsPool.takeItem(delegate, index); if (modelItem) { reuseItem(modelItem, index); m_modelItems.insert(index, modelItem); @@ -225,16 +225,21 @@ QQmlInstanceModel::ReleaseFlags QQmlTableInstanceModel::release(QObject *object, m_modelItems.remove(modelItem->index); if (reusable == Reusable) { - insertIntoReusableItemsPool(modelItem); + m_reusableItemsPool.insertItem(modelItem); + emit itemPooled(modelItem->index, modelItem->object); return QQmlInstanceModel::Pooled; } // The item is not reused or referenced by anyone, so just delete it - modelItem->destroyObject(); - emit destroyingItem(object); + destroyModelItem(modelItem); + return QQmlInstanceModel::Destroyed; +} +void QQmlTableInstanceModel::destroyModelItem(QQmlDelegateModelItem *modelItem) +{ + emit destroyingItem(modelItem->object); + modelItem->destroyObject(); delete modelItem; - return QQmlInstanceModel::Destroyed; } void QQmlTableInstanceModel::cancel(int index) @@ -257,85 +262,9 @@ void QQmlTableInstanceModel::cancel(int index) delete modelItem; } -void QQmlTableInstanceModel::insertIntoReusableItemsPool(QQmlDelegateModelItem *modelItem) -{ - // Currently, the only way for a view to reuse items is to call QQmlTableInstanceModel::release() - // with the second argument explicitly set to QQmlTableInstanceModel::Reusable. If the released - // item is no longer referenced, it will be added to the pool. Reusing of items can be specified - // per item, in case certain items cannot be recycled. - // A QQmlDelegateModelItem knows which delegate its object was created from. So when we are - // about to create a new item, we first check if the pool contains an item based on the same - // delegate from before. If so, we take it out of the pool (instead of creating a new item), and - // update all its context-, and attached properties. - // When a view is recycling items, it should call QQmlTableInstanceModel::drainReusableItemsPool() - // regularly. As there is currently no logic to 'hibernate' items in the pool, they are only - // meant to rest there for a short while, ideally only from the time e.g a row is unloaded - // on one side of the view, and until a new row is loaded on the opposite side. In-between - // this time, the application will see the item as fully functional and 'alive' (just not - // visible on screen). Since this time is supposed to be short, we don't take any action to - // notify the application about it, since we don't want to trigger any bindings that can - // disturb performance. - // A recommended time for calling drainReusableItemsPool() is each time a view has finished - // loading e.g a new row or column. If there are more items in the pool after that, it means - // that the view most likely doesn't need them anytime soon. Those items should be destroyed to - // not consume resources. - // Depending on if a view is a list or a table, it can sometimes be performant to keep - // items in the pool for a bit longer than one "row out/row in" cycle. E.g for a table, if the - // number of visible rows in a view is much larger than the number of visible columns. - // In that case, if you flick out a row, and then flick in a column, you would throw away a lot - // of items in the pool if completely draining it. The reason is that unloading a row places more - // items in the pool than what ends up being recycled when loading a new column. And then, when you - // next flick in a new row, you would need to load all those drained items again from scratch. For - // that reason, you can specify a maxPoolTime to the drainReusableItemsPool() that allows you to keep - // items in the pool for a bit longer, effectively keeping more items in circulation. - // A recommended maxPoolTime would be equal to the number of dimenstions in the view, which - // means 1 for a list view and 2 for a table view. If you specify 0, all items will be drained. - Q_ASSERT(!modelItem->incubationTask); - Q_ASSERT(!modelItem->isObjectReferenced()); - Q_ASSERT(!modelItem->isReferenced()); - Q_ASSERT(modelItem->object); - - modelItem->poolTime = 0; - m_reusableItemsPool.append(modelItem); - emit itemPooled(modelItem->index, modelItem->object); -} - -QQmlDelegateModelItem *QQmlTableInstanceModel::takeFromReusableItemsPool(const QQmlComponent *delegate) -{ - // Find the oldest item in the pool that was made from the same delegate as - // the given argument, remove it from the pool, and return it. - if (m_reusableItemsPool.isEmpty()) - return nullptr; - - for (auto it = m_reusableItemsPool.begin(); it != m_reusableItemsPool.end(); ++it) { - if ((*it)->delegate != delegate) - continue; - auto modelItem = *it; - m_reusableItemsPool.erase(it); - return modelItem; - } - - return nullptr; -} - void QQmlTableInstanceModel::drainReusableItemsPool(int maxPoolTime) { - // Rather than releasing all pooled items upon a call to this function, each - // item has a poolTime. The poolTime specifies for how many loading cycles an item - // has been resting in the pool. And for each invocation of this function, poolTime - // will increase. If poolTime is equal to, or exceeds, maxPoolTime, it will be removed - // from the pool and released. This way, the view can tweak a bit for how long - // items should stay in "circulation", even if they are not recycled right away. - for (auto it = m_reusableItemsPool.begin(); it != m_reusableItemsPool.end();) { - auto modelItem = *it; - modelItem->poolTime++; - if (modelItem->poolTime <= maxPoolTime) { - ++it; - } else { - it = m_reusableItemsPool.erase(it); - release(modelItem->object, NotReusable); - } - } + m_reusableItemsPool.drain(maxPoolTime, [=](QQmlDelegateModelItem *modelItem){ destroyModelItem(modelItem); }); } void QQmlTableInstanceModel::reuseItem(QQmlDelegateModelItem *item, int newModelIndex) |