I'm trying to make a refresh button (and later a pull down gesture) for my flutter app. I want that if I press the refresh button, that the a method is called and where data is pulled from a webserver and also a layout is getting rebuild.
This is my code so far: My main.dart:
class MyHomePageState extends State<MyHomePage> {
final GetWebsites _getWebsites = GetWebsites();
@override
void initState() {
refresh();
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: getSites(),
);
}
//Get sites => Document, store them in a Document list
Widget getSites() {
return FutureBuilder<List<html.Document>>(
//gets Dates of each date in other class and puts it in an List -> snapshot
future: _getWebsites.getWebsite(),
builder: (BuildContext context, AsyncSnapshot<List<html.Document>> snapshot) {
//Cases for Connections
switch(snapshot.connectionState) {
case ConnectionState.active:
case ConnectionState.waiting:
return const Center(
//TODO: Make better loading screen
child: RefreshProgressIndicator(),
);
case ConnectionState.none:
return const Center(
child: Text("Keine Verbindung"),
);
case ConnectionState.done:
if (snapshot.hasError) {
return const Center(
child: Text('Fehler'),
);
}
//create tabs
return buildrefresh(snapshot);
}
},
);
}
Widget buildrefresh(AsyncSnapshot<List<html.Document>> snapshot) {
return RefreshIndicator(
onRefresh: () {
return refresh();
},
child: rowortabbedLayout(snapshot),
);
}
Widget rowortabbedLayout(AsyncSnapshot<List<html.Document>> snapshot) {
if(Settings.getValue<bool>("keyrowortabbed", true)){
return TabbedLayout().createTabbedLayout(snapshot, context);
}else{
return RowLayout().createRowLayout(snapshot, context);
}
}
Future<void> refresh() async {
setState((){
FutureBuilder<List<html.Document>>(
//gets Dates of each date in other class and puts it in an List -> snapshot
future: _getWebsites.getWebsite(),
builder: (BuildContext context, AsyncSnapshot<List<html.Document>> snapshot) {
//Cases for Connections
switch(snapshot.connectionState) {
case ConnectionState.active:
case ConnectionState.waiting:
return const Center(
child: RefreshProgressIndicator(),
);
case ConnectionState.none:
return const Center(
child: Text("Keine Verbindung"),
);
case ConnectionState.done:
if (snapshot.hasError) {
return const Center(
child: Text('Fehler'),
);
}
//create tabs
return buildrefresh(snapshot);
}
},
);
});
print("Do something!");
}
Future<void> setstaterefresh() async {
setState((){});
print("Do something!");
}
}
And for the tabbed layout (there is also a row layout, but I will do this later)
class TabbedLayout{
final SiteParser _getSiteData = SiteParser();
Widget createTabbedLayout(AsyncSnapshot<List<html.Document>> snapshot, BuildContext context){
return buildrevresh(snapshot,context);
}
Widget buildrevresh(AsyncSnapshot<List<html.Document>> snapshot, BuildContext context) {
return RefreshIndicator(
onRefresh: () {
return MyHomePageState().setstaterefresh();
},
child: tabcontroller(snapshot,context),
);
}
Widget tabcontroller(AsyncSnapshot<List<html.Document>> snapshot, BuildContext context) {
return DefaultTabController(length: snapshot.data!.length,
child: Scaffold(
appBar: AppBar(
actions: <Widget> [
IconButton(
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => const MySettings()),
);
},
icon: const Icon(Icons.settings),
),
//Refresh Button:
IconButton(
icon: const Icon(Icons.refresh),
onPressed: () {
MyHomePageState().refresh();
},
),
],
bottom: TabBar(
isScrollable: true,
tabs:
//Tab names
tabBarMaker(snapshot),
),
title: const Text("Vertretungsplan")
),
body:
TabBarView(
children:
tabMaker(snapshot),
physics: const BouncingScrollPhysics(),
),
),
);
}
List<Widget> tabBarMaker(AsyncSnapshot<List<html.Document>> snapshot) {
List<Tab> tabs = [];
for(int x = 0; x<snapshot.data!.length; x ) {
tabs.add(Tab(text: snapshot.data![x].querySelector('h1.list-table-caption')!.text
.toString()));
}
return tabs;
}
//Create Tabs with contetnt for each site
List<Widget> tabMaker(AsyncSnapshot<List<html.Document>> snapshot) {
List<Widget> tabwidgets = [];
for(int x = 0; x<snapshot.data!.length; x ) {
tabwidgets.add(_buildDay(snapshot.data![x]));
}
return tabwidgets;
}
//Widget to create Tabs of each day and their contents
//Get Contents of a day
Widget _buildDay(html.Document site) {
List<tage> days = _getSiteData.getData(site);
return ListView.builder(
padding: const EdgeInsets.all(10),
itemCount: days.length,
physics: const BouncingScrollPhysics(),
itemBuilder: (context, index) {
//Build cards for each content
return MyThemes().buildCard(days[index]);
},
);
}
}
When I try this I get this error:
E/flutter (13792): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: setState() called in constructor: MyHomePageState#a8b0c(lifecycle state: created, no widget, not mounted)
E/flutter (13792): This happens when you call setState() on a State object for a widget that hasn't been inserted into the widget tree yet. It is not necessary to call setState() in the constructor, since the state is already assumed to be dirty when it is initially created.
E/flutter (13792): #0 State.setState.<anonymous closure> (package:flutter/src/widgets/framework.dart:1076:9)
E/flutter (13792): #1 State.setState (package:flutter/src/widgets/framework.dart:1087:6)
E/flutter (13792): #2 MyHomePageState.refresh (package:khsplan/main.dart:140:5)
E/flutter (13792): #3 TabbedLayout.tabcontroller.<anonymous closure> (package:khsplan/Vplan/tabbedlayout.dart:42:37)
E/flutter (13792): #4 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:989:21)
E/flutter (13792): #5 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:193:24)
E/flutter (13792): #6 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:608:11)
E/flutter (13792): #7 BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:296:5)
E/flutter (13792): #8 BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:230:7)
E/flutter (13792): #9 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:558:9)
E/flutter (13792): #10 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:94:12)
E/flutter (13792): #11 PointerRouter._dispatchEventToRoutes.<anonymous closure> (package:flutter/src/gestures/pointer_router.dart:139:9)
E/flutter (13792): #12 _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:400:8)
E/flutter (13792): #13 PointerRouter._dispatchEventToRoutes (package:flutter/src/gestures/pointer_router.dart:137:18)
E/flutter (13792): #14 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:123:7)
E/flutter (13792): #15 GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:440:19)
E/flutter (13792): #16 GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:420:22)
E/flutter (13792): #17 RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:278:11)
E/flutter (13792): #18 GestureBinding._handlePointerEventImmediately (package:flutter/src/gestures/binding.dart:374:7)
E/flutter (13792): #19 GestureBinding.handlePointerEvent (package:flutter/src/gestures/binding.dart:338:5)
E/flutter (13792): #20 GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:296:7)
E/flutter (13792): #21 GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:279:7)
E/flutter (13792): #22 _rootRunUnary (dart:async/zone.dart:1444:13)
E/flutter (13792): #23 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
E/flutter (13792): #24 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
E/flutter (13792): #25 _invoke1 (dart:ui/hooks.dart:185:10)
E/flutter (13792): #26 PlatformDispatcher._dispatchPointerDataPacket (dart:ui/platform_dispatcher.dart:293:7)
E/flutter (13792): #27 _dispatchPointerDataPacket (dart:ui/hooks.dart:98:31)
E/flutter (13792):
CodePudding user response:
Change your initState() method to the following:
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
refresh();
});
}
This way your refresh() function will be executed once your widget has completed its first build.
CodePudding user response:
Just make a refresh function
void refresh(){ setState({
}); }
and use it in your on pressed button.