Open peterhav opened 8 years ago
Can you just use the image you took as the placeholder image? Glide supports this out of the box (using the placeholder()
method), so it's not anything we should have to do:
Glide.with(this)
.using(new FirebaseImageLoader())
.placeholder(yourImageAsset)
.load(storageReference)
.into(imageView);
That said, this does incur the overhead of having to download the thing you just loaded (granted, this will be the behavior on every device other than the uploading user's). Glide talks some about it's cache invalidation here, and I'd take a look at that--our goal was to allow you to use the full power of Glide to do things like this without us having to implement everything.
Hi @mcdonamp, this could be a work-around in some situations. Unfortunately is does not help in my case: the image selection (and crop) takes place in a dedicated activity. As soon as this activity is finished, the picture should be shown in several other activities/fragments.
Not sure if this'll help but I handle the the scenario where an image is altered or changed in a dedicated activity by changing the filename which is also stored in the realtime database. (To ensure uniqueness I simply assign the filename to current time in millis.) Any db listener will notice the filename change and load the new image as Glide will not have a cache for the new file.
On Thu, Sep 29, 2016 at 10:01 AM, peterhav notifications@github.com wrote:
Hi @mcdonamp https://github.com/mcdonamp, this could be a work-around in some situations. Unfortunately is does not help in my case: the image selection (and crop) takes place in a dedicated activity. As soon as this activity is finished, the picture should be shown in several other activities/fragments.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/firebase/FirebaseUI-Android/issues/331#issuecomment-250492569, or mute the thread https://github.com/notifications/unsubscribe-auth/AQPs6YoGwPylCujC1H5sURLJY308VhCAks5qu9LWgaJpZM4KIuLd .
@peterhav @kermitdefroghere this is an interesting use case, I see how it's valuable. Looking around on Glide docs and forums it seems that they are resistant to allowing the cache to be modified directly, so there's no cache.put()
operation we could easily call (if so, I'd do it).
However I think you could do this yourself by sub-classing FirebaseImageLoader
to have a constructor that takes a @Nullable Uri
.
Then you could do something like this:
public class MyFirebaseImageLoader extends FirebaseImageLoader {
private Uri mUri;
public MyFirebaseImageLoader(@Nullable Uri uri) {
this.mUri = uri;
}
@Override
public DataFetcher<InputStream> getResourceFetcher(StorageReference model, int width, int height) {
return new MyFirebaseStorageFetcher(model);
}
private class MyFirebaseStorageFetcher extends FirebaseStorageFetcher {
MyFirebaseStorageFetcher(StorageReference ref) {
super(ref);
}
@Override
public InputStream loadData(Priority priority) throws Exception {
if (mUri != null) {
// TODO(developer): Return inputStream from Uri
} else {
super.loadData(priority);
}
}
}
}
Because the getId() value will still be based on the StorageReference, this will allow the Uri to populate the same cache entry.
There's also this documentation on Glide cache invalidation, which you may need to do in cases where you do this trick but then the upload fails or something: https://github.com/bumptech/glide/wiki/Caching-and-Cache-Invalidation
Hi @samtstern, I have tried this and it works well! The only thing is that FirebaseStorageFetcher is a private class that cannot be extended (I created a copy right now).
@peterhav I figured that might be an issue. Glad it works with a copy, I will consider how we can solve this problem in a more elegant fashion for upcoming releases.
hi @peterhav , Please would you mind sharing how you make it work with code in a gist, i am trying to do the same...
Hi @judeebene the code I'm currently using is the following:
import android.net.Uri;
import android.support.annotation.Nullable;
import android.util.Log;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.data.DataFetcher;
import com.firebase.ui.storage.images.FirebaseImageLoader;
import com.google.android.gms.tasks.Tasks;
import com.google.firebase.storage.StorageReference;
import com.google.firebase.storage.StreamDownloadTask;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
class LocalCacheSupportingFirebaseImageLoader extends FirebaseImageLoader {
private static final String TAG = LocalCacheSupportingFirebaseImageLoader.class.getName();
private Uri mUri;
LocalCacheSupportingFirebaseImageLoader(@Nullable Uri uri) {
this.mUri = uri;
}
@Override
public DataFetcher<InputStream> getResourceFetcher(StorageReference model, int width, int height) {
return new MyFirebaseStorageFetcher(model);
}
private class MyFirebaseStorageFetcher extends FirebaseStorageFetcher {
MyFirebaseStorageFetcher(StorageReference ref) {
super(ref);
}
@Override
public InputStream loadData(Priority priority) throws Exception {
if (mUri != null) {
File file = new File(mUri.getPath());
return new FileInputStream(file);
} else {
return super.loadData(priority);
}
}
}
private class FirebaseStorageFetcher implements DataFetcher<InputStream> {
private StorageReference mRef;
private StreamDownloadTask mStreamTask;
private InputStream mInputStream;
FirebaseStorageFetcher(StorageReference ref) {
mRef = ref;
}
@Override
public InputStream loadData(Priority priority) throws Exception {
mStreamTask = mRef.getStream();
mInputStream = Tasks.await(mStreamTask).getStream();
return mInputStream;
}
@Override
public void cleanup() {
// Close stream if possible
if (mInputStream != null) {
try {
mInputStream.close();
mInputStream = null;
} catch (IOException e) {
Log.w(TAG, "Could not close stream", e);
}
}
}
@Override
public String getId() {
return mRef.getPath();
}
@Override
public void cancel() {
// Cancel task if possible
if (mStreamTask != null && mStreamTask.isInProgress()) {
mStreamTask.cancel();
}
}
}
}
Note that this code is not yet being used operationally (nevertheless it seems to be working fine). I do not yet have a solution for the 'upload fail' scenario in place. If someone has a neat solution for this please let me know!
@peterhav This issue becomes more critical when trying to deal with offline usage. My app follows almost exactly the same flow as the one described, but trying to account for offline usage. This app is often used by travelers to log data entries and photos, so it is expected to have long periods of offline usage.
When the app is online, the users gets an image using intents, the Database is updated with the path to the StorageReference of the photo, and the photo is uploaded to Storage and displayed using a FirebaseRecyclerAdapter.
However, when the app is offline, the photo is never uploaded to Storage and isn't accessible to the FirebaseRecyclerAdapter so only the placeholder is displayed.
Once the app reconnects to the internet and everything is finished uploading, the photos are visible.
@samtstern Is there a way the FirebaseImageLoader class modifications suggested above can be incorporated into FirebaseUI to more directly correct these issues?
I am on the same situation with my Android app.
Any updates on this issue ?
I believe this issue can be closed in favor of https://github.com/firebase/FirebaseUI-Android/issues/993.
This is a feature request related to the new firebase-ui-storage library available since release 0.6.0:
I’m planning on using the provided integration with Glide to (efficiently) show images stored in Firebase Storage within my app. In my app I have the following workflow that is more or less the same as the sample:
As you can see this is not optimal: step 3 could be omitted by directly inserting the selected image into the local cache. My question: is this currently possible or is this type of functionality foreseen for a future release?