Future is stuck on return statement and never completes the function future called from - flutter

getInitialTripData calls getCurrentLocationData with await but it never prints "coming here 1" and on getCurrentLocationData the function goes on till printing the data and then stuck on return statement i dont know what the issue is
setInitialTripData() async {
print("coming here");
MapLocation startingPoint=await Get.find<LocationService>().getCurrentLocationData();
print("coming here 1");
if (startingPoint != null) {
tripData.startingPoint = startingPoint;
startingPointTextController.text = startingPoint.name;
update();
}
}
Future<MapLocation> getCurrentLocationData()async{
try{
if(!locationAllowed.value){
return null;
}
LocationData position=await _location.getLocation();
List<geo.Placemark> placemark =
await geo.placemarkFromCoordinates(position.latitude, position.longitude);
if(placemark.length==0 || placemark==null){
return null;
}
MapLocation mapLocation=MapLocation(name: "${placemark[0].name.isNotEmpty? placemark[0].name+", ":""}${placemark[0].subAdministrativeArea.isNotEmpty? placemark[0].subAdministrativeArea+", ":""}${placemark[0].isoCountryCode.isNotEmpty? placemark[0].isoCountryCode:""}",latitude: position.latitude,longitude: position.longitude);
print(mapLocation.getDataMap());
return mapLocation;
}
catch(e){
return null;
}
}

getCurrentLocation has a bunch of chances to return null, and you're not handling a potential null return value in setInitialTripData
your code only continues executing if startingPoint != null it seems.

Well Problem is in your getCurrentLocationData function because your function is expecting a return value of type MapLocation because you have declared in your function it's return type here
Future<MapLocation> getCurrentLocationData(){}
That's why when you return null from this function this throws an error and break your functions.
What you need to do is either remove return type or make it nullable whichever works fine like :
Future<MapLocation?> getCurrentLocationData(){}
Or
Future getCurrentLocationData(){}
Apart from that you need to make the receiving variable nullable so that it can handle null data
MapLocation? startingPoint=await Get.find<LocationService>().getCurrentLocationData();

Related

Flutter null or emptylist

it's just a small question about dart/flutter code.
I saw this code today :
Future<List<String>?> getAtSignListFromKeychain() async {
var atsignMap = await _getAtSignMap();
if (atsignMap.isEmpty) {
// no atsigns found in biometric storage
// read entries from flutter keychain
// for mobile platforms only
if (Platform.isAndroid || Platform.isIOS) {
atsignMap = await checkForValuesInFlutterKeychain();
if (atsignMap.isEmpty) {
return null;
}
} else {
return null;
}
}
var atsigns = atsignMap.keys.toList();
_logger.info('Retrieved atsigns $atsigns from Keychain');
return atsigns;
}
I don't understand interest of returning null with List? . Isn't better to write this code ?:
Future<List<String>> getAtSignListFromKeychain() async {
var atsignMap = await _getAtSignMap();
if (atsignMap.isEmpty) {
// no atsigns found in biometric storage
// read entries from flutter keychain
// for mobile platforms only
if (Platform.isAndroid || Platform.isIOS) {
atsignMap = await checkForValuesInFlutterKeychain();
if (atsignMap.isEmpty) {
return atsignMap;
}
} else {
return List.empty();
}
}
var atsigns = atsignMap.keys.toList();
_logger.info('Retrieved atsigns $atsigns from Keychain');
return atsigns;
}
Or I'm missing something ? Thank you !
First of all, there are always different solutions for different problems. I believe it is better to return a null value for some cases instead of creating an empty list in the memory and returning that. Either way, you have to check the returning value, handle errors, etc. So instead of checking if the list is empty or not, you can use just the ?? operator.
And in some cases, the list you expect with the items in it may be empty. If you return an empty list by default in such cases, you would not know if the list that you expected is really empty or is there a problem.

The function call is not returning null but still giving "null" to be returned error

