I am developing a feature to remove uploaded files. I can currently remove the reference within Cloud Firestore but I am unable to remove it from Storage. The code bellow should remove from Storage but it does not work
private void deleteImage(String id, final int position, String fileUrl) {
StorageReference storageRef = FirebaseStorage.getInstance().getReference("uploads");
// Create a reference to the file to delete
StorageReference fileRef = storageRef.child(fileUrl);
// Delete the file
fileRef.delete().addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
// File deleted successfully
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
// Uh-oh, an error occurred!
}
});
}
The error message is "No auth token for request. StorageException has occurred. Object does not exist at location. HttpResult: 404". I thought that the problem was related with my fileUrl field but I'm not sure. The fileUrl is the download image url, for example, if I copy and paste the url on web browser I can see the image. Why is not working?
As #blackapps commented, the download url that I was using was not suitable as reference to a file so I changed the value of fileUrl parameter to "filename.file_extension". The code still the same, i only changed the parameter value.
Related
I see similar questions on this site but most of the questions are related to fetching the download URL for a single uploaded image. Taking help from those posts, now I can get the download URL of a single image.
But I face a problem when I try to get download URL for multiple images uploaded together. I want to do three things...
1. Select three images
2. Upload them to Firebase Cloud Storage
3. Get the URLs of the uploaded images and save them in an ArrayList.
I can do the first two things successfully, but have not managed to achieve the third thing. When I click the "update" button, all images are perfectly stored in Cloud Storage, but show an error when requesting the download URL of all images.
Here is the code for when I click the "update" button:
upload.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
progressDialog.setMessage("Uploading .... ");
progressDialog.show();
storageReference = FirebaseStorage.getInstance().getReference().child("Pictures");
int uploadCount = 0;
// imageList is an ArrayList<Uri> which holds the address of selected 3 images.
// imageAddress is an ArrayList<String> where I want to save all downloadUrls of images (each url is saved as a string).
// imagePath is a StorageReference
while(uploadCount < imageList.size()) {
Log.d("UploadCount", uploadCount+"");
Uri uri_Image = imageList.get(uploadCount);
imagePath = storageReference.child(uri_Image.getLastPathSegment());
imagePath.putFile(uri_Image).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
imagePath.getDownloadUrl().addOnSuccessListener(newOnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
Uri downloadUri = uri;
imageAddress.add(downloadUri.toString());
Log.d("ImageAddress Size: ", imageAddress.size()+"");
}
});
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(SignOutActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
progressDialog.dismiss();
}
}); //.............
if(uploadCount == (imageList.size()-1)) {
Log.d("Good", "HELLO HELLO");
Toast.makeText(SignOutActivity.this, "Successfully Uploaded", Toast.LENGTH_LONG).show();
upload.setClickable(false);
progressDialog.dismiss();
}
else {
Log.d("BAD", "NOT HELLO "+uploadCount);
}
uploadCount = uploadCount + 1;
}
}
});
Here is the error:
2020-02-15 17:02:26.945 28207-28735/com.example.practiceapplication E/StorageException: StorageException has occurred.
Object does not exist at location.
Code: -13010 HttpResult: 404
2020-02-15 17:02:26.946 28207-28735/com.example.practiceapplication E/StorageException: {"error": {"code": 404, "message": "Not Found. Could not get object", "status": "GET_OBJECT"}}
java.io.IOException: {"error": {"code": 404, "message": "Not Found. Could not get object", "status": "GET_OBJECT"}}
at com.google.firebase.storage.network.NetworkRequest.parseResponse(com.google.firebase:firebase-storage##19.1.1:433)
at com.google.firebase.storage.network.NetworkRequest.parseErrorResponse(com.google.firebase:firebase-storage##19.1.1:450)
at com.google.firebase.storage.network.NetworkRequest.processResponseStream(com.google.firebase:firebase-storage##19.1.1:441)
at com.google.firebase.storage.network.NetworkRequest.performRequest(com.google.firebase:firebase-storage##19.1.1:272)
at com.google.firebase.storage.network.NetworkRequest.performRequest(com.google.firebase:firebase-storage##19.1.1:286)
at com.google.firebase.storage.internal.ExponentialBackoffSender.sendWithExponentialBackoff(com.google.firebase:firebase-storage##19.1.1:70)
at com.google.firebase.storage.internal.ExponentialBackoffSender.sendWithExponentialBackoff(com.google.firebase:firebase-storage##19.1.1:62)
at com.google.firebase.storage.GetDownloadUrlTask.run(com.google.firebase:firebase-storage##19.1.1:76)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
2020-02-15 17:02:30.712 28207-28207/com.example.practiceapplication D/ImageAddress Size:: 1
It will be very helpful to me if anyone tells me the correction. Thank you
Your code suffers from using a mix of local variables and shared global variables whilst dealing with asynchronous code and for loops.
In the code above, you use the global variables imagePath, imageAddress and imageList inside a for loop which ultimately is the key cause of that Exception.
Code breakdown
When you click the upload button, your code performs the following steps with errors shown in bold:
Gets the first image's URI
Updates the value of imagePath to point at that image's upload location
Starts the upload of the first image
Logs "NOT HELLO 0"
Gets the second image's URI
Updates the value of imagePath to point at that image's upload location
Starts the upload of the second image
Logs "NOT HELLO 1"
Gets the third image's URI
Updates the value of imagePath to point at that image's upload location
Starts the upload of the third image
Logs "HELLO HELLO" and Toasts "Successfully Uploaded" (not actually finished yet)
[a few moments later]
The first image finishes uploading
The download URL of the third image is requested (which throws the StorageException)
The second image finishes uploading
The download URL of the third image is requested (which throws another StorageException)
The third image finishes uploading
The download URL of the third image is requested (and would work correctly)
Fixes
To fix this, the following things must be done:
Use a local variable copy of imageList
Use a local variable for storageReference
Use a local variable for imagePath, and rename to imageRef to accurately reflect it's type
Rename imageAddress to imageAddressList to accurately reflect it's type (recommended)
Remove the while() loop and use a for iterator instead
Disable the upload button immediately instead of at the end
Upload each image and fetch the download URLs in parallel, without conflicting with each other
Only display "Successfully uploaded" or "Upload failed" messages after the uploads have actually completed
Update imageAddressList only once, rather than asynchronously.
To be done:
Handle activity lifecycle changes
Tap into currentUploadTask and bind it to a view dialog/notification to show file upload progress
Update the UI once all the uploads are done
Updated code
Note: This was typed free-hand - expect a few typos.
upload.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
progressDialog.setMessage("Uploading .... ");
progressDialog.show();
upload.setClickable(false); // disable upload button whilst uploading
final StorageReference storageReference = FirebaseStorage.getInstance().getReference().child("Pictures");
final List<Uri> clonedImageList = new ArrayList<>(imageList);
imageList.clear(); // empty old list?
int imageListSize = clonedImageList.size();
List<Task<Uri>> uploadedImageUrlTasks = new ArrayList<>(imageListSize);
for (Uri imageUri : clonedImageList) {
final String imageFilename = imageUri.getLastPathSegment();
Log.d("upload.onClick()", "Starting upload for \"" + imageFilename + "\"...");
StorageReference imageRef = storageReference.child(imageFilename); // Warning: potential for collisions/overwrite
UploadTask currentUploadTask = imageRef.putFile(imageUri);
Task<Uri> currentUrlTask = currentUploadTask
.continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() {
#Override
public Task<Uri> then(#NonNull Task<UploadTask.TaskSnapshot> task) throws Exception {
if (!task.isSuccessful()) {
Log.d("upload.onClick()", "Upload for \"" + imageFilename + "\" failed!");
throw task.getException(); // rethrow any errors
}
Log.d("upload.onClick()", "Upload for \"" + imageFilename + "\" finished. Fetching download URL...");
return imageRef.getDownloadUrl();
}
})
.continueWithTask(new Continuation<Uri, Uri>() { // purely for logging to debug, recommended to remove
#Override
public Task<Uri> then(#NonNull Task<Uri> task) throws Exception {
if (!task.isSuccessful()) {
Log.d("upload.onClick()", "Could not get download URL for \"" + imageFilename + "\"!");
throw task.getException(); // rethrow any errors
}
Log.d("upload.onClick()", "Download URL for \"" + imageFilename + "\" is \"" + task.getResult() + "\".");
return task.getResult();
}
});
uploadedImageUrlTasks.add(currentUrlTask);
}
// At this point, all the files are being uploaded in parallel
// Each upload is tracked by the tasks in uploadedImageUrlTasks
Tasks.whenAllComplete(uploadedImageUrlTasks)
.addOnCompleteListener(new OnCompleteListener<List<Task<Uri>>>() {
#Override
public void onComplete(#NonNull List<Task<Uri>> tasks) {
int tasksCount = tasks.size();
List<Uri> failedUploads = new ArrayList<>();
imageAddressList.clear(); // empty old entries?
for (Task<Uri> task : tasks) {
if (task.isSuccessful()) {
successCount++;
Uri downloadUri = task.getResult();
imageAddressList.add(downloadUri.toString());
} else {
Uri imageUri = clonedImageList.get(tasks.indexOf(task));
failedUploads.add(imageUri);
Log.e("upload.onClick()", "Failed to upload/fetch URL for \"" + imageUri.getLastPathSegment() + "\" with exception", task.getException()); // log exception
}
}
progressDialog.dismiss(); // dismiss upload dialog
if (failedUploads.size() > 0) {
Toast.makeText(SignOutActivity.this, failedUploads.size() + "/" + tasksCount + " uploads failed.", Toast.LENGTH_LONG).show();
// TODO: Do something with list of failed uploads such as readd to the now empty upload list
imageList.addAll(failedUploads);
upload.setClickable(true);
} else {
Toast.makeText(SignOutActivity.this, "Successfully uploaded all " + tasksCount + " files.", Toast.LENGTH_LONG).show();
}
// TODO: Now that imageAddressList has been updated, update the UI - e.g tell recycler view to refresh
}
});
}
});
I'm creating a system for storing multiple image links in firestore, and it's been working, I select from the gallery and upload them as List it is in the order that it is going to the bank (firestore ), because it matters to me, I select for example the images 1,2,3, and when I save their link in the firestore it gets 2,1,3 or 3,1, 2 or 3,2,1 never in the order I loaded, it seems to be according to the lightest image, as saved according to the position I loaded? I've been breaking my head with this for a few days.
already to get each image from List.get(i) to save but to no avail.
I'm saving like this in firestore ->
list_img [
0 link_img
1 link_img
2 link_img]
firestore scheme
upload from gallery
GalleryConfig config = new GalleryConfig.Build()
.limitPickPhoto(50)
.singlePhoto(false)
.hintOfPick("this is pick hint")
.filterMimeTypes(new String[]{})
.build();
GalleryActivity.openActivity(Pag_producao_hq.this, reqCode, config);
upload
private void upload_Fotos_selecionadas(Uri uri, final int totalimg, int i) {
Log.i("sdsd77", String.valueOf(i));
final StorageReference ImageFolder = FirebaseStorage.getInstance().getReference().child("imagens");
String nomeImagem = UUID.randomUUID().toString();
final StorageReference imagename = ImageFolder
.child("HQ")
.child(identificadorUsuario)
.child(nomeImagem);
arrayListImageRef.add(ImageFolder); //arraylist of type StorageRef
arrayListImageRef.add(imagename);
imagename.putFile(uri)
.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
imagename.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
String urlConvertida = uri.toString();
lista_url.add(urlConvertida);
if(lista_url.size()==totalimg){
Map<String, Object> new_imagens = new HashMap<>();
new_imagens.put("list_img", lista_url);
db.collection("HQ")
.document(getId())
.collection("Imagens")
.add(new_imagens);
dialog.dismiss();
finish();
}
}
});
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
if (!isFinishing()) {
dialog.dismiss();
}
Toast.makeText(getApplicationContext(), exception.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
Cloud Firestore does not list document as the same order of insertion. Auto IDs are not time related. You will need to add a timestamp field and query your data using order by this field.
This question already has an answer here:
Can't get download url from Firebase Storge in Android [duplicate]
(1 answer)
Closed 4 years ago.
I am trying to get download url from firebase but it gives me some another link like "com.google.android.gms.tasks.zzu#b9761c8"
You need to add listeners when retrieving the url.
Please read the documentations
taskSnapshot.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
// Got the uri
ImageUpload imageUpload = new ImageUpload(editText5.getText().toString(), uri.toString());
// Wrap with Uri.parse() when retrieving
String uploadId = mDatabaseRef.push().getKey();
mDatabaseRef.child(uploadId).setValue(imageUpload);
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
// Handle any errors
}
});
I have an UploadTask to send an image to Firebase Storage and it works but now I want to get the respective download URL but I'm facing some issues.
var upload = childRef.DownloadURL;
upload.AddOnSuccessListener(this);
I'm implementing the IOnSuccessListener interface so the function has to be:
public void OnSuccess(Java.Lang.Object result){
//get url from result
}
How can I cast the result to access the URL?
I got a solution in debugging mode
i saw the downloadurl's properties and found the Scheme and SchemeSpecificPart
Scheme = "https"
SchemeSpecificPart = "//firebasestorage.googleapis.com/v0/b/maplog-e4ba5.appspot.com/o/-L0AMbihF23YKxsL1uss?alt=media&token=5c7ccef1-c857-4982-a288-fded2f0ff1aa"
so here is my code:
void IOnSuccessListener.OnSuccess(Java.Lang.Object result)
{
var snapShot = (UploadTask.TaskSnapshot)result;
string imgUrl = snapShot.DownloadUrl.Scheme
+ ":"
+ snapShot.DownloadUrl.SchemeSpecificPart;
}
and it works!
i was looking for the solution :((
but i finally found it myself XD
I'm having the same issue, but was able to catch the error when adding the AddOnFailureListener. The error message wasn't helpful.
An unknown error occurred, please check the HTTP result code and inner
exception for server response.
The result code was 0. The error code as -13000, which is an unknown error according to Firebase error table.
FirebaseApp.InitializeApp(Application.Context);
FirebaseStorage storage = FirebaseStorage.Instance;
StorageReference storageRef = storage.GetReferenceFromUrl("gs://");
StorageReference imageRef = storageRef.Child("folder/image.jpg");
var downloadURL = imageRef.DownloadUrl.AddOnSuccessListener(this, this).AddOnFailureListener(this, this);
public void OnSuccess(Java.Lang.Object result)
{
string downloadURL = result.ToString();
}
public void OnFailure(Java.Lang.Exception e)
{
Log.Warn("FirebaseStorage", "Download Failure", e);
}
I had the same issue of the error code as -13000 which is an unknown error according to Firebase error table , i resolved by updating the playstore app in the device
I would say EncodedSchemeSpecificPart worked perfect for me
var snapShot = (UploadTask.TaskSnapshot)result;
string downloadURL =snapShot.DownloadUrl.Scheme + ":" +snapShot.DownloadUrl.EncodedSchemeSpecificPart;
For the latest Xamarin Android this is the correct answer
public async void OnSuccess(Java.Lang.Object result)
{
var snapShot = (UploadTask.TaskSnapshot)result;
if (snapShot != null)
{
var url = await snapShot.Storage.GetDownloadUrlAsync();
imageUrl = url?.ToString();
}
}
I am developing android application where a user clicks image, it gets stored in firebase, cloud functions process this image and stores the output back in the firebase in the form of text file. In order to display the output in android, application keeps checking for output file if it exists or not. If yes, then it displays the output in the application. If no, I have to keep waiting for the file till it is available.
I'm unable to find any documentation for checking if any file is exists in Firebase or not. Any help or pointers will be helpful.
Thanks.
You can use getDownloadURL which returns a Promise, which can in turn be used to catch a "not found" error, or process the file if it exists. For example:
storageRef.child("file.png").getDownloadURL().then(onResolve, onReject);
function onResolve(foundURL) {
//stuff
}
function onReject(error){
//fill not found
console.log(error.code);
}
Updated
This is another simpler and cleaner solution.
storageRef.child("users/me/file.png").getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
// Got the download URL for 'users/me/profile.png'
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
// File not found
}
});
Firebase storage API is setup in a way that the user only request a file that exists.
Thus a non-existing file will have to be handled as an error:
You can check the documentation here
If the file doesn't exist, then it will raise StorageException; however the StorageException can be raised by different reasons, each of which has a unique error code defined as a constant of StorageException class.
If the file doesn't exist, then you will get Error code of StorageException.ERROR_OBJECT_NOT_FOUND
If you've a complete URL reference of the file, then you can check whether it exists or not by:
String url = "https://firebasestorage.googleapis.com/v0/b/******************"
StorageReference ref = FirebaseStorage.getInstance().getReferenceFromUrl(url);
ref.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
Log.d(LOG_TAG, "File exists");
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
if (exception instanceof StorageException &&
((StorageException) exception).getErrorCode() == StorageException.ERROR_OBJECT_NOT_FOUND) {
Log.d(LOG_TAG, "File not exist");
}
}
});
The rest of error codes can be checked at here
my code for this
void getReferenceAndLoadNewBackground(String photoName) {
final StorageReference storageReference = FirebaseStorage.getInstance().getReference().child("Photos").child(photoName + ".png");
storageReference.getDownloadUrl()
.addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
loadBackground(storageReference);
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
int errorCode = ((StorageException) exception).getErrorCode();
if (errorCode == StorageException.ERROR_OBJECT_NOT_FOUND) {
StorageReference storageReference2 = FirebaseStorage.getInstance().getReference().child("Photos").child("photo_1.png");
loadBackground(storageReference2);
}
}
});
}
This is how I am currently checking to see if the file Exists.
The this.auth.user$ pulls an observable that displays the current user's data from the FireStore database.
I store the FileStorage profile image reference in the FireStore database.
I then use the File Path in the user's data and use it for the FileStorage reference.
Now use the observable and check to see if the downloadURL length is less than or equal to 0.
If it is indeed greater than zero then the file exists; then go do something. Else do something else.
ngOnInit() {
this.userSubscription = this.auth.user$.subscribe((x) => {
console.log(x);
this.userUID = x.userId;
this.userPhotoRef = x.appPhotoRef;
this.userDownloadURL = x.appPhotoURL;
});
const storageRef = this.storage.ref(this.userPhotoRef);
console.log(storageRef);
if (storageRef.getDownloadURL.length <= 0) {
console.log('File Does not Exist');
} else {
console.log('File Exists');
}
}