I'm trying to call a function which will populate a list by reading a stream. Means, it will read a stream and add values to a list and finally, the list will be returned by the function.
The problem is, when I'm using await for to read the stream, the code after the await for is not getting executed. And I tried to use listen, then it's not waiting to finish reading the stream. The code after the listen is getting executed even before the stream is read completely.
Following in my code -
Future<List<Map<String, dynamic>>> getNearestDriver(Stream<List<DocumentSnapshot>> driverWithinRangeStream, GeoPoint source) async {
print("Get Nearest Driver Called");
List<Map<String, dynamic>> driverAvailableList = [];
await for (List<DocumentSnapshot> documentList in driverWithinRangeStream){
documentList.forEach((DocumentSnapshot document) async {
String driverIDVar = document.data['driverid'];
GeoPoint pos = document.data['position']['geopoint'];
var point = geo.point(latitude: pos.latitude, longitude: pos.longitude);
double distanceVar = point.distance(lat: source.latitude, lng: source.longitude);
int distanceInMeter = (distanceVar*1000).round();
Map<String, dynamic> newDriverAvailable = {"driverId": driverIDVar, "distance" : distanceInMeter};
driverAvailableList.add(newDriverAvailable);
});
print(driverAvailableList); /* <- I get the data here */
}
print(driverAvailableList); /* <- But I don't get the data here. This code is not even being executed. */
}
Please let me know what's wrong here.
Would you mind to try
try{
await for (List<DocumentSnapshot> documentList in driverWithinRangeStream){
await Future.forEach(documentList, (DocumentSnapshot document) async {
try{
String driverIDVar = document.data['driverid'];
GeoPoint pos = document.data['position']['geopoint'];
var point = geo.point(latitude: pos.latitude, longitude: pos.longitude);
double distanceVar = point.distance(lat: source.latitude, lng: source.longitude);
int distanceInMeter = (distanceVar*1000).round();
Map<String, dynamic> newDriverAvailable = {"driverId": driverIDVar, "distance" : distanceInMeter};
driverAvailableList.add(newDriverAvailable);
}catch(error){
throw "throw from documentList, Error:$error";}
});
}
}catch(error){
print ("catch in driverWithinRangeStream, Error:$error");}
Related
I've been playing with mobile apps and firestore recently and wanted to put a simple predictive model inside my app. I did put it but i want to get data from my firestore to use it as input for my predictive model. The shape of my inputdim is 5 that is why i used the limit function of firestore to get 5 values but instead of values im getting the whole document content instead of the value of the field "amount"
List mlinpt = [];
final CollectionReference mlPut = FirebaseFirestore.instance
.collection('UserAccounts')
.doc(myUid)
.collection('dataInference');
getUserInputList() async {
await mlPut.orderBy('amount', descending: true).limit(5).get().then((querysnapshot) {
for (var result in querysnapshot.docs) {
mlinpt.add(result.data());
}
});
}
Future<void> predData() async {
final interpreter = await Interpreter.fromAsset('model/kerasregopt.tflite');
var input = [mlinpt];
var output = List.filled(1, 0).reshape([1, 1]);
interpreter.run(input, output);
print(output[0][0]);
this.setState(() {
predValue = output[0][0].toString();
});
}
List mlinpt = [];
final CollectionReference mlPut = FirebaseFirestore.instance
.collection('UserAccounts')
.doc(myUid)
.collection('dataInference');
getUserInputList() async {
await mlPut.orderBy('amount', descending: true).limit(5).get().then((querysnapshot) {
for (var result in querysnapshot.docs) {
mlinpt.add(result.data());
}
});
}
Future<void> predData() async {
final interpreter = await Interpreter.fromAsset('model/kerasregopt.tflite');
var input = [mlinpt];
var output = List.filled(1, 0).reshape([1, 1]);
interpreter.run(input, output);
print(output[0][0]);
this.setState(() {
predValue = output[0][0].toString();
});
}
I tried getting the snapshot of the values i want in firestore but i think i dont quite understand how it works or how i should use it
it's my code
class TrackingManager {
Location locate = new Location();
Future<Map<String, double>> trackOn() async {
LocationData getlocationdata = await locate.getLocation();
Map<String, double> locationdata = {};
locationdata['latitude'] = getlocationdata.latitude ?? 0;
locationdata['longitude'] = getlocationdata.longitude ?? 0;
return locationdata;
}
}
if controller(user) call TrackingManager and initialize object,
and use trackOn so Stores the location information of the current user.
class LocateApiRequest {
final _networkManager = NetworkManager();
final _trackingManager = TrackingManager();
Future transmit(String accessToken) async {
final locationdata = await _trackingManager.trackOn();
final response = await _networkManager
.send(ApiRequestFactory.transmit(locationdata, accessToken));
final statusCode = response.statusCode;
if (statusCode == 200) {
final responseBody = jsonDecode(response.body);
return responseBody;
}
throw statusCode;
}
}
and Send the data to the server by requesting a post
But this action is carried out only once.
Starting with when a user clicks a specific button, I want to do this on the server with a regular time (background, foreground status is not important)
how can i solve it?I've thought about using a repeat statement, but this doesn't seem reasonable
using location callback
https://pub.dev/packages/location
location.onLocationChanged.listen((LocationData currentLocation) {
// call network api
// Use current location
});
I am integrating the following system into my to-do app:
Every time the user opens the app, it should check whether the date stored in Cloud Firestore has been exceeded.
If this is the case, all To-Dos of the user should be reset to false.
This is the date in Cloud Firestore I’m looking for:
This function should check if the date has been exceeded:
Future<bool> checkTime() async{
DateTime now = DateTime.now();
var query = users.where('Startdatum', isLessThanOrEqualTo: now);
query = query.where('userID', isEqualTo: userID);
final querySnapshot = await query.get();
return querySnapshot.size > 0;
}
And this function should reset all To-Dos to false:
Future allFalse() async{
return await users.doc(userID).get().then((DocumentSnapshot doc) {
var updateMap = new Map();
var toDos = doc['Level'];
for (var item in toDos.keys) {
updateMap[item] = false;
}
doc.reference.update({'Level' : updateMap});
});
}
I created both functions in a separate file (database), as you can see here:
class DatabaseService {
String userID;
DatabaseService(this.userID);
final CollectionReference users =
FirebaseFirestore.instance.collection('users');
Future allFalse() async {
return await users.doc(userID).get().then((DocumentSnapshot doc) {
var updateMap = new Map();
var toDos = doc['Level'];
for (var item in toDos.keys) {
updateMap[item] = false;
}
doc.reference.update({'Level': updateMap});
});
}
Future<bool> checkTime() async {
DateTime now = DateTime.now();
var query = users.where('Startdatum', isLessThanOrEqualTo: now);
query = query.where('userID', isEqualTo: userID);
final querySnapshot = await query.get();
return querySnapshot.size > 0;
}
}
I create an if condition in in inite State that includes checkTime. If checkTime returns true, the Future returns allFalse, which sets all To-Dos to false.
class _UebersichtState extends State<Uebersicht> {
User? user;
late DatabaseService database;
Future<void> connect() async{
final FirebaseAuth auth = FirebaseAuth.instance;
UserCredential result = await auth.signInAnonymously();
user = result.user;
database = DatabaseService(user!.uid);
}
#override
void initState() {
// TODO: implement initState
super.initState();
connect();
Future.delayed(Duration(seconds: 3), () async{
if(await database.checkTime()) {
return await database.allFalse();}
else print('Still time left');
});
}
I used a delay because the connect () function has to be executed first, it initializes database.
When I start the app, no error appears, but the To-Dos are not reset either.
Today we have the 21. 12. 2021 and in Cloud Firestore is 14. 12. 21 deposited.
The function allFalse works, it resets the To-Dos all.
It must be the function checkTime, which does not return a bool in the if condition. I just replaced it with if (0 == 0) and that triggers allFalse.
Can someone help me?
This is just a guess, but I believe this is the problem:
query = query.where('userID', isEqualTo: userID);
The above line would only work if your document had a field userID and said field was equal to your UID, but from what I could gather, you identify the UID by the name of the documents, if that is the case, this should work?
Future<bool> checkTime() async {
CollectionReference users = FirebaseFirestore.instance.collection('users');
final now = DateTime.now();
final doc = await users.doc(userID).get();
final stufenzeit = (doc.data() as Map<String, dynamic>)['Stufenzeit'] as Map<String, dynamic>;
final storedDate = (stufenSetit['Startdatum'] as TimeStamp).toDate();
return now.compareTo(storedDate) > 0;
}
There's probably also a way to do it with queries, but I am not so well versed on those to be completely honest.
I try to use compute in Flutter. Here I try to pass multiple parameters inside a Map. But the code in my function myFunction does not work. I get no errors or something else. My code seems to be ignored. Do you find an error here?
Compute function:
Map map = Map();
map['resultList'] = resultList;
map['_getImageFileFromAssets'] = _getImageFileFromAssets;
map["picturesData"] = picturesData;
map["albumID"] = albumID;
await compute(myFunction, map);
Calls the following function:
Future<bool> myFunction(map) async {
var resultList = map["resultList"];
var _getImageFileFromAssets = map["_getImageFileFromAssets"];
var picturesData = map["picturesData"];
var albumID = map["albumID"];
print("Starten");
for (var i = 0; i < resultList.length; i++) {
print(i);
File imageFile = await _getImageFileFromAssets(resultList[i]);
final appDir = await syspath.getApplicationDocumentsDirectory();
final fileName = path.basename(imageFile.path);
final savedImage =
await File(imageFile.path).copy('${appDir.path}/$fileName');
// Creating thumbnails
final thumb = image.decodeImage(await File(savedImage.path).readAsBytes());
final thumbImage = image.copyResize(thumb, width: 500);
new File('${appDir.path}/$fileName-thumb-500.jpg')
.writeAsBytes(image.encodeJpg(thumbImage));
final finalThumbImage = File('${appDir.path}/$fileName-thumb-500.jpg');
picturesData.add(Picture(
album: albumID,
path: savedImage.path,
thumbPath: finalThumbImage.path,
timestamp: Timestamp.now()));
}
return true;
}
Ok, some code - I put this in dartpad.dev:
import 'package:flutter/foundation.dart';
void main() {
Map map = Map();
compute(myFunction, map).then((result) => print(result));
}
Future<bool> myFunction(Map map) async {
print("Starten");
// fake long process
await Future.delayed(Duration(seconds: 5));
return true;
}
and get this as a console result:
Starten
true
Also: is there a reason you need the "map" parameter in your function to be dynamic? If not, I'd declare it as type Map (like I did now).
I have problem in api calling i getting a geolocation of current place,i am passing the latitude&longitude
but i having a problem is i need to pass the latitude&longitude to certain format like this lat_11.3054724$75.8744252 so i can't try to concatinate the $ sign along with it,Also i am not getting any data when i pass latitude&longitude data i cannot use in api it throws
unhandled Exception: NoSuchMethodError: The getter 'latitude' was called on null.
E/flutter (27500): Receiver: null
E/flutter (27500): Tried calling: latitude
But i can print the data to Text but not pass to api
Code
Future<String> getMainbanner() async {
var latitude=_currentPosition.latitude.toString();
var longitude=_currentPosition.longitude.toString();
var response = await http.post(Urls.HOME_BANNER,
headers: {"Content-Type": "application/json"},
body: json.encode({
"banner_type": "Main_Banner",
"location": "lat_"+latitude+'$'+longitude,
}),);
Map<String, dynamic> value = json.decode(response.body);
if (response.statusCode == 200) {
var resp = response.body;
Map<String, dynamic> value = json.decode(resp);
var message = value['msg'];
var banner =value['bannerapp'][0];
for (int i = 0; i < banner.length; i++) {
var data = banner[i];
print("Data:"+data);
}
}
else
{
CustomDialogs().showErrorAlert(context, "Main Banner Image NotFound");
}
}
Code for fetching Current location
_getCurrentLocation() {
final Geolocator geolocator = Geolocator()..forceAndroidLocationManager;
geolocator
.getCurrentPosition(desiredAccuracy: LocationAccuracy.best)
.then((Position position) {
setState(() {
_currentPosition = position;
});
}).catchError((e) {
print(e);
});
}
Edit: The problem is, that _currentLocation is still null when you call _currentLocation.latitude, because _getcurrentLocation() needs some time to set it. There are different approaches to make it work, depending on how your architecture looks.
Change _getCurrentLocation() to an async function
Future<void> _getCurrentLocation() async {
final Geolocator geolocator = Geolocator()..forceAndroidLocationManager;
try {
final position = await geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.best);
setState(() {
_currentPosition = position;
});
} catch(e) {
print(e);
}
}
And await on it inside getMainbanner
Future<String> getMainbanner() async {
await _getCurrentLocation();
var latitude=_currentPosition.latitude.toString();
var longitude=_currentPosition.longitude.toString();
var response = await http.post(Urls.HOME_BANNER,
headers: {"Content-Type": "application/json"},
body: json.encode({
"banner_type": "Main_Banner",
"location": "lat_"+latitude+'$'+longitude,
}),);
Map<String, dynamic> value = json.decode(response.body);
if (response.statusCode == 200) {
var resp = response.body;
Map<String, dynamic> value = json.decode(resp);
var message = value['msg'];
var banner =value['bannerapp'][0];
for (int i = 0; i < banner.length; i++) {
var data = banner[i];
print("Data:"+data);
}
}
else
{
CustomDialogs().showErrorAlert(context, "Main Banner Image NotFound");
}
}
The problem is the $. $ is a special character in dart strings for interpolation so you have to add an escape \ before it.
See here:
https://dart.dev/guides/language/language-tour#strings
And you can make use of this string interpolation to build your string:
var latitude=_currentPosition.latitude;
var longitude=_currentPosition.longitude;
....
"location":"lat_$latitude\$$longitude"
...
Also, you don't need the toString() for latitude and longitude