I'm studying bloc in Flutter now and faced a problem.
In my test app I fetch weather data and when trying to display it I see no changes and no errors.
The trouble is: I do get the data and can see with print, but when it comes to displaying with BlocBuilder, it seems to not change the state.
This is the link to my repo - https://github.com/PhilippBekher/flutter_weather
The logics for displaying data are in main.dart
The weather data is accessible via the link - https://api.weatherapi.com/v1/forecast.json?key=%20f148ee51b7cd4e2390e110556221408&q=London&days=1
When trying to print the state inside the file for the cubit, I can't see the emitted state (WeatherFetchLoaded):
The screen below:
I ran your code. Here is the outcome
It came in is catch block line.Here you are emitting no value. So only Its still in loading state.
Future<void> fetchWeatherApi() async {
emit(WeatherFetchLoading());
try {
final Weather weather = await apiRepository.getWeather();
print('hello');
emit(WeatherFetchLoaded(weather: weather));
} on Failure catch (err) {
emit(WeatherFetchError(failure: err));
} catch (err) {
print("Error 1: $err"); **// Here**
}
}
It shows
'double' is not a subtype of type 'int'
This is a parsing issue while converting to the values to double.
Your approach of parsing json is not a recommended way. You can read here more about json parsing.
If you need to continue to debug ,it may be time consuming to find exact field. You can try looking on each field . You need to make sure you are parsing correct data type. Model class and json should have same data type.
Related
I am new to Flutter as well as Firestore. I will try to make sense at my best for problem I've came across while using Flutter with Firestore.
Code:
QuerySnapshot<Map<String, dynamic>> user = await checkUserExistenceInFireStore('uid', getUid);
if(user.docs.isNotEmpty){
for (var element in user.docs) {
// Here I have been forced by Flutter to use this for integer
SharedPreferencesHelper.setBlocked(int.parse(element.data()['appDisabled']));
// Instead this
SharedPreferencesHelper.setBlocked(element.data()['appDisabled']);
}
}
[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: type 'String' is not a subtype of type 'int'
Surprisingly, I've been using element.data()['appDisabled'] all the time without any problem for integers until now.
Okay, I can live with it and can use int.parse(element.data()['appDisabled']) but it gives me another problem. App works fine in debug mode but in release mode stops working.
Screenshot:
Please help. Thanks in advance.
Since Firestore is a NoSQL database and has no strict type rules and defined document structures, I think about handling corrupt data in my Flutter app.
In case you wonder why I want to request defensively, even when it is no third-party API -> I can think of three reasons why my app crashes because of corrupt data:
I add wrong data via the Firebase console like using type string for a field that should have been type number (happened repeatedly).
A bug in my app adds corrupt data to Firestore.
A user has an old version of my app installed which can not handle the new Firestore data structure.
My requirements: The app should not crash when corrupt data from Firestore is requested, but the corrupt data should be reported so that the data can be fixed in Firestore a.s.a.p.
What do you think about the following approach?
Assume we have a model Movie.
Movie {
final String title;
final int releaseYear;
Movie({required this.title, required this.releaseYear});
Movie.from(Map<String, dynamic> data)
: title = data['title'],
releaseYear = data['release_year'];
}
The named constructor from parses the document data from DocumentSnapshot.data() and returns our model. This works fine as long as the data has a field title of type String and a field release_year of type int (number in Firestore).
Let's assume the field release_year is missing in the actual data. This will let the request crash. Thus, the current user can't do anything with the respective movie and I as developer won't notice, because it happened silently on the device of the user.
To fix the first issue, we can use defensive parsing with fallback data like this: data['release_year'] ?? -1. No crash happens, but I as developer still don't notice and can't fix the data.
To fix also this issue we could use Firebase Crashlytics. The only problem is that if we use defensive parsing to prevent crashing no log will be sent to Firebase. That's why I came up with this solution:
final snapshot = await FirebaseFirestore.instance.collection('movies').doc('123').get();
try {
return Movie.from(snapshot.data()!);
} catch (e) {
await FirebaseCrashlytics.instance
.recordError(e, e.stackTrace(), reason: 'data of movie ${snapshot.id} is corrupt');
return Movie.fromCorrupt(snapshot.data()!);
}
First, the app tries to parse the document data without any fallback mechanism. If the data is corrupt an exception is thrown and catched. In the catch block, the error is send to Firebase and then the defensive parsing constructor fromCorrupt is called to let the user continue in the app with the remaining data. In fromCorrupt each field is checked on null and type, before it is used to create the model Movie. If a value is null or of a wrong type, a fallback value is used.
What do you think of my approach? Am I overengineering? 😅
I have different libraries added to my flutter application. I'm implementing a feature in the application where whenever an error or message is printed to the console from any library or error message, I want to send that error or message string to the server.
How can I listen to console in flutter programmatically so whenever a string is printed to the console I can capture it to send it to the server later?
One possible solution that I can think of is to intercept print() method and then you can get all the values whenever the print() method is called in the current zone.
After intercepting the value, you can save it to a file or so whatever you want to. I don't know if it's the most suitable way to do it.
void main() {
runZoned(() {
// Ends up printing: "Intercepted: in zone".
runApp(MyApp());
}, zoneSpecification: new ZoneSpecification(
print: (Zone self, ZoneDelegate parent, Zone zone, String line) {
parent.print(zone, "Intercepted: $line");
//save to a file or do whatever you want
}));
}
[![enter image description here][2]][2]
he problem is that the view do not get the updated data
The process flows like this
Data is fetched by loadData and put it into transactionTypeList of the viewmodel
Print the length of the list inside the load
i had another function which is also called from init to print the length of the list here i get the list
but when i try to get the same data from the builder, the builder receives a blank
Call notifyListener() instead of ChangeProvider().
And give more code if this doesn't solve.
You are not awaiting for your _model.loadData() method, so you can see that although it is called at the first of initState(), the print statement of loadData() is printed at last.
So, you need to await for loadData(), which you cannot do in initState(), and until the loadData() method is completed you need to show a loader in your build method.
I am Currently working with puppeteer Dart package, as you see in this code below.
try {
await page.waitForXPath('//*[#id="confirm-yes"]');
var confirm = await page.$x('//*[#id="confirm-yes"]');
await confirm[0].click();
}catch (e) {
print(e)
}
the code above works fine, i use it on my other tasks, however in this particular step the selector is a popup and it sometimes come up and sometimes doesnt, and so i want it to be like if the popup comes up this above code will identify the selector element and click on it, but if it isnt available than just skip this and move on, however it just gives out an exception and breaks the code. i am very new to dart in python i would have just written pass in exception block.
please help.