Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter, calling FutureBuilder from a raised button's onPressed doesn't call the builder property

Tags:

flutter

dart

I'm trying to learn Dart/Flutter and am working on an example where there's a button on the app that says "Get Data", and when I touch it I want to retrieve JSON data from a restful service.

I see the web service being called in fetchPost, but the builder property of the FutureBuilder isn't called.

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'ResultsList.dart';
import 'dart:convert';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Restul Test',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            RaisedButton(
              onPressed: (){
                FutureBuilder<ResultsList>(
                  future: fetchPost(),
                  builder: (context, snapshot){
                    print('In Builder');
                  }
                );
              },
              child: Text('Get data'),
            )
          ],
        ),
      )
    );
  }
}

Future<ResultsList> fetchPost() async {
    final response =  await http.get('http://mywebserviceurl');

    if (response.statusCode == 200){
      print('Received data');
      return ResultsList.fromJson(json.decode(response.body));
    }
    else {
      throw Exception('Failed to load data');
    }
}

Interestingly though, if I move the FutureBuilder out of the onPressed of the button to the child of Center, I do see the builder property getting called.

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'ResultsList.dart';
import 'dart:convert';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Restul Test',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: FutureBuilder<ResultsList>(
                future: fetchPost(),
                builder: (context, snapshot){
                  print ('In Builder');
                  return Container();
                }
              )
      )
    );
  }
}

Future<ResultsList> fetchPost() async {
    final response =  await http.get('http://mywebserviceurl');

    if (response.statusCode == 200){
      print('Received data');
      return ResultsList.fromJson(json.decode(response.body));
    }
    else {
      throw Exception('Failed to load data');
    }
}

Obviously I'm missing something, but any idea what I'm doing wrong?

like image 620
a344254 Avatar asked Nov 29 '18 15:11

a344254


2 Answers

If you want to get some data from request - you don't need FutureBuilder. You can do:

RaisedButton(
          onPressed: (){
            fetchPost().then((result) {
                print('In Builder');
            })
          },
          child: Text('Get data'),
        )

or

RaisedButton(
          onPressed: () async {
            var result = await fetchPost()
            print('In Builder');
          },
          child: Text('Get data'),
        )
like image 67
Andrey Turkovsky Avatar answered Dec 08 '22 01:12

Andrey Turkovsky


The onPressed method in this RaisedButton is actually not doing anything. It just creates a new FutureBuilder which does nothing but existing^^ It's like you would just call 1+1;, which just creates a value, but that value is not used to do anything.

RaisedButton(
  onPressed: (){
    FutureBuilder<ResultsList>(
      future: fetchPost(),
      builder: (context, snapshot){
        print('In Builder');
      }
    );
  },
  child: Text('Get data'),
)

You could have body be assigned to a Widget(which could just be called body or whatever you want^^), which you then change in a setState((){body = FutureBuilder(/*...*/}); call.

like image 23
leodriesch Avatar answered Dec 08 '22 01:12

leodriesch