我想根据将来会返回 map 的数据来构建卡。由于cardDetails
是从后端获取的,因此需要一些时间,但是在使用ListView.builder
构建卡时,在获取数据之前会到达itemCount
,这使得cardDetails
成为null
。如果我将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);
}
}
最佳答案
这是因为无论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();
}
},
)