Search code examples
flutterdartlistviewdart-async

Flutter Listview after run empty, but filled only with Flutter Hot reload


How can I correct this code? That might have sparked the need to win another solution.

enter image description here This result is only after a hot reload, and at the first start it is empty.

class PageOnes extends StatefulWidget {
  final String pageName;

  const PageOnes({
    required this.pageName,
    Key? key,
  }) : super(key: key);

  @override
  State<StatefulWidget> createState() => _PageOnesState();
}

class _PageOnesState extends State<PageOnes> {
  List<String> items = [];

  @override
  Widget build(BuildContext context)  {
    deviceInfo();

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.pageName),
      ),
      body: ListView.separated(
          padding: const EdgeInsets.all(8),
          itemCount: items.length,
          itemBuilder: (context, index) {
            return ListTile(
              title: Text(items[index],style: const TextStyle(fontFamily: 'Proximal', fontSize: 18),
              ),
            );
          },
          separatorBuilder: (BuildContext context, int index) => const Divider(
                thickness: 5,
                endIndent: 10,
                indent: 10,
              )),
    );
  }

   void deviceInfo() async  {
    const int MEGABYTE = 1024 * 1024;
    DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
    AndroidDeviceInfo androidDeviceInfo = await deviceInfoPlugin.androidInfo;
    items.add('Brand: ${androidDeviceInfo.manufacturer}.');
     }
}

Solution

  • You are using future method, data isnt avialble on first frame , it will take some time to fetch data. Try using FutureBuilder

    class _PageOnesState extends State<PageOnes> {
      Future<void> deviceInfo() async {
        List items = [];
        const int MEGABYTE = 1024 * 1024;
        DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
        AndroidDeviceInfo androidDeviceInfo = await deviceInfoPlugin.androidInfo;
        items.add('Brand: ${androidDeviceInfo.manufacturer}.');
    
        return items;
      }
    
      late final myFuture = deviceInfo();
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.pageName),
          ),
          body: FutureBuilder(
            future: myFuture,
            builder: (context, snapshot) {
              if(snapshot.hasData){
    
                final items  = snapshot.data;
    
                return  ListView.separated(
                padding: const EdgeInsets.all(8),
                itemCount: items.length,
                itemBuilder: (context, index) {
                  return ListTile(
                    title: Text(
                      items[index],
                      style: const TextStyle(fontFamily: 'Proximal', fontSize: 18),
                    ),
                  );
                },
                separatorBuilder: (BuildContext context, int index) =>
                    const Divider(
                      thickness: 5,
                      endIndent: 10,
                      indent: 10,
                    )),
              }
    
              return CircularProgressIndicator();
            },
          ),
        );
      }
    }
    

    Not recommended but you can trick.

    Dont call method directly inside build method. use intitState

      @override
      void initState() {
        super.initState();
        deviceInfo();
      }
    
     void deviceInfo() async  {
      .....
       setState((){});
         }