Flutter Cubit始终停留在初始状态,请求排查问题
问题:Cubit调用Firebase获取数据后状态未更新,始终停留在初始状态
我尝试使用Cubit从Firebase Firestore中获取列表数据,但调用context.read<LocationHistoryCubit>().getLocationHistoryInitial后,状态并未更新,始终停留在初始状态。已经在main.dart中声明BlocProvider,也尝试用BlocProvider包裹组件树,但问题仍未解决。
Cubit类
class LocationHistoryCubit extends Cubit<LocationHistoryState> { LocationHistoryCubit() : super(LocationHistoryInitial()); final db = FirebaseFirestore.instance; Future<String?> getNamaPerusahaan() async { String uid = FirebaseAuth.instance.currentUser!.uid; log("Current uid : $uid"); final docRef = db.collection("DataUser").doc(uid).withConverter( fromFirestore: UserModel.fromFirestore, toFirestore: (UserModel userModel, _) => userModel.toFirestore(), ); final docSnap = await docRef.get(); final user = docSnap.data(); log("user company name : ${user?.companyId}"); return user?.companyId; } void getLocationHistoryInitial(String idKendaraan) async { //TODO : convert custom date time emit(LocationHistoryLoading()); String? companyName = await getNamaPerusahaan(); List<LatLng> latLngList = []; DateTime dateInit = DateTime.now(); TimeOfDay timeEndRaw = const TimeOfDay(hour: 23, minute: 59); TimeOfDay timeStartRaw = const TimeOfDay(hour: 00, minute: 01); DateTime dateStart = DateTime( dateInit.year, dateInit.month, dateInit.day, timeStartRaw.hour, timeStartRaw.minute); DateTime dateEnd = DateTime( dateInit.year, dateInit.month, dateInit.day, timeEndRaw.hour, timeEndRaw.minute); String timeStartFormat = DateFormat('yyyy-MM-dd HH:mm').format(dateStart); String timeEndFormat = DateFormat('yyyy-MM-dd HH:mm').format(dateEnd); final docRef = db.collection("DataPerusahaan").doc(companyName).collection( 'DaftarKendaraan') .doc(idKendaraan).collection("LocationHistory") .where( 'TIS', isGreaterThan: timeStartFormat, isLessThan: timeEndFormat) .orderBy( 'TIS', descending: false); var docSnap = await docRef.get(); final latlong = docSnap.docs; for (var coord in latlong) { GeoPoint location = coord.get('GeoPoint'); latLngList.add( LatLng(location.latitude, location.longitude) ); } log("latLong List : ${latLngList.length}"); if (latLngList.isEmpty) { emit(LocationHistoryEmpty()); } else { emit(LocationHistoryComplete(latLngList)); } } }
main.dart相关代码
class MyApp extends StatefulWidget { const MyApp({Key? key}) : super(key: key); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { @override Widget build(BuildContext context) { return MaterialApp( initialRoute: '/home', routes: { '/history' : (context) => MultiBlocProvider( providers: [ BlocProvider( create: (context)=>AuthCubit() ), BlocProvider( create: (context)=>LocationHistoryCubit() ), ], child: const NewLocationHistory() ),
状态类
@immutable abstract class LocationHistoryState {} class LocationHistoryInitial extends LocationHistoryState {} class LocationHistoryLoading extends LocationHistoryState{} class LocationHistoryComplete extends LocationHistoryState{ List<LatLng> latLongList; LocationHistoryComplete(this.latLongList); } class LocationHistoryError extends LocationHistoryState{} class LocationHistoryEmpty extends LocationHistoryState{}
组件树代码
@override Widget build(BuildContext context) { return Scaffold( body: BlocBuilder<LocationHistoryCubit, LocationHistoryState>( builder: (context, state){ log("Location History : $state"); if(state is LocationHistoryEmpty){ log("Location History : $state"); log("Location History Error"); }else if(state is LocationHistoryComplete){ return FlutterMap( options: MapOptions( center: LatLng(-6.9022141, 107.622682), zoom: 14), children: [ TileLayer( urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', ), PolylineLayer( polylines: [ Polyline( color: Colors.red, strokeWidth: 2, points: state.latLongList) ], ) ], ); }else if(state is LocationHistoryError){ log("Location History : $state"); log("Location History Error"); } return Container(); } ), );
调用代码(在另一个页面的IconButton中)
IconButton( onPressed: () { //log("Markers id : ${markers[1].key}"); context.read<LocationHistoryCubit>().getLocationHistoryInitial(document.id); Navigator.pushNamed(context, '/history', arguments: document.id); }, icon: jenisKendaraan == "Motor" ? const Icon(Icons.motorcycle) : const Icon(Icons.directions_car))
问题分析与修复方案
核心错误点
你当前的逻辑存在两个关键问题:
- Cubit实例不共享:跳转前调用的
context.read<LocationHistoryCubit>()是当前页面的Cubit实例,而/history页面的Cubit是在路由内重新创建的新实例,两者完全独立。 - 操作顺序错误:先触发旧实例的状态更新,再跳转到监听新实例的页面,导致新页面永远只能看到初始状态。
修复方案
方案1:在新页面初始化时触发数据加载(推荐)
把数据加载逻辑移到NewLocationHistory页面内部,确保调用的是当前页面的Cubit实例:
修改NewLocationHistory页面
class NewLocationHistory extends StatefulWidget { const NewLocationHistory({Key? key}) : super(key: key); @override State<NewLocationHistory> createState() => _NewLocationHistoryState(); } class _NewLocationHistoryState extends State<NewLocationHistory> { @override void initState() { super.initState(); // 获取路由参数里的车辆ID final idKendaraan = ModalRoute.of(context)?.settings.arguments as String; // 调用当前页面的Cubit加载数据 context.read<LocationHistoryCubit>().getLocationHistoryInitial(idKendaraan); } @override Widget build(BuildContext context) { return Scaffold( body: BlocBuilder<LocationHistoryCubit, LocationHistoryState>( builder: (context, state){ log("Location History : $state"); if(state is LocationHistoryLoading){ return const Center(child: CircularProgressIndicator()); }else if(state is LocationHistoryEmpty){ log("Location History : $state"); return const Center(child: Text("暂无位置历史数据")); }else if(state is LocationHistoryComplete){ return FlutterMap( options: MapOptions( center: LatLng(-6.9022141, 107.622682), zoom: 14), children: [ TileLayer( urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', ), PolylineLayer( polylines: [ Polyline( color: Colors.red, strokeWidth: 2, points: state.latLongList) ], ) ], ); }else if(state is LocationHistoryError){ log("Location History : $state"); return const Center(child: Text("加载数据失败")); } return Container(); } ), ); } }
修改调用页面的IconButton
IconButton( onPressed: () { Navigator.pushNamed(context, '/history', arguments: document.id); }, icon: jenisKendaraan == "Motor" ? const Icon(Icons.motorcycle) : const Icon(Icons.directions_car) )
方案2:使用全局共享Cubit实例(适合简单场景)
如果需要跨页面共享同一个Cubit状态,可将BlocProvider移到MaterialApp外层:
修改main.dart
class _MyAppState extends State<MyApp> { @override Widget build(BuildContext context) { return MultiBlocProvider( providers: [ BlocProvider(create: (context)=>AuthCubit()), BlocProvider(create: (context)=>LocationHistoryCubit()), ], child: MaterialApp( initialRoute: '/home', routes: { '/history' : (context) => const NewLocationHistory(), // 其他路由... }, ), ); } }
这种方式下,跳转前后页面使用同一个Cubit实例,原有的调用顺序可正常生效,但需注意避免不同页面的状态污染问题。
额外优化建议
- 添加异常捕获:在Cubit方法中捕获Firebase请求异常,防止崩溃:
void getLocationHistoryInitial(String idKendaraan) async { try { emit(LocationHistoryLoading()); // 原有逻辑代码... if (latLngList.isEmpty) { emit(LocationHistoryEmpty()); } else { emit(LocationHistoryComplete(latLngList)); } } catch (e) { log("加载位置历史失败: $e"); emit(LocationHistoryError()); } }
- 完善状态UI:补充
LocationHistoryLoading状态的加载UI,提升用户体验。
内容的提问来源于stack exchange,提问作者Fikri Abdullah
相关产品推荐
相关产品推荐

