Flutter Future always return null - flutter

What is wrong in my code it always returns null
getLocation().then((r) {
if (r != null) {
print("r=" + r.length.toString());
} else {
print("result is null");
}
});
Future< List<double>> getLocation() async {
// print("getLocation called");
location = new Location();
List<double> result=[];
location.getLocation().then((loc) {
result.add(loc.latitude);
result.add(loc.longitude);
result.add(4213);
// print(loc.latitude.toString() + "," + loc.longitude.toString() +" l="+l1.length.toString());
return result;
}).catchError((e){
return result;
});
}

You are not returning anything in your function, only in your then callback.
Since you are using async syntax anyway you can just go for:
Future< List<double>> getLocation() async {
location = new Location();
List<double> result=[];
var loc = await location.getLocation();
result.add(loc.latitude);
result.add(loc.longitude);
result.add(4213);
return result;
}
I've taking error handling out of the code but you can just use try-catch if you want that.

Related

Flutter Firestore Query snapshot- result is always null

I have a simple flutter code to retrieve some data from Firestore. the data is retireved correctly, however passing the data from the future function making the result always null. can you advise how to adapt the code to return the list?
that is the class where the actual query is happening:
class DatabaseManager {
final CollectionReference BusinessProfilesCollection =
FirebaseFirestore.instance.collection("BusinessProfilesCollection");
Future GetBusinessProfilesCollection() async {
List businessprofileslist = [];
try {
await BusinessProfilesCollection.get().then((QuerySnapshot) {
QuerySnapshot.docs.forEach((element) {
businessprofileslist.add(element.data());
print(businessprofileslist[0]);
});
});
} catch (e) {
print(e.toString());
return null;
}
}
}
here is the page where I am calling the function: (however the result is always null)
class _ProfilesListPageState extends State<ProfilesListPage> {
List businessprofileslist = [];
#override
void initState() {
super.initState();
fetchBusinessProfilesList();
}
fetchBusinessProfilesList() async {
dynamic result = await DatabaseManager().GetBusinessProfilesCollection();
print(result.toString());
if (result == null) {
print('enable to retieve');
} else {
print('success');
setState(() {
businessprofileslist = result;
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold();
}
}
You're not returning anything from GetBusinessProfilesCollection but null, so the result seems somewhat expected.
I guess you want to do:
class DatabaseManager {
final CollectionReference BusinessProfilesCollection =
FirebaseFirestore.instance.collection("BusinessProfilesCollection");
Future GetBusinessProfilesCollection() async {
List businessprofileslist = [];
try {
var QuerySnapshot = await BusinessProfilesCollection.get();
querySnapshot.docs.forEach((element) {
businessprofileslist.add(element.data());
});
return businessprofileslist;
} catch (e) {
print(e.toString());
return null;
}
}
}
Btw: returning null when the load fails, is just going to lead to a null pointer exception when you then do print(result.toString());. So I recommend not catching the error and just letting it bubble up. With that your code can be simplified to:
class DatabaseManager {
final CollectionReference BusinessProfilesCollection =
FirebaseFirestore.instance.collection("BusinessProfilesCollection");
Future GetBusinessProfilesCollection() async {
var QuerySnapshot = await BusinessProfilesCollection.get();
return querySnapshot.docs.map((element) => element.data());
}
}
You just need to return the list
return businessprofileslist;
CODE :
class DatabaseManager {
final CollectionReference BusinessProfilesCollection =
FirebaseFirestore.instance.collection("BusinessProfilesCollection");
Future GetBusinessProfilesCollection() async {
List businessprofileslist = [];
try {
await BusinessProfilesCollection.get().then((QuerySnapshot) {
QuerySnapshot.docs.forEach((element) {
businessprofileslist.add(element.data());
print(businessprofileslist[0]);
});
// you just need to return the list here after filling it up
return businessprofileslist;
});
} catch (e) {
print(e.toString());
return null;
}
}
}
Code with a little improvement:
class DatabaseManager {
final CollectionReference BusinessProfilesCollection =
FirebaseFirestore.instance.collection("BusinessProfilesCollection");
Future GetBusinessProfilesCollection() async {
await BusinessProfilesCollection.get().then((QuerySnapshot) {
QuerySnapshot.docs.map((doc) => doc.data()).toList();
});
}
}
Try that with calling the function in feching
fetchBusinessProfilesList()
async {
dynamic result ;
await DatabaseManager().GetBusinessProfilesCollection().then((value){
result=value;
print(result.toString());
if (result == null) {
print('enable to retieve');
} else {
print('success');
setState(() {
businessprofileslist = result;
});
}
});
}

How to return catch exception in flutter

I working on error handling of api's. i want if api is crashed then it display a message of "Server is down" something like this, in UI.
I created a class where i'm creating methods of api, here in getBooks method if i modify the api url then it is printing this Exception, and i want it in UI. The problem is getBooks return type is List<Book>> so we can't return this Exception, any solution how to do this?
Exception
E/flutter (12924): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: Exception
here is my api code
class BooksApi {
static Future<List<Book>> getBooks(String query) async {
try {
final url = Uri.parse(
'https://gist.githubusercontent.com/JohannesMilke/d53fbbe9a1b7e7ca2645db13b995dc6f/raw/eace0e20f86cdde3352b2d92f699b6e9dedd8c70/books.json');
final response = await http.get(url);
if (response.statusCode == 200) {
final List books = json.decode(response.body);
return books.map((json) => Book.fromJson(json)).where((book) {
final titleLower = book.title.toLowerCase();
final authorLower = book.author.toLowerCase();
final searchLower = query.toLowerCase();
return titleLower.contains(searchLower) ||
authorLower.contains(searchLower);
}).toList();
} else {
throw Exception;
}
} catch (e) {
print("e");
print(e);
}
throw Exception;
}
}
and calling it like
Future init() async {
setState(() {
isLoading = true;
});
var books = await BooksApi.getBooks(query); //this
var response = await obj.getProduct();
print(response);
setState(() => this.books = books);
setState(() {
isLoading = false;
});
}
You could handle errors with then and onError :
await BooksApi.getBooks(query).then((books) async {
setState(() => {
this.books = books;
this.isLoading = false;
})
}, onError: (error) {
// do something with error
});
or a simple try-catch (you can write try-catch clauses the same way you would in synchronous code).
See handling errors.
You can also use catchError id you don't use async/await :
BooksApi.getBooks(query).then((books) {
setState(() => {
this.books = books;
this.isLoading = false;
})
}).catchError((error, stackTrace) {
print("error is: $error");
});
See futures error handling.
Try to wrap 'var books = await BooksApi.getBooks(query)' with try and catch.
...
try {
var books = await BooksApi.getBooks(query);
} catch (e) {
// To do for UI
}
...
For api, you need to make something like this:
APIModel{
final int code;
// or a success flag
// final bool success;
final String message;
final List<Book> data;
APIModel({this.code,this.message,this.data});
}
It means, every api have its own code,message,and data filed.
When you request, you can check your code or success:
var response = await request(params);
isLoading = false;
if(response.code == 0){}
// or
if(response.success){
// do what you want
}
else {
Toast.show(response.message);
}
You can use build_runner and json_serializable.

Function returns Future<dynamic>

So I'm learning flutter and I have a function which returns a UserLocation object -
getUserLocation() async {
bool _serviceEnabled;
loc.PermissionStatus _permissionGranted;
_serviceEnabled = await location.serviceEnabled();
if (!_serviceEnabled) {
_serviceEnabled = await location.requestService();
if (!_serviceEnabled) {
return;
}
}
_permissionGranted = await location.hasPermission();
if (_permissionGranted == loc.PermissionStatus.denied) {
_permissionGranted = await location.requestPermission();
if (_permissionGranted != loc.PermissionStatus.granted) {
return;
}
}
try {
_currentPosition = await location.getLocation();
} catch (e) {
print(e);
}
List<geo.Placemark> placemarks = await geo.placemarkFromCoordinates(
_currentPosition.latitude ?? 0, _currentPosition.longitude ?? 0);
var countryNameList = placemarks[0].country?.split(' ');
if (countryNameList!.isNotEmpty && countryNameList.length >= 2) {
for (var eachLetter in countryNameList) {
abbr += eachLetter[0];
}
} else {
abbr = countryNameList.toString().substring(0, 2).toUpperCase();
}
return UserLocation(
city: placemarks[0].locality ?? 'Chennai',
country: abbr,
latitude: _currentPosition.latitude,
longitude: _currentPosition.longitude);
}
Now, when I'm calling this function, It says that It returns Future<dynamic)..Future because it's an async function and dynamic because it doesn't really return anything if location.ServiceEnabled or location.hasPermission fails.
Anyways, the point is that I want to access the UserLocation object returned by this method whenever I'm calling this function from somewhere else but It always say that this function returns Future. How I can do that?? Any idea?
This should solve the problem, Set the return type of getUserLocation() function to Future<UserLocation?> and return null wherever there is nothing to return.

issue with geting all data from sqflite database

i have been trying to get all my data from a sqflite database, when i try to get a single data, this works totally fine:
Future<dynamic> getUser() async {
final db = await database;
var res = await db.query("files");
if (res.length == 0) {
return null;
} else {
var resMap = res[0];
return resMap;
}
}
but when i try to get all data using a for loop like the example below, i get an error
Future<dynamic> getUser() async {
final db = await database;
var res = await db.query("files");
var resMap;
var count = res.length;
if (count != 0) {
for (int i = 0; i < count; i++) {
resMap.add(res[i]);
}
}
return resMap;
}
the error says:
The method 'forEach' was called on null.
Receiver: null
Tried calling: forEach(Closure: (dynamic, dynamic) => Null)
i understand that it says that I've got no data,
and i also tried to remove the if statement, but still no luck!
change this method:
EDIT
Future<List<Map>> getUser() async {
final db = await database;
var res = await db.query("files");
List<Map> resMap = [];
if (res != null res.length > 0) {
for (int i = 0; i < count; i++) {
resMap.add(res[i]);
}
return resMap;
} else
{
return null;
}
}
try this in you widget
List<Map> newUser = [];
#override
void initState() {
super.initState();
getUser();
}
getUser() async {
final _userData = await DBProvider.db.getUser();
if(_userData != null ){
setState(() {
newUser = _userData;
});
} else{
setState(() {
newUser =[];
});
}
}

Flutter - Async function from a different class prints okay but returns null

The below function prints the proper value when called from main.dart, but returns null. It seems the function is somehow not awaiting for the value before returning.
Would appreciate some help.
location.dart
class Location {
StreamSubscription<Map<String, double>> _locationSubscription;
Future getLocation() async {
try{
geolocation.Location _location = new geolocation.Location();
_locationSubscription =
_location.onLocationChanged().listen((Map<String, double> result) {
print(result);
// This prints the proper value
return(result);
// But this returns null...
});
} on PlatformException {
return null;
} catch(e){
print(e);
}
}
}
main.dart
#override
void initState(){
super.initState();
getLocation();
}
getLocation() async {
var location = Location();
var loc = await location.getLocation();
print(loc);
//This prints null
}
You have to define return type of future.
class Location {
StreamSubscription<Map<String, double>> _locationSubscription;
Future<Map<String, double>> getLocation() async {
try{
geolocation.Location _location = new geolocation.Location();
_locationSubscription =
_location.onLocationChanged().listen((Map<String, double> result) {
print(result);
// This prints the proper value
return(result);
// But this returns null...
});
} on PlatformException {
return null;
} catch(e){
print(e);
}
}
}