I am developing an android app that using firebase. My app looks like
App shows card that contains image.
I don't know how to manage image when app works in offline mode.
Could you give me suggestion to resolve it ?
First, use offline capabilities of Firebase by using .setPersistenceEnabled(true);
Use a Image Managing Cloud Server like Cloudinary to store all your images.
In your Firebase database, save the Url to the image as a String.
Use a Image Library like Picasso to get your image from the url.
This worked for me, hope it helps you.
Use Picasso or similar library for load image, show it and save in memory.
Use Firebase only for upload image to cloud and get link.
Example upload image:
StorageReference storageReference = FirebaseStorage.getInstance().getReference(app.packageName + ".webp");
UploadTask uploadTask = storageReference.putFile(Uri.fromFile(new File(app.icon)));
uploadTask.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
success = false;
countDown.countDown();
Log.e(TAG, "", e);
}
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Log.i(TAG, "onSuccess");
app.setPublicIconPath(taskSnapshot.getDownloadUrl().toString());
ref.child(app.getFirebaseKey()).child("icon").setValue(app.getFirebaseValueDataPart1().getIcon());
}
});
Related
I know this is a discussed topic, but here I am, after all other solutions I've found did not solve my problem. I saved multiple images in Firebase Storage and now I want to get one of them and put it into an ImageView on an AlertDialog (or another Activity).
I've read about Glide solution, but it doesn't work for me. Gilde:
Glide.with(ViewScenesSG.this) //ViewScenesSG is the Activity
.load(reference) //the storage reference
.into(imageView); //my imageView
Dependencies for Glide (I've tried with multiple versions and 4.8.0 is the only one that doesn't give me Build error):
implementation 'com.github.bumptech.glide:glide:4.8.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
annotationProcessor 'androidx.annotation:annotation:1.1.0'
I've also read about the .using(new FirebaseImageLoader()) method, I've implemented the FirebaseImageLoader(), but the using() method is not found => build error. I believe it's been removed.
The second version I've tried is this one (found in another question here):
final long ONE_MEGABYTE = 1024 * 1024;
reference.getBytes(ONE_MEGABYTE)
.addOnSuccessListener(new OnSuccessListener<byte[]>() {
#Override
public void onSuccess(byte[] bytes) {
Bitmap bm = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
imageView.setMinimumHeight(dm.heightPixels);
imageView.setMinimumWidth(dm.widthPixels);
imageView.setImageBitmap(bm);
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
Toast.makeText(ViewScenesSG.this, "Couldn't retrieve image.", Toast.LENGTH_SHORT).show();
}
});
But every time it goes on the Failure listener. Therefore, my imageView always remains empty.
In my logcat I observed this error:
E/StorageException: Could not open resulting stream.
java.io.IOException: Could not open resulting stream.
at com.google.firebase.storage.StreamDownloadTask.createDownloadStream(com.google.firebase:firebase-storage##19.1.1:145)
at com.google.firebase.storage.StreamDownloadTask.access$000(com.google.firebase:firebase-storage##19.1.1:36)
at com.google.firebase.storage.StreamDownloadTask$1.call(com.google.firebase:firebase-storage##19.1.1:167)
at com.google.firebase.storage.StreamDownloadTask$1.call(com.google.firebase:firebase-storage##19.1.1:164)
at com.google.firebase.storage.StreamDownloadTask$StreamProgressWrapper.ensureStream(com.google.firebase:firebase-storage##19.1.1:325)
at com.google.firebase.storage.StreamDownloadTask$StreamProgressWrapper.access$100(com.google.firebase:firebase-storage##19.1.1:262)
at com.google.firebase.storage.StreamDownloadTask.run(com.google.firebase:firebase-storage##19.1.1:175)
at com.google.firebase.storage.StorageTask.lambda$getRunnable$7(com.google.firebase:firebase-storage##19.1.1:1072)
at com.google.firebase.storage.StorageTask$$Lambda$12.run(Unknown Source:2)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
E/StorageException: StorageException has occurred.
Object does not exist at location.
Code: -13010 HttpResult: 404
But the image is there, in the Storage, and the reference points directly to it:
storageRef = storage.getReference("photos").child(title); //for all images in the current folder named with the 'title' attribute
StorageReference reference = storageRef.child(imageName); //for the image I want to retrieve
What am I missing?
EDIT: Using the suggestion in the coments, I tried with:
reference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
Glide.with(ViewScenesSG.this)
.load(uri.toString())
.into(imageView);
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(ViewScenesSG.this, "Retrieving image failed",
Toast.LENGTH_SHORT).show();
}
});
but this time I get the error:
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:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
I found the following solution (as suggested in the comments before):
Using the Firebase UI plugin with Gilde, I added the following dependency:
implementation 'com.firebaseui:firebase-ui-storage:6.2.0'
Now, having the StorageReference reference pointing to the image, and the ImageView in which the content must be uploaded, the following code retrieves the image and puts it in the ImageView:
Glide.with(ViewScenesSG.this) //this is the current Activity
.load(reference)
.into(imageView);
To be mentioned that the ImageView must have the dimensions set to a specific value, not using wrap_content or match_parent (at least for height in my case), otherwise it will appear as a small icon. This can also depend on how the image was saved before in the Storage.
Hope this will help someone else as well!
I'm not sure what's going wrong in your second snippet, but in the first snippet you seem to be passing a StorageReference to Glide. Since Glide doesn't know anything about Firebase Storage, that won't work.
Instead, you should get a download URL from Firebase Storage, which is a regular HTTPS URL that provides public access to the data, and pass that to Glide to render in the view.
Something like:
reference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
// Got the download URL for 'users/me/profile.png'
Glide.with(ViewScenesSG.this)
.load(uri.toString())
.into(imageView);
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
// Handle any errors
}
});
I have image view which loads image using Glide using download link. Code is given below :
How can I get the file name stored in fire base storage from the download url ?
Glide.with(ct)
.load(downloadurllink)
.centerCrop();
placeholder(R.drawable.common_icon_dark)
.into(holder.image);
I had the same problem and I used a Regular Expression to extract the file name from the download URL
%2..*%2F(.*?)\?alt
Eg: If your download URL is https://firebasestorage.googleapis.com/v0/b/art-track.appspot.com/o/images%2Fu1nffdGQ7QPLIMp7N11vSOYorUM2%2FCapture.JPG?alt=media&token=86081f67-9065-4a13-aa0b-14fab7d44bf3 , by using %2..*%2F(.*?)\?alt you can extract "Capture.JPG"
You can get filename easily using the name property.
Example:
val httpsReference = FirebaseStorage.getInstance().getReferenceFromUrl("https://firebasestorage.googleapis.com/v0/b/art-
track.appspot.com/o/images%2Fu1nffhbfdjsa%2FN11vSOYorUM2%2FImageName.JPG?
alt=media&token=86081f67-9065-4a13-aa0b-14fab7d44bf3")
Log.d(TAG, "filename: ${httpsReference.name}")
Android Example:
StorageReference storageReference = FirebaseStorage.getInstance().getReferenceFromUrl(urlImg);
String link = storageReference.getName();
Toast.makeText(EditAQuestionP1.this, link, Toast.LENGTH_SHORT).show();
If the URL is in this pattern:
https://firebasestorage.googleapis.com/v0/b/art-track.appspot.com/o/images%2Fu1nffhbfdjsa%2FN11vSOYorUM2%2FImageName.JPG?alt=media&token=86081f67-9065-4a13-aa0b-14fab7d44bf3
then this will work to split the URL into the pattern from 2F till 2F and it will remove the extension (.jpg or .png)
String url="https://firebasestorage.googleapis.com/v0/b/art-
track.appspot.com/o/images%2Fu1nffhbfdjsa%2FN11vSOYorUM2%2FImageName.JPG?
alt=media&token=86081f67-9065-4a13-aa0b-14fab7d44bf3";
print(url.split(RegExp(r'(%2F)..*(%2F)'))[1].split(".")[0]);
There are many options. Two of the most used ones are:
1. You can use File Metadata in Firebase Storage to get the file name from URL. Basically, you create a Firebase Data Reference and then add a file metadata listener, like this:
// Create a storage reference from our app
StorageReference storageRef = storage.getReference();
// Get reference to the file
StorageReference fileRef = storageRef.child("images/forest.jpg");
fileRef.getMetadata().addOnSuccessListener(new OnSuccessListener<StorageMetadata>() {
#Override
public void onSuccess(StorageMetadata storageMetadata) {
String filename = storageMetadata.getName();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
// Uh-oh, an error occurred!
}
});
This code was taken from the documentation which I advice you to check out: File Metadata
2. Another option is to store your URL with the name in Firebase Database. This has the advantage of avoiding unnecessary listeners. That means that you can get the name with a single value event listener without having to load all of the file metadata.
database.child("files").child("url")
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String name = dataSnapShot.getValue(String.class);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
}
It depends on your implementation on how you want to do it. Hope it helps :)
The easiest way is to use the reference method:
let storage = Storage.storage()
let yourFirestoreURL = "https://firebasestorage.googleapis.com/v0/b/art-track.appspot.com/o/images%2Fu1nffdGQ7QPLIMp7N11vSOYorUM2%2FCapture.JPG?alt=media&token=86081f67-9065-4a13-aa0b-14fab7d44bf3"
let storageRef = storage.reference(forURL: yourFirestoreURL)
print(storageRef.name)
For further details, see the google guide here: https://firebase.google.com/docs/storage/ios/create-reference
var storageReference =
firebase_storage.FirebaseStorage.instance.refFromURL(url);
String imgName = storageReference.name;
print(imgName);
If you want to delete a file having the url, you can do this:
final httpsReference = FirebaseStorage.instance.refFromURL(url);
await FirebaseStorageService.deleteFile(httpsReference.fullPath);
Solution for iOS!
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"%2F(.*?)\\?alt" options:NSRegularExpressionCaseInsensitive error:&error];
NSArray *matches = [regex matchesInString:photo_url options:0 range:NSMakeRange(0, [photo_url length])];
if (matches && matches.count > 0) {
NSString *substringForFirstMatch = [photo_url substringWithRange:[matches[0] rangeAtIndex:1]];
}
I am using Cloudiary service in order to decrease the size of an uploaded video. I am getting back a URL of a picture (which I assume is the first frame of the video) back as a response. When trying to load the video from firebase I am for some reason getting a URL and not a URI. here is my method -
private void loadVideoUri(String storageUri) {
if (StringUtils.isBlank(storageUri)) {
return;
}
// load firebase storage
Task<Uri> downloadUrlTask = FirebaseStorage.getInstance().getReferenceFromUrl(storageUri).getDownloadUrl(); // -> crash happends here
if (getContext() instanceof Activity) {
downloadUrlTask.addOnCompleteListener((Activity) getContext(), mOnDownloadUrlCompleted);
} else {
downloadUrlTask.addOnCompleteListener(mOnDownloadUrlCompleted);
}
}
here is the full error -
java.lang.IllegalArgumentException: Firebase Storage URLs must point to an object in your Storage Bucket. Please obtain a URL using the Firebase Console or getDownloadUrl().
at com.google.firebase.storage.internal.Util.normalize(com.google.firebase:firebase-storage##16.0.5:134)
at com.google.firebase.storage.FirebaseStorage.getReferenceFromUrl(com.google.firebase:firebase-storage##16.0.5:281)
at com.onemdtalent.app.ui.views.mdview.FirebasePlayerView.loadVideoUri(FirebasePlayerView.java:156)
I am using Firebase storage to upload a file from Android app. After getting file storage reference from FirebaseStorage, uploading file properly with uploadTask. What my finding is, during onProgress listener of uploadTask, taskSnapshot.getTotalByteCount() is -1.
whereas, taskSnapshot.getBytesTransferred() is giving proper result. Is it a bug from Firebase?
N.b: file is uploading with no issue.
here is my code snapshot:
try {
uploadTask = fileReference.putStream(new FileInputStream(imageFile));
} catch (Exception e) {
e.printStackTrace();
}
uploadTask.addOnProgressListener(this, new
OnProgressListener<UploadTask.TaskSnapshot>() {
#Override
public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
// here taskSnapshot.getTotalByteCount() is -1
double progressPersentage = ((taskSnapshot
.getBytesTransferred() * 100.0) / taskSnapshot
.getTotalByteCount());// for file transfer
Log.d(this.getClass().getName(), taskSnapshot
.getTotalByteCount() + " Uploading " + (taskSnapshot
.getBytesTransferred()));
}
})
Because a stream represents a sequence of bytes of unspecified length, it's not unreasonable that getTotalByteCount() would be unknown.
You'll get better results using putFile():
uploadTask = fileReference.putFile(Uri.fromFile(imageFile));
I am trying to load image from my S3 Bucket in my android application. My images are private so I won't be having any specific link for each image.
I'm using link generator,
s3Client.generatePresignedUrl(Constants.S3_BUCKET_NAME, key, expiration);
It generates a URL with let's say 1 hour or 2 min expiration.
Now I have problem in loading the url. I tried loading it by using picasso ,
Picasso.with(context).load(url.toString()).resize(30,38).into(holder.photo);
but it's not quite seems to be working. When I tried that link on browser I got following error
<Code>NoSuchKey</Code>
<Message>The specified key does not exist.</Message>
Try to attach error listener to Picasso and see what's going on. Also read logcat. Print URL which you pass to Picasso, does it correct?
Picasso.Builder builder = new Picasso.Builder(getApplicationContext());
builder.listener(new Picasso.Listener() {
#Override
public void onImageLoadFailed(Picasso arg0, String err) {
Log.e("Picasso Error", "Errored " + err);
}
});
builder.loggingEnabled(true);
Picasso pic = builder.build();
pic.load("image.jpg").into(iv);