比较好的博客:
https://blog.csdn.net/qq_30379689/article/details/53203556
https://blog.csdn.net/guolin_blog/article/details/11711405
AsyncTask是对Handler与线程池的封装,目的也是实现线程间的通信,子线程执行耗时操作发送消息到主线程更新UI,使用线程池的主要原因是避免不必要的创建及销毁线程的开销
1. AsyncTask的使用方法
public class MainActivity extends Activity implements Button.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button bt_down = (Button) findViewById(R.id.button)
bt_down.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
URL url = new URL("http://blog.csdn.net/");
new MyAsyncTask().execute(url); //0. 执行execute开始执行异步任务
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
});
}
private class MyAsyncTask extends AsyncTask<URL, Integer, Long> { //AsyncTask是一个抽象类,Handler是一个普通的类
@Override
protected void onPreExecute() { //1. 主线程执行onPreExecute(执行异步任务前执行)
//异步任务开启之前回调,在主线程中执行
super.onPreExecute();
}
@Override
protected Long doInBackground(URL... urls) { //2. 线程池执行doInBackground(执行异步任务)
//执行异步任务,在线程池中执行
long totalSize = 0;
int i = 0;
try {
while (i < 100) {
Thread.sleep(50);
i = i + 5;
publishProgress(i);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
totalSize = totalSize + i;
return totalSize;
}
@Override
protected void onProgressUpdate(Integer... progress) { //3. 执行doInBackground的过程中执行publishProgress,主线程回调执行onProgressUpdate
//当doInBackground中调用publishProgress时回调,在主线程中执行
pb_progress.setProgress(progress[0]);
}
@Override
protected void onPostExecute(Long result) { //4. 主线程执行onPostExecute(执行异步任务后执行)
//在异步任务执行之后回调,在主线程中执行
Toast.makeText(MainActivity.this, "下载完成,结果是" + result, Toast.LENGTH_SHORT).show();
}
@Override
protected void onCancelled() { //5. 异步任务被取消时回调
//在异步任务被取消时回调
super.onCancelled();
}
}
}
AsyncTask的三个泛型参数:
a. Params:异步任务的参数,在执行AsyncTask时需要传入的参数,可用于在后台任务中使用。
b. Progress:进度条相关,后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位。
c. Result:任务的执行结果,当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。
参考:https://blog.csdn.net/guolin_blog/article/details/11711405
a. onPreExecute():在后台任务执行之前调用 //用于界面的初始化操作,比如显示一个进度条对话框等。
b. doInBackground(Params…):在子线程中运行 //处理耗时任务,任务一旦执行完毕就可以通过return语句来将任务的执行结果result进行返回
如果AsyncTask的第三个泛型参数指定的是void,就可以不返回任务执行结果。注意,在这个方法中是不可以进行UI操作的,如果需要更新UI元素,比如说反馈当前任务的执行进度,
可以调用publishProgress(Progress…)方法来完成。
c. onProgressUpdate(Progress…):当在doInBackground中调用了publishProgress(Progress…)方法后,这个方法就很快会被调用,方法中携带的参数就是在后台任务中传递过来的。
在这个方法中可以对UI进行操作,利用参数中的数值就可以对界面元素进行相应的更新。
d. onPostExecute(Result):在后台任务执行之后调用,当后台任务执行完毕并通过return语句将执行结果result返回时,这个方法就很快会被调用。返回的数据result会作为参数传递到此方法中,
可以利用返回的数据来进行一些UI操作,比如说提醒任务执行的结果,以及关闭掉进度条对话框等。
AsyncTask用法总结:
首先定义一个继承自AsyncTask的MyAsyncTask并复写onPreExecute、doInBackground、onPostExecute方法
主线程实例化MyAsyncTask,并调用execute方法,会依次执行onPreExecute、doInBackground、onPostExecute方法
其中onPreExecute和onPostExecute在主线程中执行,doInBackground在子线程中执行,doInBackground在执行publishProgress时会回调到主线程执行onProgressUpdate刷新UI
2. 源码分析:new MyAsyncTask().execute(url);
2.1 分析new MyAsyncTask()
public abstract class AsyncTask<Params, Progress, Result> { //Params = URL, Progress = Integer, Result = Long
public AsyncTask() { //执行new MyAsyncTask()
this((Looper) null); ---------------------------
} |
public AsyncTask(@Nullable Looper callbackLooper) { <----------
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler() //并不是获得主线程的Handler,而是获得内部类AsyncTask.InternalHandler
: new Handler(callbackLooper);
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception { //复写call()方法,执行call()时会执行doInBackground
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
...
} finally {
postResult(result);
}
return result;
}
};
mFuture = new FutureTask<Result>(mWorker) { --------------------------
@Override |
protected void done() { |
try { |
postResultIfNotInvoked(get()); |
} |
} |
}; |
} |
} |
public class FutureTask<V> implements RunnableFuture<V> { <-----------------
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable; //FutureTask.callable = mWorker
this.state = NEW;
}
}
总结:
执行new MyAsyncTask()实例化一个AsyncTask,且AsyncTask.mFuture = new FutureTask(mWorker),且mWorker = new WorkerRunnable<Params, Result>()
在new WorkerRunnable()时会复写call()方法,执行call()时会执行doInBackground
2.2 分析MyAsyncTask.execute(url);
frameworks\base\core\java\android\os\AsyncTask.java:
public abstract class AsyncTask<Params, Progress, Result> {
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, //exec = sDefaultExecutor = SERIAL_EXECUTOR = new SerialExecutor()
Params... params) { //params = new URL("http://blog.csdn.net/")
if (mStatus != Status.PENDING) { //只有异步任务的状态是PENDING时才可以往下执行
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("...");
case FINISHED:
throw new IllegalStateException("...");
}
}
mStatus = Status.RUNNING; //异步任务的状态变为RUNNING,此时如果再一次使用execute执行异步任务时会抛出异常IllegalStateException
onPreExecute(); //重点:1. 主线程执行onPreExecute
mWorker.mParams = params;
exec.execute(mFuture); ------------------------------------------------------ //exec = new SerialExecutor(),mFuture = new FutureTask(mWorker),mWorker = new WorkerRunnable()
return this; | 且mWorker.mParams = new URL("http://blog.csdn.net/")
} |
|
||主线程创建子线程,并切换到子线程中执行run() |
\/ |
private static class SerialExecutor implements Executor { |
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); |
Runnable mActive; |
public synchronized void execute(final Runnable r) { <---------------------
mTasks.offer(new Runnable() {
public void run() {
try {
r.run(); -------------------------------------------- //r = mFuture = new FutureTask(mWorker),其中FutureTask.callable = mWorker
} finally { |
scheduleNext(); |
} |
} |
}); |
if (mActive == null) { |
scheduleNext(); |
} |
} |
protected synchronized void scheduleNext() { |
if ((mActive = mTasks.poll()) != null) { |
THREAD_POOL_EXECUTOR.execute(mActive); |
} |
} |
} |
} |
|
public class FutureTask<V> implements RunnableFuture<V> { |
public void run() { <-----------------------------------------------
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable; //c = FutureTask.callable = mWorker,其中mWorker = new WorkerRunnable()
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call(); ------------------------------------------------- //执行mWorker.call(),会回调doInBackground
ran = true; |
} catch (Throwable ex) { |
result = null; |
ran = false; |
setException(ex); |
} |
if (ran) |
set(result); |
} |
} finally { |
... |
} |
} |
} |
|
public abstract class AsyncTask<Params, Progress, Result> { |
public AsyncTask(@Nullable Looper callbackLooper) { |
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() |
? getMainHandler() |
: new Handler(callbackLooper); |
mWorker = new WorkerRunnable<Params, Result>() { |
public Result call() throws Exception { <------------------------------------
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
result = doInBackground(mParams); //重点:2. 子线程执行doInBackground
Binder.flushPendingCommands();
} catch (Throwable tr) {
...
} finally {
postResult(result); -------------------------
} |
return result; |
} |
}; |
} |
private Result postResult(Result result) { <----------------
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, ---------
new AsyncTaskResult<Result>(this, result)); |
message.sendToTarget(); -------------------------------------------------------------------------
return result; | |
} | |
private Handler getHandler() { <---------------------------------------------------| |
return mHandler; //mHandler = AsyncTask.InternalHandler | |
} | |
} | |
| |
分析mHandler | |
public abstract class AsyncTask<Params, Progress, Result> { | |
public AsyncTask(@Nullable Looper callbackLooper) { | |
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() | |
? getMainHandler() ------------------- | |
: new Handler(callbackLooper); | | |
} | | |
private static Handler getMainHandler() { <------ | |
synchronized (AsyncTask.class) { | |
if (sHandler == null) { | |
sHandler = new InternalHandler(Looper.getMainLooper()); --- | |
} | | |
return sHandler; | | |
} | | |
} | | |
private static class InternalHandler extends Handler { | | |
public InternalHandler(Looper looper) { <-------------------------- | |
super(looper); | |
} | |
@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; | |
} | |
} | |
} | |
} | |
| |
| |
| |
public class Handler { | |
public final Message obtainMessage(int what, Object obj){ <----------------------- |
return Message.obtain(this, what, obj); ---------------------- |
} | |
} | |
| |
public final class Message implements Parcelable { | |
public static Message obtain(Handler h, int what, Object obj) { <----- |
Message m = obtain(); |
m.target = h; //Message.target = mHandler = AsyncTask.InternalHandler
m.callback = callback; //Message.callback = MESSAGE_POST_RESULT |
m.obj = obj; //Message.obj = new AsyncTaskResult<Result>(this, result)),其中result = doInBackground(mParams);
return m; |
} |
public void sendToTarget() { <--------------------------------------------------------------------
target.sendMessage(this); --------------------------------------------------
} |
} |
|
|
||使用Handler机制,子线程发送一个Message切换到主线程 |
\/ |
|
public abstract class AsyncTask<Params, Progress, Result> { |
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; //result = new AsyncTaskResult<Result>(this, result)),其中this = new MyAsyncTask(),result = doInBackground(mParams);
switch (msg.what) { |
case MESSAGE_POST_RESULT: |
// There is only one result |
result.mTask.finish(result.mData[0]); ---------------------- //result.mTask = new MyAsyncTask() |
break; | result.mData[0] = result = doInBackground(mParams);
case MESSAGE_POST_PROGRESS: | |
result.mTask.onProgressUpdate(result.mData); | |
break; | |
} | |
} | |
} | |
private void finish(Result result) { <----------------------------------------- |
if (isCancelled()) { //如果当前任务已经被取消掉了,就会调用onCancelled()方法 |
onCancelled(result); |
} else { |
onPostExecute(result); //重点:3. 主线程执行onPostExecute,result为执行doInBackground的返回值 |
} |
mStatus = Status.FINISHED; //任务执行完毕,状态设置为FINISHED |
} |
} |
|
public abstract class AsyncTask<Params, Progress, Result> { |
private static class AsyncTaskResult<Data> { <------------------------------------------------------------------
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task; //AsyncTaskResult.mTask = MyAsyncTask
mData = data; //AsyncTaskResult.mData = result = doInBackground(mParams);
}
}
}
若在doInBackground中调用了publishProgress(Progress...)方法,会调用onProgressUpdate(Progress...),过程分析如下:
public abstract class AsyncTask<Params, Progress, Result> {
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS, ------------------
new AsyncTaskResult<Progress>(this, values)).sendToTarget(); -----|-------------------------
} | |
} | |
} | |
public class Handler { | |
public final Message obtainMessage(int what, Object obj){ <--------------- |
return Message.obtain(this, what, obj); ------------------------- |
} | |
} | |
public final class Message implements Parcelable { | |
public static Message obtain(Handler h, int what, Object obj) { <---- |
Message m = obtain(); |
m.target = h; //Message.target = mHandler = AsyncTask.InternalHandler |
m.what = what; //Message.what = MESSAGE_POST_PROGRESS |
m.obj = obj; //Message.obj = new AsyncTaskResult<Progress>(this, values)).sendToTarget(); |
return m; |
} |
public void sendToTarget() { <------------------------------------------------------------------------
target.sendMessage(this);
}
}
||使用Handler机制,子线程发送一个Message切换到主线程
\/
public abstract class AsyncTask<Params, Progress, Result> {
private static class InternalHandler extends Handler {
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); //重点:4. 主线程执行onProgressUpdate,result.mTask = new MyAsyncTask()
break;
}
}
}
}
在定义MyAsyncTask时复写onCancelled(),在哪里被调用?
public abstract class AsyncTask<Params, Progress, Result> {
private void finish(Result result) {
if (isCancelled()) { //如果当前任务已经被取消掉了,就会调用onCancelled()方法
onCancelled(result); //重点:5. 主线程执行onCancelled,result为执行doInBackground的返回值
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
}
3. 几个问题
3.1 如果多次执行MyAsyncTask.execute()会重复执行异步任务吗?
不会,当第一次执行MyAsyncTask.execute()时MyAsyncTask.mStatus = Status.PENDING,不会抛出异常,且将状态改变为MyAsyncTask.mStatus = Status.RUNNING
当第二次执行MyAsyncTask.execute()时MyAsyncTask.mStatus != Status.PENDING,会抛出异常,不会往下执行,所以不会多次执行异步任务
3.2 MyAsyncTask.execute()时依次执行onPreExecute、doInBackground、onPostExecute方法,且onPreExecute和onPostExecute在主线程中执行,doInBackground在子线程中执行那么从onPreExecute到doInBackground是如何从主线程切换到子线程?从doInBackground到onPostExecute是如何从子线程切换到主线程?
执行MyAsyncTask.execute()时会在主线程执行onPreExecute,接着会使用SerialExecutor创建子线程,并在子线程中执行doInBackground,最终会执行postResult
使用Handler机制发送一个Message切换到主线程执行onProgressUpdate刷新UI
AsyncTask原理总结:
执行MyAsyncTask.execute()时会在主线程执行onPreExecute,接着会使用SerialExecutor创建子线程,并在子线程中执行doInBackground,最终会执行postResult将doInBackground的
执行结果result保存到AsyncTaskResult.mData中,将AsyncTaskResult保存到Message.obj中,使用Handler机制发送一个Message切换到主线程,取出result,判断当前异步任务是否已经被取消,
如果已经被取消则会调用onCancelled()方法,如果没有被取消则会调用onPostExecute
当在执行doInBackground的过程中如果执行publishProgress时会使用Handler机制发送一个Message切换到主线程执行onProgressUpdate刷新UI