I have a page that shows a list of items. This page is reached by button click on a previous page. I use a FutureBuilder to populate the list of items when the retrieval is complete. While the ConnectionState is "waiting," I show a circular progress indicator. However, the progress indicator never appears and the list page does not appear to push until the FutureBuilder completes. If I place a breakpoint in the "if (snapshot.connectionState == ConnectionState.waiting)" block, it hits that breakpoint, but the screen doesn't change on return. The screen does appear as expected, but as the list of items grows it takes longer and longer for the screen to appear. Am I missing something here:
class MyListScreen extends StatelessWidget {
RelevantObject relevantObject;
MyListScreen(this.relevantObject, {Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
final bloc = MyListBloc(relevantObject);
return FutureBuilder<Widget>(
future: _buildList(bloc, context),
builder: (BuildContext context, AsyncSnapshot<Widget> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Scaffold(
appBar: AppBar(
centerTitle: false,
title: Text(
"My Title",
),
),
body: Center(child: CircularProgressIndicator()),
);
} else {
return BlocProvider<MyListBloc>(
bloc: bloc, child: snapshot.data);
}
},
);
}
Future<Widget> _buildList(
MyListBloc bloc, BuildContext myContext) async {
//await bloc.init();
List<Widget> listView = await bloc.getListItems(myContext);
return StreamBuilder<List<MyListItem>>(
stream: bloc.drawingCanvasListStream,
builder: (context, snapshot) {
return Scaffold(
appBar: AppBar(
title: Text('My Title'),
centerTitle: false,
),
body: SingleChildScrollView(
child: Column(mainAxisSize: MainAxisSize.min, children: listView),
),
);
});
}
}
UPDATE:
I altered my approach and tried to make it a bit simpler. Here is my updated "List Screen.":
class MyListScreen extends StatefulWidget{
final bloc = MyListBloc();
@override
_MyListState createState() => _MyListState();
}
class _MyListState extends State<MyListScreen>{
@override
void initState() {
widget.bloc.getListItems(context);
super.initState();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return StreamBuilder<List<Widget>>(
stream: widget.bloc.myListStream,
builder: (context, snapshot) {
return Scaffold(
appBar: AppBar(
title: Text('My App'),
centerTitle: false,
),
body:
SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min, children: snapshot.data == null ? [Center(child: CircularProgressIndicator())] :
snapshot.data
)
,
),
);
});
}
}
The MyListBloc class has a Stream of List<Widget> that is initially an empty list. When the getListItems finishes, it adds those widgets to the stream. The MyListScreen still is not showing up until that async getListItems has finished. Hopes this new code makes it a little easier to point out my misunderstanding.
UPDATE 2:
I tried this as well to no avail:
import 'package:flutter/material.dart';
class MyListScreen extends StatefulWidget{
final bloc = MyListBloc();
@override
_MyListState createState() => _MyListState();
}
class _MyListState extends State<MyListScreen>{
@override
void initState() {
widget.bloc.getListItems(context);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('My App'),
centerTitle: false,
),
body: StreamBuilder<List<Widget>>(
stream: widget.bloc.myListStream,
builder: (context, snapshot) {
if(snapshot.connectionState == ConnectionState.waiting){
return Center(child: CircularProgressIndicator());
}
else {
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min, children: snapshot.data
)
,
);
}
})
);
}
}
widget.bloc.getListItems(context) is an async method that I do not await. Yet, the screen still does not appear until snapshot.data != null.