Home > Enterprise >  How to build a refresh method in Flutter
How to build a refresh method in Flutter

Time:01-02

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.

  • Related