mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 11:01:21 +08:00
feat(image-cache): expose onError callback (#6458)
* feat(Cache): better error handling * refactor(image-cache): add `error` parameter to `_onDownloadError` Add DownloadError interface. * refactor(image-cache): updates for iOS Use arrow functions. Remove an unnecessary `trace.write(). * refactor(image-cache): updates for Android Update Android `constructor()`. Move `key` and `image` check to `set()`. Update `trace.write`. * fix(image-cache): onError handling
This commit is contained in:

committed by
Vasil Chimev

parent
134b033b77
commit
3481e6f33f
@ -52,7 +52,10 @@ function ensureCompleteCallback() {
|
|||||||
onComplete: function (result: any, context: any) {
|
onComplete: function (result: any, context: any) {
|
||||||
// as a context we will receive the id of the request
|
// as a context we will receive the id of the request
|
||||||
onRequestComplete(context, result);
|
onRequestComplete(context, result);
|
||||||
}
|
},
|
||||||
|
onError: function (error: string, context: any) {
|
||||||
|
onRequestError(error, context);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,6 +151,14 @@ function onRequestComplete(requestId: number, result: org.nativescript.widgets.A
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onRequestError(error: string, requestId: number) {
|
||||||
|
var callbacks = pendingRequests[requestId];
|
||||||
|
delete pendingRequests[requestId];
|
||||||
|
if (callbacks) {
|
||||||
|
callbacks.rejectCallback(new Error(error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function buildJavaOptions(options: http.HttpRequestOptions) {
|
function buildJavaOptions(options: http.HttpRequestOptions) {
|
||||||
if (typeof options.url !== "string") {
|
if (typeof options.url !== "string") {
|
||||||
throw new Error("Http request must provide a valid url.");
|
throw new Error("Http request must provide a valid url.");
|
||||||
|
@ -6,10 +6,12 @@ export interface DownloadRequest {
|
|||||||
url: string;
|
url: string;
|
||||||
key: string;
|
key: string;
|
||||||
completed?: (image: any, key: string) => void;
|
completed?: (image: any, key: string) => void;
|
||||||
|
error?: (key: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Cache extends observable.Observable implements definition.Cache {
|
export class Cache extends observable.Observable implements definition.Cache {
|
||||||
public static downloadedEvent = "downloaded";
|
public static downloadedEvent = "downloaded";
|
||||||
|
public static downloadErrorEvent = "downloadError";
|
||||||
|
|
||||||
public placeholder: imageSource.ImageSource;
|
public placeholder: imageSource.ImageSource;
|
||||||
public maxRequests = 5;
|
public maxRequests = 5;
|
||||||
@ -93,6 +95,20 @@ export class Cache extends observable.Observable implements definition.Cache {
|
|||||||
else {
|
else {
|
||||||
existingRequest.completed = newRequest.completed;
|
existingRequest.completed = newRequest.completed;
|
||||||
}
|
}
|
||||||
|
if (existingRequest.error) {
|
||||||
|
if (newRequest.error) {
|
||||||
|
var existingError = existingRequest.error;
|
||||||
|
var stackError = function (key: string) {
|
||||||
|
existingError(key);
|
||||||
|
newRequest.error(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
existingRequest.error = stackError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
existingRequest.error = newRequest.error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public get(key: string): any {
|
public get(key: string): any {
|
||||||
@ -125,10 +141,7 @@ export class Cache extends observable.Observable implements definition.Cache {
|
|||||||
public _onDownloadCompleted(key: string, image: any) {
|
public _onDownloadCompleted(key: string, image: any) {
|
||||||
var request = <DownloadRequest>this._pendingDownloads[key];
|
var request = <DownloadRequest>this._pendingDownloads[key];
|
||||||
|
|
||||||
if (request.key && image) {
|
this.set(request.key, image);
|
||||||
this.set(request.key, image);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._currentDownloads--;
|
this._currentDownloads--;
|
||||||
|
|
||||||
if (request.completed) {
|
if (request.completed) {
|
||||||
@ -149,6 +162,28 @@ export class Cache extends observable.Observable implements definition.Cache {
|
|||||||
this._updateQueue();
|
this._updateQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public _onDownloadError(key: string, err: Error) {
|
||||||
|
var request = <DownloadRequest>this._pendingDownloads[key];
|
||||||
|
this._currentDownloads--;
|
||||||
|
|
||||||
|
if (request.error) {
|
||||||
|
request.error(request.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.hasListeners(Cache.downloadErrorEvent)) {
|
||||||
|
this.notify({
|
||||||
|
eventName: Cache.downloadErrorEvent,
|
||||||
|
object: this,
|
||||||
|
key: key,
|
||||||
|
error: err
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
delete this._pendingDownloads[request.key];
|
||||||
|
|
||||||
|
this._updateQueue();
|
||||||
|
}
|
||||||
|
|
||||||
private _shouldDownload(request: definition.DownloadRequest, onTop: boolean): boolean {
|
private _shouldDownload(request: definition.DownloadRequest, onTop: boolean): boolean {
|
||||||
if (this.get(request.key) || request.key in this._pendingDownloads) {
|
if (this.get(request.key) || request.key in this._pendingDownloads) {
|
||||||
return false;
|
return false;
|
||||||
@ -185,6 +220,7 @@ export class Cache extends observable.Observable implements definition.Cache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
export interface Cache {
|
export interface Cache {
|
||||||
on(eventNames: string, callback: (args: observable.EventData) => void , thisArg?: any);
|
on(eventNames: string, callback: (args: observable.EventData) => void, thisArg?: any);
|
||||||
on(event: "downloaded", callback: (args: definition.DownloadedData) => void , thisArg?: any);
|
on(event: "downloaded", callback: (args: definition.DownloadedData) => void, thisArg?: any);
|
||||||
|
on(event: "downloadError", callback: (args: definition.DownloadError) => void, thisArg?: any);
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import * as common from "./image-cache-common";
|
import * as common from "./image-cache-common";
|
||||||
|
import * as trace from "../../trace";
|
||||||
|
|
||||||
var LruBitmapCacheClass;
|
var LruBitmapCacheClass;
|
||||||
function ensureLruBitmapCacheClass() {
|
function ensureLruBitmapCacheClass() {
|
||||||
@ -45,7 +46,17 @@ export class Cache extends common.Cache {
|
|||||||
onComplete: function (result: any, context: any) {
|
onComplete: function (result: any, context: any) {
|
||||||
var instance = that.get();
|
var instance = that.get();
|
||||||
if (instance) {
|
if (instance) {
|
||||||
instance._onDownloadCompleted(context, result)
|
if (result) {
|
||||||
|
instance._onDownloadCompleted(context, result);
|
||||||
|
} else {
|
||||||
|
instance._onDownloadError(context, new Error("No result in CompletionCallback"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onError: function (err: string, context: any) {
|
||||||
|
var instance = that.get();
|
||||||
|
if (instance) {
|
||||||
|
instance._onDownloadError(context, new Error(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -61,7 +72,13 @@ export class Cache extends common.Cache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public set(key: string, image: any): void {
|
public set(key: string, image: any): void {
|
||||||
this._cache.put(key, image);
|
try {
|
||||||
|
if (key && image) {
|
||||||
|
this._cache.put(key, image);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
trace.write("Cache set error: " + err, trace.categories.Error, trace.messageType.error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public remove(key: string): void {
|
public remove(key: string): void {
|
||||||
|
36
tns-core-modules/ui/image-cache/image-cache.d.ts
vendored
36
tns-core-modules/ui/image-cache/image-cache.d.ts
vendored
@ -22,6 +22,10 @@ export interface DownloadRequest {
|
|||||||
* An optional function to be called when the download is complete.
|
* An optional function to be called when the download is complete.
|
||||||
*/
|
*/
|
||||||
completed?: (image: any, key: string) => void;
|
completed?: (image: any, key: string) => void;
|
||||||
|
/**
|
||||||
|
* An optional function to be called if the download errors.
|
||||||
|
*/
|
||||||
|
error?: (key: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,6 +36,10 @@ export class Cache extends observable.Observable {
|
|||||||
* String value used when hooking to downloaded event.
|
* String value used when hooking to downloaded event.
|
||||||
*/
|
*/
|
||||||
public static downloadedEvent: string;
|
public static downloadedEvent: string;
|
||||||
|
/**
|
||||||
|
* String value used when hooking to download error event.
|
||||||
|
*/
|
||||||
|
public static downloadErrorEvent: string;
|
||||||
/**
|
/**
|
||||||
* The image to be used to notify for a pending download request - e.g. loading indicator.
|
* The image to be used to notify for a pending download request - e.g. loading indicator.
|
||||||
*/
|
*/
|
||||||
@ -82,12 +90,17 @@ export class Cache extends observable.Observable {
|
|||||||
* @param callback - Callback function which will be executed when event is raised.
|
* @param callback - Callback function which will be executed when event is raised.
|
||||||
* @param thisArg - An optional parameter which will be used as `this` context for callback execution.
|
* @param thisArg - An optional parameter which will be used as `this` context for callback execution.
|
||||||
*/
|
*/
|
||||||
on(eventNames: string, callback: (args: observable.EventData) => void , thisArg?: any);
|
on(eventNames: string, callback: (args: observable.EventData) => void, thisArg?: any);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Raised when the image has been downloaded.
|
* Raised when the image has been downloaded.
|
||||||
*/
|
*/
|
||||||
on(event: "downloaded", callback: (args: DownloadedData) => void , thisArg?: any);
|
on(event: "downloaded", callback: (args: DownloadedData) => void, thisArg?: any);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raised if the image download errors.
|
||||||
|
*/
|
||||||
|
on(event: "downloadError", callback: (args: DownloadError) => void, thisArg?: any);
|
||||||
|
|
||||||
//@private
|
//@private
|
||||||
/**
|
/**
|
||||||
@ -99,6 +112,11 @@ export class Cache extends observable.Observable {
|
|||||||
*/
|
*/
|
||||||
_onDownloadCompleted(key: string, image: any);
|
_onDownloadCompleted(key: string, image: any);
|
||||||
//@endprivate
|
//@endprivate
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_onDownloadError(key: string, err: Error);
|
||||||
|
//@endprivate
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -114,3 +132,17 @@ export interface DownloadedData extends observable.EventData {
|
|||||||
*/
|
*/
|
||||||
image: imageSource.ImageSource;
|
image: imageSource.ImageSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides data for download error.
|
||||||
|
*/
|
||||||
|
export interface DownloadError extends observable.EventData {
|
||||||
|
/**
|
||||||
|
* A string indentifier of the cached image.
|
||||||
|
*/
|
||||||
|
key: string;
|
||||||
|
/**
|
||||||
|
* Gets the error.
|
||||||
|
*/
|
||||||
|
error: Error;
|
||||||
|
}
|
||||||
|
@ -83,11 +83,16 @@ export class Cache extends common.Cache {
|
|||||||
public _downloadCore(request: common.DownloadRequest) {
|
public _downloadCore(request: common.DownloadRequest) {
|
||||||
ensureHttpRequest();
|
ensureHttpRequest();
|
||||||
|
|
||||||
var that = this;
|
|
||||||
httpRequest.request({ url: request.url, method: "GET" })
|
httpRequest.request({ url: request.url, method: "GET" })
|
||||||
.then(response => {
|
.then((response) => {
|
||||||
var image = UIImage.alloc().initWithData(response.content.raw);
|
try {
|
||||||
that._onDownloadCompleted(request.key, image);
|
var image = UIImage.alloc().initWithData(response.content.raw);
|
||||||
|
this._onDownloadCompleted(request.key, image);
|
||||||
|
} catch (err) {
|
||||||
|
this._onDownloadError(request.key, err);
|
||||||
|
}
|
||||||
|
}, (err) => {
|
||||||
|
this._onDownloadError(request.key, err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,10 +5,12 @@
|
|||||||
export class CompleteCallback {
|
export class CompleteCallback {
|
||||||
constructor(implementation: ICompleteCallback);
|
constructor(implementation: ICompleteCallback);
|
||||||
onComplete(result: Object, context: Object): void;
|
onComplete(result: Object, context: Object): void;
|
||||||
|
onError(error: string, context: Object): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICompleteCallback {
|
export interface ICompleteCallback {
|
||||||
onComplete(result: Object, context: Object): void;
|
onComplete(result: Object, context: Object): void;
|
||||||
|
onError(error: string, context: Object): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export module Image {
|
export module Image {
|
||||||
|
Reference in New Issue
Block a user