BottomSheet中StatefulBuilder调用setState报dispose后调用错误求解决
The issue here is that your mounted check is referencing the parent widget's state, not the StatefulBuilder's state inside the bottom sheet. When the bottom sheet is closed, the StatefulBuilder's state gets disposed, but the parent widget might still be mounted—so your existing check doesn't prevent calling newSetState on a disposed state.
Here's the cleanest solution using a dedicated StatefulWidget for your bottom sheet content, which properly manages its own state and mounted status:
Step 1: Create a reusable FolderInfoBottomSheet widget
import 'package:path/path.dart' as path; class FolderInfoBottomSheet extends StatefulWidget { final String folderPath; final FileStat fileStat; const FolderInfoBottomSheet({ super.key, required this.folderPath, required this.fileStat, }); @override State<FolderInfoBottomSheet> createState() => _FolderInfoBottomSheetState(); } class _FolderInfoBottomSheetState extends State<FolderInfoBottomSheet> { String _size = '0 KB'; @override void initState() { super.initState(); _loadFolderSize(); } Future<void> _loadFolderSize() async { // Get your folder size as before final folderSize = await getFolderSize(widget.folderPath); // Check if this bottom sheet's state is still mounted before updating if (!mounted) return; setState(() { _size = folderSize; }); } @override Widget build(BuildContext context) { return SingleChildScrollView( child: Column( children: [ const SizedBox(height: 2.0), const Text( 'Info', style: TextStyle(fontWeight: FontWeight.bold), ), const SizedBox(height: 2.0), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( child: Align( alignment: Alignment.centerRight, child: Text('Name: '), ), ), Expanded(child: Text(path.basename(widget.folderPath))), ], ), const SizedBox(height: 2.0), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( child: Align( alignment: Alignment.centerRight, child: Text('Size: '), ), ), Expanded(child: Text(_size)), ], ), const SizedBox(height: 2.0), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( child: Align( alignment: Alignment.centerRight, child: Text('Last Modified Date: '), ), ), Expanded(child: Text(widget.fileStat.modified.toString())), ], ), const SizedBox(height: 2.0), ], ), ); } }
Step 2: Update your showModalBottomSheet call
Replace your existing bottom sheet code with this:
final lastItem = selectedFilesAndFolders.last; final fileStat = lastItem.statSync(); showModalBottomSheet( context: context, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(12.0), topRight: Radius.circular(12.0), ), ), builder: (context) { return FolderInfoBottomSheet( folderPath: lastItem.path, fileStat: fileStat, ); }, );
Why this works:
- The
mountedcheck now references the bottom sheet's own state, so it correctly detects when the bottom sheet has been closed and disposed. - All state related to the bottom sheet (like
_size) is encapsulated within the widget, making your code more organized and maintainable. - The folder size is loaded in
initState, which runs once when the bottom sheet is created, avoiding unnecessary re-runs.
Alternative Fix (Using StatefulBuilder):
If you prefer to keep using StatefulBuilder, you can capture its context and check if it's still mounted before calling newSetState. However, you'll need to use a ValueNotifier to preserve the size state between rebuilds:
showModalBottomSheet( context: context, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(12.0), topRight: Radius.circular(12.0), ), ), builder: (context) { final sizeNotifier = ValueNotifier<String>('0 KB'); final lastItem = selectedFilesAndFolders.last; getFolderSize(lastItem.path).then((value) { // Check if the bottom sheet's context is still mounted if (!context.mounted) return; sizeNotifier.value = value; }); return StatefulBuilder(builder: (sbContext, newSetState) { return SingleChildScrollView( child: Column( children: [ // ... other widgets Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( child: Align( alignment: Alignment.centerRight, child: Text('Size: '), ), ), Expanded( child: ValueListenableBuilder<String>( valueListenable: sizeNotifier, builder: (_, value, __) => Text(value), ), ), ], ), // ... rest of the UI ], ), ); }); }, );
The dedicated StatefulWidget approach is strongly recommended for better code structure and maintainability.
内容的提问来源于stack exchange,提问作者MSARKrish

