標籤:android應用
轉載請表明出處:http://blog.csdn.net/u012637501(嵌入式_小J的天空)
一、引言 我們知道Android的UI線程主要負責處理使用者的按鍵事件、使用者觸屏事件及螢幕繪圖事件等,對於其他的操作盡量不要在UI線程中實現,因為這些操作很有可能會阻塞UI線程,比如一些耗時操作,會導致UI介面停止回應,從而降低了使用者的體驗。所以,為了避免UI線程失去響應的問題,Android建議將耗時操作放在新線程中完成,但新線程也可能需要動態更新UI組件:比如需要從網上擷取一個網頁,然後在TextView中將其原始碼顯示出來,此時就應該將串連網路,擷取網路資料的操作(耗時)放在新線程中完成。 但是,問題來了:當擷取網路資料之後,由於新線程不允許直接更新UI組件,我們該如何更新UI組件資料呢?為瞭解決新線程不能更新UI組件問題,Android提供了如下幾種解決方案:(1)使用Handler訊息傳遞機制實現線程之間的通訊(如上一篇文章所述);(2)Activity.runOnUiThread(Runnable);(3)View.post(Runnable);(4)View.postDelayed(Runnable long);(5)非同步任務。又由於(2)~(4)方式有可能導致編程有點繁瑣,而非同步任務則可簡化這種操作。
二、AsyncTask簡介 Android的類AsyncTask對線程間通訊進行了封裝,提供了簡易的編程方式使後台線程和UI線程進行通訊:後台線程執行非同步任務,並把操作結果通知UI。不再需要子線程和Handler就可以完成非同步作業並且重新整理使用者介面。
1.AsyncTask類 AsyncTask<>是一個抽象類別,通常用於被繼承,繼承AsyncTask時需要指定如下三種泛型參數:(1)Params:啟動任務執行輸入參數的類型;(2)Progress:背景工作完成的進度值(百分比)的類型;(3)Result:後台執行任務完成後返回結果的類型,如String、Integer;
2.Async類中主要方法(1)onPreExecute():該方法將在執行實際的後台操作前被UI線程調用。可以在該方法中做一些準備工作,如在介面上顯示一個進度條,或者一些控制項的執行個體化,這個方法可以不用實現。-----(UI線程調用,後台線程未啟動,初始化工作)(2)doInBackground(Params...values):將在onPreExecute 方法執行後馬上執行,該方法運行在後台線程中。這裡將主要負責執行那些比較耗時的幕後處理工作。可以調用 publishProgress()方法來即時更新任務進度。該方法是抽象方法,子類必須實現。-----(後台線程調用,執行背景工作)
(3)onProgressUpdate(Progress...values):在publishProgress方法被調用後,UI 線程將調用這個方法從而在介面上展示任務的進展情況,例如通過一個進度條進行展示。-----(UI線程調用,展現背景工作進展)
(4)onPostExecute(Result):在doInBackground 執行完成後,onPostExecute 方法將被UI線程調用,背景計算結果(doInBackground方法返回值)將通過該方法傳遞到UI線程,並且在介面上展示給使用者。-----(UI線程調用,顯示後台線程運行結果)(5) onCancelled():在使用者取消線程操作的時候調用。在主線程中調用onCancelled()的時候調用。-----(UI線程調用,取消後台線程)
三、非同步任務處理開發步驟1.建立AsyncTask的子類,並為三個泛型參數指定類型。如果某個泛型參數不需要指定類型,則將它指定為Void。2.根據需要實現AsyncTask上述五中方法;3.調用AsyncTask子類的執行個體的execute(Params... params)開始執行耗時任務。另外,使用AsyncTask類需要遵守的以下準則:(1)Task的執行個體必須在UI線程中建立;(2)execute(Params...)方法必須在UI線程中調用;(3)不要手動的調用onPreExecute(), onPostExecute(Result),doInBackground(Params...),onProgressUpdate(Progress...)這幾個方法,需要在UI線程中執行個體化這個task來調用;(4)該task只能被執行一次,否者多次調用時將會出現異常。
四、源碼實戰
1.實現功能
2.源碼實現
(1)MainActivity.java功能:用以擷取介面組件,執行個體化一個AsyncTask子類對象並調用其exeute(Integer....params)方法以指定參數params運行一個任務。
package com.example.android_asynctask;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.ProgressBar;import android.widget.TextView;public class MainActivity extends Activity { private Button downbtn; private TextView textView; private ProgressBar progressBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); downbtn = (Button)findViewById(R.id.download); textView = (TextView)findViewById(R.id.text); progressBar = (ProgressBar)findViewById(R.id.progressBar); final DownloadTest download = new DownloadTest(textView,progressBar);//擷取一個DownloadTest對象,並傳遞組件對象參數 downbtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { download.execute(200); } }); }}
(2)DownloadTest.java功能:繼承於AsyncTask的子類,其中onPreExecute()作用是為運行後台線程(子線程)完成初始化工作;doInBackground方法運行後台線程;onProgressUpdate方法更新UI;onPostExecute方法處理後台線程運行結果。
package com.example.android_asynctask;import android.graphics.Color;import android.os.AsyncTask;import android.view.View;import android.widget.ProgressBar;import android.widget.TextView;public class DownloadTest extends AsyncTask<Integer,Integer,String>{ private TextView tv; private ProgressBar pb; //帶參數構造方法 DownloadTest(TextView text,ProgressBar bar) { this.tv = text; this.pb = bar; } //不帶參數構造方法 DownloadTest() { } /*1.onPreExecute方法 * 為子線程(後台)運行初始化相關內容 */ protected void onPreExecute() { tv.setVisibility(View.VISIBLE); //設定顯示文本組件 pb.setVisibility(View.VISIBLE); //設定顯示進度條 super.onPreExecute(); } /*2.doInBackground方法 * 運行一個後台線程,該線程實現每arg0[0]毫秒調用一次onProgressUpdate方法 */ protected String doInBackground(Integer... arg0) { for(int i=0;i<100;i++) { publishProgress(i); //調用onProgressUpdate方法並傳遞參數i try { Thread.sleep(arg0[0]);//累加一次,線程休眠argo[0]毫秒 } catch (InterruptedException e) { e.printStackTrace(); } } return "下載完畢"; //後檯子線程運行完畢後,返回的值 } /*3.onProgressUpdate方法 * 調用publishProgress(i)時調用該方法,並傳遞參數i給形參values[0]*/ @Override protected void onProgressUpdate(Integer... values) { pb.setProgress(values[0]); //設定進度條值 tv.setText("已經下載"+values[0]+"%"); //文本組件顯示提示資訊 super.onProgressUpdate(values); } /*4.onPostExecute * 處理後台線程得到的結果 * */ protected void onPostExecute(String result) { pb.setVisibility(View.INVISIBLE);//隱藏進度條 tv.setVisibility(View.VISIBLE);//顯示UI文本顯示框組件 tv.setText(result); tv.setTextSize(20); tv.setTextColor(Color.RED); super.onPostExecute(result); }}
效果示範:
源碼分析: 通過源碼我們可以知道,主線程通過調用AsyncTask子類的execute()方法,進而調用AsyncTask子類的onPreExecute方法,用以再運行後台線程之前為其初始化相關內容。然後,在新建立的子線程中調用doInBackground()方法實現後台線程功能並通過publishProgress()方法調用onProgressUpdate()方法更新UI內容,最後在主線中執行onPostExecute方法來處理後台線程啟動並執行結果。注意:其中只有doInBackground()方法,以及publishProgress()方法是在子線程中執行的,其他的方法都是在主線程中執行的,所以可以在這些方法中更新介面組件。
Android筆記二十六.Android非同步任務處理(AsyncTask)