Android异步任务机制之AsycTask
在Android中實現異步任務機制有兩種方式,Handler和AsyncTask。
Handler已經在上一篇文章?異步消息處理機制(Handler 、 Looper 、MessageQueue)源碼解析?說過了。
本篇就說說AsyncTask的異步實現。
| 1、什么時候使用 AsnyncTask |
在上一篇文章已經說了,主線程主要負責控制UI頁面的顯示、更新、交互等。 為了有更好的用戶體驗,UI線程中的操作要求越短越好。
我們把耗時的操作(例如網絡請求、數據庫操作、復雜計算)放到單獨的子線程中操作,以避免主線程的阻塞。但是在子線程中不能更新UI界面,這時候需要使用handler。
但如果耗時的操作太多,那么我們需要開啟太多的子線程,這就會給系統帶來巨大的負擔,隨之也會帶來性能方面的問題。在這種情況下我們就可以考慮使用類AsyncTask來異步執行任務,不需要子線程和handler,就可以完成異步操作和刷新UI。
不要隨意使用AsyncTask,除非你必須要與UI線程交互.默認情況下使用Thread即可,要注意需要將線程優先級調低.AsyncTask適合處理短時間的操作,長時間的操作,比如下載一個很大的視頻,這就需要你使用自己的線程來下載,不管是斷點下載還是其它的.
| 2、AsnyncTask原理 |
AsyncTask主要有二個部分:一個是與主線程的交互,另一個就是線程的管理調度。雖然可能多個AsyncTask的子類的實例,但是AsyncTask的內部Handler和ThreadPoolExecutor都是進程范圍內共享的,其都是static的,也即屬于類的,類的屬性的作用范圍是CLASSPATH,因為一個進程一個VM,所以是AsyncTask控制著進程范圍內所有的子類實例。
AsyncTask內部會創建一個進程作用域的線程池來管理要運行的任務,也就就是說當你調用了AsyncTask的execute()方法后,AsyncTask會把任務交給線程池,由線程池來管理創建Thread和運行Therad。
| 3、AsyncTask介紹 |
Android的AsyncTask比Handler更輕量級一些(只是代碼上輕量一些,而實際上要比handler更耗資源),適用于簡單的異步處理。?
?
Android之所以有Handler和AsyncTask,都是為了不阻塞主線程(UI線程),因為UI的更新只能在主線程中完成,因此異步處理是不可避免的。
AsyncTask:對線程間的通訊做了包裝,是后臺線程和UI線程可以簡易通訊:后臺線程執行異步任務,將result告知UI線程。
使用AsyncTask分為兩步:
① 繼承AsyncTask類實現自己的類
<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">abstract</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">class</span> AsyncTask<Params, Progress, Result> {</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>Params: 輸入參數,對應excute()方法中傳遞的參數。如果不需要傳遞參數,則直接設為void即可。
Progress:后臺任務執行的百分比
Result:返回值類型,和doInBackground()方法的返回值類型保持一致。
②復寫方法
最少要重寫以下這兩個方法:
-
doInBackground(Params…)
在子線程(其他方法都在主線程執行)中執行比較耗時的操作,不能更新UI,可以在該方法中調用publishProgress(Progress…)來更新任務的進度。Progress方法是AsycTask中一個final方法只能調用不能重寫。
-
onPostExecute(Result)
使用在doInBackground 得到的結果處理操作UI, 在主線程執行,任務執行的結果作為此方法的參數返回。?
?
有時根據需求還要實現以下三個方法: -
onProgressUpdate(Progress…)
可以使用進度條增加用戶體驗度。 此方法在主線程執行,用于顯示任務執行的進度。
-
onPreExecute()
這里是最終用戶調用Excute時的接口,當任務執行之前開始調用此方法,可以在這里顯示進度對話框。
-
onCancelled()
用戶調用取消時,要做的操作
| 4、AsyncTask示例 |
按照上面的步驟定義自己的異步類:
<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">class</span> MyTask extends AsyncTask<String, Integer, String> { <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//執行的第一個方法用于在執行后臺任務前做一些UI操作 </span>@Override <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onPreExecute</span>() { } <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//第二個執行方法,在onPreExecute()后執行,用于后臺任務,不可在此方法內修改UI</span>@Override <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">protected</span> String <span class="hljs-title" style="box-sizing: border-box;">doInBackground</span>(String... <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">params</span>) { <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//處理耗時操作</span><span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"后臺任務執行完畢"</span>; } <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">/*這個函數在doInBackground調用publishProgress(int i)時觸發,雖然調用時只有一個參數 但是這里取到的是一個數組,所以要用progesss[0]來取值 第n個參數就用progress[n]來取值 */</span>@Override <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onProgressUpdate</span>(Integer... progresses) { <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//"loading..." + progresses[0] + "%"</span>super.onProgressUpdate(progress); } <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">/*doInBackground返回時觸發,換句話說,就是doInBackground執行完后觸發 這里的result就是上面doInBackground執行后的返回值,所以這里是"后臺任務執行完畢" */</span>@Override <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onPostExecute</span>(String result) { } <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//onCancelled方法用于在取消執行中的任務時更改UI </span>@Override <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onCancelled</span>() { } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li></ul>在主線程申明該類的對象,調用對象的execute()函數開始執行。
<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">MyTask t= <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> MyTask(); t.execute();<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//這里沒有參數</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>| 5、使用AsyncTask需要注意的地方 |
-
AsnycTask內部的Handler需要和主線程交互,所以AsyncTask的實例必須在UI線程中創建
-
AsyncTaskResult的doInBackground(mParams)方法執行異步任務運行在子線程中,其他方法運行在主線程中,可以操作UI組件。
-
一個AsyncTask任務只能被執行一次。
-
運行中可以隨時調用AsnycTask對象的cancel(boolean)方法取消任務,如果成功,調用isCancelled()會返回true,并且不會執行 onPostExecute() 方法了,而是執行 onCancelled() 方法。
-
對于想要立即開始執行的異步任務,要么直接使用Thread,要么單獨創建線程池提供給AsyncTask。默認的AsyncTask不一定會立即執行你的任務,除非你提供給他一個單獨的線程池。如果不與主線程交互,直接創建一個Thread就可以了。
原文地址: http://blog.csdn.net/Amazing7/article/details/51425510
總結
以上是生活随笔為你收集整理的Android异步任务机制之AsycTask的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android 异步消息处理机制(Han
- 下一篇: 说说PendingIntent的内部机制