package com.example.gradlebuildsimple;
import java.io.InterruptedIOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
/**
* 自定义AsyncTask:
* 异步任务异常处理
* @date 2013-11-4下午5:43:32
*/
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 StackTraceElement[] launchLocation;
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());
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() {
execute(Thread.currentThread().getStackTrace());
}
protected void execute(StackTraceElement[] launchLocation) {
this.launchLocation = 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);
}
/**
* @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.
* <p/>
* 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 Task<ResultT> newTask() {
return new Task<ResultT>(this);
}
public static class Task<ResultT> implements Callable<Void> {
protected SafeAsyncTask<ResultT> parent;
protected Handler handler;
public Task(SafeAsyncTask<ResultT> parent) {
this.parent = parent;
this.handler = parent.handler != null ? parent.handler : new Handler(Looper.getMainLooper());
}
public Void call() throws Exception {
try {
doPreExecute();
doSuccess(doCall());
} catch (final Exception e) {
try {
doException(e);
} catch (Exception f) {
// logged but ignored
Log.e("BACKGROUND_TASK", "Exception in", f);
}
} catch (final Throwable t) {
try {
doThrowable(t);
} catch (Exception f) {
// logged but ignored
Log.e("BACKGROUND_TASK", "Exception in", f);
}
} finally {
doFinally();
}
return null;
}
protected void doPreExecute() throws Exception {
postToUiThreadAndWait(new Callable<Object>() {
public Object call() throws Exception {
parent.onPreExecute();
return null;
}
});
}
protected ResultT doCall() throws Exception {
return parent.call();
}
protected void doSuccess(final ResultT r) throws Exception {
postToUiThreadAndWait(new Callable<Object>() {
public Object call() throws Exception {
parent.onSuccess(r);
return null;
}
});
}
protected void doException(final Exception e) throws Exception {
if (parent.launchLocation != null) {
final ArrayList<StackTraceElement> stack = new ArrayList<StackTraceElement>(Arrays.asList(e.getStackTrace()));
stack.addAll(Arrays.asList(parent.launchLocation));
e.setStackTrace(stack.toArray(new StackTraceElement[stack.size()]));
}
postToUiThreadAndWait(new Callable<Object>() {
public Object call() throws Exception {
if (e instanceof InterruptedException || e instanceof InterruptedIOException) parent.onInterrupted(e);
else parent.onException(e);
return null;
}
});
}
protected void doThrowable(final Throwable e) throws Exception {
if (parent.launchLocation != null) {
final ArrayList<StackTraceElement> stack = new ArrayList<StackTraceElement>(Arrays.asList(e.getStackTrace()));
stack.addAll(Arrays.asList(parent.launchLocation));
e.setStackTrace(stack.toArray(new StackTraceElement[stack.size()]));
}
postToUiThreadAndWait(new Callable<Object>() {
public Object call() throws Exception {
parent.onThrowable(e);
return null;
}
});
}
protected void doFinally() throws Exception {
postToUiThreadAndWait(new Callable<Object>() {
public Object call() throws Exception {
parent.onFinally();
return null;
}
});
}
/**
* Posts the specified runnable to the UI thread using a handler,
* and waits for operation to finish. If there's an exception,
* it captures it and rethrows it.
*
* @param c the callable to post
* @throws Exception on error
*/
protected void postToUiThreadAndWait(final Callable c) throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
final Exception[] exceptions = new Exception[1];
// Execute onSuccess in the UI thread, but wait
// for it to complete.
// If it throws an exception, capture that exception
// and rethrow it later.
handler.post(new Runnable() {
public void run() {
try {
c.call();
} catch (Exception e) {
exceptions[0] = e;
} finally {
latch.countDown();
}
}
});
// Wait for onSuccess to finish
latch.await();
if (exceptions[0] != null) throw exceptions[0];
}
}
}
======================================================================================================================================================================================
具体用法如下和AsyncTask类似:
private class CountryAsyncTask extends SafeAsyncTask<List<String>> {
private boolean showLoading;
public CountryAsyncTask(boolean showLoading) {
this.showLoading = showLoading;
}
@Override
protected void onPreExecute() throws Exception {
super.onPreExecute();
if(showLoading) {
loadingDialog.show();
}
}
@Override
public List<String> call() throws Exception {
List<String> result = null;
switch(pager) {
case 0:
result = firstList;
break;
case 1:
result = secondList;
break;
case 2:
result = thirdList;
break;
}
Thread.sleep(3000);
return result;
}
@Override
protected void onSuccess(List<String> newItems) throws Exception {
super.onSuccess(newItems);
pager++;
if(listView.getAdapter() == null) {
listView.setAdapter(adapter);
}
listView.onFinishLoading(true, newItems);
}
@Override
protected void onFinally() throws RuntimeException {
super.onFinally();
if(loadingDialog.isShowing()) {
loadingDialog.dismiss();
}
}
}