移除 Notification.visitAncestor
通知(Notification)現在只遍歷作為通知監聽者的祖先元件(Widgets)。
摘要
#通知(Notification)現在僅遍歷作為通知監聽者的祖先元件,提升了效率。
背景
#通知 API 會遍歷元件樹(element tree),以尋找通知接收者。這導致了一些不理想的效能表現:
- 如果沒有對應通知類型的接收者,則會遍歷並進行型別檢查整個通知發送點以上的元件樹。
- 若在同一畫格(frame)中有多個通知(這在滾動元件很常見),則會多次遍歷元件樹。
如果在同一頁面上有多個或巢狀的滾動元件(Scrolling Widgets),情況會變得更糟——每個滾動元件每個畫格都會發送多個通知。例如,在 Dart/Flutter Devtools 的 flamegraph 頁面中,我們發現約有 30% 的 CPU 時間花在發送通知上。
為了降低發送通知的成本,我們已將通知發送機制修改為只拜訪作為通知監聽者的祖先元件,從而減少每個畫格需要遍歷的元件數量。
然而,舊的通知系統在其 API 中透過 Notification.visitAncestor 方法暴露了遍歷每個元件的行為。由於現在不再遍歷所有祖先元件,因此此方法已不再支援。
變更說明
#
Notification.visitAncestor 已被移除。
任何繼承自 Notification 的類別,都不應再覆寫此方法。
如果你沒有實作自訂 Notification 並覆寫 Notification.visitAncestor,
則無需進行任何更動。
遷移指南
#
如果你有繼承自 Notification 並覆寫
Notification.visitAncestor 的子類別,則必須刪除該覆寫,或使用以下程式碼選擇性地採用舊式通知發送方式。
遷移前的程式碼:
import 'package:flutter/widgets.dart';
class MyNotification extends Notification {
@override
bool visitAncestor(Element element) {
print('Visiting $element');
return super.visitAncestor(element);
}
}
void methodThatSendsNotification(BuildContext? context) {
MyNotification().dispatch(context);
}
遷移後的程式碼:
import 'package:flutter/widgets.dart';
class MyNotification extends Notification {
bool visitAncestor(Element element) {
print('Visiting $element');
if (element is ProxyElement) {
final Widget widget = element.widget;
if (widget is NotificationListener<MyNotification>) {
return widget.onNotification?.call(notification) ?? true;
}
}
return true;
}
}
void methodThatSendsNotification(BuildContext? context) {
context?.visitAncestor(MyNotification().visitAncestor);
}
請注意,這種做法相較於 Notification.dispatch 的新預設行為,效能較差。
時間軸
#
合併於版本:2.12.0-4.1
穩定版釋出:3.0.0
參考資料
#API 文件:
相關議題:
相關 PR:
Unless stated otherwise, the documentation on this site reflects Flutter 3.44.0. Page last updated on 2026-06-14. View source or report an issue.