如何加载 ListView.builder 的数据以从提供商的数据构建

How to load data for ListView.builder to build from provider's data

我希望我的应用程序创建一个 ListView.builder,其中包含从后端 API 使用提供程序和 http 包获取的用户数据。

提供商获取数据的方法(现在工作正常):

  Future<List<User>> fetchUsersList() async {
   var resp = await UserService().getAllUsers();
    if (resp.statusCode == 200) {
     return userListFromJson(resp.body);
    } else {
     decodeErrorMessage(resp);
     return _usersList = [];
   }
 }

我创建 ListView.builder 的代码:

class _StaffViewState extends State<StaffView> {
    bool _searchaMode = false;
    bool _fetchingData = false;
    List<User> _userList = List<User>();

@override
Widget build(BuildContext context) {

    Provider.of<UserProvider>(context).fetchUsersList().then(
     (data) => this._userList = data);
   

return Consumer<UserProvider>(
  builder: (context, providerData, _) => Scaffold(
    appBar: AppBar(
      title: _searchaMode == false
          ? Text('Staff\s List')
          : TextField(
              autofocus: true,
              cursorColor: Colors.white,
              onSubmitted: (String value) async {
                await showDialog<void>(
                  context: context,
                  builder: (BuildContext context) {
                    return AlertDialog(
                      title: const Text('Thanks!'),
                      content: Text('You typed "$value".'),
                      actions: <Widget>[
                        FlatButton(
                          onPressed: () {
                            Navigator.pop(context);
                          },
                          child: const Text('OK'),
                        ),
                      ],
                    );
                  },
                );
              },
              style: TextStyle(
                color: Colors.white,
              ),
              decoration: InputDecoration(
                hintText: 'Search . . .',
                hintStyle: TextStyle(color: Colors.white),
                border: InputBorder.none,
              ),
            ),
      actions: [
        _searchaMode == false
            ? IconButton(
                onPressed: () {
                  setState(() {
                    _searchaMode = true;
                  });
                },
                icon: Icon(Icons.search),
              )
            : IconButton(
                onPressed: () {
                  setState(() {
                    _searchaMode = false;
                  });
                },
                icon: Icon(
                  Icons.cancel,
                  color: Colors.tealAccent,
                ),
              ),
        RaisedButton.icon(
          onPressed: () async {},
          color: Colors.yellow.shade900,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.only(
              bottomLeft: Radius.circular(100.0),
              topLeft: Radius.circular(100.0),
            ),
          ),
          icon: Icon(
            Icons.add,
            size: 25.0,
            color: Colors.white,
          ),
          label: Text(
            'Add User',
            style: TextStyle(
              fontSize: 15.0,
              fontWeight: FontWeight.bold,
              color: Colors.white,
            ),
          ),
        ),
      ],
    ),
    drawer: AppSideNav(),
    body: _fetchingData == true
        ? pr.show()
        : ListView.builder(
            itemCount: _userList.length,
            itemBuilder: (context, index) {
              return Container(
                decoration: BoxDecoration(
                  border: Border(
                    bottom: BorderSide(
                      width: .9,
                      color: Colors.yellow.shade700,
                    ),
                  ),
                ),
                child: ListTile(
                  leading: Image.network(
                      providerData.getUsersList()[index].image != null
                          ? providerData.getUsersList()[index].image
                          : 'https://via.placeholder.com/150'),
                  title: Center(
                      child:
                          Text(providerData.getUsersList()[index].email)),
                  subtitle: Center(
                      child: Text(providerData.getUsersList()[index].nid)),
                  trailing:
                      providerData.getUsersList()[index].isAuthority == true
                          ? Text('Authority')
                          : providerData.getUsersList()[index].isStaff ==
                                  true
                              ? Text('Staff')
                              : Text('General User'),
                  contentPadding: EdgeInsets.symmetric(horizontal: 20.0),
                  visualDensity: VisualDensity.adaptivePlatformDensity,
                  isThreeLine: false,
                  onTap: () {},
                ),
              );
            },
          ),
       ),
     );
   }
 }

正在加载我的数据以构建列表。但问题是发生错误说 在构建过程中调用了 setState() 或 markNeedsBuild()

我的问题是使用提供程序包填充数据的实际方式是什么,其中将首先执行 dataFetching 方法,然后构建列表。

