react-native-fast-image 9.3.0 → 9.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/android/src/main/java/com/dylanvann/fastimage/FastImageSharedDownloads.java +64 -19
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewWithUrl.java +16 -7
- package/dist/index.cjs.js.flow +1 -1
- package/dist/index.cjs.web.js.flow +1 -1
- package/dist/index.d.ts +2 -4
- package/dist/index.js.flow +1 -1
- package/dist/index.web.js.flow +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -257,7 +257,7 @@ It can also be set in `style`; the prop wins. Either one overrides `resizeMode`.
|
|
|
257
257
|
|
|
258
258
|
**Type:** `ResizeMode` · **Default:** `'cover'`
|
|
259
259
|
|
|
260
|
-
**Deprecated:** Use `objectFit` instead
|
|
260
|
+
**Deprecated:** Use `objectFit` instead.
|
|
261
261
|
|
|
262
262
|
How the image fills the view.
|
|
263
263
|
|
|
@@ -22,10 +22,13 @@ import java.util.ArrayList;
|
|
|
22
22
|
import java.util.Arrays;
|
|
23
23
|
import java.util.Comparator;
|
|
24
24
|
import java.util.HashMap;
|
|
25
|
+
import java.util.HashSet;
|
|
26
|
+
import java.util.Iterator;
|
|
25
27
|
import java.util.List;
|
|
26
28
|
import java.util.Map;
|
|
27
|
-
import java.util.
|
|
29
|
+
import java.util.Set;
|
|
28
30
|
import java.util.TreeMap;
|
|
31
|
+
import java.util.TreeSet;
|
|
29
32
|
import java.util.concurrent.ConcurrentHashMap;
|
|
30
33
|
import java.util.concurrent.LinkedBlockingQueue;
|
|
31
34
|
import java.util.concurrent.ThreadFactory;
|
|
@@ -64,13 +67,18 @@ import okio.BufferedSource;
|
|
|
64
67
|
// once every request has read what it needed.
|
|
65
68
|
//
|
|
66
69
|
// At most MAX_RUNNING downloads run at once, as SDWebImage's downloader limits
|
|
67
|
-
// them
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
70
|
+
// them, and at most as many wait for their response from a host as the
|
|
71
|
+
// client's dispatcher sends to a host at once (5 by default): OkHttp would
|
|
72
|
+
// hold the others in the order they came, where a more urgent request can't
|
|
73
|
+
// move them up. The others wait to send their request, most urgent first
|
|
74
|
+
// (Glide's priority: views before preloads), and the most urgent one waiting
|
|
75
|
+
// for a host's room keeps a running slot, so less urgent downloads to other
|
|
76
|
+
// hosts can't take them all. A running download's response is read as soon
|
|
77
|
+
// as it arrives, on its own thread (OkHttp counts a request to its host until
|
|
78
|
+
// its callback returns): a response left unread on an HTTP/2 connection
|
|
79
|
+
// would hold back the others on it. A download that stalls fails like any
|
|
80
|
+
// other, with the timeouts of the clients (FastImageOkHttpProgressGlideModule),
|
|
81
|
+
// which only count once it has started.
|
|
74
82
|
final class FastImageSharedDownloads {
|
|
75
83
|
// The longest response kept in memory, and the most bytes held in memory
|
|
76
84
|
// for downloads at once: encoded images (not decoded bitmaps, which
|
|
@@ -98,9 +106,9 @@ final class FastImageSharedDownloads {
|
|
|
98
106
|
// lock).
|
|
99
107
|
private static final Map<String, Download> downloads = new HashMap<>();
|
|
100
108
|
// Guarded by downloads: downloads waiting to start, most urgent first, then
|
|
101
|
-
// in the order they were asked for; how many are running
|
|
102
|
-
// held in memory.
|
|
103
|
-
private static final
|
|
109
|
+
// in the order they were asked for; how many are running, and how many
|
|
110
|
+
// wait for their response from each host; and the bytes held in memory.
|
|
111
|
+
private static final TreeSet<Download> queue = new TreeSet<>(new Comparator<Download>() {
|
|
104
112
|
@Override
|
|
105
113
|
public int compare(Download a, Download b) {
|
|
106
114
|
int byPriority = a.priority.compareTo(b.priority);
|
|
@@ -109,6 +117,7 @@ final class FastImageSharedDownloads {
|
|
|
109
117
|
});
|
|
110
118
|
private static long orders = 0;
|
|
111
119
|
private static int running = 0;
|
|
120
|
+
private static final Map<String, Integer> sentTo = new HashMap<>();
|
|
112
121
|
private static long held = 0;
|
|
113
122
|
// Stores not yet released (see busy()).
|
|
114
123
|
private static final AtomicInteger open = new AtomicInteger();
|
|
@@ -165,9 +174,10 @@ final class FastImageSharedDownloads {
|
|
|
165
174
|
static String busy() {
|
|
166
175
|
synchronized (downloads) {
|
|
167
176
|
int stores = open.get();
|
|
168
|
-
if (downloads.isEmpty() && queue.isEmpty() && running == 0 &&
|
|
177
|
+
if (downloads.isEmpty() && queue.isEmpty() && running == 0 && sentTo.isEmpty() && held == 0
|
|
178
|
+
&& stores == 0) return null;
|
|
169
179
|
return downloads.size() + " downloads, " + queue.size() + " waiting, " + running + " running, "
|
|
170
|
-
+ held + " bytes in memory, " + stores + " stores open";
|
|
180
|
+
+ sentTo + " waiting for a response, " + held + " bytes in memory, " + stores + " stores open";
|
|
171
181
|
}
|
|
172
182
|
}
|
|
173
183
|
|
|
@@ -253,13 +263,25 @@ final class FastImageSharedDownloads {
|
|
|
253
263
|
}
|
|
254
264
|
}
|
|
255
265
|
|
|
256
|
-
// Starts the downloads waiting that can run now
|
|
266
|
+
// Starts the downloads waiting that can run now, most urgent first: those
|
|
267
|
+
// whose host has room, leaving a slot for each host without (see above).
|
|
257
268
|
private static void startQueued() {
|
|
258
269
|
List<Download> starting = new ArrayList<>();
|
|
259
270
|
List<Request> requests = new ArrayList<>();
|
|
260
271
|
synchronized (downloads) {
|
|
261
|
-
|
|
262
|
-
|
|
272
|
+
Set<String> full = new HashSet<>();
|
|
273
|
+
Iterator<Download> waiting = queue.iterator();
|
|
274
|
+
while (running + full.size() < MAX_RUNNING && waiting.hasNext()) {
|
|
275
|
+
Download download = waiting.next();
|
|
276
|
+
String host = download.request.url().host();
|
|
277
|
+
Integer sent = sentTo.get(host);
|
|
278
|
+
if (sent != null && sent >= download.client.dispatcher().getMaxRequestsPerHost()) {
|
|
279
|
+
full.add(host);
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
waiting.remove();
|
|
283
|
+
sentTo.put(host, sent == null ? 1 : sent + 1);
|
|
284
|
+
download.host = host;
|
|
263
285
|
download.queued = false;
|
|
264
286
|
download.running = true;
|
|
265
287
|
running++;
|
|
@@ -539,6 +561,10 @@ final class FastImageSharedDownloads {
|
|
|
539
561
|
private final long order;
|
|
540
562
|
private boolean queued = false;
|
|
541
563
|
private boolean running = false;
|
|
564
|
+
// Guarded by downloads. The host its request was sent to, until its
|
|
565
|
+
// response (or failure) arrives.
|
|
566
|
+
@Nullable
|
|
567
|
+
private String host;
|
|
542
568
|
// Guarded by this. The call, once started, and whether the download
|
|
543
569
|
// was cancelled (before it started, it doesn't).
|
|
544
570
|
@Nullable
|
|
@@ -585,7 +611,9 @@ final class FastImageSharedDownloads {
|
|
|
585
611
|
return;
|
|
586
612
|
}
|
|
587
613
|
Download download;
|
|
588
|
-
|
|
614
|
+
// Queued one, or moved a waiting one to another url (whose host
|
|
615
|
+
// can have room).
|
|
616
|
+
boolean queueChanged = false;
|
|
589
617
|
InputStream ready = null;
|
|
590
618
|
synchronized (downloads) {
|
|
591
619
|
// Cancelled before it got here.
|
|
@@ -601,7 +629,7 @@ final class FastImageSharedDownloads {
|
|
|
601
629
|
downloads.put(fetcher.key, download);
|
|
602
630
|
download.queued = true;
|
|
603
631
|
queue.add(download);
|
|
604
|
-
|
|
632
|
+
queueChanged = true;
|
|
605
633
|
} else if (download.queued) {
|
|
606
634
|
// A more urgent request moves it up (until it leaves).
|
|
607
635
|
if (fetcher.priority.compareTo(download.priority) < 0) download.reprioritize(fetcher.priority);
|
|
@@ -612,6 +640,7 @@ final class FastImageSharedDownloads {
|
|
|
612
640
|
download.url = fetcher.url;
|
|
613
641
|
download.client = fetcher.client;
|
|
614
642
|
download.request = request;
|
|
643
|
+
queueChanged = true;
|
|
615
644
|
}
|
|
616
645
|
}
|
|
617
646
|
fetcher.download = download;
|
|
@@ -627,7 +656,7 @@ final class FastImageSharedDownloads {
|
|
|
627
656
|
}
|
|
628
657
|
}
|
|
629
658
|
if (ready != null) fetcher.deliver(ready, callback);
|
|
630
|
-
if (
|
|
659
|
+
if (queueChanged) startQueued();
|
|
631
660
|
}
|
|
632
661
|
|
|
633
662
|
// Sends the request (off the main thread, and outside the locks:
|
|
@@ -656,10 +685,24 @@ final class FastImageSharedDownloads {
|
|
|
656
685
|
if (started != null) started.cancel();
|
|
657
686
|
}
|
|
658
687
|
|
|
688
|
+
// With downloads locked: its request has its response, failed, or
|
|
689
|
+
// wasn't sent, so another can be sent to its host.
|
|
690
|
+
private void responded() {
|
|
691
|
+
if (host == null) return;
|
|
692
|
+
int sent = sentTo.get(host) - 1;
|
|
693
|
+
if (sent == 0) {
|
|
694
|
+
sentTo.remove(host);
|
|
695
|
+
} else {
|
|
696
|
+
sentTo.put(host, sent);
|
|
697
|
+
}
|
|
698
|
+
host = null;
|
|
699
|
+
}
|
|
700
|
+
|
|
659
701
|
// It no longer runs: the next download waiting can start.
|
|
660
702
|
private void stopped() {
|
|
661
703
|
synchronized (downloads) {
|
|
662
704
|
if (!running) return;
|
|
705
|
+
responded();
|
|
663
706
|
running = false;
|
|
664
707
|
FastImageSharedDownloads.running--;
|
|
665
708
|
}
|
|
@@ -853,6 +896,7 @@ final class FastImageSharedDownloads {
|
|
|
853
896
|
fromHttpCache = response.networkResponse() == null && response.cacheResponse() != null;
|
|
854
897
|
final long length = body.contentLength();
|
|
855
898
|
synchronized (downloads) {
|
|
899
|
+
responded();
|
|
856
900
|
// No progress without a length.
|
|
857
901
|
if (length <= 0) silent = true;
|
|
858
902
|
}
|
|
@@ -862,6 +906,7 @@ final class FastImageSharedDownloads {
|
|
|
862
906
|
readInto(body, length);
|
|
863
907
|
}
|
|
864
908
|
});
|
|
909
|
+
startQueued();
|
|
865
910
|
}
|
|
866
911
|
|
|
867
912
|
// Sends a progress step, unless the download has stopped: checked and
|
|
@@ -832,6 +832,9 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
832
832
|
private Object mModel;
|
|
833
833
|
// Whether the loading image has loaded or failed.
|
|
834
834
|
private boolean mLoadEnded = false;
|
|
835
|
+
// Whether the loading request is the image that's showing loaded again
|
|
836
|
+
// (reloadForSize's or reblur's), which sends no events.
|
|
837
|
+
private boolean mLoadingQuietly = false;
|
|
835
838
|
// Set by reblur: the next load is the same one again, so it doesn't send
|
|
836
839
|
// onLoadStart (it sends its other events, as the load it replaces would
|
|
837
840
|
// have).
|
|
@@ -942,13 +945,16 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
942
945
|
.error(current.clone())
|
|
943
946
|
.listener(new FastImageRequestListener(null, true, false));
|
|
944
947
|
if (meanwhile == null) builder = builder.thumbnail(current);
|
|
945
|
-
into(shown, builder, meanwhile);
|
|
948
|
+
into(shown, builder, meanwhile, true);
|
|
946
949
|
}
|
|
947
950
|
|
|
948
951
|
// blurRadius changed, and nothing else that needs a reload: the image
|
|
949
952
|
// that's showing, blurred again, with no events, as reloadForSize does: it's
|
|
950
953
|
// decoded again from the cache and blurred on Glide's threads, and the view
|
|
951
|
-
// keeps the current image until then
|
|
954
|
+
// keeps the current image until then. If that fails, it shows the image
|
|
955
|
+
// from Glide's caches; cache: 'web' skips them, so the view shows
|
|
956
|
+
// defaultSource (or nothing) then. Also while it's loading again that way
|
|
957
|
+
// (e.g. the blur changes every frame): that load is replaced. A load that
|
|
952
958
|
// hasn't finished starts again with the new blur, without a second
|
|
953
959
|
// onLoadStart. Nothing loaded (defaultSource, which isn't blurred, or
|
|
954
960
|
// nothing): the next load has the new blur.
|
|
@@ -956,7 +962,7 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
956
962
|
private void reblur() {
|
|
957
963
|
if (requestManager == null || mBaseRequest == null) return;
|
|
958
964
|
RequestBuilder<Drawable> shown = mShownRequest;
|
|
959
|
-
if (shown != null && shown == mLoadingRequest) {
|
|
965
|
+
if (shown != null && (shown == mLoadingRequest || mLoadingQuietly)) {
|
|
960
966
|
RequestBuilder<Drawable> request = mBaseRequest.clone().apply(renderingOptions(mModel));
|
|
961
967
|
RequestBuilder<Drawable> current = fromCache(shown);
|
|
962
968
|
Drawable meanwhile = shownCopy(shown);
|
|
@@ -966,7 +972,7 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
966
972
|
.error(current.clone())
|
|
967
973
|
.listener(new FastImageRequestListener(null, true, false));
|
|
968
974
|
if (meanwhile == null) builder = builder.thumbnail(current);
|
|
969
|
-
into(request, builder, meanwhile);
|
|
975
|
+
into(request, builder, meanwhile, true);
|
|
970
976
|
} else if (mLoadingRequest != null && !mLoadEnded) {
|
|
971
977
|
mRestarting = true;
|
|
972
978
|
mNeedsReload = true;
|
|
@@ -1007,10 +1013,13 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
1007
1013
|
|
|
1008
1014
|
// Starts loading the request (built by builder), showing meanwhile (if
|
|
1009
1015
|
// not null) until it loads, and recording the size Glide loads it at. The size callback is added first, so it has the size by
|
|
1010
|
-
// the time the image loads, even from the memory cache.
|
|
1011
|
-
|
|
1016
|
+
// the time the image loads, even from the memory cache. Quiet: the image
|
|
1017
|
+
// that's showing, loaded again (no events).
|
|
1018
|
+
private void into(RequestBuilder<Drawable> request, RequestBuilder<Drawable> builder, @Nullable Drawable meanwhile,
|
|
1019
|
+
boolean quiet) {
|
|
1012
1020
|
final int load = mLoadCount;
|
|
1013
1021
|
mLoadingRequest = request;
|
|
1022
|
+
mLoadingQuietly = quiet;
|
|
1014
1023
|
mLoadEnded = false;
|
|
1015
1024
|
mLoadingWidth = 0;
|
|
1016
1025
|
mLoadingHeight = 0;
|
|
@@ -1218,7 +1227,7 @@ class FastImageViewWithUrl extends AppCompatImageView implements ReactPointerEve
|
|
|
1218
1227
|
if (imageSource != null)
|
|
1219
1228
|
builder.listener(new FastImageRequestListener(imageSource, thumbnail, true));
|
|
1220
1229
|
|
|
1221
|
-
into(request, builder, meanwhile);
|
|
1230
|
+
into(request, builder, meanwhile, false);
|
|
1222
1231
|
}
|
|
1223
1232
|
}
|
|
1224
1233
|
|
package/dist/index.cjs.js.flow
CHANGED
|
@@ -125,7 +125,7 @@ export type FastImageProps = $ReadOnly<{|
|
|
|
125
125
|
|
|
126
126
|
tintColor?: number | string,
|
|
127
127
|
objectFit?: ?ObjectFit,
|
|
128
|
-
// Deprecated: objectFit
|
|
128
|
+
// Deprecated: use objectFit.
|
|
129
129
|
resizeMode?: ?ResizeModes,
|
|
130
130
|
fallback?: ?boolean,
|
|
131
131
|
recyclingKey?: ?string,
|
|
@@ -125,7 +125,7 @@ export type FastImageProps = $ReadOnly<{|
|
|
|
125
125
|
|
|
126
126
|
tintColor?: number | string,
|
|
127
127
|
objectFit?: ?ObjectFit,
|
|
128
|
-
// Deprecated: objectFit
|
|
128
|
+
// Deprecated: use objectFit.
|
|
129
129
|
resizeMode?: ?ResizeModes,
|
|
130
130
|
fallback?: ?boolean,
|
|
131
131
|
recyclingKey?: ?string,
|
package/dist/index.d.ts
CHANGED
|
@@ -329,8 +329,7 @@ export interface FastImageProps extends AccessibilityProps, ViewProps {
|
|
|
329
329
|
* image repeats its first frame, and `defaultSource` repeats too.
|
|
330
330
|
*
|
|
331
331
|
* @default 'cover'
|
|
332
|
-
* @deprecated Use `objectFit` instead
|
|
333
|
-
* `objectFit` value and isn't deprecated.
|
|
332
|
+
* @deprecated Use `objectFit` instead.
|
|
334
333
|
*/
|
|
335
334
|
resizeMode?: ResizeMode;
|
|
336
335
|
/**
|
|
@@ -568,8 +567,7 @@ export interface PreloadFailure {
|
|
|
568
567
|
export type PreloadResult = PreloadSuccess | PreloadFailure;
|
|
569
568
|
export interface FastImageStaticProperties {
|
|
570
569
|
/**
|
|
571
|
-
* @deprecated Use the `objectFit` prop instead of `resizeMode
|
|
572
|
-
* `'repeat'`.
|
|
570
|
+
* @deprecated Use the `objectFit` prop instead of `resizeMode`.
|
|
573
571
|
*/
|
|
574
572
|
resizeMode: typeof resizeMode;
|
|
575
573
|
priority: typeof priority;
|
package/dist/index.js.flow
CHANGED
|
@@ -125,7 +125,7 @@ export type FastImageProps = $ReadOnly<{|
|
|
|
125
125
|
|
|
126
126
|
tintColor?: number | string,
|
|
127
127
|
objectFit?: ?ObjectFit,
|
|
128
|
-
// Deprecated: objectFit
|
|
128
|
+
// Deprecated: use objectFit.
|
|
129
129
|
resizeMode?: ?ResizeModes,
|
|
130
130
|
fallback?: ?boolean,
|
|
131
131
|
recyclingKey?: ?string,
|
package/dist/index.web.js.flow
CHANGED
|
@@ -125,7 +125,7 @@ export type FastImageProps = $ReadOnly<{|
|
|
|
125
125
|
|
|
126
126
|
tintColor?: number | string,
|
|
127
127
|
objectFit?: ?ObjectFit,
|
|
128
|
-
// Deprecated: objectFit
|
|
128
|
+
// Deprecated: use objectFit.
|
|
129
129
|
resizeMode?: ?ResizeModes,
|
|
130
130
|
fallback?: ?boolean,
|
|
131
131
|
recyclingKey?: ?string,
|