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

Flutter重复点击当前导航页触发ConnectionState.waiting问题求助

问题描述

应用加载时事件可正常显示,切换至其他页面无异常,但点击当前所在页面的导航栏按钮时,页面会进入ConnectionState.waiting状态,无法显示事件,其他页面也存在同样问题。

提供的主页代码

class MainPage extends StatefulWidget {
  const MainPage({super.key});

  @override
  State<MainPage> createState() => _MainPageState();
}

/** 
 * Future builder is a staeful widhget that subs to a future that will return its value. 
 * value starts calculates returns and finishes. 
 * it takes the shiunk of code that produces the value and subs to it and i will give you the ability to 
 * return various widgets that needs to be returned to the screen 
 * ties ui with db. 
 * 
 */
class _MainPageState extends State<MainPage> {
  late final EventsService _eventsService;
  late final Future<DatabaseUser> _user;
  late final Stream<List<DatabaseEvent>> _events;

  int _currentIndex = 1;
  String _title = "Crewmunity";

  @override
  void initState() {
    /** we create a new event service every time 
     * so we will create a singleton 
     * we create a service a service or class which is only one in our entire application. 
     * there shouldnt be other copies. 
     * 
     */
    _eventsService = EventsService();
    _eventsService.open();
    _user = _eventsService.getOrCreateUser(email: userEmail);
    _events = _eventsService.allEvents;

    super.initState();
  }

  // no need for now
  // @override
  // dispose() {
  //   _eventsService.close();
  //   super.dispose();
  // }

  String get userEmail => AuthService.firebase().currentUser!.email!;
  @override
  Widget build(BuildContext context) {
    var theme = Theme.of(context);
    final style = theme.textTheme.displaySmall!.copyWith(
      color: theme.colorScheme.onPrimary,
    ); // the textTheme has different fonts
    return Scaffold(
      appBar: CustomAppbar(title: _title),
      body: FutureBuilder(
        future: _user, //_eventsService.getOrCreateUser(email: userEmail),
        builder: (context, snapshot) {
          switch (snapshot.connectionState) {
            case ConnectionState.done:
              return StreamBuilder(
                stream: _events,
                builder: (context, snapshot) {
                  switch (snapshot.connectionState) {
                    case ConnectionState.active:
                      /**
                     *  listview box scroll view which is a stateless widget
                     * builder we will pass 2 params
                     * we need for the item count to listen to the snapshot. 
                     */
                      if (snapshot.hasData) {
                        final allEvents = snapshot.data as List<DatabaseEvent>;
                        allEvents.sort((a, b) => b.date.compareTo(a.date));
                        return EventListView(
                            events: allEvents,
                            onDeleteEvent: (event) async {
                              await _eventsService.deleteEvent(id: event.id);
                            },
                            onTap: (event) {
                              Navigator.of(context).pushNamed(
                                  createUpdateEventRoute,
                                  arguments: event);
                            },
                            isUserPage: false);
                      } else {
                        return const CircularProgressIndicator();
                      }

                    case ConnectionState.waiting:
                      return const Text("Waiting for all events");
                    default:
                      return CircularProgressIndicator();
                  }
                },
              );
            default:
              return const CircularProgressIndicator();
          }
        },
      ),
      bottomNavigationBar: CustomBottomNanBar(
        currentIndex: _currentIndex,
      ),
    );
  }
}

问题原因

  1. 页面重复重建:点击当前导航栏按钮时,BottomNavigationBar默认逻辑可能会销毁并重新创建当前页面实例,导致initState重新执行,Stream订阅被重置,进入等待状态。
  2. EventsService未实现单例:当前代码每次进入页面都会新建EventsService实例,重复打开数据库连接,导致流的订阅状态混乱。
  3. 未保持页面状态:页面切换时没有保留状态,每次重建都需要重新初始化Future和Stream。

解决方案

1. 实现EventsService单例

确保整个应用只有一个服务实例,避免重复创建数据库连接:

class EventsService {
  // 单例实现
  static final EventsService _instance = EventsService._internal();
  factory EventsService() => _instance;
  EventsService._internal();

  // 初始化逻辑放在内部,确保只执行一次
  bool _isOpened = false;
  void open() {
    if (!_isOpened) {
      // 原open逻辑
      _isOpened = true;
    }
  }

  // 其他原有代码...
}

2. 保持页面状态

使用AutomaticKeepAliveClientMixin让页面在切换时保留状态,避免重建:

class _MainPageState extends State<MainPage> with AutomaticKeepAliveClientMixin {
  // ... 原有代码

  @override
  bool get wantKeepAlive => true; // 开启状态保持

  @override
  Widget build(BuildContext context) {
    super.build(context); // 必须调用super.build
    // ... 原有build代码
  }
}

3. 优化BottomNavigationBar页面切换逻辑

使用IndexedStack包裹页面列表,确保页面实例不会被销毁:

// 假设导航栏对应的页面列表
final List<Widget> _pages = [
  // 其他页面
  MainPage(),
  // 其他页面
];

// 在Scaffold的body中替换为IndexedStack
body: IndexedStack(
  index: _currentIndex,
  children: _pages,
),

4. 增加Stream错误处理

在StreamBuilder中添加错误分支,避免因流异常导致页面卡住:

case ConnectionState.active:
  if (snapshot.hasError) {
    return Text('加载失败: ${snapshot.error}');
  }
  if (snapshot.hasData) {
    // 原有显示逻辑
  } else {
    return const CircularProgressIndicator();
  }

内容的提问来源于stack exchange,提问作者jason

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 03:42:28