Skip to content

Commit 46e08b4

Browse files
committed
Update to support preloading sources.
Sources for preloading have the same keys as the source prop. Also update readme to document preloading.
1 parent c21c24c commit 46e08b4

File tree

8 files changed

+190
-102
lines changed

8 files changed

+190
-102
lines changed

FastImage.js

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import {
88

99
const resolveAssetSource = require('react-native/Libraries/Image/resolveAssetSource')
1010

11+
const FastImageViewNativeModule = NativeModules.FastImageView
12+
1113
class FastImage extends Component {
1214
setNativeProps(nativeProps) {
1315
this._root.setNativeProps(nativeProps)
@@ -55,13 +57,8 @@ FastImage.priority = {
5557
high: 'high',
5658
}
5759

58-
FastImage.prefetch = function(source) {
59-
let urls = source
60-
if (typeof source === 'string') {
61-
urls = [source]
62-
}
63-
64-
NativeModules.FastImageView.prefetch(urls)
60+
FastImage.preload = sources => {
61+
FastImageViewNativeModule.preload(sources)
6562
}
6663

6764
const FastImageSourcePropType = PropTypes.shape({

README.md

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ and
3636
- [x] Aggressively cache images.
3737
- [x] Add authorization headers.
3838
- [x] Prioritize images.
39+
- [x] Preload images.
3940
- [x] GIF support.
4041

4142
## Usage
@@ -63,13 +64,13 @@ const YourImage = () =>
6364

6465
## Properties
6566

66-
`source?: object`
67+
### `source?: object`
6768

6869
Source for the remote image to load.
6970

7071
---
7172

72-
`source.uri?: string`
73+
### `source.uri?: string`
7374

7475
Remote url to load the image from. e.g. `'https://facebook.github.io/react/img/logo_og.png'`.
7576

@@ -81,15 +82,15 @@ Headers to load the image with. e.g. `{ Authorization: 'someAuthToken' }`.
8182

8283
---
8384

84-
`source.priority?: enum`
85+
### `source.priority?: enum`
8586

8687
- `FastImage.priority.low` - Low Priority
8788
- `FastImage.priority.normal` **(Default)** - Normal Priority
8889
- `FastImage.priority.high` - High Priority
8990

9091
---
9192

92-
`resizeMode?: enum`
93+
### `resizeMode?: enum`
9394

9495
- `FastImage.resizeMode.contain` **(Default)** - Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions (width and height) of the image will be equal to or less than the corresponding dimension of the view (minus padding).
9596
- `FastImage.resizeMode.cover` - Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions (width and height) of the image will be equal to or larger than the corresponding dimension of the view (minus padding).
@@ -98,16 +99,44 @@ Headers to load the image with. e.g. `{ Authorization: 'someAuthToken' }`.
9899

99100
---
100101

101-
`onLoad?: () => void`
102+
### `onLoad?: () => void`
102103

103104
Called on a successful image fetch.
104105

105106
---
106107

107-
`onError?: () => void`
108+
### `onError?: () => void`
108109

109110
Called on an image fetching error.
110111

112+
---
113+
114+
### `children`
115+
116+
`FastImage` does not currently support children.
117+
Absolute positioning can be used as an alternative.
118+
119+
(This is because `FastImage` supplies a `android.widget.imageview` and not a `android.view.viewgroup`.)
120+
121+
## Static Methods
122+
123+
### `FastImage.preload: (source[]) => void`
124+
125+
Preload images to display later. e.g.
126+
127+
```js
128+
FastImage.preload([
129+
{
130+
uri: 'https://facebook.github.io/react/img/logo_og.png',
131+
headers: { Authorization: 'someAuthToken' },
132+
},
133+
{
134+
uri: 'https://facebook.github.io/react/img/logo_og.png',
135+
headers: { Authorization: 'someAuthToken' },
136+
},
137+
])
138+
```
139+
111140
## Development
112141

113142
```bash
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.dylanvann.fastimage;
2+
3+
import android.widget.ImageView;
4+
import android.widget.ImageView.ScaleType;
5+
6+
import com.bumptech.glide.Priority;
7+
import com.bumptech.glide.load.model.GlideUrl;
8+
import com.bumptech.glide.load.model.LazyHeaders;
9+
import com.facebook.react.bridge.NoSuchKeyException;
10+
import com.facebook.react.bridge.ReadableMap;
11+
import com.facebook.react.bridge.ReadableMapKeySetIterator;
12+
13+
import java.util.HashMap;
14+
import java.util.Map;
15+
16+
class FastImageViewConverter {
17+
static GlideUrl glideUrl(ReadableMap source) {
18+
final String uriProp = source.getString("uri");
19+
// Get the headers prop and add to glideUrl.
20+
GlideUrl glideUrl;
21+
try {
22+
final ReadableMap headersMap = source.getMap("headers");
23+
ReadableMapKeySetIterator headersIterator = headersMap.keySetIterator();
24+
LazyHeaders.Builder headersBuilder = new LazyHeaders.Builder();
25+
while (headersIterator.hasNextKey()) {
26+
String key = headersIterator.nextKey();
27+
String value = headersMap.getString(key);
28+
headersBuilder.addHeader(key, value);
29+
}
30+
LazyHeaders headers = headersBuilder.build();
31+
glideUrl = new GlideUrl(uriProp, headers);
32+
} catch (NoSuchKeyException e) {
33+
// If there is no headers object.
34+
glideUrl = new GlideUrl(uriProp);
35+
}
36+
return glideUrl;
37+
}
38+
39+
private static Map<String, Priority> REACT_PRIORITY_MAP =
40+
new HashMap<String, Priority>() {{
41+
put("low", Priority.LOW);
42+
put("normal", Priority.NORMAL);
43+
put("high", Priority.HIGH);
44+
}};
45+
46+
static Priority priority(ReadableMap source) {
47+
// Get the priority prop.
48+
String priorityProp = "normal";
49+
try {
50+
priorityProp = source.getString("priority");
51+
} catch (Exception e) {
52+
// Noop.
53+
}
54+
final Priority priority = REACT_PRIORITY_MAP.get(priorityProp);
55+
return priority;
56+
}
57+
58+
private static Map<String, ImageView.ScaleType> REACT_RESIZE_MODE_MAP =
59+
new HashMap<String, ImageView.ScaleType>() {{
60+
put("contain", ScaleType.FIT_CENTER);
61+
put("cover", ScaleType.CENTER_CROP);
62+
put("stretch", ScaleType.FIT_XY);
63+
put("center", ScaleType.CENTER);
64+
}};
65+
66+
public static ScaleType scaleType(String resizeMode) {
67+
if (resizeMode == null) resizeMode = "contain";
68+
final ImageView.ScaleType scaleType = REACT_RESIZE_MODE_MAP.get(resizeMode);
69+
return scaleType;
70+
}
71+
}

android/src/main/java/com/dylanvann/fastimage/FastImageViewManager.java

Lines changed: 11 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,17 @@
44
import android.graphics.drawable.ColorDrawable;
55
import android.graphics.drawable.Drawable;
66
import android.widget.ImageView;
7-
import android.widget.ImageView.ScaleType;
87

9-
import com.bumptech.glide.DrawableRequestBuilder;
10-
import com.bumptech.glide.DrawableTypeRequest;
118
import com.bumptech.glide.Glide;
129
import com.bumptech.glide.Priority;
13-
import com.bumptech.glide.RequestManager;
1410
import com.bumptech.glide.load.data.DataFetcher;
1511
import com.bumptech.glide.load.model.GlideUrl;
16-
import com.bumptech.glide.load.model.LazyHeaders;
1712
import com.bumptech.glide.load.model.stream.StreamModelLoader;
1813
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
1914
import com.bumptech.glide.request.RequestListener;
2015
import com.bumptech.glide.request.target.ImageViewTarget;
2116
import com.bumptech.glide.request.target.Target;
22-
import com.bumptech.glide.signature.StringSignature;
23-
import com.facebook.react.bridge.NoSuchKeyException;
2417
import com.facebook.react.bridge.ReadableMap;
25-
import com.facebook.react.bridge.ReadableMapKeySetIterator;
2618
import com.facebook.react.bridge.WritableMap;
2719
import com.facebook.react.bridge.WritableNativeMap;
2820
import com.facebook.react.common.MapBuilder;
@@ -33,9 +25,7 @@
3325

3426
import java.io.IOException;
3527
import java.io.InputStream;
36-
import java.util.HashMap;
3728
import java.util.Map;
38-
import java.util.UUID;
3929

4030
import javax.annotation.Nullable;
4131

@@ -49,21 +39,6 @@ class FastImageViewManager extends SimpleViewManager<ImageView> {
4939

5040
private static Drawable TRANSPARENT_DRAWABLE = new ColorDrawable(Color.TRANSPARENT);
5141

52-
private static Map<String, Priority> REACT_PRIORITY_MAP =
53-
new HashMap<String, Priority>() {{
54-
put("low", Priority.LOW);
55-
put("normal", Priority.NORMAL);
56-
put("high", Priority.HIGH);
57-
}};
58-
59-
private static Map<String, ImageView.ScaleType> REACT_RESIZE_MODE_MAP =
60-
new HashMap<String, ImageView.ScaleType>() {{
61-
put("contain", ScaleType.FIT_CENTER);
62-
put("cover", ScaleType.CENTER_CROP);
63-
put("stretch", ScaleType.FIT_XY);
64-
put("center", ScaleType.CENTER);
65-
}};
66-
6742
@Override
6843
public String getName() {
6944
return REACT_CLASS;
@@ -125,51 +100,27 @@ public void setSrc(ImageView view, @Nullable ReadableMap source) {
125100
return;
126101
}
127102

128-
final String uriProp = source.getString("uri");
129-
130-
// Get the headers prop and add to glideUrl.
131-
GlideUrl glideUrl;
132-
try {
133-
final ReadableMap headersMap = source.getMap("headers");
134-
ReadableMapKeySetIterator headersIterator = headersMap.keySetIterator();
135-
LazyHeaders.Builder headersBuilder = new LazyHeaders.Builder();
136-
while (headersIterator.hasNextKey()) {
137-
String key = headersIterator.nextKey();
138-
String value = headersMap.getString(key);
139-
headersBuilder.addHeader(key, value);
140-
}
141-
LazyHeaders headers = headersBuilder.build();
142-
glideUrl = new GlideUrl(uriProp, headers);
143-
} catch (NoSuchKeyException e) {
144-
// If there is no headers object.
145-
glideUrl = new GlideUrl(uriProp);
146-
}
103+
// Get the GlideUrl which contains header info.
104+
final GlideUrl glideUrl = FastImageViewConverter.glideUrl(source);
147105

148-
// Get the priority prop.
149-
String priorityProp = "normal";
150-
try {
151-
priorityProp = source.getString("priority");
152-
} catch (Exception e) {
153-
// Noop.
154-
}
155-
final Priority priority = REACT_PRIORITY_MAP.get(priorityProp);
106+
// Get priority.
107+
final Priority priority = FastImageViewConverter.priority(source);
156108

157109
// Cancel existing request.
158110
Glide.clear(view);
159111

160112
Glide
161-
.with(view.getContext())
162-
.load(glideUrl)
163-
.priority(priority)
164-
.placeholder(TRANSPARENT_DRAWABLE)
165-
.listener(LISTENER)
166-
.into(view);
113+
.with(view.getContext())
114+
.load(glideUrl)
115+
.priority(priority)
116+
.placeholder(TRANSPARENT_DRAWABLE)
117+
.listener(LISTENER)
118+
.into(view);
167119
}
168120

169121
@ReactProp(name = "resizeMode")
170122
public void setResizeMode(ImageView view, String resizeMode) {
171-
if (resizeMode == null) resizeMode = "contain";
172-
final ImageView.ScaleType scaleType = REACT_RESIZE_MODE_MAP.get(resizeMode);
123+
final ImageView.ScaleType scaleType = FastImageViewConverter.scaleType(resizeMode);
173124
view.setScaleType(scaleType);
174125
}
175126

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,54 @@
11
package com.dylanvann.fastimage;
22

33
import android.app.Activity;
4+
import android.graphics.Color;
5+
import android.graphics.drawable.ColorDrawable;
6+
import android.graphics.drawable.Drawable;
47

58
import com.bumptech.glide.Glide;
9+
import com.bumptech.glide.Priority;
610
import com.bumptech.glide.load.engine.DiskCacheStrategy;
7-
8-
import com.facebook.react.bridge.ReadableArray;
11+
import com.bumptech.glide.load.model.GlideUrl;
912
import com.facebook.react.bridge.ReactApplicationContext;
1013
import com.facebook.react.bridge.ReactContextBaseJavaModule;
1114
import com.facebook.react.bridge.ReactMethod;
15+
import com.facebook.react.bridge.ReadableArray;
16+
import com.facebook.react.bridge.ReadableMap;
17+
18+
class FastImageViewModule extends ReactContextBaseJavaModule {
19+
20+
private static final String REACT_CLASS = "FastImageView";
21+
22+
FastImageViewModule(ReactApplicationContext reactContext) {
23+
super(reactContext);
24+
}
25+
26+
@Override
27+
public String getName() {
28+
return REACT_CLASS;
29+
}
30+
31+
private static Drawable TRANSPARENT_DRAWABLE = new ColorDrawable(Color.TRANSPARENT);
1232

13-
public class FastImageViewModule extends ReactContextBaseJavaModule {
14-
public FastImageViewModule(ReactApplicationContext reactContext) {
15-
super(reactContext);
16-
}
17-
18-
@Override
19-
public String getName() {
20-
return "FastImageView";
21-
}
22-
23-
@ReactMethod
24-
public void prefetch(final ReadableArray urls) {
25-
final Activity activity = getCurrentActivity();
26-
activity.runOnUiThread(new Runnable() {
27-
@Override
28-
public void run() {
29-
for (int i = 0; i < urls.size(); i++) {
30-
Glide
31-
.with(activity.getApplicationContext())
32-
.load(urls.getString(i))
33-
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
34-
.preload();
35-
}
36-
}
37-
});
38-
}
33+
@ReactMethod
34+
public void preload(final ReadableArray sources) {
35+
final Activity activity = getCurrentActivity();
36+
activity.runOnUiThread(new Runnable() {
37+
@Override
38+
public void run() {
39+
for (int i = 0; i < sources.size(); i++) {
40+
final ReadableMap source = sources.getMap(i);
41+
final GlideUrl glideUrl = FastImageViewConverter.glideUrl(source);
42+
final Priority priority = FastImageViewConverter.priority(source);
43+
Glide
44+
.with(activity.getApplicationContext())
45+
.load(glideUrl)
46+
.priority(priority)
47+
.placeholder(TRANSPARENT_DRAWABLE)
48+
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
49+
.preload();
50+
}
51+
}
52+
});
53+
}
3954
}

0 commit comments

Comments
 (0)