In my StatefulWidget in initState i have a method:
@override
void initState() {
super.initState();
getMyChannels();
}
getMyChannels
method run a http method to get data from service and store data into database:
void getMyChannels() async {
// get data from servise and store them
_myChannel = await MyToolsProvider()
.getChannelMe("df6b88b6-f47d****");
getToolsRelToChannels(); // get data from database
setState(() {});
}
As you can see i have getToolsRelToChannels
method. This method fetch data from local database. This data must be stored by await MyToolsProvider() .getChannelMe("df6b88b6-f47d****");
method into database.
This is .getChannelMe
method:
Future<ProgramsByActiveToolsModel> getChannelMe(String auth) async {
Map<String, dynamic> header = {
'Content-Type': "application/json",
"Authorization": 'Bearer $auth'
};
try {
var result = await NetworkCLient()
.getRequest(url: '$URL/api/me', header: header);
if (result != null) {
var programsByActiveToolsModel =
ProgramsByActiveToolsModel.fromJson(result);
if (programsByActiveToolsModel.responseCode == 200) {
programsByActiveToolsModel.data.forEach((item) async {
await DBProvider.db.addMyTools(item);
saveToolsbyChannelId(header, item.id);
});
return programsByActiveToolsModel;
} else
return null;
}
} catch (e) {
throw e;
}
}
In addMyTools
method i store each data in one table of my database and i call saveToolsbyChannelId
method for each item. This is main data that I need too.
Future<void> saveToolsbyChannelId(Map header, int channelId) async {
header["Authorization"] = 'Bearer 92122926-****';
try {
var count = await DBProvider.db.getCountToolsbyChannelId(channelId);
if (count == 0) {
var result = await NetworkCLient().getRequest(
url: '$URL/api/channel/$channelId', header: header);
if (result != null) {
var logToolsRunModel = LogTools.LogToolsRunModel.fromJson(result);
if (logToolsRunModel.responseCode == 200) {
logToolsRunModel.data.forEach((item) {
DBProvider.db.addTools(item);
});
}
}
}
} catch (e) {
throw e;
}
}
After fetching data from my service i sore these data into sqlite database .Now it's await MyToolsProvider().getChannelMe
job is done!
It's time to explain getToolsRelToChannels();
:
void getToolsRelToChannels() async {
_toolsRun =
await MyToolsProvider().getToolsRelatedMyChannel(_selectedChannel);
setState(() {});
}
getToolsRelatedMyChannel
this method must be wait till all data in this method DBProvider.db.addTools(item)
added into database and after inserting my widget must be recreated.
Future<List<ToolsByChannelIdDbModel>> getToolsRelatedMyChannel(
int channelId) async {
List<ToolsByChannelIdDbModel> list = List<ToolsByChannelIdDbModel>();
try {
var result = await DBProvider.db.getToolsById(channelId);
result.forEach((item) {
list.add(ToolsByChannelIdDbModel.fromJson(item));
});
return list;
} catch (e) {
print(e);
}
}
}
but my code is wrong because after running await MyToolsProvider().getChannelMe(***)
getToolsRelToChannels
method is executed and nothing is stored into database to fetching yet!!!
How could i notify my main widget after finishing database inserting??? I can not to use FutureBuilder because when run for first time, my database is empty !!!
You should await saveToolsbyChannelId
in getChannelMe
and await DBProvider.db.addTools(item);
in saveToolsbyChannelId
, otherwise you are trying to read from the database before the data has been written to it. This is assuming the rest of your code is correct, which we cannot tell for sure because there are lots of variables such as _selectedChannel
that we know nothing about.
UPDATED - Check below. What you want is to await ALL async
operations. In your case
@override
void initState() async {
super.initState();
await getMyChannels();
}
and
await saveToolsbyChannelId(header, item.id);
and if DBProvider.db.addTools
is asynchronous, then
await DBProvider.db.addTools(item);
UPDATE:
Since its not possible to make initState()
async
, you can use a callback in the future:
@override
void initState() {
super.initState();
var channelsFuture = getMyChannels();
channelsFuture.then((resp){
setState(() {});
});
}
I'd suggest that you reconsider your whole approach (from a clean architecture point of view). Take a look at the BLoC pattern . It basically boils down to this :
initState()
. There's a stream listener in the widget that listens to the completion of the task by BLoC.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.