FlutterError (dependOnInheritedWidgetOfExactType<_InheritedProviderScope<Books?>>() or dependOnInheritedElement() was called before - flutter

I have a code like following in books_overview.dart:
#override
void initState() {
Provider.of<Books>(context).fetchAndSetBooks();
Future.delayed(Duration.zero).then((_) {
Provider.of<Books>(context).fetchAndSetBooks();
});
super.initState();
}
And a code like below within books.dart
Future<void> fetchAndSetBooks([bool filterByUser = false]) async {
final filterString =
filterByUser ? 'orderBy="creatorId"&equalTo="$userId"' : '';
var url = Uri.parse(
'https://flutter-update.firebaseio.com/Books.json?auth=$authToken&$filterString');
try {
final response = await http.get(url);
final extractedData = json.decode(response.body) as Map<String, dynamic>;
if (extractedData == null) {
return;
}
}
And I get the following error:
FlutterError
(dependOnInheritedWidgetOfExactType<_InheritedProviderScope<Books?>>()
or dependOnInheritedElement() was called before
_BooksOverviewScreenState.initState() completed.
At this line of the code inside ``books_overview.dart`:
Provider.of<Books>(context).fetchAndSetBooks();
First of all, I would like to know is this a good way of using provider package(As the origin of the code is from a Flutter tutorial course)?
Secondly I like to know what is the problem and how can I fix it?
PS: I tried to change the first code as following but it didn't help:
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
Provider.of<Contests>(context).fetchAndSetContests();
});
}

Related

Flutter Firestore getDocuments() not working on initState

I'm having an issue trying to call a document from Firestore in initState. I can pull data from a StreamBuilder just fine, but I just want to call the data once on initState.
Here is what I'm doing:
class _PainLevelState extends State<PainLevel> {
final FirebaseAuth _auth = FirebaseAuth.instance;
final CollectionReference userCollection =
Firestore.instance.collection('users');
static final now = DateTime.now();
String _uid;
double myPainLevel = 0;
Future<void> getCurrentUser() async {
final FirebaseUser user = await _auth.currentUser();
if (mounted) {
setState(() {
_uid = user.uid;
});
}
}
Future<void> getCurrentPainLevel() async {
await userCollection
.document(_uid)
.collection('pain')
.where('time',
isGreaterThanOrEqualTo: DateTime(now.year, now.month, now.day))
.getDocuments()
.then((QuerySnapshot docs) {
if (docs.documents.isNotEmpty) {
print('yes');
} else {
print('no');
}
});
}
#override
void initState() {
super.initState();
getCurrentUser();
getCurrentPainLevel();
}
...
I just get a "no" every time I print to console. It's not get any documents when there is one. If I take the same code inside the future and put it somewhere else, like in the build method, it works, but it constantly builds and I don't want that. Any suggestion as to why it is not working? Thanks in advance.
I'm guessing here that your code will not always work, because getCurrentPainLevel might get called before getCurrentUser is completed, which will cause _uid to be null and therefore, not work as expected. Try to put then keyword after getCurrentUser method, like this:
#override
void initState() {
super.initState();
getCurrentUser().then((_) {
getCurrentPainLevel();
});
}
By the way, you should NOT be calling async methods in initState. Try to put the code somewhere else, like WidgetsBinding.instance.addPostFrameCallback(...).

Why can´t I save int with shared_preferences?

I tried to build a simple application, which shoul save and output a value whith shared_preferences. I tried to save an int, but it doesnt´t work. It could be, that the mistake is because of I tried to "convert" the code a youtuber did with a String instead of an int. Can anybody find my mistake? Below is the change code I tried.
int lastLoginInt = 1;
String nameKey = "_key_name";
#override
void initState() {
super.initState();
}
Future<bool> saveLastLoginInt() async {
SharedPreferences preferences = await SharedPreferences.getInstance();
return await preferences.setInt(nameKey, lastLoginInt);
}
Future<int> loadLastLoginInt() async {
SharedPreferences preferences = await SharedPreferences.getInstance();
return preferences.getInt(nameKey);
}
setLastLoginInt() {
loadLastLoginInt().then((value) {
setState(() {
lastLoginInt = value;
});
});
}
You are not calling functions.
Probably you should do this at your initState() function..like this..
#override
void initState() {
super.initState();
saveLastLoginInt();
}
Then use setLastLoginInt() where needed.

Only static members can accessed in initializes

I have issue in set my List variable(_tasks) with a method(readSavedTasks) being called to setup for the values. Here's the code line that have the error.
Future<List<ListTasks>> readSavedTasks() async {
List<ListTasks> tasksSaved = await DataStorage().readTasks();
return Future.value(tasksSaved);
}
List<ListTasks> _tasks = readSavedTasks();
Can anybody help me on this?
You can't use non-static members in initialisation. This is a better approach:
Future<List<ListTasks>> readSavedTasks() async {
List<ListTasks> tasksSaved = await DataStorage().readTasks();
return Future.value(tasksSaved);
}
#override
void initState() {
super.initState();
_init();
}
Future<void> _init() async {
List<ListTasks> _tasks = await readSavedTasks();
}

Flutter initState wait for async function to complete

in my main.dart i have among others those two functions:
Future<void> _fetchMasterData() async {
print("Start fetch");
var jwt = await API.attemptLogIn();
if (jwt != null) {
Map<String, dynamic> answer = jsonDecode(jwt);
if (answer['message'] == 'Auth ok') {
jwtToken = 'Bearer ' + answer['token'];
}
}
await _getArticles();
await _getMainCategories();
await _getIngredients();
await _getArticleIngredients();
print("EndMasterData fetch");
}
And
#override
void initState() {
super.initState();
_fetchMasterData();
}
What i would like to have is to wait in initState till _fethcMasterData is done bevore Widgert build is called.
Is that possible? Many thanks for any help!
Here how I use an async func in initstate;
builder() async {
favoriteDatabase =
await $FloorFavoriteDatabase.databaseBuilder('favorite_database.db')
.build();
setState(() {
favoriteDao = favoriteDatabase.favoriteDao;
});
}
#override
void initState() {
// TODO: implement initState
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
WidgetsBinding.instance.addPostFrameCallback((_) =>
getNamePreferences().then(updateName));
});
builder();
favoriteDao.findAllMoviesAsStreamW();
favoriteDao.findAllMoviesAsStream();
}
Also you can check this mini article too.
It is not possible to await in initState, so when you finish all loading process then you can call SetState method which populate your widget with actual data.
Second solution could be use of futurebuilder or streambuilder where you want to show data but it is only possible if any methods data is not dependent on each other.
Future<void> _fetchMasterData() async {
print("Start fetch");
var jwt = await API.attemptLogIn();
if (jwt != null) {
Map<String, dynamic> answer = jsonDecode(jwt);
if (answer['message'] == 'Auth ok') {
jwtToken = 'Bearer ' + answer['token'];
}
}
await _getArticles();
await _getMainCategories();
await _getIngredients();
await _getArticleIngredients();
print("EndMasterData fetch");
SetState((){}); // added line
}

Flutter throws error when context is passed to a Provider from the init method

I have a MainScreen (stateful) with the following method:
#override
void initState() {
super.initState();
WidgetsBinding.instance
.addPostFrameCallback((_) async {
loadFirebaseUser(context);
});
}
My 'loadFirebaseUser' method is in another file called Constants.dart which can be used from any screen.
The function is as follows:
Future<bool> loadFirebaseUser(BuildContext context) async {
Auth _auth = Auth();
FirebaseUser cUser = await _auth.currentUser();
if (cUser.isEmailVerified) {
DocumentSnapshot snapshot = await Firestore.instance
.collection('Profile')
.document(cUser.uid)
.get();
if (snapshot.data != null) {
User user = Provider.of<UserData>(context).getUser();
user = User.fromMap(snapshot);
Provider.of<UserData>(context).setUser(user);
return true;
} else {
return false;
}
}
return false;
}
I am getting the follwing error when this code is executed:
Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe.
Needless to say that as result of this the user is not getting loaded. The error points to the following line:
User user = Provider.of<UserData>(context).getUser();
I want the 'loadFirebaseUSer' function to execute automatically and not on any button click, so this is the only place I know to place this code. Is there a way to achieve this differently? Thanks
Did you tried to get context this way?
Future.delayed(Duration.zero, () {
var myState = Provider.of<MyState>(context);
.......
});