//------------------------------------------------------------------------------
// Copyright (c) 2012 Microsoft Corporation. All rights reserved.
//
// Description: See the class level JavaDoc comments.
//------------------------------------------------------------------------------
package com.microsoft.live;
import java.util.ArrayList;
import android.os.AsyncTask;
import com.microsoft.live.EntityEnclosingApiRequest.UploadProgressListener;
/**
* ApiRequestAsync performs an async ApiRequest by subclassing AsyncTask
* and executing the request inside of doInBackground and giving the
* response to the appropriate listener on the main/UI thread.
*/
class ApiRequestAsync<ResponseType> extends AsyncTask<Void, Long, Runnable>
implements UploadProgressListener {
public interface Observer<ResponseType> {
public void onComplete(ResponseType result);
public void onError(LiveOperationException e);
}
public interface ProgressObserver {
public void onProgress(Long... values);
}
private class OnCompleteRunnable implements Runnable {
private final ResponseType response;
public OnCompleteRunnable(ResponseType response) {
assert response != null;
this.response = response;
}
@Override
public void run() {
for (Observer<ResponseType> observer : observers) {
observer.onComplete(this.response);
}
}
}
private class OnErrorRunnable implements Runnable {
private final LiveOperationException exception;
public OnErrorRunnable(LiveOperationException exception) {
assert exception != null;
this.exception = exception;
}
@Override
public void run() {
for (Observer<ResponseType> observer : observers) {
observer.onError(this.exception);
}
}
}
/**
* Static constructor. Prefer to use this over the normal constructor, because
* this will infer the generic types, and be less verbose.
*
* @param request
* @return a new ApiRequestAsync
*/
public static <T> ApiRequestAsync<T> newInstance(ApiRequest<T> request) {
return new ApiRequestAsync<T>(request);
}
/**
* Static constructor. Prefer to use this over the normal constructor, because
* this will infer the generic types, and be less verbose.
*
* @param request
* @return a new ApiRequestAsync
*/
public static <T> ApiRequestAsync<T> newInstance(EntityEnclosingApiRequest<T> request) {
return new ApiRequestAsync<T>(request);
}
private final ArrayList<Observer<ResponseType>> observers;
private final ArrayList<ProgressObserver> progressListeners;
private final ApiRequest<ResponseType> request;
{
this.observers = new ArrayList<Observer<ResponseType>>();
this.progressListeners = new ArrayList<ProgressObserver>();
}
/**
* Constructs a new ApiRequestAsync object and initializes its member variables.
*
* This method attaches a progress observer to the EntityEnclosingApiRequest, and call
* publicProgress when ever there is an on progress event.
*
* @param request
*/
public ApiRequestAsync(EntityEnclosingApiRequest<ResponseType> request) {
assert request != null;
// Whenever the request has upload progress we need to publish the progress, so
// listen to progress events.
request.addListener(this);
this.request = request;
}
/**
* Constructs a new ApiRequestAsync object and initializes its member variables.
*
* @param operation to launch in an asynchronous manner
*/
public ApiRequestAsync(ApiRequest<ResponseType> request) {
assert request != null;
this.request = request;
}
public boolean addObserver(Observer<ResponseType> observer) {
return this.observers.add(observer);
}
public boolean addProgressObserver(ProgressObserver observer) {
return this.progressListeners.add(observer);
}
@Override
public void onProgress(long totalBytes, long numBytesWritten) {
publishProgress(Long.valueOf(totalBytes), Long.valueOf(numBytesWritten));
}
public boolean removeObserver(Observer<ResponseType> observer) {
return this.observers.remove(observer);
}
public boolean removeProgressObserver(ProgressObserver observer) {
return this.progressListeners.remove(observer);
}
@Override
protected Runnable doInBackground(Void... args) {
ResponseType response;
try {
response = this.request.execute();
} catch (LiveOperationException e) {
return new OnErrorRunnable(e);
}
return new OnCompleteRunnable(response);
}
@Override
protected void onPostExecute(Runnable result) {
super.onPostExecute(result);
result.run();
}
@Override
protected void onProgressUpdate(Long... values) {
for (ProgressObserver listener : this.progressListeners) {
listener.onProgress(values);
}
}
}