如何在Future Builder的Flutter中等待ListView中的itemCount?

时间:2020-04-07 23:47:03

标签: flutter dart sharedpreferences

我想根据将来收到的返回地图的数据来制作卡片。由于cardDetails是从后端获取的,因此需要一些时间,但是在使用ListView.builder构建卡时,它会在获取数据之前到达itemCount,这使得cardDetailsnull。如果我对itemCount的值进行硬编码,则错误消失,并且我可以根据需要获得卡。有关如何解决此问题的任何线索都将有所帮助。

更新:它正在进入snapshot.hasError状态,但是我无法确定是哪个错误

在用户界面

 if (_localStorageService.getStringFromLocalStorage() != 'testFalse')
              FutureBuilder(
                future: _localStorageService.getMapFromLocalStorage(),
                builder: (BuildContext context, AsyncSnapshot snapshot) {
                  if (snapshot.hasData) {
                    cardDetails = snapshot.data;
                    return ListView.builder(
                      itemBuilder: (context, index) {
                        print("Shared Pref hasData");
                        return cardDetails == null
                            ? CircularProgressIndicator()
                            : HomepageCards(
                                user: widget.user,
                                cardDetails: cardDetails[
                                    cardDetails.keys.toList()[index]],
                              );
                      },
                      // verify if cardDetails is null to prevent app crash
                      itemCount:
                          (cardDetails == null ? 0 : cardDetails.keys.length),
                      scrollDirection: Axis.vertical,
                      controller: _controller,
                      shrinkWrap: true,
                    );
                  } else if (snapshot.hasError) {
//                    TODO: Shimmer skeleton
                  }
                  return CircularProgressIndicator();
                },
              )
            else
              StreamBuilder<DocumentSnapshot>(
                stream: Firestore()
                    .collection('homepage')
                    .document(widget.user.uid)
                    .collection('h')
                    .document('28032020')
                    .snapshots(),
                builder: (context, snapshot) {
                  if (snapshot.data != null) {
                    cardDetails = {};
                    snapshot.data.data.forEach((index, individualDetail) {
                      cardDetails[index] = individualDetail;
                    });
                    _localStorageService
                        .storeCardInSharedPreference(cardDetails);
                    cardDetailKeys = snapshot.data.data.keys;
                  } else if (snapshot.hasError) {
//                    TODO: Show skeletal shimmer
                  } else {
                    // TODO: Convert it to Shimmer with card skeletal layout
                    CircularProgressIndicator();
                  }
                  return cardDetails == null
                      ? CircularProgressIndicator()
                      : ListView.builder(
                          itemBuilder: (context, index) {
                            return HomepageCards(
                              user: widget.user,
                              cardDetails:
                                  cardDetails[cardDetails.keys.toList()[index]],
                            );
                          },
                          itemCount: (cardDetailKeys == null
                              ? 0
                              : cardDetailKeys.length),
                          scrollDirection: Axis.vertical,
                          controller: _controller,
                          shrinkWrap: true,
                        );
                },
              )

用于共享首选项的LocalStorage服务

class LocalStorageService {
  static SharedPreferences _sharedPreferences;
  final String screenkey;
  String value;
  String _initialSharedValue;

  LocalStorageService({@required this.screenkey});

  initialiseLocalStorage() async {
    _sharedPreferences = await SharedPreferences.getInstance();
    persist(screenkey);
  }

  Future<void> persist(String key) async {
    _initialSharedValue = _sharedPreferences?.getString(key);
    // will be null if never previously saved
    if (_initialSharedValue == null) {
      _initialSharedValue = 'testFalse';
    }
    await _sharedPreferences?.setString(screenkey, _initialSharedValue);
    print("share = ${_sharedPreferences?.getString(screenkey)}");
  }

  storeCardInSharedPreference(Map cardDetails) async {
    await _sharedPreferences?.setString(screenkey, json.encode(cardDetails));
  }

  getMapFromLocalStorage() async {
    return await json.decode(_sharedPreferences?.getString(screenkey));
  }

  String getStringFromLocalStorage() {
    return _sharedPreferences?.getString(screenkey);
  }
}

1 个答案:

答案 0 :(得分:1)

这是因为无论futurebuilder的状态如何,都将返回Listview。 如果要控制futurebuilder的状态,则必须将返回内容放在if / else / case中。

因此:

FutureBuilder(
            future: _localStorageService.getStringFromLocalStorage(),
            builder: (BuildContext context, AsyncSnapshot snapshot) {
              if (snapshot.hasData) {
                cardDetails = snapshot.data;
                print("number of cards = ${cardDetails.keys.length}");
                return ListView.builder(
                itemBuilder: (context, index) {
                  print("card details in futute : ${snapshot.data}");
                  return cardDetails == null
                      ? CircularProgressIndicator()
                      : HomepageCards(
                          user: widget.user,
                          cardDetails:
                              cardDetails[cardDetails.keys.toList()[index]],
                        );
                },
                // verify if cardDetails is null to prevent app crash
                itemCount: (cardDetails == null? 0: cardDetails.keys.length),
                scrollDirection: Axis.vertical,
                controller: _controller,
                shrinkWrap: true,
              );
              } else if (snapshot.hasError) {
                print("Error here in snapshot");
                return Center(child:Text("An error has occurred"));
              } else {
                return CircularProgressIndicator();
              }

            },
          )