How do I call async property in Widget build method

前端 未结 3 1105
-上瘾入骨i
-上瘾入骨i 2020-12-06 16:38

I\'m new to Flutter and Dart, and I\'m trying to build a Flutter app which displays the device information on the screen. For this purpose I\'m trying to use this library: \

3条回答
  •  鱼传尺愫
    2020-12-06 16:51

    I would suggest you to use a FutureBuilder:

    import 'package:flutter/material.dart';
    
    class MyApp extends StatefulWidget {
      @override
      _MyAppState createState() => _MyAppState();
    }
    
    class _MyAppState extends State {
      // save in the state for caching!
      DeviceInfoPlugin _deviceInfoPlugin;
    
      @override
      void initState() {
        super.initState();
        _deviceInfoPlugin = DeviceInfoPlugin();
      }
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'My Device Info',
          home: Scaffold(
            appBar: AppBar(
              title: Text('My Device Info'),
            ),
            body: FutureBuilder(
              future: _deviceInfoPlugin.androidInfo,
              builder: (BuildContext context, AsyncSnapshot snapshot) {
                if (!snapshot.hasData) {
                  // while data is loading:
                  return Center(
                    child: CircularProgressIndicator(),
                  );
                } else {
                  // data loaded:
                  final androidDeviceInfo = snapshot.data;
                  return Center(
                    child: Text('Android version: ${androidDeviceInfo.version}'),
                  );
                }
              },
            ),
          ),
        );
      }
    }
    

    In general, when using FutureBuilder or Futures, you have to keep in mind that the enclosing widget can be rebuilt at any time (e.g. because the device was rotated, or the keyboard is shown). That means the build method is called again.

    In this particular case it's not a problem because the plugin caches the value and returns it instantly, but in general you should NEVER create or get a Future inside of the build method. Instead, do it from initState or a click event handler:

    import 'package:flutter/material.dart';
    
    class FooWidget extends StatefulWidget {
      @override
      _FooWidgetState createState() => _FooWidgetState();
    }
    
    class _FooWidgetState extends State {
      Future _bar;
    
      @override
      void initState() {
        super.initState();
        _bar = doSomeLongRunningCalculation();
      }
    
      void _retry() {
        setState(() {
          _bar = doSomeLongRunningCalculation();
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Column(
          children: [
            FutureBuilder(
              future: _bar,
              builder: (BuildContext context, AsyncSnapshot snapshot) {
                if (snapshot.hasData) {
                  return Text('The answer to everything is ${snapshot.data}');
                } else {
                  return Text('Calculating answer...');
                }
              },
            ),
            RaisedButton(
              onPressed: _retry,
              child: Text('Retry'),
            )
          ],
        );
      }
    }
    
    Future doSomeLongRunningCalculation() async {
      await Future.delayed(Duration(seconds: 5)); // wait 5 sec
      return 42;
    }
    

提交回复
热议问题