I'm migrating my old version flutter code to latest version with null safety feature.
In a function call I am getting the error "The body might complete normally, causing 'null' to be returned, but the return type is a potentially non-nullable type". I have enclosed my code in try catch block and in catch block I added rethrow statement to prevent null exception.
This is my code.
Future<Map<String, dynamic>> fetchTimeline(http.Client client) async {
try {
print('INVOICE URL: ${globals.ursl.getURL(URLS.GETINVOICEURL)}');
Response response;
Dio dio = new Dio();
response = await dio.get(globals.ursl.getURL(URLS.GETINVOICEURL));
print('INVOICE GET RESPONSE: $response');
if (response.statusCode == 200) {
Map mapobject = (json.decode(response.toString()));
var succes = mapobject['success'];
if (succes == 1) {
if (mapobject['Invoice'][0]['address'] == null ||
mapobject['Invoice'][0]['address'] == '') {
address = '';
} else {
address = mapobject['Invoice'][0]['address'];
}
if (mapobject['Invoice'][0]['contact'] == null ||
mapobject['Invoice'][0]['contact'] == '')
phone = '';
else
phone = mapobject['Invoice'][0]['contact'];
if (mapobject['Invoice'][0]['restaurant_name'] == null ||
mapobject['Invoice'][0]['restaurant_name'] == '') {
name = ' ';
} else {
name = mapobject['Invoice'][0]['restaurant_name'];
}
logo = mapobject['Invoice'][0]['logo'];
globals.invoiceData = mapobject['Invoice'][0];
startTime();
return mapobject['Invoice'][0];
} else {
return {};
}
}
} catch (error) {
client.close();
print("CONNECTION CLOSED: $error");
rethrow;
}
}
I have added rethrow in catch block but still error is there.
Anyone there to help me out.
Thanks
It's a little hard to see with all the nested if statements, but you aren't returning a Map<String, dynamic> in every branch. This condition if (response.statusCode == 200) { ... } does not have a corresponding else branch, and so if the statusCode is some value other than 200 you are not returning anything (which means you are implicitly returning null in that case).

Flutter : Conditions must have a static type of 'bool'

