async-await does not run well on Flutter - sqlite

I updated sqlite database in using code,(this method working correctly)
updateSubmitRequest(int id, String status) async {
var db = await db1;
await db.rawUpdate('''
UPDATE submitRequestTable
SET status = ?
WHERE id = ?
''', [status, id]);
}
update.dart
I updated status like this,
print('before update ${submitRequest[i].status}');
await HelperDatabase1()
.updateSubmitRequest(submitRequest[i].id, 'Pending');
print('after update ${submitRequest[i].status}');
display
List submitRequest = (await HelperDatabase1().displaySubmitRequest());
method
displaySubmitRequest() async {
var db = await db1;
final List<Map<String, dynamic>> maps =
await db.query('submitRequestTable');
return List.generate(maps.length, (i) {
return SubmitRequestModel(
id: maps[i]['id'],
equipmentId: maps[i]['equipmentId'],
woDescriptionId: maps[i]['woDescriptionId'],
details: maps[i]['details'],
priorityId: maps[i]['priorityId'],
workTypeId: maps[i]['workTypeId'],
sourceId: maps[i]['sourceId'],
fileName: maps[i]['fileName'],
filepath: maps[i]['filepath'],
isOffline: maps[i]['isOffline'],
systemDate: maps[i]['systemDate'],
username: maps[i]['username'],
subItemId: maps[i]['subItemId'],
status: maps[i]['status']);
});
}
in my LogCat output like this,
I/flutter (15908): before update success
I/flutter (15908): after update success
Why doesn't it change to Pending?
My update method runs correctly.

Related

Saving to Firebase storage not possible in an isolate

I have an app feature where the user picks images from his phone and then uploads them to Firebase Storage.
I thought that the upload process should be done in a separate isolate.
I keep getting an exception which I think is related to the Multi Image Picker package.
The exception is:
E/flutter (12961): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)]
Unhandled Exception: Exception: NoSuchMethodError: The getter
'defaultBinaryMessenger' was called on null.
When the user presses on the upload button, this method is called:
Future<void> _initIsolate() async {
ReceivePort receivePort = ReceivePort();
receivePort.listen(
(message) {
print(message.toString());
},
onDone: () => print('Done'),
onError: (error) => print('$error'),
);
await compute(
_function, // This function is called in the separate isolate
{
'sendingPort': receivePort.sendPort,
'images': images,
},
);
}
The _function method is as follows:
static void _function(Map<String, dynamic> parameterMap) async {
SendPort sendingPort = parameterMap['sendingPort'];
List<Asset> images = parameterMap['images'];
List<String> urls = [];
int index = 0;
images.forEach(
(image) async {
String url = await getDownloadUrl(image); // a helper method
urls.add(url);
sendingPort.send('Image number: $index uploaded');
index += 1;
},
);
final CollectionReference collectionRef = FirebaseFirestore.instance.collection('offers');
final user = CurrentUser.getCurrentUser();
await collectionRef.doc(user.uid).set(
{
'time': FieldValue.serverTimestamp(),
'urls': urls,
},
);
}
The helper method _getDownloadUrl is as follows:
Future<String> getDownloadUrl(Asset image) async {
String rannum = Uuid().v1();
final ByteData byteData = await image.getByteData(); // --> This produces a defaultBinaryMessenger
final List<int> imageData = byteData.buffer.asUint8List();
Reference reference = FirebaseStorage.instance.ref().child("offers/$rannum");
UploadTask uploadTask = reference.putData(imageData);
TaskSnapshot downloadUrl = await uploadTask.whenComplete(() => null);
Future<String> futureUrl = downloadUrl.ref.getDownloadURL();
return futureUrl;
}
The getByteData method is part of the multi_image_picker package.
The source code is:
Future<ByteData> getByteData({int quality = 100}) async {
if (quality < 0 || quality > 100) {
throw new ArgumentError.value(
quality, 'quality should be in range 0-100');
}
Completer completer = new Completer<ByteData>();
ServicesBinding.instance.defaultBinaryMessenger // --> Exception here. ServicesBinding.instance is null
.setMessageHandler(_originalChannel, (ByteData message) async {
completer.complete(message);
ServicesBinding.instance.defaultBinaryMessenger
.setMessageHandler(_originalChannel, null);
return message;
});
await MultiImagePicker.requestOriginal(_identifier, quality);
return completer.future;
}
Why is the ServicesBinding.instance null?
Since this method is working fine without using Isolates, does this have something to do with the isolates?

My FirebaseStorage method isn't Running in Flutter. After the `firebase_storage: ^4.0.0`

