flutter FirebaseStorage onComplete - firebase

void validateAndUpload() async {
if (_formKey.currentState.validate()) {
setState(() => isLoading = true);
if (_image1 != null) {
if (selectedSizes.isNotEmpty) {
String imageUrl1;
final FirebaseStorage storage = FirebaseStorage.instance;
final String picture1 =
"${DateTime.now().millisecondsSinceEpoch.toString()}.jpg";
StorageUploadTask task1 =
storage.ref().child(picture1).putFile(_image1);
task1.onComplete.then((snapshot1) async {
imageUrl1 = await snapshot1.ref.getDownloadURL();
_productServices.uploadProduct(
productName: productNameController.text,
brandName: _currentBrand,
details: detailController.text,
category: _currentCategory,
quantity: int.parse(quantityController.text),
size: selectedSizes,
picture: imageUrl1,
feature: feature,
sale: sale,
price: double.parse(priceController.text));
_formKey.currentState.reset();
The getter 'onComplete' isn't defined for the type 'UploadTask'. (Documentation) Try importing the library that defines 'onComplete', correcting the name to the name of an existing getter, or defining a getter or field named 'onComplete'.

That error seems correct. Did you mean whenComplete?
I typically prefer to simply await the task though:
var ref = storage.ref().child(picture1);
await ref.putFile(_image1);
imageUrl1 = await ref.getDownloadURL();
...

final ref = FirebaseStorage.instance
.ref("${DateTime.now().millisecondsSinceEpoch.toString()}.jpg");
var uploadEvent = ref.putFile(_image1!);
String imageUrl = await (await uploadEvent.whenComplete(() => null))
.ref
.getDownloadURL();

Related

Flutter - File() constructor "The argument type 'String' can't be assigned to the parameter type 'List<Object>'"

I'm new to flutter and trying to send image via chat section. I'm getting 2 errors in my code. how can I solve this. appreciate your help on this.
error: The argument type 'String' can't be assigned to the parameter
type 'List'.
error: 2 positional argument(s) expected, but 1 found. )
Complete Reproducible Code on DartPad
final FirebaseAuth _auth = FirebaseAuth.instance;
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
File? imageFile;
Future getImage() async {
ImagePicker _picker = ImagePicker();
await _picker.pickImage(source: ImageSource.gallery).then((xFile) {
if (xFile != null) {
imageFile = File(xFile.path);
uploadImage();
}
});
}
Future uploadImage() async {
String fileName = Uuid().v1();
int status = 1;
await _firestore
.collection('chatdetail')
.doc(friendUid)
.collection('chats')
.doc(fileName)
.set({
"sendby": _auth.currentUser!.displayName,
"message": "",
"type": "img",
"time": FieldValue.serverTimestamp(),
});
var ref =
FirebaseStorage.instance.ref().child('images').child("$fileName.jpg");
//error in ImageFile
var uploadTask = await ref.putFile(imageFile!).catchError((error) async {
await _firestore
.collection('chatdetail')
.doc(friendUid)
.collection('chats')
.doc(fileName)
.delete();
status = 0;
});
if (status == 1) {
String imageUrl = await uploadTask.ref.getDownloadURL();
await _firestore
.collection('chatdetail')
.doc(friendUid)
.collection('chats')
.doc(fileName)
.update({"message": imageUrl});
print(imageUrl);
}
}
Replace import 'dart:html'; with 'import 'dart:io';'. You just imported the wrong package. File you want is from dart:io not dart:html.

What is the the method to use onComplete function to add Images to Firebase Storage

I have made a function to upload three images to firebase storage. I have been doing it with the help of a tutorial. Since the tutorial uses old version codes I am trying my maximum to change it to a newer version. In the tutorial, it uses onComplete method to get the task snapshot. But in the pub.dev docs it is said that these methods have been removed and their is an exception Like this(
BREAKING: isCanceled, isComplete, isInProgress, isPaused and isSuccessful have now been removed. Instead, you should subscribe to the stream (for paused/progress/complete/error events) or the task Future for task completion/errors.)
please tell what does this mean and how can I change my below code according to it.
there is an error showing in the place where I type onComplete
void validateAndUpload() async{
if (_formKey.currentState.validate()) {
if (_image1 != null && _image2 != null && _image3 != null) {
if (selectedSizes.isNotEmpty) {
String imageUrl1;
String imageUrl2;
String imageUrl3;
final FirebaseStorage storage = FirebaseStorage.instance;
final String picture1 =
'1${DateTime.now().millisecondsSinceEpoch.toString()}.jpg';
UploadTask task1 = storage.ref().child(picture1).putFile(_image1);
final String picture2 =
'2${DateTime.now().millisecondsSinceEpoch.toString()}.jpg';
UploadTask task2 = storage.ref().child(picture2).putFile(_image2);
final String picture3 =
'3${DateTime.now().millisecondsSinceEpoch.toString()}.jpg';
UploadTask task3 = storage.ref().child(picture3).putFile(_image3);
TaskSnapshot snapshot1 = await task1.onComplete.then((snapshot) => snapshot);
TaskSnapshot snapshot2 = await task1.onComplete.then((snapshot) => snapshot);
task3.onComplete.then((snapshot3) async{
imageUrl1 = await snapshot1.ref.getDownloadURL();
imageUrl2 = await snapshot2.ref.getDownloadURL();
imageUrl3 = await snapshot3.ref.getDownloadURL();
});
} else {
Fluttertoast.showToast(
msg: "Sizes cannot be Empty",
backgroundColor: Colors.red,
textColor: Colors.white);
}
} else {
Fluttertoast.showToast(
msg: "Images are not Filled",
backgroundColor: Colors.red,
textColor: Colors.white);
}
}
}
You are almost there! As the error says either you have to listen for the UploadTask streams or await for UploadTask to complete. For your case,
TaskSnapshot snapshot1 = await task1;
TaskSnapshot snapshot2 = await task2;
TaskSnapshot snapshot3 = await task3;
imageUrl1 = await snapshot1.ref.getDownloadURL();
imageUrl2 = await snapshot2.ref.getDownloadURL();
imageUrl3 = await snapshot3.ref.getDownloadURL();
For more ref - https://firebase.flutter.dev/docs/storage/usage/#handling-tasks

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?

" task.future.then " keeps throwing an error in my Flutter code

This is my code -
Future uploadImage() async {
var randomno = Random(25);
final StorageReference firebaseStorageRef = FirebaseStorage.instance
.ref()
.child('profilepics/${randomno.nextInt(5000).toString()}.jpg');
StorageUploadTask task = firebaseStorageRef.putFile(selectedImage);
task.future.then((value) {
setState(() {
userManagement
.updateProfilePic(value.downloadUrl.toString())
.then((val) {
setState(() {
profilePicUrl = value.downloadUrl.toString();
isLoading = false;
});
});
});
}).catchError((e) {
print(e);
});
}
This is the error it gives -
The getter 'future' isn't defined for the type 'StorageUploadTask'.
Try importing the library that defines 'future', correcting the name to the name of an existing getter, or defining a getter or field named 'future'.
Although i have already imported dart:async and dart:io
Please help, thanks
StorageUploadTask doesnt have a property called future, you have to use onComplete the following:
final StorageReference firebaseStorageRef = FirebaseStorage.instance
.ref()
.child('profilepics/${randomno.nextInt(5000).toString()}.jpg');
StorageUploadTask task = firebaseStorageRef.putFile(selectedImage);
task.onComplete.then((value) {
setState(() {
userManagement
.updateProfilePic(value.ref.getDownloadURL().toString())
.then((val) {
setState(() {
profilePicUrl = value.ref.getDownloadURL().toString();
isLoading = false;
});
});
});
https://github.com/FirebaseExtended/flutterfire/blob/master/packages/firebase_storage/lib/src/upload_task.dart#L28
now 'onComplete' is also showing error
The getter 'onComplete' isn't defined for the type 'UploadTask'.
Try importing the library that defines 'onComplete', correcting the name to the name of an existing getter, or defining a getter or field named 'onComplete'.

Flutter Firebase upload multiple images

Uploading multiple images and waiting for the URL list, images were loaded to firestore successfully after few seconds and returns the url but before that the future function returns with null
Future<List<dynamic>> uploadImage() async {
_imageFile.forEach((image) async {
String rannum = Uuid().v1();
StorageReference reference =
FirebaseStorage.instance.ref().child('Reviews').child(rannum);
StorageUploadTask uploadTask = reference.putFile(image);
StorageTaskSnapshot downloadUrl = (await uploadTask.onComplete);
String _url = await downloadUrl.ref.getDownloadURL();
_urllist.add(_url);
});
return _urllist;
}
You have to call your function like this:
uploadImage(_imageFile).then((List<String> urls) => urls.forEach((element) => print(element)))
And I also changed your function:
Future<List<String>> uploadImage(List<File> _imageFile) async {
List<String> _urllist = [];
await _imageFile.forEach((image) async {
String rannum = Uuid().v1();
StorageReference reference =
FirebaseStorage.instance.ref().child('Reviews').child(rannum);
StorageUploadTask uploadTask = reference.putFile(image);
StorageTaskSnapshot downloadUrl = await uploadTask.onComplete;
String _url = await downloadUrl.ref.getDownloadURL();
_urllist.add(_url);
});
return _urllist;
}
also I don't understand why you enclosed with brackets "await uploadTask.onComplete"

Resources