androidflutterdartrefreshpull-to-refresh

pull to refresh won't stop refreshing in flutter


i have a question

here i am fetching data from api and i made a second page that i can post from my app in api .

when i post something and i come back to the main page that there is a lit of all of the post from my api , i need a refresh ... when i refresh it the new post will be added but the refreshing circle won't stop refreshing ..

i have no idea what to do ..

one place i read it's because of set state that creates an infinitive loop .. but i my case i need the set state to update the ui .. please tell me what to do . please help me thank u .

this is my code :

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyPage(),
    );
  }
}

class MyPage extends StatefulWidget {
  const MyPage({super.key});

  @override
  State<MyPage> createState() => _MyPageState();
}

class _MyPageState extends State<MyPage> {
  final RefreshController _myrefreshcontroller = RefreshController();
  late List<Post>? listpost;
  @override
  void initState() {
    fetchAllPosts().then((value) => listpost = value);
    super.initState();
  }

  void _onRefresh() async {
    await fetchAllPosts().then((value) {
      setState(() {
        listpost = value;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('welcome welcome'),
      ),
      body: Center(
        child: FutureBuilder(
          future: fetchAllPosts(),
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return SmartRefresher(
                controller: _myrefreshcontroller,
                onRefresh: _onRefresh,
                child: ListView.builder(
                  itemCount: listpost!.length,
                  itemBuilder: (context, index) {
                    return Card(
                      child: ListTile(
                        contentPadding: const EdgeInsets.all(20),
                        title: Padding(
                            padding: const EdgeInsets.all(20),
                            child: Text(listpost![index].id.toString())),
                        subtitle: Padding(
                            padding: const EdgeInsets.all(20),
                            child: Text(listpost![index].content.toString())),
                      ),
                    );
                  },
                ),
              );
            } else if (snapshot.hasError) {
              return Text("${snapshot.error}");
            }
            return const CircularProgressIndicator();
          },
        ),
      ),

Solution

  • The package you’re using for refreshing recommends adding _refreshController.refreshCompleted() on a successful refresh, which your code is missing. With a bit of error handling, it should look like this:

    void _onRefresh() async {
        fetchAllPosts().then((value) {
          setState(() {
            listPost = value;
          });
          _refreshController.refreshCompleted();
        }).catchError((error) {
          _refreshController.refreshFailed();
        });
      }
    

    And yes, while the setState would cause the infinite loop if you were using Flutter’s default RefreshIndicator, in cases where you need to trigger a rebuild in your FutureBuilder without resetting the future, you can workaround this by making the future memoized first.

    In summary, memoizing your future would change the behaviour of your FutureBuilder to only rebuild when the future itself changes and not on every setState call.

    To do this, based on your code, the code before your _onRefresh method would now look like this:

      final RefreshController _refreshController = RefreshController();
      late Future<List<Post>> futurePosts;
      late List<Post>? listPost;
    
      @override
      void initState() {
        super.initState();
        futurePosts = fetchAllPosts();
      }
    

    and in your FutureBuilder, you would update the future to use the memoized data, which would then look like:

    FutureBuilder<List<Post>>(
       future: futurePosts,
        …