Android多線程(一)


在Android應用的開發過程中,我們不可避免的要使用多線程,獲取服務器數據、下載網絡數據、遍歷文件目錄查找特定文件等等耗時的工作都離不開線程的知識。Android繼承了Java的多線程體系,同時又實現了許多更加簡易的API來操作線程。通過這些API,我們可以方便快捷的實現線程的創建、線程間的交互。我打算記下最近自己學習Android多線程機制時的學習筆記,一來可以供以后翻閱查看,二來為那些正疑惑與此的朋友提供一條解決問題的途徑。

先大致說一下我想寫的內容:

一、AsyncTask

二、Thread 與 Handler

三、HandlerThread

全部內容分為3篇Bolg。

下面正式開始第一部分吧!

一、AsyncTask

(0)參考文檔:http://developer.android.com/reference/android/os/AsyncTask.html

(1)簡單介紹:

  AsyncTask這是一個很便捷的關於線程的API,它將比較耗時(幾秒)的工作放在非UI線程中運行,然后將結果的展示放在UI線程中。整個過程不涉及到任何關於Thread、Handler及Message等的處理。

  先來說說AsyncTask的構造吧,它接收3個泛型參數,分別代表了后台工作的傳入參數類型、進度的參數類型、結果的參數類型。每一個的具體含義會在接下來的AsyncTask的執行過程中講到。要想使用AsyncTask就必須拓展為它的子類同時指定3個泛型參數,然后在子類的中重寫幾個重要的方法。下面就AsyncTask的執行過程來寫。

(2)AsyncTask的執行過程:

  AsyncTask中的回調方法有:

onPreExecute(),UI線程中執行,一般用來處理執行異步任務前的准備工作,比如彈出一個進度條,展現一個對話框告知用戶正在執行一項任務。

doInBackground(Params...),在非UI線程中執行,這里是異步任務的核心,所有需要耗時的工作全在這里執行,因為不是在UI線程中,因此不會存在阻塞UI線程的危險,不會引發ANR錯誤。

onProgressUpdate(Progress...),在UI 線程中執行,一般用來更新任務執行的進度,它的調用時在publishProgress(Progress...)調用之后接着被調用的,我們可以在doInBackground(Params...)中多次調用publishProgress(Progress...)來告知用戶任務的執行狀態。

onPostExecute(Result),在UI線程中執行,任務完成后(doInBackground(Params...)執行結束)且任務沒被取消時,會執行該方法,用來處理異步任務得到的結果。

onCancelled(Result),在UI線程中執行,當任務以柔和的方式結束(AsyncTask.cancel(false))這個方法會取代onPostExecute(Result)得以執行(當然這里也要看程序的執行邏輯,有沒有在doInBackground(Params...)中檢測任務是否被取消)

  關於泛型參數:

  三個泛型參數分別是:Params,Progress,Result。在上面的回調方法接受中我們可以看到它們分別所處那個方法,Params是啟動異步任務時傳入的參數,比如啟動異步任務從網上下載一張圖片傳入圖片的URL地址。Progress是進度參數類型,調用publishProgress(Progress...)時的參數需和Progress類型相容。比如用一個整數去描述進度,Progress及時Integer。Result是結果參數類型,異步任務完成后,如需返回一個結果,那么這個結果的類型就是Result類型。特別地,可以用Void去代替任何一個或多個泛型參數,這樣做就以為着不需要參數。

(3)一個簡單的例子:

話說百聞不如一見,下面我就用一個極簡單的例子說明AsyncTask的使用過程。先說我要干啥,我用一個異步任務來更新一個進度條(簡單吧!粗暴吧!顫抖吧,地球人!O(∩_∩)O)

注:示例沒什么格式,強迫症患者見諒!!

先給出布局:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout
 3     xmlns:android="http://schemas.android.com/apk/res/android"
 4     android:layout_width="match_parent"
 5     android:layout_height="match_parent"
 6     android:layout_margin="15dp">
 7 
 8 
 9     <TextView
10         android:layout_width="wrap_content"
11         android:layout_height="wrap_content"
12         android:layout_centerHorizontal="true"
13         android:text="AsyncTask示例"
14         android:textSize="30sp"/>
15 
16     <ProgressBar
17         android:id="@+id/progress"
18         style="@android:style/Widget.ProgressBar.Horizontal"
19         android:layout_width="match_parent"
20         android:layout_height="wrap_content"
21         android:layout_centerInParent="true"/>
22 
23 
24     <Button
25         android:id="@+id/cancel"
26         android:layout_width="match_parent"
27         android:layout_height="wrap_content"
28         android:layout_alignParentBottom="true"
29         android:text="cancel"/>
30 
31     <Button
32         android:id="@+id/start"
33         android:layout_width="match_parent"
34         android:layout_height="wrap_content"
35         android:layout_above="@+id/cancel"
36         android:text="start"/>
37 </RelativeLayout>

