I have a very simple setup. A TabBarView with 2 tabs. On the first tab the user would choose an option. With this first option, something would be loaded from an API to display on the second tab in a FutureBuilder. The problem is that the FutureBuilder gets stuck on ConnectionState.none. The only way to fix this is by waiting for a while before calling setState again so that the FutureBuilder updates. Any ideas on how to solve this? It has been bugging me for way too long.
Minimum reproducible example (tested on DartPad):
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: TabWidget(),
);
}
}
class TabWidget extends StatefulWidget {
@override
_TabWidgetState createState() => _TabWidgetState();
}
class _TabWidgetState extends State<TabWidget> with SingleTickerProviderStateMixin {
late final TabController _tabController;
Future<String>? _future;
@override
void initState() {
super.initState();
_tabController = TabController(length: 2, vsync: this);
}
Future<String> _loadStuff(int i) async {
await Future.delayed(Duration(milliseconds: 100));
return "Loaded $i!";
}
void onNext(int i) async {
_tabController.index += 1;
setState(() {
_future = _loadStuff(i);
});
// Only works when calling setState after the tab has changed!
// await Future.delayed(Duration(seconds: 1));
// setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Example")),
body: TabBarView(
physics: NeverScrollableScrollPhysics(),
controller: _tabController,
children: [
ListView(
children: [
ListTile(title: Text("Option 1"), onTap: () => onNext(1)),
ListTile(title: Text("Option 2"), onTap: () => onNext(2)),
ListTile(title: Text("Option 3"), onTap: () => onNext(3)),
],
),
FutureBuilder<String>(
future: _future,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Center(child: Text(snapshot.data!));
} else {
return Center(child: CircularProgressIndicator());
}
},
),
],
),
);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
}