Repeater Model very slow to copy an array item
-
We are facing a performance issue in our project. We are using Qt/QML and C++ backend and we are working on the Grid Buttons. If we are changing or updating the data model the repeater section takes more delay to update all the buttons so UI is very slow. Based on the number of buttons the delay gets increased, if 64 buttons are updated means it took 6-sec to load.
when we try to update the data or copy an array of objects into the model container (data Model) of Repeater, it consumes more time to copy all items. For e.g., 30 objects consuming 2 sec. If object counts are increased, then the time consumed also increases proportionally.
As per console debug print, After executing this line console.log("GRID update data model"), it takes 2 sec to execute the next command.
How to avoid this delay in repeater?
Target Processor Name: IMX537
Qt version: Qt 5.15.2 (GCC 9.3.0, 64 bit)
Note: this delay issue happened in target device only. In local compilation did not see this delay.
Code:function handleModelChanged() { delegateModel.model = areaViewModel; const newUiType = areaViewModel.uiType if (newUiType !== uiType || !modelDataIsEqual(delegateModel, dataModel) ) { var buttons = [] for (var row = 0; row < delegateModel.model.rowCount(); row++) { var item = delegateModel.items.get(row).model; var button = dataModelItemToButton(item); buttons.push(button); } console.log("GRID clear data model") dataModel = [] console.log("GRID change uiType " + uiType + " -> " + newUiType) uiType = newUiType console.log("GRID update data model") dataModel = buttons; console.log("GRID buttons changed uiType=" + uiType + " cls=" + areaViewModel.callClass); } } Repeater { id: areaRepeater model: dataModel delegate: { gridButton; } onItemAdded: { if (index == areaRepeater.count - 1) { console.log("GRID repeater added " + areaRepeater.count + " buttons") updateItems() } } } } function modelDataIsEqual(modelData, data) { if (!modelData || !data || modelData.model.rowCount() !== data.length) return false; for (var i = 0; i < modelData.model.rowCount(); ++i) { const item = modelData.items.get(i).model; const button = data[i]; if (button.dataAreaShortName !== item.dataAreaShortName || button.dataAreaName !== item.dataAreaName || button.dataIsExitArea !== item.dataIsExitArea || button.dataAreaGridCols !== item.dataAreaGridCols || button.dataIsGroupedButton !== item.dataIsGroupedButton || button.dataAreaLocked !== item.dataAreaLocked || button.dataAreaIcon !== item.dataAreaIcon || button.dataIsDopArea !== item.dataIsDopArea || button.dataIsSideGroup !== item.dataIsSideGroup || dlaButtonStyle !== areaModel.combineBtnStyle || oddEvenBtnAppearance !== areaModel.getLockedButtonAppearance() || button.dataButtonAppearance !== item.dataButtonAppearance || button.dataCrowdedArea !== item.dataCrowdedArea || button.dataOverCrowdedArea !== item.dataOverCrowdedArea || button.dataPeopleIconArea !== item.dataPeopleIconArea || button.dataSideStateIconArea !== item.dataSideStateIconArea) { return false; } } return true; } function dataModelItemToButton(item) { if (!item) return null; return { dataAreaShortName: item.dataAreaShortName, dataAreaName: item.dataAreaName, dataIsExitArea: item.dataIsExitArea, dataAreaGridCols: item.dataAreaGridCols, dataIsGroupedButton: item.dataIsGroupedButton, dataAreaLocked: item.dataAreaLocked, dataAreaIcon: item.dataAreaIcon, dataIsDopArea: item.dataIsDopArea, dataIsSideGroup: item.dataIsSideGroup, dataButtonAppearance : item.dataButtonAppearance, dataCrowdedArea: item.dataCrowdedArea, dataOverCrowdedArea: item.dataOverCrowdedArea, dataPeopleIconArea : item.dataPeopleIconArea, dataSideStateIconArea : item.dataSideStateIconArea } }
As I mentioned above, larger number of buttons means delay also increased. Like 100ms took for enter one button into model. Somewhere, mentioned use ListModel in Repeater for loading the dataitem. But i tried that one also, seems same delay was happened. I have checked in my target device most of the delay causing to execute this line only dataModel = buttons; I couldn't ignore this line, Since, once copied into the datamodel then only see all the buttons.Any other way to reduce this delay?
-
My general advice after a quick skim, which happens to be the same advice for most view performance issues is:
- As noted, use a QAbstractItemModel instead of a javascript list. This will allow the view to limit updates to new or changed items.
- Move as much of the imperative javascript code as possible into declarative syntax.
- Move as much of the remaining imperative javascript code as possible into C++.
- Avoid copying objects as is done in dataModelItemToButton().
- Dynamically load complex portions of the delegate. The relevance of this particular tip isn't clear here, as the delegate doesn't appear to be valid QML.
- Consider a ListView, GridView, PathView, etc instead of Repeater.
https://doc.qt.io/qt-6/qml-qtquick-repeater.html#considerations-when-using-repeater:
The Repeater type creates all of its delegate items when the repeater is first created. This can be inefficient if there are a large number of delegate items and not all of the items are required to be visible at the same time. If this is the case, consider using other view types like ListView (which only creates delegate items when they are scrolled into view) or use the Dynamic Object Creation methods to create items as they are required.
And before doing any of this:
Use the QML profiler built into Creator.