You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 10:20:41