下面是AsyncTask的邏輯代碼:

  1 package comfallblank.github.asynctasktest;
  2 
  3 import android.os.AsyncTask;
  4 import android.os.Bundle;
  5 import android.support.v7.app.AppCompatActivity;
  6 import android.util.Log;
  7 import android.view.View;
  8 import android.widget.Button;
  9 import android.widget.ProgressBar;
 10 
 11 public class MainActivity extends AppCompatActivity {
 12 
 13     private ProgressBar mProgressBar;
 14     private Button mStartButton;
 15     private Button mCancelButton;
 16 
 17     @Override
 18     protected void onCreate(Bundle savedInstanceState) {
 19         super.onCreate(savedInstanceState);
 20         setContentView(R.layout.activity_main);
 21         mProgressBar = (ProgressBar) findViewById(R.id.progress);
 22         //設置ProgressBar暫時不可見,一會在異步任務的中顯示它。
 23         mProgressBar.setVisibility(View.GONE);
 24 
 25         final MyTask myTask =  new MyTask();
 26         mStartButton = (Button) findViewById(R.id.start);
 27         mStartButton.setOnClickListener(new View.OnClickListener() {
 28             @Override
 29             public void onClick(View view) {
 30                 myTask.execute();
 31             }
 32         });
 33 
 34         mCancelButton = (Button) findViewById(R.id.cancel);
 35         mCancelButton.setOnClickListener(new View.OnClickListener() {
 36             @Override
 37             public void onClick(View view) {
 38                 myTask.cancel(false);
 39             }
 40         });
 41 
 42 
 43     }
 44 
 45    private class MyTask extends AsyncTask<Void,Integer,String>{
 46 
 47        private static final  String TAG = "MyTask";
 48 
 49        @Override
 50        protected void onPreExecute() {
 51            super.onPreExecute();
 52            //准備工作,顯示進度條
 53            mProgressBar.setVisibility(View.VISIBLE);
 54            //打印日志,查看執行路徑,下同
 55            Log.d(TAG,"onPreExecute");
 56        }
 57 
 58        @Override
 59        protected String doInBackground(Void... voids) {
 60            Log.d(TAG,"doInBackground");
 61            //每1s對進度條更新10%
 62            synchronized (this){
 63                for (int i = 1;i<=10;i++){
 64                    try {
 65                        Thread.sleep(1000*1);
 66                        publishProgress(i*10);
 67                        if (isCancelled()){
 68                            return "Task cancelled";
 69                        }
 70                    } catch (InterruptedException e) {
 71                        e.printStackTrace();
 72                    }
 73 
 74                }
 75            }
 76            return "Task executed";
 77        }
 78 
 79        @Override
 80        protected void onProgressUpdate(Integer... values) {
 81            super.onProgressUpdate(values);
 82            mProgressBar.setProgress(values[0]);
 83            Log.d(TAG,"onProgressUpdate");
 84        }
 85 
 86        @Override
 87        protected void onPostExecute(String s) {
 88            super.onPostExecute(s);
 89            Log.d(TAG, s);
 90            Log.d(TAG,"onPostExecute");
 91 
 92        }
 93 
 94        @Override
 95        protected void onCancelled(String s) {
 96            super.onCancelled(s);
 97            Log.d(TAG, s);
 98            Log.d(TAG, "onCancelled");
 99        }
100    }
101 }

LogCat日志:

執行完畢,沒有中途取消任務:

10-06 13:55:05.871 6737-6737/comfallblank.github.asynctasktest D/MyTask: onPreExecute
10-06 13:55:05.891 6737-13040/comfallblank.github.asynctasktest D/MyTask: doInBackground
10-06 13:55:06.922 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:07.923 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:08.914 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:09.925 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:09.975 6737-6753/comfallblank.github.asynctasktest W/art: Suspending all threads took: 18.035ms
10-06 13:55:10.926 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:11.937 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:12.938 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:13.939 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:14.950 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:15.951 6737-6737/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:55:15.971 6737-6737/comfallblank.github.asynctasktest D/MyTask: Task executed
10-06 13:55:15.971 6737-6737/comfallblank.github.asynctasktest D/MyTask: onPostExecute

中途取消任務:

10-06 13:56:10.644 14129-14129/comfallblank.github.asynctasktest D/MyTask: onPreExecute
10-06 13:56:10.654 14129-14302/comfallblank.github.asynctasktest D/MyTask: doInBackground
10-06 13:56:11.665 14129-14129/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:56:12.666 14129-14129/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:56:13.667 14129-14129/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:56:14.668 14129-14129/comfallblank.github.asynctasktest D/MyTask: onProgressUpdate
10-06 13:56:15.689 14129-14129/comfallblank.github.asynctasktest D/MyTask: Task cancelled
10-06 13:56:15.689 14129-14129/comfallblank.github.asynctasktest D/MyTask: onCancelled

關於AsyncTask的一些注意事項:

(1)AsyncTask對象只能使用一次,也就是說一個對象執行完畢或者中途被cancel后,不能再次調用execute().

(2)AsyncTask.execute()只能在主線程中調用。

(3)AsyncTask不能處理並發,多個AsyncTask也是有執行順序的,且同一個應用的所有AsyncTask都是在同一進程中執行,按照隊列排序依次執行。

(4)AsyncTask只能處理那些耗時不是特別長的任務,對於需要長時間執行的任務最好自己實現Thread。

AsyncTask很方便,它屏蔽了所有Thread、Handler、Looper、Message及Messagequene的細節,這或許就是封裝的魅力吧!但當你真正明白了Android的線程通訊之后你就會明白那些良好設計帶來的美感。

以此拋磚引玉!可能多有偏頗,望多交流!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM