AsyncTask
程序员文章站
2022-05-15 21:20:06
...
<!DOCTYPE html><html><head><title>AsyncTask</title><meta charset='utf-8'><link href='https://dn-maxiang.qbox.me/res-min/themes/marxico.css' rel='stylesheet'></head><body><div id='preview-contents' class='note-content'>
<div id="wmd-preview" class="preview-content"></div>
<div id="wmd-preview-section-1" class="wmd-preview-section preview-content">
</div><div id="wmd-preview-section-2" class="wmd-preview-section preview-content">
<h1 id="asynctask">AsyncTask</h1>
<p></p>
<p>异步的短时间任务,最多到几秒的操作</p>
<ul><li>三个类型 <br>
1.Params 传递给任务的参数 <br>
2.Progress 执行中返回的阶段类型 <br>
3.Result 最终结果的返回类型</li>
<li>4个步骤 <br>
1.onPreExecute 在UI线程中执行一般是用来配置任务 <br>
2.doInBackground 在后台执行,返回类型必须是Result类型,可以调用publishProgress来向UI线程报告进度 <br>
3.onProgressUpdate 在UI线程中执行,可以用来在UI上显示进度条等 <br>
4.onPostExecute 在UI线程中执行,Result被传入作为参数</li>
<li>取消任务 <br>
1.调用cancel可以使接下来调用的isCancel方法返回true <br>
2.取消任务后在doInBackground 结束后会调用onCancelled 而不是onPostExecute <br>
3.cancel只可以设置标志位,并不能立即中断任务,需要在doInBackground 在执行的过程中周期性的去检查isCancel</li>
<li>线程相关 <br>
1.AsyncTask类必须在UI线程中加载(系统自动加载) <br>
2.AsyncTask实例必须在UI线程中进行构造 <br>
3.不要手动调用doInBackground 等方法 <br>
4.AsyncTask只能执行一次,再次执行会抛出异常 <br>
5.AsyncTask保证所有的回调都是同步的,所以在4个步骤中不必考虑并发问题</li>
</ul>
</div><div id="wmd-preview-section-3" class="wmd-preview-section preview-content">
<pre class="prettyprint hljs-dark"><code class="language-java hljs"> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">AsyncTask</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-comment">//Callable 的包装,将给executor执行</span><br> mWorker = <span class="hljs-keyword">new</span> WorkerRunnable<Params, Result>() {<br> <span class="hljs-function"><span class="hljs-keyword">public</span> Result <span class="hljs-title">call</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception </span>{<br> mTaskInvoked.set(<span class="hljs-keyword">true</span>);<br><br> Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);<br> <span class="hljs-comment">//noinspection unchecked</span><br> <span class="hljs-keyword">return</span> postResult(doInBackground(mParams));<br> }<br> };<br> <span class="hljs-comment">//控制mWorker执行的future,用来在必要的时候取消执行</span><br> mFuture = <span class="hljs-keyword">new</span> FutureTask<Result>(mWorker) {<br> <span class="hljs-annotation">@Override</span><br> <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">done</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-keyword">try</span> {<br> postResultIfNotInvoked(get());<br> } <span class="hljs-keyword">catch</span> (InterruptedException e) {<br> android.util.Log.w(LOG_TAG, e);<br> } <span class="hljs-keyword">catch</span> (ExecutionException e) {<br> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"An error occured while executing doInBackground()"</span>,<br> e.getCause());<br> } <span class="hljs-keyword">catch</span> (CancellationException e) {<br> postResultIfNotInvoked(<span class="hljs-keyword">null</span>);<br> }<br> }<br> };<br> }<br></code></pre>
<p>调用execute后实际会转到executeOnExecutor上,代码如下:</p>
</div><div id="wmd-preview-section-244" class="wmd-preview-section preview-content">
<pre class="prettyprint hljs-dark"><code class="language-java hljs"><br><span class="hljs-comment">/* 这里的exec是可以制定的,默认的是AsyncTask的sDefaultExecutor,这是个SerialExecutor即所有任务需要顺序执行<br>也可以传入自定义的Executor来实现任务的并发执行<br>*/</span><br> <span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,<br> Params... params) {<br> <span class="hljs-comment">//状态判断,也是为什么只能执行一次</span><br> <span class="hljs-keyword">if</span> (mStatus != Status.PENDING) {<br> <span class="hljs-keyword">switch</span> (mStatus) {<br> <span class="hljs-keyword">case</span> RUNNING:<br> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalStateException(<span class="hljs-string">"Cannot execute task:"</span><br> + <span class="hljs-string">" the task is already running."</span>);<br> <span class="hljs-keyword">case</span> FINISHED:<br> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalStateException(<span class="hljs-string">"Cannot execute task:"</span><br> + <span class="hljs-string">" the task has already been executed "</span><br> + <span class="hljs-string">"(a task can be executed only once)"</span>);<br> }<br> }<br><br> mStatus = Status.RUNNING;<br><span class="hljs-comment">// 此方法还没有进入到exec中所以onPreExecute还是在UI线程中操作</span><br> onPreExecute();<br><span class="hljs-comment">// 将params传入到mWoeker中,并将包涵mWorker的future送给exec去执行</span><br> mWorker.mParams = params;<br> exec.execute(mFuture);<br><br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;<br> }<br></code></pre>
<p>默认的执行是在SerialExecutor中执行的,它可以保证所有的AsyncTask的doInBackground是同步执行的</p>
</div><div id="wmd-preview-section-1115" class="wmd-preview-section preview-content">
<pre class="prettyprint hljs-dark"><code class="language-java hljs"> <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SerialExecutor</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Executor</span> </span>{<br> <span class="hljs-keyword">final</span> ArrayDeque<Runnable> mTasks = <span class="hljs-keyword">new</span> ArrayDeque<Runnable>();<br> Runnable mActive;<br><span class="hljs-comment">// 这个方法可以保证传进的r都是顺序执行的,即一个结束后另一个才开始</span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">void</span> <span class="hljs-title">execute</span><span class="hljs-params">(<span class="hljs-keyword">final</span> Runnable r)</span> </span>{<br> mTasks.offer(<span class="hljs-keyword">new</span> Runnable() {<br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-keyword">try</span> {<br> r.run();<br> } <span class="hljs-keyword">finally</span> {<br> scheduleNext();<br> }<br> }<br> });<br> <span class="hljs-comment">//当第一个任务时候会触发,或者当某个任务结束时候下一个task还没有到达的时候也会触发</span><br> <span class="hljs-comment">//当任务在前一个任务还没有结束就到达了,那么会在上面的scheduleNext直接触发执行</span><br> <span class="hljs-keyword">if</span> (mActive == <span class="hljs-keyword">null</span>) {<br> scheduleNext();<br> }<br> }<br><span class="hljs-comment">//将任务送给THREAD_POOL_EXECUTOR 执行</span><br> <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">void</span> <span class="hljs-title">scheduleNext</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-keyword">if</span> ((mActive = mTasks.poll()) != <span class="hljs-keyword">null</span>) {<br> THREAD_POOL_EXECUTOR.execute(mActive);<br> }<br> }<br> }<br></code></pre>
<p>上面可以看到onPreExecute是在主线程中执行的,然后是doInBackGround在独立的线程中,那么它是又如何回到UI线程中的呢? <br>
这是因为AsyncTask构造了一个基于主线程的Handler ,代码如下:</p>
</div><div id="wmd-preview-section-1326" class="wmd-preview-section preview-content">
<pre class="prettyprint hljs-dark"><code class="language-java hljs"> <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">InternalHandler</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Handler</span> </span>{<br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">InternalHandler</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-comment">// 确保可以在主线程中执行</span><br> <span class="hljs-keyword">super</span>(Looper.getMainLooper());<br> }<br><br> <span class="hljs-annotation">@SuppressWarnings</span>({<span class="hljs-string">"unchecked"</span>, <span class="hljs-string">"RawUseOfParameterizedType"</span>})<br> <span class="hljs-annotation">@Override</span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">handleMessage</span><span class="hljs-params">(Message msg)</span> </span>{<br> AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;<br> <span class="hljs-keyword">switch</span> (msg.what) {<br> <span class="hljs-keyword">case</span> MESSAGE_POST_RESULT:<br> <span class="hljs-comment">// There is only one result,会调用onProgressUpdate</span><br> result.mTask.finish(result.mData[<span class="hljs-number">0</span>]);<br> <span class="hljs-keyword">break</span>;<br> <span class="hljs-keyword">case</span> MESSAGE_POST_PROGRESS:<br> result.mTask.onProgressUpdate(result.mData);<br> <span class="hljs-keyword">break</span>;<br> }<br> }<br> }<br></code></pre>
<p>onProgressUpdate 和 onPostExecute 都是在handler中执行的所以自然是在主线程,而将消息传递给handler的是publishProgress 和 postResult</p>
<p>publishProgress 比较简单就是从Handler 获取小心然后发送,这个在AsyncTask内部没有调用,主要用来给用户自定义的子类在doInBackground中使用</p>
<p>postResult 是在mWorker中定义会在结束后发消息给handler</p></div><div id="wmd-preview-section-footnotes" class="preview-content"></div></div></body></html>
<div id="wmd-preview" class="preview-content"></div>
<div id="wmd-preview-section-1" class="wmd-preview-section preview-content">
</div><div id="wmd-preview-section-2" class="wmd-preview-section preview-content">
<h1 id="asynctask">AsyncTask</h1>
<p></p>
<p>异步的短时间任务,最多到几秒的操作</p>
<ul><li>三个类型 <br>
1.Params 传递给任务的参数 <br>
2.Progress 执行中返回的阶段类型 <br>
3.Result 最终结果的返回类型</li>
<li>4个步骤 <br>
1.onPreExecute 在UI线程中执行一般是用来配置任务 <br>
2.doInBackground 在后台执行,返回类型必须是Result类型,可以调用publishProgress来向UI线程报告进度 <br>
3.onProgressUpdate 在UI线程中执行,可以用来在UI上显示进度条等 <br>
4.onPostExecute 在UI线程中执行,Result被传入作为参数</li>
<li>取消任务 <br>
1.调用cancel可以使接下来调用的isCancel方法返回true <br>
2.取消任务后在doInBackground 结束后会调用onCancelled 而不是onPostExecute <br>
3.cancel只可以设置标志位,并不能立即中断任务,需要在doInBackground 在执行的过程中周期性的去检查isCancel</li>
<li>线程相关 <br>
1.AsyncTask类必须在UI线程中加载(系统自动加载) <br>
2.AsyncTask实例必须在UI线程中进行构造 <br>
3.不要手动调用doInBackground 等方法 <br>
4.AsyncTask只能执行一次,再次执行会抛出异常 <br>
5.AsyncTask保证所有的回调都是同步的,所以在4个步骤中不必考虑并发问题</li>
</ul>
</div><div id="wmd-preview-section-3" class="wmd-preview-section preview-content">
<pre class="prettyprint hljs-dark"><code class="language-java hljs"> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">AsyncTask</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-comment">//Callable 的包装,将给executor执行</span><br> mWorker = <span class="hljs-keyword">new</span> WorkerRunnable<Params, Result>() {<br> <span class="hljs-function"><span class="hljs-keyword">public</span> Result <span class="hljs-title">call</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception </span>{<br> mTaskInvoked.set(<span class="hljs-keyword">true</span>);<br><br> Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);<br> <span class="hljs-comment">//noinspection unchecked</span><br> <span class="hljs-keyword">return</span> postResult(doInBackground(mParams));<br> }<br> };<br> <span class="hljs-comment">//控制mWorker执行的future,用来在必要的时候取消执行</span><br> mFuture = <span class="hljs-keyword">new</span> FutureTask<Result>(mWorker) {<br> <span class="hljs-annotation">@Override</span><br> <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">done</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-keyword">try</span> {<br> postResultIfNotInvoked(get());<br> } <span class="hljs-keyword">catch</span> (InterruptedException e) {<br> android.util.Log.w(LOG_TAG, e);<br> } <span class="hljs-keyword">catch</span> (ExecutionException e) {<br> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"An error occured while executing doInBackground()"</span>,<br> e.getCause());<br> } <span class="hljs-keyword">catch</span> (CancellationException e) {<br> postResultIfNotInvoked(<span class="hljs-keyword">null</span>);<br> }<br> }<br> };<br> }<br></code></pre>
<p>调用execute后实际会转到executeOnExecutor上,代码如下:</p>
</div><div id="wmd-preview-section-244" class="wmd-preview-section preview-content">
<pre class="prettyprint hljs-dark"><code class="language-java hljs"><br><span class="hljs-comment">/* 这里的exec是可以制定的,默认的是AsyncTask的sDefaultExecutor,这是个SerialExecutor即所有任务需要顺序执行<br>也可以传入自定义的Executor来实现任务的并发执行<br>*/</span><br> <span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,<br> Params... params) {<br> <span class="hljs-comment">//状态判断,也是为什么只能执行一次</span><br> <span class="hljs-keyword">if</span> (mStatus != Status.PENDING) {<br> <span class="hljs-keyword">switch</span> (mStatus) {<br> <span class="hljs-keyword">case</span> RUNNING:<br> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalStateException(<span class="hljs-string">"Cannot execute task:"</span><br> + <span class="hljs-string">" the task is already running."</span>);<br> <span class="hljs-keyword">case</span> FINISHED:<br> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalStateException(<span class="hljs-string">"Cannot execute task:"</span><br> + <span class="hljs-string">" the task has already been executed "</span><br> + <span class="hljs-string">"(a task can be executed only once)"</span>);<br> }<br> }<br><br> mStatus = Status.RUNNING;<br><span class="hljs-comment">// 此方法还没有进入到exec中所以onPreExecute还是在UI线程中操作</span><br> onPreExecute();<br><span class="hljs-comment">// 将params传入到mWoeker中,并将包涵mWorker的future送给exec去执行</span><br> mWorker.mParams = params;<br> exec.execute(mFuture);<br><br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;<br> }<br></code></pre>
<p>默认的执行是在SerialExecutor中执行的,它可以保证所有的AsyncTask的doInBackground是同步执行的</p>
</div><div id="wmd-preview-section-1115" class="wmd-preview-section preview-content">
<pre class="prettyprint hljs-dark"><code class="language-java hljs"> <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SerialExecutor</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Executor</span> </span>{<br> <span class="hljs-keyword">final</span> ArrayDeque<Runnable> mTasks = <span class="hljs-keyword">new</span> ArrayDeque<Runnable>();<br> Runnable mActive;<br><span class="hljs-comment">// 这个方法可以保证传进的r都是顺序执行的,即一个结束后另一个才开始</span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">void</span> <span class="hljs-title">execute</span><span class="hljs-params">(<span class="hljs-keyword">final</span> Runnable r)</span> </span>{<br> mTasks.offer(<span class="hljs-keyword">new</span> Runnable() {<br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-keyword">try</span> {<br> r.run();<br> } <span class="hljs-keyword">finally</span> {<br> scheduleNext();<br> }<br> }<br> });<br> <span class="hljs-comment">//当第一个任务时候会触发,或者当某个任务结束时候下一个task还没有到达的时候也会触发</span><br> <span class="hljs-comment">//当任务在前一个任务还没有结束就到达了,那么会在上面的scheduleNext直接触发执行</span><br> <span class="hljs-keyword">if</span> (mActive == <span class="hljs-keyword">null</span>) {<br> scheduleNext();<br> }<br> }<br><span class="hljs-comment">//将任务送给THREAD_POOL_EXECUTOR 执行</span><br> <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">void</span> <span class="hljs-title">scheduleNext</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-keyword">if</span> ((mActive = mTasks.poll()) != <span class="hljs-keyword">null</span>) {<br> THREAD_POOL_EXECUTOR.execute(mActive);<br> }<br> }<br> }<br></code></pre>
<p>上面可以看到onPreExecute是在主线程中执行的,然后是doInBackGround在独立的线程中,那么它是又如何回到UI线程中的呢? <br>
这是因为AsyncTask构造了一个基于主线程的Handler ,代码如下:</p>
</div><div id="wmd-preview-section-1326" class="wmd-preview-section preview-content">
<pre class="prettyprint hljs-dark"><code class="language-java hljs"> <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">InternalHandler</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Handler</span> </span>{<br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">InternalHandler</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-comment">// 确保可以在主线程中执行</span><br> <span class="hljs-keyword">super</span>(Looper.getMainLooper());<br> }<br><br> <span class="hljs-annotation">@SuppressWarnings</span>({<span class="hljs-string">"unchecked"</span>, <span class="hljs-string">"RawUseOfParameterizedType"</span>})<br> <span class="hljs-annotation">@Override</span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">handleMessage</span><span class="hljs-params">(Message msg)</span> </span>{<br> AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;<br> <span class="hljs-keyword">switch</span> (msg.what) {<br> <span class="hljs-keyword">case</span> MESSAGE_POST_RESULT:<br> <span class="hljs-comment">// There is only one result,会调用onProgressUpdate</span><br> result.mTask.finish(result.mData[<span class="hljs-number">0</span>]);<br> <span class="hljs-keyword">break</span>;<br> <span class="hljs-keyword">case</span> MESSAGE_POST_PROGRESS:<br> result.mTask.onProgressUpdate(result.mData);<br> <span class="hljs-keyword">break</span>;<br> }<br> }<br> }<br></code></pre>
<p>onProgressUpdate 和 onPostExecute 都是在handler中执行的所以自然是在主线程,而将消息传递给handler的是publishProgress 和 postResult</p>
<p>publishProgress 比较简单就是从Handler 获取小心然后发送,这个在AsyncTask内部没有调用,主要用来给用户自定义的子类在doInBackground中使用</p>
<p>postResult 是在mWorker中定义会在结束后发消息给handler</p></div><div id="wmd-preview-section-footnotes" class="preview-content"></div></div></body></html>
推荐阅读
-
android异步任务设计思详解(AsyncTask)
-
Android中实现异步任务机制的AsyncTask方式的使用讲解
-
AsyncTask官方文档教程整理
-
一起学Android之AsyncTask
-
Android带进度条的下载图片示例(AsyncTask异步任务)
-
Android使用AsyncTask加载图片的操作流程
-
android volley对于AsyncTask和httpclient的比较
-
Android AsyncTask实现异步处理任务的方法详解
-
Android 线程之间通信的多种方式AsyncTask、IntentService、HandlerThread,RxJava,runOnUiThread
-
AsyncTask详解