My Problem
Can Anyone Help I'm trying to send my images to firebase storage then retrieving the download URL and saving to the firebasefirestore. But my FirebaseStorage method isn't running.
Happening After firebase_storage: ^4.0.0 update
My FirebaseStorage().ref().child('path).putFile() method isn't running
FirebaseStorage()
.ref()
.child("Accounts Posts/Images/").putFile(//MyFIle);
Here's my Code
static final FirebaseStorage storage = FirebaseStorage.instance;
static final FirebaseFirestore _firestore = FirebaseFirestore.instance;
Future<dynamic> sendData(SearchTileModel st, List<File> data) async {
bool completed = false;
CollectionReference _collec = _firestore.collection('Accounts Posts');
List<String> _imageUrls = [];
print(data.length);
data.length > 0
? data.asMap().forEach((
index,
element,
) async {
print(index);
print(element);
String downloadUrl;
/////// HERE this code doesn't get called up ////////////
StorageTaskSnapshot snapshot = await FirebaseStorage()
.ref()
.child("Accounts Posts/Images/${index}")
.putFile(element)
.onComplete
.then((value) {
downloadUrl = value.ref.getDownloadURL().toString();
return;
});
print(downloadUrl);
print(snapshot);
print(snapshot.error);
if (snapshot.error == null) {
await snapshot.ref
.getDownloadURL()
.then((value) => downloadUrl = value.toString());
print(downloadUrl);
_imageUrls.insert(index, downloadUrl);
if (st.images.length == _imageUrls.length) {
SearchTileModel newModel = st;
newModel.images = _imageUrls;
await _collec
.doc('${newModel.placeName} : name')
.set(
st.toJson(),
SetOptions(mergeFields: [
'images',
]),
)
.whenComplete(() {
return completed = true;
}).catchError((onError) {
print('${onError.toString()}');
completed = false;
});
}
} else {
completed = false;
print('Error from image repo ${snapshot.error.toString()}');
throw ('This file is not an image');
}
})
: print('No Images Selected');
if (data.length == 0) {
SearchTileModel newModel = st;
newModel.images = _imageUrls;
await _collec
.doc('${newModel.placeName} : name')
.set(
st.toJson(),
SetOptions(mergeFields: [
'images',
]),
)
.whenComplete(() {
return completed = true;
}).catchError((onError) {
print('${onError.toString()}');
completed = false;
});
}
return completed;
}
Here's Debug Console Output
All the print Statements showing the method is not running.
I also thought that due to await it was taking time but no after waiting for 10 mins nothing happened.
I/flutter (14005): true
I/flutter (14005): redtfgn
I/flutter (14005): File:
'/storage/emulated/0/Android/data/com.example.medium/files/Pictures/scaled_ec614e8a-0522-4cae-97be-
3ed50356de9c3343447263121135351.jpg'
I/flutter (14005): 1
I/flutter (14005): running
I/flutter (14005): 0
I/flutter (14005): File:
'/storage/emulated/0/Android/data/com.example.medium/files/Pictures/scaled_ec614e8a-0522-4cae-97be-
3ed50356de9c3343447263121135351.jpg'
I/flutter (14005): Till Here the code is Running
Update Got these lines
I/BiChannelGoogleApi(17801): [FirebaseAuth: ] getGoogleApiForMethod()
returned Gms: com.google.firebase.auth.api.internal.zzaq#cdf79f2
E/StorageUtil(17801): error getting token
java.util.concurrent.TimeoutException: Timed out waiting for Task
D/NetworkSecurityConfig(17801): No Network Security Config specified, using
platform default
W/NetworkRequest(17801): no auth token for request
I changed the rule of firebase storage too
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write ;
}
}
}
I can see that you are using .ref() in order to get the reference.
Checking the documentation, you can see that the used one is getReference()
StorageReference storageRef = storage.getReference();
Therefore, it might be better to set the storage reference as indicated in the documentation. Also the code for uploading the file would be like this:
Uri file = Uri.fromFile(new File("path/to/images/rivers.jpg"));
StorageReference riversRef = storageRef.child("images/"+file.getLastPathSegment());
uploadTask = riversRef.putFile(file);

Updating User Data in Cloud Firestore

