I have a HomePage with DataTable with several hundred rows, which takes a while to load. The HomePageState reloads every time I sort the data table - while building, the whole page freezes for a second or two.
Is it possible to add a progress indicator, build the new state in the background and show it after the build is done?
In other words, I want this to happen when a user sorts the table:
CircularProgressIndicator shows up
The new state is shown after the new state is built
Hoping you are using FutureBuilder for getting data.
FutureBuilder(
future: fetchData(),
builder: (_, dataSnapshot) {
if (dataSnapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else {
return Container(), // Your widgets code
);
}
},
)
inside else block get data like dataSnapshot.data -- Use this to render widgets.
Related
Here is snippet of code for loading data from firebase realtime database to a list:
var CategoryName = FirebaseDatabase.instance.reference().child('CategoryNames').once()
.then((DataSnapshot dataSnapshot){
var key = dataSnapshot.value.keys;
for(var i in key)
{
// print(dataSnapshot.value[i]['Name']);
CategoriesOnly categoriesOnly = new CategoriesOnly(
dataSnapshot.value[i]['Name']
);
categoriesOnlyList.add(categoriesOnly);
}
setState(() {
print(categoryItemList.length);
});
});
I'm storing these data into a list and showing them into ListView.builder.
And I want to show the screen once data is fully loaded meanwhile it show some kind of loading widget or loading screen but in my case screen looks blank and after sometime it shows the data. And if internet connectivity is slow blank screen appears for a minutes and loads it(because my data contains images as well). And also I want if loading time exceeds from some specific time it will show try reloading again or internet connectivity error. Please help.
As the other people already said I think the best solution would be a FutureBuilder like this:
FutureBuilder(
future: //your future you want the data from,
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text("None");
case ConnectionState.active:
return Text("active");
case ConnectionState.waiting: /while you are waiting for the data...
return CupertinoActivityIndicator(); //thats the typical apple loading
return CircularProgressIndicator(); // this would be a blue circle
case ConnectionState.done:
//you have the data and can access it with 'snapshot.data'
}
}),
I'm currently working on an app and I want to get some data of a user's friends. Ideally, after sign in, this information is loaded up onto the screen for viewing.
I initially made my function call to do this within the "build" method of my HomeScreen, but this caused an infinite loop as the function call ended with "notifyListeners()".
That being said, where should I place my call to avoid a loop, while still having the UI update once the data has been fetched from the database?
You should have a look at the FutureBuilder widget, which provides great functionality to load async data and show the result once available. While the data is loading, or if your code runs into an error, you can show a different widget. Essentially it works like this:
FutureBuilder<String>(
future: _yourFuture,
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.active:
case ConnectionState.waiting:
// Return loading indicator
return Container();
case ConnectionState.done:
if (snapshot.hasError) {
// Return error
return Container();
} else if (snapshot.hasData) {
// Data loaded => use snapshot.data to access it
return Container();
}
}
})
I would not recommend to load data during initState(), since this method cannot be async and thus, you cannot await your result.
I hope that helps.
So the first picture has codes from the first page where I have a StreamBuilder in my flutter app, there I tried navigating to the stateful widget named PickupScreen containing the code in second picture and it gave me an error which says SetState( or markNeedsbuild() called during build.So I called the widget directly and it worked but the problem is I cannot go the previous page I know I can't use pop but I need a solution for returning to previous page and show the else code.Currently I am Navigating to another page named HomePage.
You can't do it like that. Either you manage your screen state based on your widget.channel.stream or you must design your UI in a different way so you can actually push a new screen on your screen 1 and then you will be able to pop.
If you still want to keep it like that, you can do something like the following in your first screen:
return StreamBuilder(
stream: widget.channel.stream,
builder: (context, snapshot){
if(snapshot.hasData && jsonDecode(snapshot.data['ntype'] == 10){
WidgetsBinding.instance.addPostFrameCallback((_) => Navigator.push(context, MaterialPageRoute(builder: (_) => PickupScreen(data: jsonDecode(snapshot.data))));
return const SizedBox();
} else {
return _isLoading ? LoadingScreen() : Scaffold();
}
});
Also, next time, make sure you copy/paste code instead of screenshots to make it easy to edit with modifications. :)
Fast question: how can I perform a navigation inside the build method of a widget?
I'm developing a Flutter App.
I use Bloc architecture.
I have screen with a create form. When the user presses a button, it calls a REST api. While the call is being executed I display a circular progress. When the progress ends I want the screen to be popped (using navigation).
To display the job status I use a Stream in the bloc and a StreamBuilder in the widget. So I want to do something like this:
return StreamBuilder<Job<T>>(
stream: jobstream,
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data.jobStatus == JobStatus.progress)
// job being executed, display progress
return Center(child: CircularProgressIndicator());
else if (snapshot.data.jobStatus == JobStatus.success)
Navigator.pop(context); // Problem here!
return Center(child: CircularProgressIndicator());
} else {
return DisplayForm();
}
});
I have problems with the line: Navigator.pop(context);
Because navigation is not allowed during a build.
How can I do this navigation?
My currect dirty solution is using the following function, but its ugly:
static void deferredPop(BuildContext context) async{
Future.delayed(
Duration(milliseconds: 1),
() => Navigator.pop(context)
);
}
You can add a callback to be executed after the build method is complete with this line of code:
WidgetsBinding.instance.addPostFrameCallback((_) => Navigator.pop(context));
'Because navigation is not allowed during a build.' that being said you should consider creating a separate function that will receive as an input something that you will take into consideration whether to pop that screen.
I want to populate my lists by making API calls when moving to a screen in flutter. I tried calling the async function in the init state however it takes time to load the data of course, and that leads to a null error.
I tried using a future builder in my view. However, I want to make multiple API calls and I don't think that is possible with one future builder. And I would like to avoid having different future builders for each list.
Is there a neat way to do this?
Also is it advisable to load data and pass it on from the previous screen.. since I would like to avoid the loading time?
current code
FutureBuilder(
future: getAllData,
initialData: [],
builder: (context, snapshot) {
if (!snapshot.hasData || snapshot.data.isEmpty) return Center(child: CircularProgressIndicator(valueColor: new AlwaysStoppedAnimation<Color>(Colors.red),));
else {
return createNewTaskView(context, snapshot.data);
}
}),
init method
#override
void initState() {
this.getAllData = getSocieties();
}