我们的项目面临性能问题。我们正在使用 Qt/QML 和 C++ 后端,并且正在开发网格按钮。如果我们更改或更新数据模型,中继器部分需要更多延迟来更新所有按钮,因此 UI 非常慢。根据按钮数量,延迟会增加,如果更新 64 个按钮,则意味着加载需要 6 秒。
当我们尝试更新数据或将对象数组复制到Repeater的模型容器(数据模型)中时,复制所有项目会消耗更多时间。例如,30 个对象耗时 2 秒。如果对象数量增加,那么消耗的时间也会成比例增加。
根据控制台调试打印,执行此行后
console.log("GRID update data model")
,执行下一条命令需要2秒。
如何避免中继器出现这种延迟?
注意:此延迟问题仅发生在目标设备中。在本地编译中没有看到这个延迟。
代码:
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;
}
正如我上面提到的,按钮数量增多意味着延迟也会增加。就像将一个按钮输入模型需要 100 毫秒。在某处提到在 Repeater 中使用 ListModel 来加载数据项。但我也尝试过,似乎也发生了同样的延迟。
当处理大量按钮时,即使在Repeater中使用ListModel,也可能有其他因素导致速度变慢。
代码中的性能问题可能是由于 modelDataIsEqual 函数造成的,该函数似乎在循环内进行了多次比较。比较循环内对象的每个属性可能代价高昂,特别是当对象很复杂或具有嵌套属性时。
function modelDataIsEqual(modelData, data) {
if (!modelData || !data || modelData.model.rowCount() !== data.length) {
return false;
}
const modelRowCount = modelData.model.rowCount();
for (let i = 0; i < modelRowCount; ++i) {
const item = modelData.items.get(i).model;
const button = data[i];
const isEqual = (
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
);
if (!isEqual) {
return false;
}
}
return true;}