Flutter 等待 Notifier 的构造函数被初始化

时间:2020-12-25 02:33:00

标签: flutter dart

我试图在 listView 构建器中显示我在初始化构造函数时加载的列表。 这现在不起作用,因为 listView 在构造函数完成加载我的列表之前运行。

怎么办?

我的通知者:

class TablesNotifier with ChangeNotifier {

  // Services
  // ---------------------------------------------------------------------------
  final jsonSelectorService = locator<JsonSelectorService>();

  // Variables
  // ---------------------------------------------------------------------------
  List<AltitudeModel> altitudes;

  // Constructor
  // ---------------------------------------------------------------------------
  TablesNotifier(){
    _initialise();
  }

  // Initialisation
  // ---------------------------------------------------------------------------
  Future _initialise() async{
    print('--- initialise');
    altitudes = await jsonSelectorService.altitudes();
  }
}

我的屏幕:

class TableScreen extends StatelessWidget {
  final String title;
  TableScreen({Key key, @required this.title}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _buildBody(context),
    );
  }
  
  Widget _buildBody(BuildContext context)
  {
    var _tableProvider = Provider.of<TablesNotifier>(context);
    return ListView.builder(
      itemCount: _tableProvider.altitudes.length,
      itemBuilder: (context, index) {
        return ListTile(
          title: Text('${_tableProvider.altitudes[index]}'),
        );
      },
    );
  }
}

2 个答案:

答案 0 :(得分:1)

您可以在下面复制粘贴运行完整代码
我使用 7 秒延迟来模拟 jsonSelectorService
第 1 步:您可以检查 _tableProvider.altitudes == null 并返回 CircularProgressIndicator()ListView
第 2 步:当 altitudes 数据准备好时调用 notifyListeners()
代码片段

Future _initialise() async {
    print('--- initialise');
    await Future.delayed(Duration(seconds: 7), () {});
    altitudes = [
      AltitudeModel(title: "1"),
      AltitudeModel(title: "2"),
      AltitudeModel(title: "3"),
      AltitudeModel(title: "4"),
      AltitudeModel(title: "5")
    ];

    notifyListeners();
  }
  
Widget _buildBody(BuildContext context) {
    var _tableProvider = Provider.of<TablesNotifier>(context);
    return _tableProvider.altitudes == null
        ? Center(child: CircularProgressIndicator())
        : ListView.builder(

工作演示

enter image description here

完整代码

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => TablesNotifier(),
      builder: (context, child) => MaterialApp(
        home: TableScreen(),
      ),
    );
  }
}

class AltitudeModel {
  String title;

  AltitudeModel({this.title});
}

class TablesNotifier with ChangeNotifier {
  // Services
  // ---------------------------------------------------------------------------
  //final jsonSelectorService = locator<JsonSelectorService>();

  // Variables
  // ---------------------------------------------------------------------------
  List<AltitudeModel> altitudes;

  // Constructor
  // ---------------------------------------------------------------------------
  TablesNotifier() {
    _initialise();
  }

  // Initialisation
  // ---------------------------------------------------------------------------
  Future _initialise() async {
    print('--- initialise');
    await Future.delayed(Duration(seconds: 7), () {});
    altitudes = [
      AltitudeModel(title: "1"),
      AltitudeModel(title: "2"),
      AltitudeModel(title: "3"),
      AltitudeModel(title: "4"),
      AltitudeModel(title: "5")
    ];

    notifyListeners();
  }
}

class TableScreen extends StatelessWidget {
  final String title;
  TableScreen({Key key, @required this.title}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _buildBody(context),
    );
  }

  Widget _buildBody(BuildContext context) {
    var _tableProvider = Provider.of<TablesNotifier>(context);
    return _tableProvider.altitudes == null
        ? Center(child: CircularProgressIndicator())
        : ListView.builder(
            itemCount: _tableProvider.altitudes.length,
            itemBuilder: (context, index) {
              return ListTile(
                title: Text('${_tableProvider.altitudes[index].title}'),
              );
            },
          );
  }
}

答案 1 :(得分:1)

最快的方法是使用 FutureBuilder 确保 altitudes 列表在发送到 UI 之前已完全加载。你可以这样做:

Widget _buildBody(BuildContext context) {
    var _tableProvider = Provider.of<TablesNotifier>(context);
    return FutureBuilder<List<AltitudeModel>>(
        initialData: <AltitudeModel>[] // Here you can even set the initial data of your list
        future: _tableProvider.altitudes,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return Container(child: Center(child: CircularProgressIndicator()));
          }
          return ListView.builder(
            itemCount: snapshot.data.length,
            itemBuilder: (context, index) {
              return ListTile(
                title: Text('${snapshot.data[index]}'),
              );
            },
          );
        }
    );
  }