Reputation: 425
Hello I am trying to upload multiple images, wait for them to return, compile the download uri's into an object and send it back to my activity. I am using this as reference for upload, firebase. So far i have this
private void saveStepWithImages(@NonNull Step step, Callback callback){
if(step.getStepId() == null){
Collection<Image> images = step.getImages().values();
List<Task<Uri>> taskArrayList= new ArrayList<>();
for (Image i: images) {
taskArrayList.add(uploadImageTask(new ImageUtils().StringToBitMap(i.getImageUrl()), i.getImageReference()));
}
Tasks.whenAll(taskArrayList).addOnCompleteListener(task -> {
Uri downloadUri = task.getResult(); // throws an error because task.getResult is void
});
}else{
updateStepInFirebase(step, callback);
}
}
and in my upload images
private Task<Uri> uploadImageTask(final Bitmap bitmap, String prepend){
final StorageReference ref = mStorageRef.child( prepend );
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] data = baos.toByteArray();
UploadTask uploadTask = ref.putBytes(data);
bitmap.recycle();
return uploadTask.continueWithTask(task -> {
bitmap.recycle();
return ref.getDownloadUrl();
});
}
Step is a custom object i created it contains a Map of images with a string as the key and the value being an image. My image class looks like this
public class Image implements Parcelable {
private String imageUrl;
private String imageReference;
public void Image(){
}
//Setters and getters here;
}
Any suggestions would be really appreciated. Thanks!
Upvotes: 5
Views: 1616
Reputation: 583
You can upload multiple files to firebase by nesting all the calls in one array, and adding each call to the Task API of firebase:
Define the reference and an array of tasks
StorageReference mStorageRef = FirebaseStorage.getInstance().getReference();
List<Task> myTasks = new ArrayList<>();
In this example im using a map that contains each file an its corresponding storage destination
for (Map.Entry<String, Attachment> entry : storageRouteMap.entrySet()) {
String path = entry.getKey();
final Attachment localAtt = entry.getValue();
Uri fileUri = localAtt.getMyUri();
I will put each task in the array of tasks, for a file i have three tasks, one for uploading the file, one for getting the url of the storage and one for writing the metadata in the real time database.
final StorageReference ref = mStorageRef.child(path);
ThreadPerTaskExecutor executor = new ThreadPerTaskExecutor();
UploadTask t1 = ref.putFile(fileUri);
myTasks.add(t1);
Task<Uri> t2 = t1.continueWithTask(executor,new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() {
@Override
public Task<Uri> then(@NonNull Task<UploadTask.TaskSnapshot> task) throws Exception {
if (!task.isSuccessful()) {
throw task.getException();
}
return ref.getDownloadUrl();
}
});
myTasks.add(t2);
Task<Void> t3 = t2.continueWithTask(executor,new Continuation<Uri, Task<Void>>() {
@Override
public Task<Void> then(@NonNull Task<Uri> task) throws Exception {
if (!task.isSuccessful()) {
throw task.getException();
}
Attachment uploadAtt = new Attachment();
uploadAtt.name = localAtt.name;
uploadAtt.url = task.getResult().toString();
uploadAtt.type = localAtt.type;
String idAtt = UtilFirebase.getAttachmentReference().push().getKey();
UtilLog.LogToConsole(TAG," => "+postId+" => "+uidAuthor+" =>"+idAtt);
return UtilFirebase.getAttachmentReference()
.child(postId)
.child(uidAuthor)
.child(idAtt)
.setValue(uploadAtt);
}
}).continueWith(executor,new VideoTransaction(communityId,localAtt.size,localAtt.type));
myTasks.add(t3);
}
Finally i will see if all the tasks where completed or if there was an error, either way this will communicate the result to the main thread.
Task finish = Tasks.whenAll((Collection) myTasks);
finish.addOnCompleteListener(new ThreadPerTaskExecutor(), new OnCompleteListener() {
@Override
public void onComplete(@NonNull Task task) {
if (task.isSuccessful()) {
callback.onComplete();
} else {
callback.onError(task.getException().toString());
}
}
});
Upvotes: 0
Reputation: 139029
The key for solving this problem is to use Tasks's whenAllSuccess() method:
Returns a Task with a list of Task results that completes successfully when all of the specified Tasks complete successfully.
Insted of Tasks's whenAll() method:
Returns a Task that completes successfully when all of the specified Tasks complete successfully.
Please see more informations about Tasks class.
Upvotes: 5