I've been having a problem trying to update data from a logged in user. I have the uid, but there has to be a connection between the uid and the collection of users, so that the program picks the right user to update, but I don't know how to make it.
Here's what I have:
FirebaseUser loggedInUser;
final _firestore = Firestore.instance;
//
double _latitude;
double _longitude;
void getCurrentLocation() async {
try {
Position position = await Geolocator()
.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
setState(() {
_latitude = position.latitude;
_longitude = position.longitude;
});
_firestore
.collection('users')
.document('${loggedInUser.uid}')
.updateData({'location': GeoPoint(_latitude, _longitude)});
} catch (e) {
print(e);
}
}
Here's what I've been getting:
E/flutter ( 9187): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: PlatformException(Error performing updateData, NOT_FOUND: No document to update: projects/app-#####/databases/(default)/documents/users/CGyByl58ELc0zirlVjJpv5OWAc42, null)
So it is using the right uid ("CGyByl58ELc0zirlVjJpv5OWAc42")
Here's a screenshot from the Authentication tab of Firebase:
But what I'm trying to get is the name of the collection of this user in the database:
The user id is different than the document id, that's why you get that error since no document exists with the userId. You need to use the userId as the document id:
void addUser() async{
var firebaseUser = await FirebaseAuth.instance.currentUser();
Firestore.instance.collection("users").document(firebaseUser.uid).setData(
{
"age" : 38,
}).then((_){
print("success!");
});
}
Now you will have the userId as the document id and you can update the document using the userId

DateTime not a subtype of type TimeStamp/Unhandled Exception: Invalid argument: Instance of 'Future<LocationData>

So I am using the nearby connections API to discover devices around me and store their data in firestore however I keep getting 2 warnings about the location I am getting from the user that I came in contact with and the time i came in contact with them
These are the 2 warnings:
1)DateTime not a subtype of type TimeStamp
2)Unhandled Exception: Invalid argument: Instance of Future<.LocationData.>
as I try to add these values to firestore
here is my discovery method:
void discovery() async {
try {
bool a = await Nearby().startDiscovery(loggedInUser.email, strategy,
onEndpointFound: (id, name, serviceId) async {
print('I saw id:$id with name:$name'); // the name here is an email
var docRef =
_firestore.collection('users').document(loggedInUser.email);
// When I discover someone I will see their email
docRef.collection('met_with').document(name).setData({
'email': await getUsernameOfEmail(email: name),
'contact time': DateTime.now() as Timestamp ,
'contact location': location.getLocation(),
});
}, onEndpointLost: (id) {
print(id);
});
print('DISCOVERING: ${a.toString()}');
} catch (e) {
print(e);
}
}
This is another method where I retrieve the info I discovered from firestore:
void addContactsToList() async {
await getCurrentUser();
_firestore
.collection('users')
.document(loggedInUser.email)
.collection('met_with')
.snapshots()
.listen((snapshot) {
for (var doc in snapshot.documents) {
String currEmail = doc.data['email'];
DateTime currTime = doc.data.containsKey('contact time')
? (doc.data['contact time'] as Timestamp).toDate()
: null;
String currLocation = doc.data.containsKey('contact location')
? doc.data['contact location']
: null;
String _infection = doc.data['infected'];
if (!contactTraces.contains(currEmail)) {
contactTraces.add(currEmail);
contactTimes.add(currTime);
contactLocations.add(currLocation);
infection.add(_infection);
}
}
setState(() {});
print(loggedInUser.email);
});
}
Any fix for this please?
Use an async function to convert the Future<.LocationData.> to LocationData.
var data;
void convertData() async{
var futuredata = await FutureLocationData;
setState(() {
data = futuredata });
}

Flutter async programming

After using a dataset I want to check how many datasets are unused. If I'm above the threshold I want to fetch new data.
useQuestion(Question question) async {
print("using question $question");
question.used=1;
final db = await database;
int count = await db.rawUpdate(
'UPDATE Question SET used = ? WHERE question = ?',
[question.used,question.question]);
print(question);
print("Made $count changes");
var questions = await _checkQuestionThreshold();
print(questions);
for (var q in questions) {
newQuestion(Question.fromJson(q));
}
}
Check Threshold
_checkQuestionThreshold() async {
print("count questions...");
final db = await database;
var res = await db.query("Question");
int count = Sqflite.firstIntValue(
await db.rawQuery('SELECT COUNT(*) FROM Question'));
int countUsed = Sqflite.firstIntValue(
await db.rawQuery('SELECT COUNT(*) FROM Question where used="1"'));
int i = 0;
if (count < 1 || (countUsed / count) < 0.5) {
print("Okay... we fetch new...");
return await _fetchFromFirebase();
}
Fetching from DB:
_fetchFromFirebase() async {
var questionJson;
databaseReference.once().then((DataSnapshot snapshot) async {
questionJson = await snapshot.value;
}).catchError((e) {
print(e);
});
return questionJson;
}
However I get the following error when calling for (var q in questions) {
newQuestion(Question.fromJson(q));
} and I'm wondering what exactly I am missing.
I/flutter ( 5150): count questions...
I/flutter ( 5150): Okay... we fetch new...
I/flutter ( 5150): null
E/flutter ( 5150): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: NoSuchMethodError: The getter 'iterator' was called on null.
E/flutter ( 5150): Receiver: null
Your issue is that questions is null, so trying to iterate over it is going to throw an error.
Looking at your code, the root of the error seems to come from your _fetchFromFirebase method. In this case, you call databaseReference.once(), and in the then part you assign the result to questionJson. However, you never await on this call, so the _fetchFromFirebase method ends up returning the value of questionJson immediately after the call is made without waiting for it to finish. At that point, questionJson will be null, so that's what gets returned.
In general, I advise to not mix the Future.then.catchError pattern with the async/await pattern, as it can result in confusing logic that hides what is actually happening. As such, I'd recommend sticking just to async/await like so:
_fetchFromFirebase() async {
try {
final snapshot = await databaseReference.once();
final questionJson = await snapshot.value;
return questionJson;
} catch (e) {
print(e);
return null;
}
}

Resources