欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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&lt;Params, Result&gt;() {<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&lt;Result&gt;(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&lt;Params, Progress, Result&gt; 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&lt;Runnable&gt; mTasks = <span class="hljs-keyword">new</span> ArrayDeque&lt;Runnable&gt;();<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&lt;?&gt; result = (AsyncTaskResult&lt;?&gt;) 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>
相关标签: AsyncTask