AsyncTask的使用及其源码分析
1. AsyncTask 简介
AsyncTask是一个抽象类,它是由Android封装的一个轻量级异步类,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线程中更新UI。
2.实例
先看下效果:
代码如下:
public class MainActivity extends AppCompatActivity { private TextView mTv; private Button mBtn; private int mNum = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTv = findViewById(R.id.mTv); mBtn = findViewById(R.id.mBtn); mBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { new MyAsyncTask().execute("I am zuowei.zhang"); } }); } private class MyAsyncTask extends AsyncTask { @Override protected void onPreExecute() { super.onPreExecute(); mNum = 0; mTv.setText("0"); } @Override protected Void doInBackground(String... strings) { Log.e("zzw", strings[0].toString()); while (mNum < 100) { try { Thread.sleep(100); mNum++; publishProgress(mNum); } catch (InterruptedException e) { e.printStackTrace(); } } return null; } @Override protected void onProgressUpdate(Integer... values) { mTv.setText(String.valueOf(values[0])); super.onProgressUpdate(values); } @Override protected void onPostExecute(Void aVoid) { Toast.makeText(getApplicationContext(), "运行结束", Toast.LENGTH_SHORT).show(); super.onPostExecute(aVoid); } }}
2.1 AsyncTask的核心方法
2.1.1 onPreExecute
这个方法在异步任务开始执行之前调用。在主线程执行,主要用于进行一些界面上的初始化操作。
2.1.2 doInBackground
这个方法中的所有代码会在子线程中运行,在这个方法中处理耗时操作。在这个方法中不可用进行UI操作。在此任务中调用publishProgress 方法,将子线程运行过程中的数据传递给主线程。
2.1.3 onProgressUpdate
当子线程中调用了publishProgress方法后,这个方法就会被调用,方法中携带的参数是从子线程中传递过来的。
2.1.4 onPostExecute
当doInBackground的代码执行完毕,并通过return 进行返回时候,这个方法就会被调用。返回的数据会作为参数传递到此方法中。
上面几个方法的调用顺序为: onPreExecute() --> doInBackground() --> publishProgress() --> onProgressUpdate() --> onPostExecute()。
3.源码分析
AsyncTask是一个抽象类,需要创建一个类来继承它,此抽象类带有三个泛型的参数,
public abstract class AsyncTask { ... ...}
三个泛型类型参数的含义如下:
**Params:**开始异步任务执行时传入的参数类型;
**Progress:**异步任务执行过程中,返回下载进度值的类型;
**Result:**异步任务执行完成后,返回的结果类型;
接下来看看它的构造方法:
public AsyncTask() { //1 this((Looper) null); } public AsyncTask(@Nullable Handler handler) { //2 this(handler != null ? handler.getLooper() : null); } public AsyncTask(@Nullable Looper callbackLooper) { //3 mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() ? getMainHandler() : new Handler(callbackLooper); mWorker = new WorkerRunnable() { public Result call() throws Exception { mTaskInvoked.set(true); Result result = null; try { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked result = doInBackground(mParams); Binder.flushPendingCommands(); } catch (Throwable tr) { mCancelled.set(true); throw tr; } finally { postResult(result); } return result; } }; 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); } } }; }
AsyncTask内部有三种不同参数的构造方法。如前面第2步的实例,一般很少重写构造方法,所以内部调用的是第1个构造方法。最终调用到第3个构造方法。在此方法中,Handler 是由 方法 getMainHandler 获取:
private static Handler getMainHandler() { synchronized (AsyncTask.class) { if (sHandler == null) { sHandler = new InternalHandler(Looper.getMainLooper()); } return sHandler; } }
创建一个主线程的Handler。
继续看第3个构造方法中还初始化了两个变量,mWorker和mFuture。这两个变量留着后面的步骤分析。
启动AsyncTask的时候,调用的是方法 execute。
@MainThread public final AsyncTask execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
调用了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 来判断当前任务的运行状态。而且在这里看到了AsyncTask 中的第一个方法 onPreExecute(),此方法处于AsyncTask 开始运行时前调用到。把参数 params 传递到 mWorker 中,并且 调用了exec.execute(mFuture),把构造方法中创建的 mFuture传递进去了。
exec 对象往上追是 sDefaultExecutor,而这个AsyncTask中创建的对象:
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
而 SERIAL_EXECUTOR 为:public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
再看SerialExecutor类:
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); } } }
SerialExecutor 是个静态内部类,在这个类中维护了一个队列,通过锁使得该队列确保AsyncTask中的任务是一个个加入到队列中,执行完一个才执行下一个。
在这个方法中主要有两个步骤:
a. 向队列中加入一个新的任务,即之前实例化后的mFuture对象
b. 调用 scheduleNext()
方法,调用THREAD_POOL_EXECUTOR执行队列头部的任务。
SerialExecutor 类仅仅为了保持任务执行是串行的,实际执行是由 THREAD_POOL_EXECUTOR 完成。
public static final Executor THREAD_POOL_EXECUTOR; 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; }
THREAD_POOL_EXECUTOR 是一个线程池,开启了一定数量的核心线程和工作线程。然后调用线程池的execute 方法去执行线程。从上面的流程可以看出,执行的线程是mFuture。
这时候在回头看看mFuture和mWorker:
mWorker = new WorkerRunnable() { public Result call() throws Exception { mTaskInvoked.set(true); Result result = null; try { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked result = doInBackground(mParams); Binder.flushPendingCommands(); } catch (Throwable tr) { mCancelled.set(true); throw tr; } finally { postResult(result); } return result; } }; 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); } }
在mWorker 中的call 方法执行了耗时操作,也就是 doInBackground 方法。当执行完毕后调用了 postResult(result) 方法:
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult(this, result)); message.sendToTarget(); return result; }
此方法会把result 传递给了内部的Handler跳转到主线程中,通过前面的分析,内部的Handler为 InternalHandler:
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; } } }
在 InternalHandler中,如果接受到的消息是 MESSAGE_POST_RESULT ,就会调用 finish 方法:
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
这时候会判断任务是否取消,如果取消则调用onCancelled()方法,如果正常执行完成则会调用 onPostExecute() 方法。在doInBackground 方法中,经常会调用 publishProgress() 方法来传递进度,看下此方法的源码:
protected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult
在此方法中,会发送消息为 MESSAGE_POST_PROGRESS 到 Handler 中,在Handler接收到消息时候会调用到方法 onProgressUpdate()。这样 AsyncTask 的核心方法就都执行到了。
更多相关文章
- android apk如何引用系统framework.jar,settingslib.jar
- Android海康监控视频调用demo
- Android中pendingIntent的深入理解
- Android线程优先级规定及其设置的具体方法
- Android(安卓)性能优化:多线程
- Android(安卓)Jetpack -- Lifecycle
- 【Android(安卓)消息处理】Handler、Looper、Message 源码浅析
- Android(安卓)学习笔记——旋转模拟器方向,全屏,窗口生命周期
- Activity销毁时如何保存Fragment状态