public class AsyncTaskActivity extends AppCompatActivity {
private TextView mProgress;
private ImageView mImage;
private MyDownloadAsyncTask myDownloadAsyncTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_async_task);
initView();
}
public void download(View view) {
myDownloadAsyncTask = new MyDownloadAsyncTask();
myDownloadAsyncTask.execute("https://www.baidu.com/img/baidu_jgylogo3.gif");
}
public void cancel(View view) {
myDownloadAsyncTask.cancel(true);
}
private void initView() {
mProgress = (TextView) findViewById(R.id.progress);
mImage = (ImageView) findViewById(R.id.image);
}
public class MyDownloadAsyncTask extends AsyncTask {
@Override
protected void onPreExecute() {
//doInBackground执行之前
mProgress.setText("下载任务准备开始");
}
@Override
protected void onPostExecute(Bitmap bitmap) {
//doInBackground执行之后
if (bitmap != null) {
mImage.setImageBitmap(bitmap);
}
}
@Override
protected void onProgressUpdate(Integer... values) {
//doInBackground执行中
mProgress.setText("任务进行中:" + values[0] + "%");
}
@Override
protected Bitmap doInBackground(String... strings) {
Log.e("MyDownloadAsyncTask", "ThreadName:" + Thread.currentThread().getName());
try {
URL url = new URL(strings[0]);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
// 使用 URL 连接进行输出
httpURLConnection.setDoOutput(true);
// 使用 URL 连接进行输入
httpURLConnection.setDoInput(true);
// 忽略缓存
httpURLConnection.setUseCaches(false);
// 设置URL请求方法
httpURLConnection.setRequestMethod("GET");
InputStream inputStream = httpURLConnection.getInputStream();
int contentLength = httpURLConnection.getContentLength();
ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
byte[] buff = new byte[100];
int length = 0;
int sum = 0;
while ((length = inputStream.read(buff)) > 0) {
swapStream.write(buff, 0, length);
sum += length;
double percent = sum * 1.0f / contentLength * 100;
publishProgress((int) percent);
}
byte[] bytes = swapStream.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
return bitmap;
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
}
AsyncTask一共不多七百多行代码,所以可以先看一下其中包含的方法和成员变量。
先来看下成员变量的具体有哪些:
/**
* 日志Tag
*/
private static final String LOG_TAG = "AsyncTask";
/**
* CPU核心数
*/
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
/**
* 线程池核心线程数
*/
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
/**
* 线程池最大线程数
*/
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
/**
* 线程闲置超时时间
*/
private static final int KEEP_ALIVE_SECONDS = 30;
/**
* 线程工厂
*/
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
/**
* 保证原子性 支持原子指令Integer型
*/
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
/**
* LinkedBlockingQueue链表结构有序阻塞队列用来存取任务 容量为128
*/
private static final BlockingQueue sPoolWorkQueue =
new LinkedBlockingQueue(128);
/**
* 执行任务的线程池
*/
public static final Executor THREAD_POOL_EXECUTOR;
/**
* 任务排队的线程池
*/
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
/**
* 结果消息
*/
private static final int MESSAGE_POST_RESULT = 0x1;
/**
* 进度消息
*/
private static final int MESSAGE_POST_PROGRESS = 0x2;
/**
* 任务排队的线程池 SerialExecutor
*/
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
/**
* UI线程主线程的Handler
*/
private static InternalHandler sHandler;
/**
* 一个封装了带Params的Callable抽象类,用来执行任务
*/
private final WorkerRunnable mWorker;
/**
* 处理结果任务
*/
private final FutureTask mFuture;
/**
* AsyncTask的状态
*/
private volatile Status mStatus = Status.PENDING;
/**
* 当前任务是否被取消
*/
private final AtomicBoolean mCancelled = new AtomicBoolean();
/**
* 当前任务是否被调用
*/
private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
接下来看AsyncTask的几个内部类:
/**
* 存放任务结果
* @param
*/
@SuppressWarnings({"RawUseOfParameterizedType"})
private static class AsyncTaskResult {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
/**
* 主线程Handler
*/
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult> result = (AsyncTaskResult>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
/**
* 由ArrayDeque队列构成的串行线程池
*/
private static class SerialExecutor implements Executor {
final ArrayDeque mTasks = new ArrayDeque();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
/**
* 封装了带Params的Callable抽象类
* @param
* @param
*/
private static abstract class WorkerRunnable implements Callable {
Params[] mParams;
}
/**
* 状态枚举
*
*/
public enum Status {
/**
* 未执行状态
*/
PENDING,
/**
* 运行状态
*/
RUNNING,
/**
* 运行完成状态
*/
FINISHED,
}
搞清楚了有些啥,就来可以研究AsyncTask到底是怎么运行的了。从使用方法来看,是先自定义了一个AsyncTask并且new了一个实例,那么首先要走的就是构造方法。
public AsyncTask(@Nullable Looper callbackLooper) {
/**
* 初始化mHandler
*/
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
/**
* 初始化WorkerRunnable
*/
mWorker = new WorkerRunnable() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
//线程优先级设置后台线程
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//执行doInBackground返回result
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
//异常则取消
mCancelled.set(true);
throw tr;
} finally {
//调用postResult方法
postResult(result);
}
return result;
}
};
/**
* 初始化FutureTask
*/
mFuture = new FutureTask(mWorker) {
@Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
构造方法中初始化了一个Handler,因为传入是空所以拿到的Handler是主线程的Handler,通过此Handler接收消息处理与主线程的交互。除此之外还初始化一个WorkerRunnable,这个抽象类之前看过知识继承了Callable接口,并且保存了一个我们传入的参数Params。在call方法中调用了doInBackground方法并返回result。如果catch到异常就会取消任务,最终都会执行postResult方法将运行结果发送出去。
postResult方法的代码:
/**
* 发送提交结果的消息
* @param result
* @return
*/
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult(this, result));
message.sendToTarget();
return result;
}
发送message给handler处理,msg.what为MESSAGE_POST_RESULT,msg.obj传一个AsyncTaskResult 。
在回到构造函数,看到接着new了一个FutureTask对象,并且将worker传入。
可以看到FutureTask继承RunnableFuture接口,而RunnableFuture又继承了Runnable和Future,所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。在done方法里get获取到mWorker的call方法的返回值后会调用postResultIfNotInvoked方法。
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
在postResultIfNotInvoked方法里根据mTaskInvoked状态执行postResult方法。至此构造函数结束。
除了构造方法,静态代码块也会在类加载时运行,接着看静态代码块里的内容:
/**
* 静态代码块中初始化线程池
*/
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
静态代码块中只是初始化了执行任务的线程池。
接下来我们在是使用时调用了AsyncTask的execute方法,来看execute方法。
public final AsyncTask execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
execute方法调用了executeOnExecutor方法传入了参数和sDefaultExecutor线程池。sDefaultExecutor是一个串行任务队列线程池。
/**
* 任务排队的线程池
*/
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
/**
* 任务排队的线程池 SerialExecutor
*/
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
/**
* 由ArrayDeque队列构成的串行线程池
*/
private static class SerialExecutor implements Executor {
final ArrayDeque mTasks = new ArrayDeque();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
sDefaultExecutor由一个数组结构的双向队列构成,从队列中取出任务后放入THREAD_POOL_EXECUTOR执行。
继续看executeOnExecutor方法:
public final AsyncTask executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
首先是根据mStatus状态,Running或者Finish则会抛出异常。所以一个AsyncTask只能调用execute方法一次。若状态正确则把Status修改为Running 。然后调用onPreExecute()方法,并且将传入的params传给mWorker中,然后调用线程池的execute方法传入mFuture。任务执完成后发送消息。Handler接收到根据message.what的类型分别调用finish方法和onProgressUpdate方法。调用finish方法再会根据是否取消状态来调用onPostExecute和onCancelled方法,至此工作流程结束。
/**
* 主线程Handler
*/
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult> result = (AsyncTaskResult>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
AsyncTask的工作流程图:
AsyncTask的结构图:
1、AsyncTask 对象必须在主线程创建。
sHandler是静态的对象,为了能够将环境切换到主线程,就必须要求这个对象必须在主线程创建,由于静态成员变量会在类加载时候进行初始化,也就变相要求AsyncTask的类必须在主线程中加在。
2、Android3.0之前AsyncTask是并行执行任务,3.0之后为串行执行。
从3.0之后的源码,可知SerialExecutor是一个串行的任务线程池,所以3.0之后的AsyncTask是串行执行任务。
3.0之前,源码中并没有SerialExecutor这个线程池,只有一个任务执行线程池,所以是并发的。3.0之后想要并行执行任务,只需要调用executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,params)设置即可。
3、内存泄漏
在Activity中使用AsyncTask,AsyncTask持有Activity的引用,如果在网络请求没有结束,但是Activity已经被关闭的情况下,Actuvity的引用的不到释放,就会造成内存泄漏。
解决方法:
1、将AsyncTask设置为static,设置成静态对象后,在Activity类初始化的时候会初始化,会占用一定内存,但是会和Activity同生命周期,Activity销毁时AsyncTask也会被销毁。
2、使用弱引用WeakReference,这样gc运行时就会回收,避免内存泄漏。
public final boolean cancel(boolean mayInterruptIfRunning) {
mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
}
futreTask的cancel方法
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&
U.compareAndSwapInt(this, STATE, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
t.interrupt();
} finally { // final state
U.putOrderedInt(this, STATE, INTERRUPTED);
}
}
} finally {
finishCompletion();
}
return true;
}