@override
   void initState() {
     super.initState();

    use api here
  }

你不应该在 build 中调用 API ,因为每次框架重建屏幕时你都会有一个新的调用,而是在 initState().[=14 中调用它=]

如果您需要等待 API 数据,请在 build 函数中使用 FutureBuilder,以便在检索到数据后自动重建。

您可以简单地使用 FutureBuilder 小部件,而不是在 build 函数的开头或 initState 函数中调用您的提取函数。通过这种方式,您可以准确指定在加载时显示什么以及完成时显示什么,而无需添加越来越多的成员变量。

您修改后的代码可能如下所示:

class _StaffViewState extends State<StaffView> {
  
  bool _searchaMode = false;

  @override
  Widget build(BuildContext context) {
    return Consumer<UserProvider>(
      builder: (context, providerData, _) => FutureBuilder(
        future: providerData.fetchUsersList(),
        builder: (context, snapshot) {
          if (snapshot.connectionState != ConnectionState.done) {
            return Text("Loading...");
          }

          List<User> userList = snapshot.data;

          return Scaffold(
            appBar: AppBar(
              title: _searchaMode == false
                  ? Text('Staff\s List')
                  : TextField(
                      autofocus: true,
                      cursorColor: Colors.white,
                      onSubmitted: (String value) async {
                        await showDialog<void>(
                          context: context,
                          builder: (BuildContext context) {
                            return AlertDialog(
                              title: const Text('Thanks!'),
                              content: Text('You typed "$value".'),
                              actions: <Widget>[
                                FlatButton(
                                  onPressed: () {
                                    Navigator.pop(context);
                                  },
                                  child: const Text('OK'),
                                ),
                              ],
                            );
                          },
                        );
                      },
                      style: TextStyle(
                        color: Colors.white,
                      ),
                      decoration: InputDecoration(
                        hintText: 'Search . . .',
                        hintStyle: TextStyle(color: Colors.white),
                        border: InputBorder.none,
                      ),
                    ),
              actions: [
                _searchaMode == false
                    ? IconButton(
                        onPressed: () {
                          setState(() {
                            _searchaMode = true;
                          });
                        },
                        icon: Icon(Icons.search),
                      )
                    : IconButton(
                        onPressed: () {
                          setState(() {
                            _searchaMode = false;
                          });
                        },
                        icon: Icon(
                          Icons.cancel,
                          color: Colors.tealAccent,
                        ),
                      ),
                RaisedButton.icon(
                  onPressed: () async {},
                  color: Colors.yellow.shade900,
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.only(
                      bottomLeft: Radius.circular(100.0),
                      topLeft: Radius.circular(100.0),
                    ),
                  ),
                  icon: Icon(
                    Icons.add,
                    size: 25.0,
                    color: Colors.white,
                  ),
                  label: Text(
                    'Add User',
                    style: TextStyle(
                      fontSize: 15.0,
                      fontWeight: FontWeight.bold,
                      color: Colors.white,
                    ),
                  ),
                ),
              ],
            ),
            drawer: AppSideNav(),
            body: ListView.builder(
                    itemCount: userList.length,
                    itemBuilder: (context, index) {
                      return Container(
                        decoration: BoxDecoration(
                          border: Border(
                            bottom: BorderSide(
                              width: .9,
                              color: Colors.yellow.shade700,
                            ),
                          ),
                        ),
                        child: ListTile(
                          leading: Image.network(
                              providerData.getUsersList()[index].image != null
                                  ? providerData.getUsersList()[index].image
                                  : 'https://via.placeholder.com/150'),
                          title: Center(
                              child: Text(
                                  providerData.getUsersList()[index].email)),
                          subtitle: Center(
                              child:
                                  Text(providerData.getUsersList()[index].nid)),
                          trailing: providerData
                                      .getUsersList()[index]
                                      .isAuthority ==
                                  true
                              ? Text('Authority')
                              : providerData.getUsersList()[index].isStaff ==
                                      true
                                  ? Text('Staff')
                                  : Text('General User'),
                          contentPadding:
                              EdgeInsets.symmetric(horizontal: 20.0),
                          visualDensity: VisualDensity.adaptivePlatformDensity,
                          isThreeLine: false,
                          onTap: () {},
                        ),
                      );
                    },
                  ),
          );
        },
      ),
    );
  }
}