【问题标题】:How to load data for ListView.builder to build from provider's data如何为 ListView.builder 加载数据以从提供者的数据构建
【发布时间】:2020-11-30 12:00:47
【问题描述】:

我希望我的应用程序创建一个 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 方法,然后构建列表。

【问题讨论】:

    标签: flutter flutter-dependencies flutter-provider flutter-listview


    【解决方案1】:

    您可以简单地使用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: () {},
                            ),
                          );
                        },
                      ),
              );
            },
          ),
        );
      }
    }
    
    

    【讨论】:

      【解决方案2】:
      @override
         void initState() {
           super.initState();
      
          use api here
        }
      

      【讨论】:

      • 尝试了 initialState 但它给出了这个错误.. 在 _StaffViewState.initState() 完成之前调用了dependOnInheritedWidgetOfExactType<_inheritedproviderscope>>() 或dependOnInheritedElement()。
      • 其实用 didChangeDependencies() 试过了,但总是报错。
      • 不,它不起作用...它说 ::: _StaffViewState.initState() 返回了一个 Future。
      【解决方案3】:

      您不应该在 build 内调用 API,因为每次框架重建屏幕时都会有一个新的调用,而是在 initState() 内调用它。

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

      【讨论】:

      • @override Widget build(BuildContext context) { FutureBuilder _getUserData() { Provider.of(context) .fetchUsersList() .then((data) => this._userList = data);这是怎么...?
      • 那我该怎么称呼它..?
      • 只需在initState 上调用_userDataFuture = providerData.fetchUsersList(),将future 保存到_userDataFuture,将这个future 传递给FutureBuilder,完成后你会得到结果,不需要then子句,因为它可以在构建器中。
      猜你喜欢
      • 2023-03-03
      • 2018-10-16
      • 1970-01-01
      • 2021-02-05
      • 1970-01-01
      • 2017-01-08
      • 1970-01-01
      • 1970-01-01
      • 2020-04-27
      相关资源
      最近更新 更多