Flutter问题:切换底部导航时HomeScreen重复重建并发起HTTP请求
问题:底部导航切换后HomeScreen重复发起HTTP请求
在Flutter应用中实现了带底部导航栏的IndexPage,通过setState修改_selectedIndex切换页面。HomeScreen的initState方法中调用PropertyController的getFeaturedProperty发起HTTP请求,首次进入仅执行一次,但每次切换底部导航返回HomeScreen时,页面都会重建,initState再次执行并重复发起HTTP请求,触发加载骨架屏。已尝试使用AutomaticKeepAliveClientMixin保持状态,但问题仍未解决。
解决方案
1. 改用PageView管理页面(推荐方案)
PageView本身会维护子页面的状态,配合AutomaticKeepAliveClientMixin能有效避免页面重建。修改IndexPage代码如下:
class _IndexPageState extends State<IndexPage> { int _selectedIndex = 0; final PageController _pageController = PageController(initialPage: 0); final List<Widget> _widgetOptions = <Widget>[ const HomeScreen(), const ExploreScreen(), const InvestScreen(), const WalletScreen(), const MoreScreen(), ]; @override void initState() { connectRequiredApi(); super.initState(); } @override void dispose() { _pageController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: PageView( controller: _pageController, physics: const NeverScrollableScrollPhysics(), // 禁止滑动切换,仅通过底部导航控制 children: _widgetOptions, ), ), bottomNavigationBar: BottomNavigationBar( items: [ BottomNavigationBarItem( icon: _selectedIndex == 0 ? const Icon(IconlyBold.home, size: 22) : const Icon(IconlyLight.home, size: 22), label: "Home", ), // 保留其他BottomNavigationBarItem BottomNavigationBarItem( icon: _selectedIndex == 4 ? const Icon(IconlyBold.category, size: 22) : const Icon(IconlyLight.category, size: 22), label: 'More', ), ], currentIndex: _selectedIndex, onTap: itemTapped, ), ); } void itemTapped(int index) { if (index == 2) { showToast(context, "Coming Soon"); } else { setState(() { _selectedIndex = index; }); _pageController.jumpToPage(index); } } void connectRequiredApi() async { await Get.find<MapController>().checkLocationPermission(); //...// } }
2. 用自定义KeepAliveWrapper包裹页面(轻量方案)
如果不想改用PageView,可以实现一个KeepAliveWrapper来包裹HomeScreen,强制保留状态:
// 自定义KeepAliveWrapper class KeepAliveWrapper extends StatefulWidget { final Widget child; const KeepAliveWrapper({super.key, required this.child}); @override State<KeepAliveWrapper> createState() => _KeepAliveWrapperState(); } class _KeepAliveWrapperState extends State<KeepAliveWrapper> with AutomaticKeepAliveClientMixin { @override Widget build(BuildContext context) { super.build(context); return widget.child; } @override bool get wantKeepAlive => true; }
然后修改IndexPage的页面列表:
final List<Widget> _widgetOptions = <Widget>[ KeepAliveWrapper(child: const HomeScreen()), const ExploreScreen(), const InvestScreen(), const WalletScreen(), const MoreScreen(), ];
3. 控制器层面避免重复请求(兜底方案)
在PropertyController中判断数据是否已加载,即使页面重建也不会重复发起HTTP请求:
Future<void> getFeaturedProperty() async { // 数据已存在则直接返回,不发起请求 if (_featuredPropertyList.isNotEmpty && _popularPropertyList.isNotEmpty) { homeLoading = false; update(["home_page.dart", "explore_prop_page.dart"]); return; } homeLoading = true; update(["home_page.dart", "explore_prop_page.dart"]); ResponseModel response = await propertyRepo.getFeaturedProperties(); if (response.statusCode == 200) { _featuredPropertyList.clear(); _featuredPropertyList.addAll((response.data as List) .map((e) => PropertyModel.fromJson(e)) .toList()); } await getPopularProperties(); homeLoading = false; update(["home_page.dart", "explore_prop_page.dart"]); }
内容的提问来源于stack exchange,提问作者Brightcode
相关产品推荐
相关产品推荐

