Reputation: 1202
now i have this script
Future<List<HotProducts>> _loadHotProducts;
Future<List<NewProducts>> _loadNewProducts;
Future<List<Promotion>> _loadPromotions;
Future<List<LatestSoldItem>> _loadLatestSoldItem;
setState(() {
userId = result;
_loadHotProducts = HotProductsApiClient().fetchHotProducts(http.Client(), userId);
_loadNewProducts = NewProductApiClient().fetchNewProducts(http.Client(), userId);
_loadPromotions = PromotionApiClient().fetchPromotion(http.Client());
_loadLatestSoldItem = LatestSoldApiClient().fetchProducts(http.Client(), userId);
});
all my script above is about calling data from my server. Now, i want to run it one by one. So, i'm trying this way
_loadHotProducts = HotProductsApiClient().fetchHotProducts(http.Client(), userId).then((_){
_loadNewProducts = NewProductApiClient().fetchNewProducts(http.Client(), userId);
});
I get this errors
The getter 'length' was called on null.
Receiver: null
Tried calling: length
How can i fix it ? or is there any better way ?
Upvotes: 0
Views: 432
Reputation: 54377
The problem you encounter is inside your fetch function
you have to await
all your http
and future
job
You can copy paste run correct and problem code in DartPad
The following demo have 3 layer function call, you check effect with or without await
When you doubt, just print message and you will see execution sequence
The following correct and problem is provided as below
full code correct
import 'dart:async';
import 'dart:math';
Future<String> fetchHotProductsLongJob() async {
await Future.delayed(const Duration(seconds: 10), () {
print('fetchHotProductsLongJob then');
});
print("fetchHotProductsLongJob done");
return "abc";
}
Future<String> fetchHotProducts() async {
await Future.delayed(const Duration(seconds: 7), () {
print("fetchHotProducts then");
});
await fetchHotProductsLongJob();
print("fetchHotProducts done");
return "abc";
}
Future<String> fetchNewProductsLongJob() async {
await Future.delayed(const Duration(seconds: 10), () {
print('fetchNewProductsLongJob then');
});
print("fetchNewProductsLongJob done");
return "abc";
}
Future<String> fetchNewProducts() async {
await Future.delayed(const Duration(seconds: 3), () async{
print("fetchNewProducts then");
await fetchNewProductsLongJob();
});
print("fetchNewProducts done");
return "abc";
}
void main() async{
print("fetchHotProducts job start");
var Job1 = await fetchHotProducts();
print("fetchHotProducts job done");
print("fetchNewProducts job start");
var Job2 = await fetchNewProducts();
print("fetchNewProducts job done");
}
correct output
fetchHotProducts job start
fetchHotProducts then
fetchHotProductsLongJob then
fetchHotProductsLongJob done
fetchHotProducts done
fetchHotProducts job done
fetchNewProducts job start
fetchNewProducts then
fetchNewProductsLongJob then
fetchNewProductsLongJob done
fetchNewProducts done
fetchNewProducts job done
problem code after remove some await
import 'dart:async';
import 'dart:math';
Future<String> fetchHotProductsLongJob() async {
Future.delayed(const Duration(seconds: 10), () {
print('fetchHotProductsLongJob then');
});
print("fetchHotProductsLongJob done");
return "abc";
}
Future<String> fetchHotProducts() async {
Future.delayed(const Duration(seconds: 7), () {
print("fetchHotProducts then");
});
fetchHotProductsLongJob();
print("fetchHotProducts done");
return "abc";
}
Future<String> fetchNewProductsLongJob() async {
await Future.delayed(const Duration(seconds: 10), () {
print('fetchNewProductsLongJob then');
});
print("fetchNewProductsLongJob done");
return "abc";
}
Future<String> fetchNewProducts() async {
await Future.delayed(const Duration(seconds: 3), () async{
print("fetchNewProducts then");
await fetchNewProductsLongJob();
});
print("fetchNewProducts done");
return "abc";
}
void main() async{
print("fetchHotProducts job start");
var Job1 = await fetchHotProducts();
print("fetchHotProducts job done");
print("fetchNewProducts job start");
var Job2 = await fetchNewProducts();
print("fetchNewProducts job done");
}
problem code output
you can see fetchHotProducts job still not finish
fetchHotProducts job start
fetchHotProductsLongJob done
fetchHotProducts done
fetchHotProducts job done
fetchNewProducts job start
fetchNewProducts then
fetchHotProducts then
fetchHotProductsLongJob then
fetchNewProductsLongJob then
fetchNewProductsLongJob done
fetchNewProducts done
fetchNewProducts job done
Upvotes: 1
Reputation: 1109
await
is meant to interrupt the process flow until the async
method has finished.
then
however does not interrupt the process flow (meaning the next instructions will be executed) but enables you to run code when the async
method is finished.
In your example, you cannot achieve what you want when you use then
because the code is not waiting and the return statement is processed and thus returns an empty List
.
When you add the await
, you explicitly say: don't go further until my Future
is completed.
_loadHotProducts = await HotProductsApiClient().fetchHotProducts(http.Client(), userId);
_loadNewProducts = await NewProductApiClient().fetchNewProducts(http.Client(), userId);
_loadPromotions = await PromotionApiClient().fetchPromotion(http.Client());
_loadLatestSoldItem = await LatestSoldApiClient().fetchProducts(http.Client(), userId);
Using await
directly in the setState
won't work, since setState
function isn't async
and it is not recommended. Just wrap them with an async
function that will be called in the setState
method. So the final result should be something like this:
Future<List<HotProducts>> _loadHotProducts;
Future<List<NewProducts>> _loadNewProducts;
Future<List<Promotion>> _loadPromotions;
Future<List<LatestSoldItem>> _loadLatestSoldItem;
Future load() async {
userId = result;
_loadHotProducts = await HotProductsApiClient().fetchHotProducts(http.Client(), userId);
_loadNewProducts = await NewProductApiClient().fetchNewProducts(http.Client(), userId);
_loadPromotions = await PromotionApiClient().fetchPromotion(http.Client());
_loadLatestSoldItem = await LatestSoldApiClient().fetchProducts(http.Client(), userId);
}
setState(() {
load();
});
Upvotes: 1
Reputation: 1010
you could use await
Future<List<HotProducts>> _loadHotProducts;
Future<List<NewProducts>> _loadNewProducts;
Future<List<Promotion>> _loadPromotions;
Future<List<LatestSoldItem>> await _loadLatestSoldItem;
userId = result;
_loadHotProducts = await HotProductsApiClient().fetchHotProducts(http.Client(), userId);
_loadNewProducts = await NewProductApiClient().fetchNewProducts(http.Client(), userId);
_loadPromotions = await PromotionApiClient().fetchPromotion(http.Client());
_loadLatestSoldItem = await LatestSoldApiClient().fetchProducts(http.Client(), userId);
setState(() {});
You will need to make the method async.
Upvotes: 0