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

Flutter Web已认证状态下首页重复加载两次的问题排查求助

Flutter Web已认证状态下首页重复加载两次的问题排查求助

我现在在开发一个Flutter Web应用,用了Bloc状态管理。我做了一个authOrApp路由用来检查用户是否已认证,但每次启动Web应用时,如果用户是已认证状态,首页会快速加载两次。问题在于首页里还有另一个Bloc要做比较重的处理,加载两次直接导致整个过程变慢了。我自己没找出原因,想请教下大家有没有什么排查思路?

下面是我的main.dart代码:

import 'dart:io';
import 'package:envelog/manage_users/bloc/manage_users_bloc.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:http/io_client.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:envelog/auth_or_app/bloc/auth_or_app_bloc.dart';
import 'package:envelog/values/bloc/values_bloc.dart';
import 'package:envelog/values/models/values.dart';
import 'package:envelog/excerpt/bloc/excerpt_bloc.dart';
import 'package:envelog/excerpt/models/excerpt.dart';
import 'package:envelog/expense/bloc/expense_bloc.dart';
import 'package:envelog/expense/models/expense.dart';
import 'package:envelog/login/bloc/login_bloc.dart';
import 'package:envelog/login/models/logged_user.dart';
import 'package:envelog/nfc/bloc/nfc_bloc.dart';
import 'package:envelog/nfc/models/nfc.dart';
import 'package:envelog/observation/bloc/observation_bloc.dart';
import 'package:envelog/observation/models/observation.dart';
import 'package:envelog/refuel/bloc/refuel_bloc.dart';
import 'package:envelog/refuel/models/refuel.dart';
import 'package:envelog/side_menu/bloc/side_menu_bloc.dart';
import 'package:envelog/trip/bloc/trip_bloc.dart';
import 'package:envelog/trip/models/trip.dart';
import 'package:envelog/utils/app_routes.dart';
// ignore: depend_on_referenced_packages
import 'package:flutter_localizations/flutter_localizations.dart';

final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

void main() async {
  await Hive.initFlutter();
  await hiveAdapters();
  // await Hive.deleteBoxFromDisk('pendingNfcOperations'); // substitua pelo nome correto da box
  await Hive.openBox<LoggedUser>('loggedUser');
  await Hive.openBox<Trip>('trips');
  await Hive.openBox<Nfc>('nfcs');
  await Hive.openBox<Values>('values');
  await Hive.openBox<Refuel>('refuels');
  await Hive.openBox<Observation>('observations');
  await Hive.openBox<Excerpt>('excerpts');
  await Hive.openBox<Expense>('expenses');
  await Hive.openBox<Map>('pendingTripOperations');
  await Hive.openBox<Map>('pendingValuesOperations');
  await Hive.openBox<Map>('pendingNfcOperations');
  await Hive.openBox<Map>('pendingExcerptOperations');
  await Hive.openBox<Map>('pendingExpenseOperations');
  await Hive.openBox<Map>('pendingRefuelOperations');
  await Hive.openBox<Map>('pendingObservationOperations');

  HttpOverrides.global = MyHttpOverrides();
  runApp(const MyApp());
}

Future<void> hiveAdapters() async {
  Hive.registerAdapter(LoggedUserAdapter());
  Hive.registerAdapter(TripAdapter());
  Hive.registerAdapter(ExcerptAdapter());
  Hive.registerAdapter(ExpenseAdapter());
  Hive.registerAdapter(NfcAdapter());
  Hive.registerAdapter(RefuelAdapter());
  Hive.registerAdapter(ObservationAdapter());
  Hive.registerAdapter(ValuesAdapter());
}

class MyHttpOverrides extends HttpOverrides {
  @override
  HttpClient createHttpClient(SecurityContext? context) {
    final client = super.createHttpClient(context);
    client.badCertificateCallback = (X509Certificate cert, String host, int port) => true;
    return client;
  }
}

http.Client createHttpClientWithBypass() {
  final ioClient = HttpClient()
    ..badCertificateCallback = (X509Certificate cert, String host, int port) => true;
  return IOClient(ioClient);
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MultiBlocProvider(
      providers: [
        BlocProvider(
          create: (context) => LoginBloc(),
        ),
        if (!kIsWeb)
          BlocProvider(
            create: (context) => AuthOrAppBloc(),
          ),
        if (kIsWeb)
          BlocProvider(
            create: (context) => AuthOrAppBloc()..add(AuthOrAppInitialEvent()),
          ),
        BlocProvider(
          create: (context) => SideMenuBloc(),
        ),
        BlocProvider(
          create: (context) => TripBloc()..add(TripInitialEvent()),
        ),
        BlocProvider(
          create: (context) => ExcerptBloc(),
        ),
        BlocProvider(
          create: (context) => ExpenseBloc(),
        ),
        BlocProvider(
          create: (context) => NfcBloc(),
        ),
        BlocProvider(
          create: (context) => RefuelBloc(),
        ),
        BlocProvider(
          create: (context) => ObservationBloc(),
        ),
        BlocProvider(
          create: (context) => ValuesBloc(),
        ),
        BlocProvider(
          create: (context) => ManageUsersBloc(),
        ),
      ],
      child: MaterialApp(
        navigatorKey: navigatorKey,
        localizationsDelegates: const [
          ...GlobalMaterialLocalizations.delegates,
          GlobalWidgetsLocalizations.delegate,
          // Other localization delegates if needed
        ],
        supportedLocales: const [
          Locale('pt', 'BR'), // 这里假设你用的是葡萄牙语巴西地区,可根据实际调整
        ],
        // 这里应该还有你的路由配置,比如initialRoute或者onGenerateRoute
      ),
    );
  }
}

我自己初步想到的几个排查方向,也想和大家讨论下

  1. AuthOrAppBloc的状态流转问题:会不会是AuthOrAppInitialEvent触发后,Bloc重复发射了"已认证"状态,导致路由被两次导航到首页?可以在Bloc的mapEventToState里加打印,看状态发射了几次。
  2. TripBloc的初始化时机:我在MultiBlocProvider里直接给TripBloc绑定了TripInitialEvent,会不会在Web环境下,因为Widget树的重建,这个Bloc被初始化了两次?可以给TripBloc的构造函数加打印,看实例化了几次。
  3. 路由跳转的逻辑问题:authOrApp路由的判断逻辑里,是不是用了push而不是pushReplacement?或者有没有在认证状态变化时,重复触发了路由跳转?
  4. Web环境的特殊生命周期:Flutter Web在初始化时,有没有可能因为浏览器的渲染机制,导致整个Widget树被重建了两次?可以在首页的initState里加打印,看执行了几次。
相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 06:17:59