1 /* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_SYNTAX_FOREACH_LAZY_FOR_EACH_BUILDER_H 17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_SYNTAX_FOREACH_LAZY_FOR_EACH_BUILDER_H 18 19 #include <cstdint> 20 #include <list> 21 #include <map> 22 #include <optional> 23 #include <string> 24 #include <unordered_map> 25 #include <unordered_set> 26 #include <utility> 27 28 #include "base/log/ace_trace.h" 29 #include "base/utils/noncopyable.h" 30 #include "base/utils/time_util.h" 31 #include "base/utils/utils.h" 32 #include "core/components_ng/base/frame_node.h" 33 #include "core/components_ng/base/inspector.h" 34 #include "core/components_ng/base/ui_node.h" 35 #include "core/components_v2/foreach/lazy_foreach_component.h" 36 #include "core/pipeline_ng/pipeline_context.h" 37 38 namespace OHOS::Ace::NG { 39 40 typedef struct OperationInfo { OperationInfoOperationInfo41 OperationInfo():node(nullptr) {} 42 int32_t changeCount = 0; 43 int32_t fromDiffTo = 0; 44 std::string key; 45 RefPtr<UINode> node; 46 bool isDeleting = false; 47 bool isChanged = false; 48 bool moveIn = false; 49 bool isExchange = false; 50 std::vector<std::string> extraKey; 51 } OperationInfo; 52 53 using LazyForEachChild = std::pair<std::string, RefPtr<UINode>>; 54 using LazyForEachCacheChild = std::pair<int32_t, RefPtr<UINode>>; 55 56 class ACE_EXPORT LazyForEachBuilder : public virtual AceType { 57 DECLARE_ACE_TYPE(NG::LazyForEachBuilder, AceType) 58 public: 59 LazyForEachBuilder() = default; 60 ~LazyForEachBuilder() override = default; 61 GetTotalCount()62 int32_t GetTotalCount() 63 { 64 return OnGetTotalCount(); 65 } 66 UpdateHistoricalTotalCount(int32_t count)67 void UpdateHistoricalTotalCount(int32_t count) 68 { 69 historicalTotalCount_ = count; 70 } 71 72 int32_t GetTotalCountOfOriginalDataset(); 73 74 std::pair<std::string, RefPtr<UINode>> GetChildByIndex(int32_t index, bool needBuild, bool isCache = false); 75 ExpandChildrenOnInitial()76 void ExpandChildrenOnInitial() 77 { 78 OnExpandChildrenOnInitialInNG(); 79 } 80 81 void OnDataReloaded(); 82 83 bool OnDataAdded(size_t index); 84 85 bool OnDataBulkAdded(size_t index, size_t count); 86 87 RefPtr<UINode> OnDataDeleted(size_t index); 88 89 std::list<std::pair<std::string, RefPtr<UINode>>>& OnDataBulkDeleted(size_t index, size_t count); 90 91 bool OnDataChanged(size_t index); 92 93 std::list<std::pair<std::string, RefPtr<UINode>>>& OnDataBulkChanged(size_t index, size_t count); 94 95 void OnDataMoveToNewPlace(size_t from, size_t to); 96 97 bool OnDataMoved(size_t from, size_t to); 98 99 std::pair<int32_t, std::list<std::pair<std::string, RefPtr<UINode>>>> OnDatasetChange( 100 std::list<V2::Operation> DataOperations); 101 102 void RepairDatasetItems(std::map<int32_t, LazyForEachChild>& cachedTemp, 103 std::map<int32_t, LazyForEachChild>& expiringTempItem_, std::map<int32_t, int32_t>& indexChangedMap); 104 105 void RepairMoveOrExchange(std::map<int32_t, LazyForEachChild>& expiringTempItem_, 106 OperationInfo& info, LazyForEachChild& child, int32_t index, int32_t changedIndex); 107 108 void CollectIndexChangedCount(std::map<int32_t, int32_t>& indexChangedMap); 109 110 bool ClassifyOperation(V2::Operation& operation, int32_t& initialIndex, 111 std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp); 112 113 bool ValidateIndex(int32_t index, const std::string& type); 114 115 void OperateAdd(V2::Operation& operation, int32_t& initialIndex); 116 117 void OperateDelete(V2::Operation& operation, int32_t& initialIndex); 118 119 void OperateMove(V2::Operation& operation, int32_t& initialIndex, 120 std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp); 121 122 void OperateChange(V2::Operation& operation, int32_t& initialIndex, 123 std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp); 124 125 std::map<int32_t, LazyForEachChild>::iterator FindItem(int32_t index, 126 std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp); 127 128 void OperateExchange(V2::Operation& operation, int32_t& initialIndex, 129 std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp); 130 131 void OperateReload(std::map<int32_t, LazyForEachChild>& expiringTemp); 132 133 void ThrowRepeatOperationError(int32_t index); 134 135 void RecordOutOfBoundaryNodes(int32_t index); 136 InvalidIndexOfChangedData(size_t index)137 void InvalidIndexOfChangedData(size_t index) 138 { 139 for (auto& [key, child] : expiringItem_) { 140 if (static_cast<size_t>(child.first) == index) { 141 child.first = -1; 142 break; 143 } 144 } 145 } 146 GetChildByKey(const std::string & key)147 RefPtr<UINode> GetChildByKey(const std::string& key) 148 { 149 return nullptr; 150 } 151 GetItems(std::list<std::pair<std::string,RefPtr<UINode>>> & childList)152 std::map<int32_t, LazyForEachChild>& GetItems(std::list<std::pair<std::string, RefPtr<UINode>>>& childList) 153 { 154 startIndex_ = -1; 155 endIndex_ = -1; 156 int32_t lastIndex = -1; 157 bool isCertained = false; 158 159 decltype(cachedItems_) items(std::move(cachedItems_)); 160 161 for (auto& [index, node] : items) { 162 if (!node.second) { 163 cachedItems_.try_emplace(index, std::move(node)); 164 continue; 165 } 166 167 auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true)); 168 if (frameNode && !frameNode->IsActive()) { 169 ACE_SYNTAX_SCOPED_TRACE("LazyForEach not active index[%d]", index); 170 frameNode->SetJSViewActive(false, true); 171 expiringItem_.try_emplace(node.first, LazyForEachCacheChild(index, std::move(node.second))); 172 continue; 173 } 174 cachedItems_.try_emplace(index, std::move(node)); 175 if (startIndex_ == -1) { 176 startIndex_ = index; 177 } 178 if (isLoop_) { 179 if (isCertained) { 180 continue; 181 } 182 if (lastIndex > -1 && index - lastIndex > 1) { 183 startIndex_ = index; 184 endIndex_ = lastIndex; 185 isCertained = true; 186 } else { 187 endIndex_ = std::max(endIndex_, index); 188 } 189 } else { 190 endIndex_ = std::max(endIndex_, index); 191 } 192 lastIndex = index; 193 } 194 195 if (needTransition) { 196 for (auto& [key, node] : expiringItem_) { 197 if (!node.second) { 198 continue; 199 } 200 auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true)); 201 if (frameNode && frameNode->IsOnMainTree()) { 202 childList.emplace_back(key, node.second); 203 } 204 } 205 needTransition = false; 206 } 207 208 return cachedItems_; 209 } 210 RemoveAllChild()211 void RemoveAllChild() 212 { 213 ACE_SYNTAX_SCOPED_TRACE("LazyForEach RemoveAllChild"); 214 for (auto& [index, node] : cachedItems_) { 215 if (!node.second) { 216 continue; 217 } 218 auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true)); 219 if (frameNode) { 220 frameNode->SetActive(false); 221 } 222 auto tempNode = node.second; 223 auto pair = expiringItem_.try_emplace(node.first, LazyForEachCacheChild(index, std::move(node.second))); 224 if (!pair.second) { 225 TAG_LOGW(AceLogTag::ACE_LAZY_FOREACH, "Use repeat key for index: %{public}d", index); 226 ProcessOffscreenNode(tempNode, true); 227 } 228 } 229 } 230 SetActiveChildRange(int32_t start,int32_t end)231 bool SetActiveChildRange(int32_t start, int32_t end) 232 { 233 ACE_SYNTAX_SCOPED_TRACE("LazyForEach active range start[%d], end[%d]", start, end); 234 int32_t count = GetTotalCount(); 235 UpdateHistoricalTotalCount(count); 236 bool needBuild = false; 237 for (auto& [index, node] : cachedItems_) { 238 if ((index < count) && ((start <= end && start <= index && end >= index) || 239 (start > end && (index <= end || index >= start)))) { 240 if (node.second) { 241 auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true)); 242 if (frameNode) { 243 frameNode->SetActive(true); 244 } 245 continue; 246 } 247 auto keyIter = expiringItem_.find(node.first); 248 if (keyIter != expiringItem_.end() && keyIter->second.second) { 249 node.second = keyIter->second.second; 250 expiringItem_.erase(keyIter); 251 auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true)); 252 if (frameNode) { 253 frameNode->SetActive(true); 254 } 255 } 256 needBuild = true; 257 continue; 258 } 259 if (!node.second) { 260 continue; 261 } 262 auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true)); 263 if (frameNode) { 264 frameNode->SetActive(false); 265 } 266 auto tempNode = node.second; 267 auto pair = expiringItem_.try_emplace(node.first, LazyForEachCacheChild(index, std::move(node.second))); 268 if (!pair.second) { 269 TAG_LOGW(AceLogTag::ACE_LAZY_FOREACH, "Use repeat key for index: %{public}d", index); 270 ProcessOffscreenNode(tempNode, true); 271 } 272 needBuild = true; 273 } 274 return needBuild; 275 } 276 GetChildIndex(const RefPtr<FrameNode> & targetNode)277 int32_t GetChildIndex(const RefPtr<FrameNode>& targetNode) 278 { 279 for (auto& [index, node] : cachedItems_) { 280 if (node.second) { 281 auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true)); 282 if (frameNode == targetNode) { 283 return index; 284 } 285 } 286 } 287 for (auto& [key, node] : expiringItem_) { 288 if (!node.second) { 289 continue; 290 } 291 auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true)); 292 if (frameNode && frameNode == targetNode) { 293 return node.first; 294 } 295 } 296 return -1; 297 } 298 299 void UpdateMoveFromTo(int32_t from, int32_t to); 300 void ResetMoveFromTo(); 301 int32_t ConvertFormToIndex(int32_t index); 302 SetFlagForGeneratedItem(PropertyChangeFlag propertyChangeFlag)303 void SetFlagForGeneratedItem(PropertyChangeFlag propertyChangeFlag) 304 { 305 for (const auto& item : cachedItems_) { 306 if (!item.second.second) { 307 continue; 308 } 309 item.second.second->ForceUpdateLayoutPropertyFlag(propertyChangeFlag); 310 } 311 } 312 CacheItem(int32_t index,std::unordered_map<std::string,LazyForEachCacheChild> & cache,const std::optional<LayoutConstraintF> & itemConstraint,int64_t deadline,bool & isTimeout)313 RefPtr<UINode> CacheItem(int32_t index, std::unordered_map<std::string, LazyForEachCacheChild>& cache, 314 const std::optional<LayoutConstraintF>& itemConstraint, int64_t deadline, bool& isTimeout) 315 { 316 ACE_SCOPED_TRACE("Builder:BuildLazyItem [%d]", index); 317 auto itemInfo = OnGetChildByIndex(ConvertFormToIndex(index), expiringItem_); 318 CHECK_NULL_RETURN(itemInfo.second, nullptr); 319 auto pair = cache.try_emplace(itemInfo.first, LazyForEachCacheChild(index, itemInfo.second)); 320 auto context = itemInfo.second->GetContext(); 321 CHECK_NULL_RETURN(context, itemInfo.second); 322 auto frameNode = AceType::DynamicCast<FrameNode>(itemInfo.second->GetFrameChildByIndex(0, false, true)); 323 context->SetPredictNode(frameNode); 324 if (!itemInfo.second->RenderCustomChild(deadline)) { 325 isTimeout = true; 326 context->ResetPredictNode(); 327 return itemInfo.second; 328 } 329 if (pair.second) { 330 ProcessOffscreenNode(itemInfo.second, false); 331 } else { 332 TAG_LOGW(AceLogTag::ACE_LAZY_FOREACH, "Use repeat key for index: %{public}d", index); 333 } 334 itemInfo.second->Build(nullptr); 335 context->ResetPredictNode(); 336 itemInfo.second->SetJSViewActive(false, true); 337 cachedItems_[index] = LazyForEachChild(itemInfo.first, nullptr); 338 339 return itemInfo.second; 340 } 341 CheckCacheIndex(std::set<int32_t> & idleIndexes,int32_t count)342 void CheckCacheIndex(std::set<int32_t>& idleIndexes, int32_t count) 343 { 344 for (int32_t i = 1; i <= cacheCount_ - endShowCached_; i++) { 345 if (isLoop_) { 346 if ((startIndex_ <= endIndex_ && endIndex_ + i < count) || 347 startIndex_ > endIndex_ + i) { 348 idleIndexes.emplace(endIndex_ + i); 349 } else if ((endIndex_ + i) % count < startIndex_) { 350 idleIndexes.emplace((endIndex_ + i) % count); 351 } 352 } else { 353 if (endIndex_ + i < count) { 354 idleIndexes.emplace(endIndex_ + i); 355 } 356 } 357 } 358 for (int32_t i = 1; i <= cacheCount_ - startShowCached_; i++) { 359 if (isLoop_) { 360 if ((startIndex_ <= endIndex_ && startIndex_ >= i) || 361 startIndex_ > endIndex_ + i) { 362 idleIndexes.emplace(startIndex_ - i); 363 } else if ((startIndex_ - i + count) % count > endIndex_) { 364 idleIndexes.emplace((startIndex_ - i + count) % count); 365 } 366 } else { 367 if (startIndex_ >= i) { 368 idleIndexes.emplace(startIndex_ - i); 369 } 370 } 371 } 372 } 373 PreBuildByIndex(int32_t index,std::unordered_map<std::string,LazyForEachCacheChild> & cache,int64_t deadline,const std::optional<LayoutConstraintF> & itemConstraint,bool canRunLongPredictTask)374 bool PreBuildByIndex(int32_t index, std::unordered_map<std::string, LazyForEachCacheChild>& cache, 375 int64_t deadline, const std::optional<LayoutConstraintF>& itemConstraint, bool canRunLongPredictTask) 376 { 377 if (GetSysTimestamp() > deadline) { 378 if (!DeleteExpiringItemImmediately()) { 379 cache.merge(expiringItem_); 380 } 381 return false; 382 } 383 bool isTimeout = false; 384 preBuildingIndex_ = -1; 385 auto uiNode = CacheItem(index, cache, itemConstraint, deadline, isTimeout); 386 if (isTimeout) { 387 preBuildingIndex_ = index; 388 return false; 389 } 390 if (!canRunLongPredictTask && itemConstraint) { 391 return false; 392 } 393 if (canRunLongPredictTask && uiNode && itemConstraint) { 394 RefPtr<FrameNode> frameNode = DynamicCast<FrameNode>(uiNode); 395 while (!frameNode) { 396 auto tempNode = uiNode; 397 uiNode = tempNode->GetFirstChild(); 398 if (!uiNode) { 399 break; 400 } 401 frameNode = DynamicCast<FrameNode>(uiNode); 402 } 403 if (frameNode) { 404 frameNode->GetGeometryNode()->SetParentLayoutConstraint(itemConstraint.value()); 405 FrameNode::ProcessOffscreenNode(frameNode); 406 } 407 } 408 return true; 409 } 410 ProcessPreBuildingIndex(std::unordered_map<std::string,LazyForEachCacheChild> & cache,int64_t deadline,const std::optional<LayoutConstraintF> & itemConstraint,bool canRunLongPredictTask,std::set<int32_t> & idleIndexes)411 bool ProcessPreBuildingIndex(std::unordered_map<std::string, LazyForEachCacheChild>& cache, int64_t deadline, 412 const std::optional<LayoutConstraintF>& itemConstraint, bool canRunLongPredictTask, 413 std::set<int32_t>& idleIndexes) 414 { 415 if (idleIndexes.find(preBuildingIndex_) == idleIndexes.end()) { 416 preBuildingIndex_ = -1; 417 return true; 418 } 419 idleIndexes.erase(preBuildingIndex_); 420 return PreBuildByIndex(preBuildingIndex_, cache, deadline, itemConstraint, canRunLongPredictTask); 421 } 422 423 bool PreBuild(int64_t deadline, const std::optional<LayoutConstraintF>& itemConstraint, bool canRunLongPredictTask); 424 ProcessCachedIndex(std::unordered_map<std::string,LazyForEachCacheChild> & cache,std::set<int32_t> & idleIndexes)425 void ProcessCachedIndex(std::unordered_map<std::string, LazyForEachCacheChild>& cache, 426 std::set<int32_t>& idleIndexes) 427 { 428 auto expiringIter = expiringItem_.begin(); 429 while (expiringIter != expiringItem_.end()) { 430 const auto& key = expiringIter->first; 431 const auto& node = expiringIter->second; 432 auto iter = idleIndexes.find(node.first); 433 if (iter != idleIndexes.end() && node.second) { 434 LoadCacheByIndex(cache, idleIndexes, node, key, iter, expiringIter); 435 } else { 436 LoadCacheByKey(cache, idleIndexes, node, key, expiringIter); 437 } 438 } 439 } 440 LoadCacheByIndex(std::unordered_map<std::string,LazyForEachCacheChild> & cache,std::set<int32_t> & idleIndexes,const LazyForEachCacheChild & node,const std::string & key,const std::set<int32_t>::iterator & iter,std::unordered_map<std::string,LazyForEachCacheChild>::iterator & expiringIter)441 void LoadCacheByIndex(std::unordered_map<std::string, LazyForEachCacheChild>& cache, std::set<int32_t>& idleIndexes, 442 const LazyForEachCacheChild& node, const std::string& key, const std::set<int32_t>::iterator& iter, 443 std::unordered_map<std::string, LazyForEachCacheChild>::iterator& expiringIter) 444 { 445 ProcessOffscreenNode(node.second, false); 446 447 if (node.first == preBuildingIndex_) { 448 cache.try_emplace(key, node); 449 } else { 450 cache.try_emplace(key, std::move(node)); 451 cachedItems_.try_emplace(node.first, LazyForEachChild(key, nullptr)); 452 idleIndexes.erase(iter); 453 } 454 455 expiringIter++; 456 } 457 LoadCacheByKey(std::unordered_map<std::string,LazyForEachCacheChild> & cache,std::set<int32_t> & idleIndexes,const LazyForEachCacheChild & node,const std::string & key,std::unordered_map<std::string,LazyForEachCacheChild>::iterator & expiringIter)458 void LoadCacheByKey(std::unordered_map<std::string, LazyForEachCacheChild>& cache, std::set<int32_t>& idleIndexes, 459 const LazyForEachCacheChild& node, const std::string& key, 460 std::unordered_map<std::string, LazyForEachCacheChild>::iterator& expiringIter) 461 { 462 NotifyDataDeleted(node.second, static_cast<size_t>(node.first), true); 463 ProcessOffscreenNode(node.second, true); 464 NotifyItemDeleted(RawPtr(node.second), key); 465 466 if (node.second) { 467 node.second->DetachFromMainTree(); 468 } 469 if (DeleteExpiringItemImmediately()) { 470 expiringIter = expiringItem_.erase(expiringIter); 471 } else { 472 expiringIter++; 473 } 474 } 475 ProcessOffscreenNode(RefPtr<UINode> uiNode,bool remove)476 void ProcessOffscreenNode(RefPtr<UINode> uiNode, bool remove) 477 { 478 if (uiNode) { 479 auto frameNode = DynamicCast<FrameNode>(uiNode); 480 while (!frameNode) { 481 auto tempNode = uiNode; 482 uiNode = tempNode->GetFirstChild(); 483 if (!uiNode) { 484 break; 485 } 486 frameNode = DynamicCast<FrameNode>(uiNode); 487 } 488 if (frameNode) { 489 if (!remove) { 490 Inspector::AddOffscreenNode(frameNode); 491 } else { 492 Inspector::RemoveOffscreenNode(frameNode); 493 } 494 } 495 } 496 } 497 ClearAllOffscreenNode()498 void ClearAllOffscreenNode() 499 { 500 for (auto& [key, node] : expiringItem_) { 501 ProcessOffscreenNode(node.second, true); 502 } 503 for (auto& [key, node] : cachedItems_) { 504 ProcessOffscreenNode(node.second, true); 505 } 506 } 507 508 virtual void ReleaseChildGroupById(const std::string& id) = 0; 509 510 virtual void RegisterDataChangeListener(const RefPtr<V2::DataChangeListener>& listener) = 0; 511 512 virtual void UnregisterDataChangeListener(V2::DataChangeListener* listener) = 0; 513 SetCacheCount(int32_t cacheCount)514 void SetCacheCount(int32_t cacheCount) 515 { 516 cacheCount_ = cacheCount; 517 } 518 SetIsLoop(bool isLoop)519 void SetIsLoop(bool isLoop) 520 { 521 isLoop_ = isLoop; 522 } 523 clearDeletedNodes()524 void clearDeletedNodes() 525 { 526 nodeList_.clear(); 527 } 528 SetUseNewInterface(bool useNewInterface)529 void SetUseNewInterface(bool useNewInterface) 530 { 531 useNewInterface_ = useNewInterface; 532 } 533 GetCachedUINodeMap()534 const std::unordered_map<std::string, LazyForEachCacheChild>& GetCachedUINodeMap() 535 { 536 return expiringItem_; 537 } 538 GetAllChildren()539 const std::map<int32_t, LazyForEachChild>& GetAllChildren() 540 { 541 if (!cachedItems_.empty()) { 542 startIndex_ = cachedItems_.begin()->first; 543 endIndex_ = cachedItems_.rbegin()->first; 544 } 545 if (isLoop_ && !cachedItems_.empty()) { 546 int32_t lastIndex = -1; 547 for (auto& [index, node] : cachedItems_) { 548 if (lastIndex > -1 && index - lastIndex > 1) { 549 startIndex_ = index; 550 endIndex_ = lastIndex; 551 break; 552 } 553 } 554 } 555 return cachedItems_; 556 } 557 SetJSViewActive(bool active)558 void SetJSViewActive(bool active) 559 { 560 for (const auto& node : cachedItems_) { 561 if (node.second.second == nullptr) { 562 continue; 563 } 564 node.second.second->SetJSViewActive(active, true); 565 } 566 for (const auto& node : expiringItem_) { 567 if (node.second.second == nullptr) { 568 continue; 569 } 570 node.second.second->SetJSViewActive(active, true); 571 } 572 } 573 PaintDebugBoundaryTreeAll(bool flag)574 void PaintDebugBoundaryTreeAll(bool flag) 575 { 576 for (const auto& node : cachedItems_) { 577 if (node.second.second == nullptr) { 578 continue; 579 } 580 node.second.second->PaintDebugBoundaryTreeAll(flag); 581 } 582 for (const auto& node : expiringItem_) { 583 if (node.second.second == nullptr) { 584 continue; 585 } 586 node.second.second->PaintDebugBoundaryTreeAll(flag); 587 } 588 } 589 NotifyItemDeleted(UINode * node,const std::string & key)590 void NotifyItemDeleted(UINode* node, const std::string& key) 591 { 592 OnItemDeleted(node, key); 593 } 594 595 void GetAllItems(std::vector<UINode*>& items); 596 SetShowCached(int32_t start,int32_t end)597 void SetShowCached(int32_t start, int32_t end) 598 { 599 startShowCached_ = start; 600 endShowCached_ = end; 601 } 602 603 protected: 604 virtual int32_t OnGetTotalCount() = 0; 605 OnItemDeleted(UINode * node,const std::string & key)606 virtual void OnItemDeleted(UINode* node, const std::string& key) {}; 607 DeleteExpiringItemImmediately()608 virtual bool DeleteExpiringItemImmediately() 609 { 610 return false; 611 } 612 613 virtual LazyForEachChild OnGetChildByIndex( 614 int32_t index, std::unordered_map<std::string, LazyForEachCacheChild>& cachedItems) = 0; 615 616 virtual LazyForEachChild OnGetChildByIndexNew(int32_t index, 617 std::map<int32_t, LazyForEachChild>& cachedItems, 618 std::unordered_map<std::string, LazyForEachCacheChild>& expiringItems) = 0; 619 620 virtual void OnExpandChildrenOnInitialInNG() = 0; 621 622 virtual void NotifyDataChanged(size_t index, const RefPtr<UINode>& lazyForEachNode, bool isRebuild = true) = 0; 623 624 virtual void NotifyDataDeleted(const RefPtr<UINode>& lazyForEachNode, size_t index, bool removeIds) = 0; 625 626 virtual void NotifyDataAdded(size_t index) = 0; 627 628 virtual void KeepRemovedItemInCache(NG::LazyForEachChild node, 629 std::unordered_map<std::string, NG::LazyForEachCacheChild>& cachedItems) = 0; 630 631 private: 632 void RecycleItemsOutOfBoundary(); 633 void RecycleChildByIndex(int32_t index); 634 635 std::map<int32_t, LazyForEachChild> cachedItems_; 636 std::unordered_map<std::string, LazyForEachCacheChild> expiringItem_; 637 std::list<std::pair<std::string, RefPtr<UINode>>> nodeList_; 638 std::map<int32_t, OperationInfo> operationList_; 639 enum class OP { ADD, DEL, CHANGE, MOVE, EXCHANGE, RELOAD }; 640 std::map<std::string, OP> operationTypeMap = {{"add", OP::ADD}, 641 {"delete", OP::DEL}, 642 {"change", OP::CHANGE}, 643 {"move", OP::MOVE}, 644 {"exchange", OP::EXCHANGE}, 645 {"reload", OP::RELOAD}}; 646 std::list<int32_t> outOfBoundaryNodes_; 647 std::optional<std::pair<int32_t, int32_t>> moveFromTo_; 648 649 int32_t startIndex_ = -1; 650 int32_t endIndex_ = -1; 651 int32_t cacheCount_ = 0; 652 int32_t startShowCached_ = 0; 653 int32_t endShowCached_ = 0; 654 int32_t preBuildingIndex_ = -1; 655 int32_t totalCountOfOriginalDataset_ = 0; 656 int32_t historicalTotalCount_ = 0; 657 bool needTransition = false; 658 bool isLoop_ = false; 659 bool useNewInterface_ = false; 660 ACE_DISALLOW_COPY_AND_MOVE(LazyForEachBuilder); 661 }; 662 } // namespace OHOS::Ace::NG 663 664 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_SYNTAX_FOREACH_LAZY_FOR_EACH_BUILDER_H 665