1919import com .bumptech .glide .signature .ObjectKey ;
2020import com .dylanvann .fastimage .custom .EtagCallback ;
2121import com .dylanvann .fastimage .custom .EtagRequester ;
22- import com .dylanvann .fastimage .custom .PersistEtagCallbackWrapper ;
2322import com .dylanvann .fastimage .custom .persistence .ObjectBox ;
2423import com .facebook .react .bridge .ReadableArray ;
2524import com .facebook .react .bridge .ReadableMap ;
@@ -86,7 +85,6 @@ public void setSrc(FastImageViewWithUrl view, @Nullable ReadableMap source) {
8685 return ;
8786 }
8887
89- //final GlideUrl glideUrl = FastImageViewConverter.getGlideUrl(view.getContext(), source);
9088 final FastImageSource imageSource = FastImageViewConverter .getImageSource (view .getContext (), source );
9189 if (imageSource .getUri ().toString ().length () == 0 ) {
9290 ThemedReactContext context = (ThemedReactContext ) view .getContext ();
@@ -117,11 +115,7 @@ private void load(final FastImageViewWithUrl view, @NonNull final ReadableMap so
117115 final FastImageSource imageSource = FastImageViewConverter .getImageSource (view .getContext (), source );
118116 final GlideUrl glideUrl = imageSource .getGlideUrl ();
119117
120- // Cancel existing request.
121118 view .glideUrl = glideUrl ;
122- // if (requestManager != null) {
123- // requestManager.clear(view);
124- // }
125119
126120 final String key = glideUrl .toStringUrl ();
127121 FastImageOkHttpProgressGlideModule .expect (key , this );
@@ -138,6 +132,7 @@ private void load(final FastImageViewWithUrl view, @NonNull final ReadableMap so
138132 final int viewId = view .getId ();
139133 eventEmitter .receiveEvent (viewId , REACT_ON_LOAD_START_EVENT , new WritableNativeMap ());
140134
135+ final RequestOptions options = FastImageViewConverter .getOptions (context , imageSource , source );
141136 if (requestManager != null ) {
142137 final String url = imageSource .getGlideUrl ().toStringUrl ();
143138 if (!url .startsWith ("http" )) {
@@ -149,118 +144,102 @@ private void load(final FastImageViewWithUrl view, @NonNull final ReadableMap so
149144 // - android.resource://
150145 // - data:image/png;base64
151146 .load (imageSource .getSourceForLoad ())
152- .apply (FastImageViewConverter . getOptions ( context , imageSource , source ) )
147+ .apply (options )
153148 .listener (new FastImageRequestListener (key ))
154149 .into (view );
155150 return ;
156151 }
157152
158- final RequestOptions options = FastImageViewConverter .getOptions (context , imageSource , source );
159-
160- // getEtag handles persistence of etag
161- getEtag (url , new EtagCallback () {
162- @ Override
163- public void onError (String error ) {
164- loadImage (view , url , null , options , key );
165- }
166-
167- @ Override
168- public void onEtag (@ Nullable final String etag ) {
169- loadImage (view , url , etag , options , key );
170- }
171- });
153+ loadImage (view , url , options , key );
172154 }
173155 }
174156
175157 /**
176- * Refreshes an image. Won't do anything if etag hasn't changed.
177- * When there was a new image the new image will be shown + the image
178- * and etag cache will be updated.
179- * @param url
180- */
181- private void refresh (final FastImageViewWithUrl view , final String url ) {
182- EtagRequester .requestEtag (url , new PersistEtagCallbackWrapper (url , new EtagCallback () {
183- @ Override
184- public void onError (final String error ) {
185- loadImage (view , url , null , null , null );
186- }
187-
188- @ Override
189- public void onEtag (final String etag ) {
190- loadImage (view , url , etag , null , null );
191- }
192- })
193- );
158+ * This will make a head request to the URL to get the ETAG.
159+ * The request is then forwarded to glide, which uses the
160+ * ETAG as signature, see {@link #loadImageWithSignature}.
161+ **/
162+ private void loadImage (final FastImageViewWithUrl view , final String url , @ Nullable final RequestOptions options , final @ Nullable String key ) {
163+ String prevEtag = ObjectBox .getEtagByUrl (url );
164+
165+ // We need to make a head request to the URL with the ETAG attached.
166+ // - When we get a new etag Glide will send out another request
167+ // - If the signature (etag) doesn't change, Glide won't bother sending out a request
168+ EtagRequester .requestEtag (url , prevEtag , new EtagCallback () {
169+ @ Override
170+ public void onEtag (String etag ) {
171+ // Note: here at this point the etag in the ObjectBox has been updated
172+ // to the new etag. That's why we pass down the the previous.
173+ loadImageWithSignature (view , url , etag , prevEtag , options , key );
174+ }
175+
176+ @ Override
177+ public void onError (String error ) {
178+ loadImageWithSignature (view , url , prevEtag , prevEtag , options , key );
179+ }
180+ });
194181 }
195182
196183 /**
197- *
198- * @param view
199- * @param url
200- * @param etag Optional
201- * @param options Optional
202- * @param key Optional, when set it will emit events
184+ * This loads the actual image either from server or from cache
185+ * depending on whether a cache entry for the given signature
186+ * exists yet.
187+ * If a prev signature is passed it will show the image for the
188+ * url + prevSignature as long as the new image from the url (with
189+ * the new signature) is being loaded.
203190 */
204- private void loadImage (final FastImageViewWithUrl view , final String url , @ Nullable final String etag , @ Nullable final RequestOptions options , final @ Nullable String key ) {
205- getActivityFromContext (view .getContext ()).runOnUiThread (new Runnable () {
206- @ Override
207- public void run () {
208- if (requestManager == null ) {
209- Log .e (FastImageViewManager .class .getSimpleName (), "Can't refresh as requestManager was null!" );
210- return ;
211- }
191+ private void loadImageWithSignature (
192+ final FastImageViewWithUrl view ,
193+ final String url ,
194+ @ Nullable String signature ,
195+ @ Nullable String prevSignature ,
196+ @ Nullable final RequestOptions options ,
197+ @ Nullable final String key )
198+ {
199+ getActivityFromContext (view .getContext ()).runOnUiThread (() -> {
200+ if (requestManager == null ) {
201+ Log .e (FastImageViewManager .class .getSimpleName (), "Can't refresh as requestManager was null!" );
202+ return ;
203+ }
204+
205+ // cancel any previous requests
206+ requestManager .clear (view );
212207
208+ // Request the new image
209+ RequestBuilder <Drawable > imageRequest = requestManager
210+ .load (url );
213211
212+ // When we have a previous signature we want to show the previous
213+ // image, until the new one is loaded. This is done with a
214+ // thumbnail request. Without this there would be a "white flickering"
215+ // until the (new) image is loaded.
216+ if (prevSignature != null ) {
217+ // Create a "thumbnail" which is literally the cached image while we load the new image
214218 RequestBuilder <Drawable > thumbnailRequest = requestManager
215219 .load (url );
216-
217- // add etag as signature when its set
218- String prevEtag = ObjectBox .getEtagByUrl (url );
219- if (prevEtag != null ) {
220- thumbnailRequest = thumbnailRequest .signature (new ObjectKey (prevEtag ));
221- }
222-
223- RequestBuilder <Drawable > imageRequest = requestManager
224- .load (url )
220+ thumbnailRequest = thumbnailRequest .signature (new ObjectKey (prevSignature ));
221+ imageRequest = imageRequest
225222 .thumbnail (thumbnailRequest )
226223 .skipMemoryCache (true );
224+ }
227225
228- if (etag != null ) {
229- imageRequest = imageRequest .signature (new ObjectKey (etag ));
230- } else if (prevEtag != null ) {
231- // in case we received no etag (e.g. loading error due to no network)
232- // we still want to consider getting cache with the prev etag.
233- imageRequest = imageRequest .signature (new ObjectKey (prevEtag ));
234- }
235-
236- if (options != null ) {
237- imageRequest = imageRequest .apply (options );
238- }
239-
240- if (key != null ) {
241- imageRequest = imageRequest .listener (new FastImageRequestListener (key ));
242- }
243-
244- // finally, load the image
245- imageRequest .into (view );
226+ if (signature != null ) {
227+ imageRequest = imageRequest .signature (new ObjectKey (signature ));
246228 }
229+ if (options != null ) {
230+ imageRequest = imageRequest .apply (options );
231+ }
232+ if (key != null ) {
233+ imageRequest = imageRequest .listener (new FastImageRequestListener (key ));
234+ }
235+
236+ // finally, load the image
237+ imageRequest .into (view );
247238 });
248239 }
249240
250- /**
251- * Returns the etag from cache. If there is no cached etag it will request
252- * the server to get it, save it to the cache, and return it.
253- * @param url
254- * @param callback
255- */
256- private void getEtag (String url , EtagCallback callback ) {
257- String etag = ObjectBox .getEtagByUrl (url );
258-
259- if (etag == null ) {
260- EtagRequester .requestEtag (url , new PersistEtagCallbackWrapper (url , callback ));
261- } else {
262- callback .onEtag (etag );
263- }
241+ private void refresh (final FastImageViewWithUrl view , final ReadableMap source ) {
242+ load (view , source );
264243 }
265244
266245 @ ReactProp (name = "tintColor" , customType = "Color" )
@@ -389,8 +368,7 @@ public void receiveCommand(FastImageViewWithUrl root, int commandId, @Nullable R
389368 switch (commandId ) {
390369 case FORCE_REFRESH_IMAGE : {
391370 if (root .source != null ) {
392- final FastImageSource imageSource = FastImageViewConverter .getImageSource (root .getContext (), root .source );
393- refresh (root , imageSource .getGlideUrl ().toStringUrl ());
371+ refresh (root , root .source );
394372 }
395373 return ;
396374 }
0 commit comments