I'm trying to learn firebase with flutter and i ran into this problem
here is my code :
FirebaseFirestore.instance
.collection('attendees')
.doc(user.uid)
.snapshots()
.listen((snapshot) {
if (snapshot.data() != null) {
if (snapshot.data()!['attending']) {
_attending = Attending.yes;
} else {
_attending = Attending.no;
}
} else {
_attending = Attending.unknown;
}
notifyListeners();
});
what is the solution ?
the exact problem is within this line :
if (snapshot.data()!['attending']) {
how can I rewrite this so i wont ruin the current functionality ?
I appreciate your help inadvance
The reason you are getting error -
Conditions must have a static type of 'bool'
because on line snapshot.data()!['attending'] an = sign is missing.
To make your code work just do
if (snapshot.data() != snapshot.data()!['attending']) {
_attending = Attending.yes;
} else {
_attending = Attending.no;
}
Understanding The Error
I would also like to point out that Dart a stricter language (more like Java in terms of 'truthy' values).
In JavaScript you can use any ‘truthy’ value in a conditional statement. In Dart you cannot use ‘truthy’ values. For example:
var name = 'Joe';
if (name) {
// do something...
OR
var a = 1
if(a){
//this would work in JavaScript
}
You cannot do such things in Java or Dart. The reason is that Dart requires that a condition is a bool true not just a 'truthy' value. You could correct the code by changing it to:
if (name.isNotEmpty)
OR
if(a==1)
{
//these == signs are really important
}
Just store the snapshot.data() to the local map variable and do the operations by that.
_attendingSubscription = FirebaseFirestore.instance
.collection('attendees')
.doc(user.uid)
.snapshots()
.listen((snapshot) {
final Map<String, dynamic>? data = snapshot.data();
if (data != null) {
_attending = data['attending'] ? Attending.yes : Attending.no;
} else {
_attending = Attending.unknown;
}
notifyListeners();
});

The input does not contain any JSON tokens (Blazor, HttpClient)

i have an http Get method like below
public async Task<Ricetta> GetRicettaByNome(string nome)
{
Ricetta exist = default(Ricetta);
var ExistRicetta = await appDbContext.Ricetta.FirstOrDefaultAsync(n => n.Nome == nome);
if(ExistRicetta != null)
{
exist = ExistRicetta;
return exist;
}
exist = null;
return exist;
}
It gets called by a controller like this:
[HttpGet("exist/{nome}")]
public async Task<ActionResult<Ricetta>> GetRicettaByNome(string nome)
{
try
{
if (string.IsNullOrEmpty(nome))
{
return BadRequest();
}
var result = await ricetteRepository.GetRicettaByNome(nome);
if (result != null)
return result;
return default(Ricetta);
}
catch (Exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, "NON HAI INTERNET!");
}
}
But when i call my api to get the resposne by an httpclient like this:
public async Task<Ricetta> GetRicettaByNome(string nome)
{
return await httpClient.GetJsonAsync<Ricetta>($"api/Ricette/exist/{nome}");
}
i got this error:
the input does not contain any JSON tokens. Expected the input to start with a valid JSON token, when isFinalBlock is true. Path: $ | LineNumber: 0 | BytePositionInLine: 0.'
This is the expected result when you return null from your API. And default(Ricetta) is the same as null.
You will have to handle this some other way. GetJsonAsync<T>() is convenient shorthand when you know you will always have data. It is not the best option for dealing with null.
You can see (in dev tools) that the status code is 204 (No Content) for null. You can detect that or catch the error from GetJsonAsync.
Your error exist in your repository part where GetJsonAsync<>. You need to use HttpResponseMessage and check the content before Deserialize for example:
private async ValueTask<T> GetJsonAsync(string ur)
{
using HttpResponseMessage response = awiat _client.GetAsync(url);
//some method to validate response
ValidateResponse(response);
//then validate your content
var content = await ValidateContent(response).ReadAsStringAsync();
return JsonSerializer.Desrialize<T>(content, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
}
//Here is the method that you need
private HttpContent ValidateContent(HttpResponseMessage response)
{
if(string.IsNullOrEmpty(response.Content?.ReadingAsString().Result))
{
return response.Content= new StringContent("null",Encoding.UTF8, MediaTypeNames.Application.Json);
}
else
{
return response.Content;
}
}

Flutter : Why This Method Not Works?

In QuerySnapshot It Has "Day1" and "Day2" Boths are Day of Week Like "Saturday". If "Day1" or "Day2" is Today I need to Return "true". But This method always returns false. I need to know why the If condition (In Loop) is not working and How can I Solve this?
bool class_count(Stream<QuerySnapshot> stream) {
bool class_ = false;
String dateFormat = DateFormat('EEEE').format(DateTime.now());
//This Line Return Day Like "Saturday"
stream.forEach((element) {
if (element != null) {
for (int count = 0; count < element.documents.length; count++) {
if (element.documents[count].data['Day1'].toString() == dateFormat)
class_ = true;
if (element.documents[count].data['Day2'].toString() ==
dateFormat) if (element.documents[count].data['Day2']
.toString() ==
dateFormat) class_ = true;
}
}
});
print(class_);
return class_;
}
Bacause stream's forEach is asynchronous. So this loop will not wait while it completes. In your code you set class_ to false, then create a future which will be executed in future, and return classs_ at once. So it still equal to false.
Try to add async suffix to method and await before stream.forEach. And then your method must return Future<bool> and been called as
final class = await class_count(someStream);
I think the best way to handle stream events is add listener for stream and process data in it.
stream.listener((event) {
// here must be your code which will be executed each time stream will get event
});
stream.forEach() method returns a Future type value. So you have to call this method inside a another Asynchronous function and also it needs to be await until that future completes.
Solution:-
Convert your class_count() synchronous method to a Asynchronous method by,
Adding async keyword to method header.
Change your return type into a Future<bool>.
Add await keyword before stream.forEach() method call (Asynchronous operation).
Code:-
[Read comments carefully to understand the program flow correctly]
//1- Return type should be a Future type => Future<bool>.
//2- Add async keyword before method body => async.
Future<bool> class_count(Stream<QuerySnapshot> stream) async{
bool class_ = false;
String dateFormat = DateFormat('EEEE').format(DateTime.now());
//3 - Adding await keyword before asynchronous operation => await.
//
await stream.forEach((element) {
if (element != null) {
for (int count = 0; count < element.documents.length; count++) {
if (element.documents[count].data['Day1'].toString() == dateFormat)
class_ = true;
if (element.documents[count].data['Day2'].toString() ==
dateFormat) if (element.documents[count].data['Day2']
.toString() ==
dateFormat) class_ = true;
}
}
});
//After stream.forEach() method completes its loop these below statements will execute.
//Every statements inside the function body will only execute one after another.
//so below statements are only executes after the above operation completes.
print(class_);
return class_;
}
One extra tip :- By using StreamSubcription you can get streams of data, instead of future.