diff --git a/flutter/lib/common/widgets/peer_card.dart b/flutter/lib/common/widgets/peer_card.dart index 15ca8932d..7827298b6 100644 --- a/flutter/lib/common/widgets/peer_card.dart +++ b/flutter/lib/common/widgets/peer_card.dart @@ -250,6 +250,9 @@ class _PeerCardState extends State<_PeerCard> color: Colors.transparent, elevation: 0, margin: EdgeInsets.zero, + // to-do: memory leak here, more investigation needed. + // Continious rebuilds of `Obx()` will cause memory leak here. + // The simple demo does not have this issue. child: Obx( () => Container( foregroundDecoration: deco.value, diff --git a/flutter/lib/common/widgets/peer_tab_page.dart b/flutter/lib/common/widgets/peer_tab_page.dart index c941a1b93..359750788 100644 --- a/flutter/lib/common/widgets/peer_tab_page.dart +++ b/flutter/lib/common/widgets/peer_tab_page.dart @@ -108,7 +108,7 @@ class _PeerTabPageState extends State Widget build(BuildContext context) { final model = Provider.of(context); Widget selectionWrap(Widget widget) { - return model.multiSelectionMode ? createMultiSelectionBar() : widget; + return model.multiSelectionMode ? createMultiSelectionBar(model) : widget; } return Column( @@ -362,8 +362,7 @@ class _PeerTabPageState extends State .toList()); } - Widget createMultiSelectionBar() { - final model = Provider.of(context); + Widget createMultiSelectionBar(PeerTabModel model) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -381,7 +380,7 @@ class _PeerTabPageState extends State Row( children: [ selectionCount(model.selectedPeers.length), - selectAll(), + selectAll(model), closeSelection(), ], ) @@ -512,8 +511,7 @@ class _PeerTabPageState extends State ); } - Widget selectAll() { - final model = Provider.of(context); + Widget selectAll(PeerTabModel model) { return Offstage( offstage: model.selectedPeers.length >= model.currentTabCachedPeers.length, diff --git a/flutter/lib/common/widgets/peers_view.dart b/flutter/lib/common/widgets/peers_view.dart index a73ef0f0b..b18de82d9 100644 --- a/flutter/lib/common/widgets/peers_view.dart +++ b/flutter/lib/common/widgets/peers_view.dart @@ -167,6 +167,9 @@ class _PeersViewState extends State<_PeersView> @override Widget build(BuildContext context) { + // We should avoid too many rebuilds. MacOS(m1, 14.6.1) on Flutter 3.19.6. + // Continious rebuilds of `ChangeNotifierProvider` will cause memory leak. + // Simple demo can reproduce this issue. return ChangeNotifierProvider( create: (context) => widget.peers, child: Consumer(builder: (context, peers, child) { @@ -245,6 +248,9 @@ class _PeersViewState extends State<_PeersView> : Container(child: visibilityChild); } + // We should avoid too many rebuilds. Win10(Some machines) on Flutter 3.19.6. + // Continious rebuilds of `ListView.builder` will cause memory leak. + // Simple demo can reproduce this issue. final Widget child = Obx(() => stateGlobal.isPortrait.isTrue ? ListView.builder( itemCount: peers.length, diff --git a/flutter/lib/models/peer_tab_model.dart b/flutter/lib/models/peer_tab_model.dart index 3c0fe636d..7dab2574d 100644 --- a/flutter/lib/models/peer_tab_model.dart +++ b/flutter/lib/models/peer_tab_model.dart @@ -184,10 +184,17 @@ class PeerTabModel with ChangeNotifier { notifyListeners(); } + // `notifyListeners()` will cause many rebuilds. + // So, we need to reduce the calls to "notifyListeners()" only when necessary. + // A better way is to use a new model. setCurrentTabCachedPeers(List peers) { Future.delayed(Duration.zero, () { + final isPreEmpty = _currentTabCachedPeers.isEmpty; _currentTabCachedPeers = peers; - notifyListeners(); + final isNowEmpty = _currentTabCachedPeers.isEmpty; + if (isPreEmpty != isNowEmpty) { + notifyListeners(); + } }); }