network congestion improvements (part 1)

Reviewed By: dmmiller

Differential Revision: D3553287

fbshipit-source-id: ea33bb7d929cbc0229bfe8537c3a4fc58fe9691e
This commit is contained in:
Olivier Notteghem 2016-07-18 12:07:29 -07:00 committed by Facebook Github Bot 2
parent 40c06b99a2
commit e27c1495bd
2 changed files with 85 additions and 5 deletions

View File

@ -34,6 +34,11 @@ var {
ImageLoader,
} = NativeModules;
let _requestId = 1;
function generateRequestId() {
return _requestId++;
}
/**
* <Image> - A react component for displaying different types of images,
* including network images, static resources, temporary local images, and
@ -148,8 +153,17 @@ var Image = React.createClass({
* Prefetches a remote image for later use by downloading it to the disk
* cache
*/
prefetch(url: string) {
return ImageLoader.prefetchImage(url);
prefetch(url: string, callback: ?Function) {
const requestId = generateRequestId();
callback && callback(requestId);
return ImageLoader.prefetchImage(url, requestId);
},
/**
* Abort prefetch request
*/
abortPrefetch(requestId: number) {
ImageLoader.abortRequest(requestId);
},
},

View File

@ -9,7 +9,10 @@
package com.facebook.react.modules.image;
import javax.annotation.Nullable;
import android.net.Uri;
import android.util.SparseArray;
import com.facebook.common.executors.CallerThreadExecutor;
import com.facebook.common.references.CloseableReference;
@ -21,19 +24,23 @@ import com.facebook.imagepipeline.image.CloseableImage;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableMap;
public class ImageLoaderModule extends ReactContextBaseJavaModule {
public class ImageLoaderModule extends ReactContextBaseJavaModule implements
LifecycleEventListener {
private static final String ERROR_INVALID_URI = "E_INVALID_URI";
private static final String ERROR_PREFETCH_FAILURE = "E_PREFETCH_FAILURE";
private static final String ERROR_GET_SIZE_FAILURE = "E_GET_SIZE_FAILURE";
private final Object mCallerContext;
private final Object mEnqueuedRequestMonitor = new Object();
private final SparseArray<DataSource<Void>> mEnqueuedRequests = new SparseArray<>();
public ImageLoaderModule(ReactApplicationContext reactContext) {
super(reactContext);
@ -50,9 +57,16 @@ public class ImageLoaderModule extends ReactContextBaseJavaModule {
return "ImageLoader";
}
/**
* Fetch the width and height of the given image.
*
* @param uriString the URI of the remote image to prefetch
* @param promise the promise that is fulfilled when the image is successfully prefetched
* or rejected when there is an error
*/
@ReactMethod
public void getSize(
String uriString,
final String uriString,
final Promise promise) {
if (uriString == null || uriString.isEmpty()) {
promise.reject(ERROR_INVALID_URI, "Cannot get the size of an image for an empty URI");
@ -105,11 +119,16 @@ public class ImageLoaderModule extends ReactContextBaseJavaModule {
* Prefetches the given image to the Fresco image disk cache.
*
* @param uriString the URI of the remote image to prefetch
* @param requestId the client-supplied request ID used to identify this request
* @param promise the promise that is fulfilled when the image is successfully prefetched
* or rejected when there is an error
*/
@ReactMethod
public void prefetchImage(String uriString, final Promise promise) {
public void prefetchImage(
final String uriString,
final int requestId,
final Promise promise)
{
if (uriString == null || uriString.isEmpty()) {
promise.reject(ERROR_INVALID_URI, "Cannot prefetch an image for an empty URI");
return;
@ -127,6 +146,7 @@ public class ImageLoaderModule extends ReactContextBaseJavaModule {
return;
}
try {
removeRequest(requestId);
promise.resolve(true);
} finally {
dataSource.close();
@ -136,12 +156,58 @@ public class ImageLoaderModule extends ReactContextBaseJavaModule {
@Override
protected void onFailureImpl(DataSource<Void> dataSource) {
try {
removeRequest(requestId);
promise.reject(ERROR_PREFETCH_FAILURE, dataSource.getFailureCause());
} finally {
dataSource.close();
}
}
};
registerRequest(requestId, prefetchSource);
prefetchSource.subscribe(prefetchSubscriber, CallerThreadExecutor.getInstance());
}
@ReactMethod
public void abortRequest(final int requestId) {
DataSource<Void> request = removeRequest(requestId);
if (request != null) {
request.close();
}
}
private void registerRequest(int requestId, DataSource<Void> request) {
synchronized (mEnqueuedRequestMonitor) {
mEnqueuedRequests.put(requestId, request);
}
}
private @Nullable DataSource<Void> removeRequest(int requestId) {
synchronized (mEnqueuedRequestMonitor) {
DataSource<Void> request = mEnqueuedRequests.get(requestId);
mEnqueuedRequests.remove(requestId);
return request;
}
}
@Override
public void onHostResume() {
}
@Override
public void onHostPause() {
}
@Override
public void onHostDestroy() {
// cancel all requests
synchronized (mEnqueuedRequestMonitor) {
for (int i = 0, size = mEnqueuedRequests.size(); i < size; i++) {
@Nullable DataSource<Void> enqueuedRequest = mEnqueuedRequests.valueAt(i);
if (enqueuedRequest != null) {
enqueuedRequest.close();
}
}
mEnqueuedRequests.clear();
}
}
}