package roboguice.util;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import android.os.Handler;
import android.util.Log;
/**
* A class similar but unrelated to android's {@link android.os.AsyncTask}.
*
* Unlike AsyncTask, this class properly propagates exceptions.
*
* If you're familiar with AsyncTask and are looking for {@link android.os.AsyncTask#doInBackground(Object[])},
* we've named it {@link #call()} here to conform with java 1.5's {@link java.util.concurrent.Callable} interface.
*
* Current limitations: does not yet handle progress, although it shouldn't be
* hard to add.
*
* If using your own executor, you must call future() to get a runnable you can execute.
*
* @param <ResultT>
*/
@Deprecated
public abstract class SafeAsyncTask<ResultT> implements Callable<ResultT> {
public static final int DEFAULT_POOL_SIZE = 25;
protected static final Executor DEFAULT_EXECUTOR = Executors.newFixedThreadPool(DEFAULT_POOL_SIZE);
protected Handler handler;
protected Executor executor;
protected FutureTask<Void> future;
/**
* Sets executor to Executors.newFixedThreadPool(DEFAULT_POOL_SIZE) and
* Handler to new Handler()
*/
public SafeAsyncTask() {
this.executor = DEFAULT_EXECUTOR;
}
/**
* Sets executor to Executors.newFixedThreadPool(DEFAULT_POOL_SIZE)
*/
public SafeAsyncTask( Handler handler ) {
this.handler = handler;
this.executor = DEFAULT_EXECUTOR;
}
/**
* Sets Handler to new Handler()
*/
public SafeAsyncTask( Executor executor ) {
this.executor = executor;
}
public SafeAsyncTask( Handler handler, Executor executor ) {
this.handler = handler;
this.executor = executor;
}
public FutureTask<Void> future() {
future = new FutureTask<Void>( newTask(), null );
return future;
}
public SafeAsyncTask<ResultT> executor( Executor executor ) {
this.executor = executor;
return this;
}
public Executor executor() {
return executor;
}
public SafeAsyncTask<ResultT> handler( Handler handler ) {
this.handler = handler;
return this;
}
public Handler handler() {
return handler;
}
public void execute() {
final StackTraceElement[] launchLocation = Ln.isDebugEnabled() ? Thread.currentThread().getStackTrace() : null;
execute(launchLocation);
}
protected void execute( StackTraceElement[] launchLocation ) {
executor.execute( future() );
}
public boolean cancel( boolean mayInterruptIfRunning ) {
if( future==null )
throw new UnsupportedOperationException("You cannot cancel this task before calling future()");
return future.cancel(mayInterruptIfRunning);
}
public boolean isCancelled(){
return future == null ? false : future.isCancelled();
}
/**
* @throws Exception, captured on passed to onException() if present.
*/
protected void onPreExecute() throws Exception {}
/**
* @param t the result of {@link #call()}
* @throws Exception, captured on passed to onException() if present.
*/
@SuppressWarnings({"UnusedDeclaration"})
protected void onSuccess( ResultT t ) throws Exception {}
/**
* Called when the thread has been interrupted, likely because
* the task was canceled.
*
* By default, calls {@link #onException(Exception)}, but this method
* may be overridden to handle interruptions differently than other
* exceptions.
*
* @param e an InterruptedException or InterruptedIOException
*/
protected void onInterrupted( Exception e ) {
onException(e);
}
/**
* Logs the exception as an Error by default, but this method may
* be overridden by subclasses.
*
* @param e the exception thrown from {@link #onPreExecute()}, {@link #call()}, or {@link #onSuccess(Object)}
* @throws RuntimeException, ignored
*/
protected void onException( Exception e ) throws RuntimeException {
onThrowable(e);
}
protected void onThrowable( Throwable t ) throws RuntimeException {
Log.e("roboguice", "Throwable caught during background processing", t);
}
/**
* @throws RuntimeException, ignored
*/
protected void onFinally() throws RuntimeException {}
protected Runnable newTask() {
return new SafeAsyncTaskAndroidCallable();
}
public class SafeAsyncTaskAndroidCallable extends AndroidCallable<ResultT> {
@Override
public ResultT doInBackground() throws Exception {
return call();
}
@Override
public void onException(Exception e) {
SafeAsyncTask.this.onException(e);
}
@Override
public void onFinally() {
SafeAsyncTask.this.onFinally();
}
@Override
public void onPreCall() {
try {
SafeAsyncTask.this.onPreExecute();
} catch (Exception e) {
throw new RuntimeException(e); // This will halt the UI thread
}
}
@Override
public void onSuccess(ResultT result) {
try {
SafeAsyncTask.this.onSuccess(result);
} catch (Exception e) {
throw new RuntimeException(e); //This will halt the UI thread
}
}
}
}