Android中AsyncTask與handler用法實例分析
本文實例講述了Android中AsyncTask與handler用法。分享給大家供大家參考,具體如下:
首先,我們得明確下一個概念,什么是UI線程。顧名思義,ui線程就是管理著用戶界面的那個線程!
android的ui線程操作并不是安全的,并且和用戶直接進行界面交互的操作都必須在ui線程中進行才可以。這種模式叫做單線程模式。
我們在單線程模式下編程一定要注意:不要阻塞ui線程、確保只在ui線程中訪問ui組件
當(dāng)我們要執(zhí)行一個復(fù)雜耗時的算法并且最終要將計算結(jié)果反映到ui上時,我們會發(fā)現(xiàn),我們根本沒辦法同時保證上面的兩點要求;我們肯定會想到開啟一個新的線程,讓這個復(fù)雜耗時的任務(wù)到后臺去執(zhí)行,但是執(zhí)行完畢了呢?我們發(fā)現(xiàn),我們無法再與ui進行交互了。
為了解決這種情況,android為我們提供了很多辦法。
1)、handler和message機制:通過顯示的拋出、捕獲消息與ui進行交互;
2)、Activity.runOnUiThread(Runnable):如果當(dāng)前線程為ui線程,則立即執(zhí)行;否則,將參數(shù)中的線程操作放入到ui線程的事件隊列中,等待執(zhí)行。
3)、View.post(Runnable):將操作放入到message隊列中,如果放入成功,該操作將會在ui線程中執(zhí)行,并返回true,否則返回false
4)、View.postDelayed(Runnable, long)跟第三條基本一樣,只不過添加了一個延遲時間。
5)、android1.5以后為我們提供了一個工具類來搞定這個問題AsyncTask.
AsyncTask是抽象類,定義了三種泛型類型 Params,Progress,Result。
Params 啟動任務(wù)執(zhí)行的輸入?yún)?shù),比如HTTP請求的URL
Progress 后臺任務(wù)執(zhí)行的百分比。
Result 后臺執(zhí)行任務(wù)最終返回的結(jié)果,比如String
用程序調(diào)用,開發(fā)者需要做的就是實現(xiàn)這些方法。
1) 子類化AsyncTask
2) 實現(xiàn)AsyncTask中定義的下面一個或幾個方法
onPreExecute(),該方法將在執(zhí)行實際的后臺操作前被UI thread調(diào)用??梢栽谠摲椒ㄖ凶鲆恍?zhǔn)備工作,如在界面上顯示一個進度條。
doInBackground(Params…),將在onPreExecute 方法執(zhí)行后馬上執(zhí)行,該方法運行在后臺線程中。這里將主要負(fù)責(zé)執(zhí)行那些很耗時的后臺計算工作??梢哉{(diào)用 publishProgress方法來更新實時的任務(wù)進度。該方法是抽象方法,子類必須實現(xiàn)。
onProgressUpdate(Progress…),在publishProgress方法被調(diào)用后,UI thread將調(diào)用這個方法從而在界面上展示任務(wù)的進展情況,例如通過一個進度條進行展示。
onPostExecute(Result),在doInBackground 執(zhí)行完成后,onPostExecute 方法將被UI thread調(diào)用,后臺的計算結(jié)果將通過該方法傳遞到UI thread.
為了正確的使用AsyncTask類,以下是幾條必須遵守的準(zhǔn)則:
1) Task的實例必須在UI thread中創(chuàng)建
2) execute方法必須在UI thread中調(diào)用
3) 不要手動的調(diào)用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)這幾個方法
4) 該task只能被執(zhí)行一次,否則多次調(diào)用時將會出現(xiàn)異常
package cn.com.chenzheng_java;
import android.os.AsyncTask;
/**
*
* @author chenzheng_java
* @description 異步任務(wù)AcyncTask示例
*
*/
public class MyAsyncTask extends AsyncTask<String, Integer, Object> {
/**
* 該方法由ui線程進行調(diào)用,用戶可以在這里盡情的訪問ui組件。
* 很多時候,我們會在這里顯示一個進度條啥的,以示后臺正在
* 執(zhí)行某項功能。
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
}
/**
* 該方法由后臺進程進行調(diào)用,進行主要的耗時的那些計算。
* 該方法在onPreExecute方法之后進行調(diào)用。當(dāng)然在執(zhí)行過程中
* 我們可以每隔多少秒就調(diào)用一次publishProgress方法,更新
* 進度信息
*/
@Override
protected Object doInBackground(String... params) {
return null;
}
/**
* doInBackground中調(diào)用了publishProgress之后,ui線程就會
* 調(diào)用該方法。你可以在這里動態(tài)的改變進度條的進度,讓用戶知道
* 當(dāng)前的進度。
*/
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
/**
* 當(dāng)doInBackground執(zhí)行完畢之后,由ui線程調(diào)用。可以在這里
* 返回我們計算的最終結(jié)果給用戶。
*/
@Override
protected void onPostExecute(Object result) {
super.onPostExecute(result);
}
}
下面介紹最本質(zhì)的多線程:hanlder和message機制:
為何需要多線程:
在日常應(yīng)用中,我們通常需要處理一些“后臺,用戶不可見”的操作,例如說,我們需要下載一個音樂,要是你的應(yīng)用必須等用戶下載完成之后才可以進行別的操作,那肯定讓用戶非常的不爽。這時候,我們通常的做法是,讓這些操作去后臺執(zhí)行,然后等后臺執(zhí)行完畢之后,再給用戶彈出相應(yīng)的提示信息。這時候,我們就需要使用多線程機制,然后通過創(chuàng)建一個新的線程來執(zhí)行這些操作。
明白了,實現(xiàn)需求,我們就準(zhǔn)備著手實現(xiàn)了。但是,經(jīng)過進一步的了解,我們悲劇的發(fā)現(xiàn),android中的線程機制是,只能在UI線程中和用戶進行交互。當(dāng)我們創(chuàng)建了一個新線程,執(zhí)行了一些后臺操作,執(zhí)行完成之后,我們想要給用戶彈出對話框以確認(rèn),但是卻悲劇的發(fā)現(xiàn),我們根本無法返回UI主線程了。(UI線程就是你當(dāng)前看到的這些交互界面所屬的線程)。
這時候,我們?nèi)绻胍獙崿F(xiàn)這些功能,我們就需要一個android為我們提供的handler和message機制。
先講解下編程機制:
我們通常在UI線程中創(chuàng)建一個handler,handler相當(dāng)于一個處理器,它主要負(fù)責(zé)處理和綁定到該handler的線程中的message。每一個handler都必須關(guān)聯(lián)一個looper,并且兩者是一一對應(yīng)的,注意,這點很重要哦!此外,looper負(fù)責(zé)從其內(nèi)部的messageQueue中拿出一個個的message給handler進行處理。因為我們這里handler是在UI線程中實現(xiàn)的,所以經(jīng)過這么一個handler、message機制,我們就可以回到UI線程中了。
handler:處理后臺進程返回數(shù)據(jù)的工作人員。
message:后臺進程返回的數(shù)據(jù),里面可以存儲bundle等數(shù)據(jù)格式
messageQueue:是線程對應(yīng)looper的一部分,負(fù)責(zé)存儲從后臺進程中拋回的和當(dāng)前handler綁定的message,是一個隊列。
looper:looper相當(dāng)于一個messageQueue的管理人員,它會不停的循環(huán)的遍歷隊列,然后將符合條件的message一個個的拿出來交給handler進行處理。
注意,handler是在UI線程中聲明的,如果我們直接用類似代碼執(zhí)行一個線程的話,實際上并沒有創(chuàng)建一個新的線程,因為handler已經(jīng)跟默認(rèn)的UI線程中的looper綁定了。
如果有興趣的話,可以去看下Handler的默認(rèn)空構(gòu)造函數(shù)便知道原因了,里面直接綁定了當(dāng)前UI線程的looper。
下面給出一個比較簡單,并且實用的實例。
public class MainActivity extends Activity implements OnClickListener {
private Button btnTXT;
private TextView tvTXT;
private StringBuffer returnMsg;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnTXT = (Button)findViewById(R.id.btnTXT);
tvTXT = (TextView)findViewById(R.id.tvTXT);
btnTXT.setOnClickListener(this);
}
@Override
public void onClick(View v) {
returnMsg = new StringBuffer();
// 創(chuàng)建一個包含Looper的線程,這里如果沒有HandlerThread的調(diào)用,會直接將后邊的MyRunnable放到UI線程隊列(myHandler.post(new MyRunnable()))
HandlerThread handlerThread = new HandlerThread("handler_thread");
handlerThread.start(); // 啟動自定義處理線程
myHandler = new MyHandler(handlerThread.getLooper()); // 將handler綁定到新線程
myHandler.post(new MyRunnable()); // 在新線程中執(zhí)行任務(wù)
}
/** 主線程Handler,可以與UI控件交互 */
Handler mainHanlder = new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.what == 0) {
tvTXT.setText(returnMsg.toString()); // 與主線程控件打交道(直接訪問)
}
}
};
/** 構(gòu)造Hanlder,不可與UI控件直接交互 */
private MyHandler myHandler = null;
private class MyHandler extends Handler{
/**
* 使用默認(rèn)的構(gòu)造函數(shù),會將handler綁定當(dāng)前UI線程的looper。
* 如果想使用多線程這里是不能使用默認(rèn)的構(gòu)造方法的。
*/
public MyHandler(){
super();
}
/** 構(gòu)造函數(shù),自定義looper */
public MyHandler(Looper looper) {
super(looper);
}
// 處理具體的message消息,繼承自父類的方法
@Override
public void handleMessage(Message msg) {
int what = msg.what;
Bundle bundle = (Bundle)msg.obj; // 提取bundle中的信息
String name = bundle.getString("name");
String sex = bundle.getString("sex");
boolean marry = bundle.getBoolean("marray");
int age = bundle.getInt("age");
StringBuffer strBuf = new StringBuffer(); // 拼接bundle信息
strBuf.append("what = ").append(what).append("\n\n");
strBuf.append("name = ").append(name).append("\n");
strBuf.append("sex = ").append(sex).append("\n");
strBuf.append("marry = ").append(marry).append("\n");
strBuf.append("age = ").append(age).append("\n\n");
strBuf.append("http://blog.csdn.net/sunboy_2050");
returnMsg = returnMsg.append(strBuf); // 保存要顯示的結(jié)果
mainHanlder.sendEmptyMessage(0); // 向主線程mainHanlder發(fā)送消息,與UI控件交互顯示結(jié)果
super.handleMessage(msg);
}
}
// 構(gòu)造Runnable,處理后臺業(yè)務(wù)邏輯,如下載
private class MyRunnable implements Runnable{
@Override
public void run() {
try {
Message msg = Message.obtain(myHandler); // 捕獲myHandler消息
msg.what = 10;
Bundle bundle = new Bundle(); // 封裝bundle信息
bundle.putString("name", "yanggang");
bundle.putString("sex", "pure boy");
bundle.putBoolean("marry", false);
bundle.putInt("age", 18);
msg.obj = bundle;
long thID = Thread.currentThread().getId();
returnMsg.append(thID).append(" : send msg start...").append("\n");
msg.sendToTarget(); // 向myHandler發(fā)送消息
Thread.sleep(3000);
} catch (Exception e) {
Log.i("", "Runnable send msg error...");
e.printStackTrace();
}
}
}
}
運行結(jié)果:

完整實例代碼代碼點擊此處本站下載。
希望本文所述對大家Android程序設(shè)計有所幫助。
相關(guān)文章
Android開發(fā)實現(xiàn)廣告無限循環(huán)功能示例
這篇文章主要介紹了Android開發(fā)實現(xiàn)廣告無限循環(huán)功能,結(jié)合完整實例形式分析了Android廣告圖片輪播功能的具體實現(xiàn)步驟與相關(guān)功能、布局等操作技巧,需要的朋友可以參考下2017-11-11
Android中AutoCompleteTextView與MultiAutoCompleteTextView的用法
這篇文章主要介紹了Android中AutoCompleteTextView與MultiAutoCompleteTextView的用法,需要的朋友可以參考下2014-07-07
Android ListView實現(xiàn)無限循環(huán)滾動
這篇文章主要為大家詳細(xì)介紹了Android ListView實現(xiàn)無限循環(huán)滾動,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-06-06
Android開發(fā)強制橫屏和強制豎屏設(shè)置實例代碼
本篇文章主要介紹了Android開發(fā)強制橫屏和強制豎屏設(shè)置實例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-04-04
Android利用屬性動畫實現(xiàn)優(yōu)酷菜單
這篇文章主要為大家詳細(xì)介紹了Android利用屬性動畫實現(xiàn)優(yōu)酷菜單,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-01-01
Android學(xué)習(xí)之SharedPerference存儲詳解
這篇文章主要為大家詳細(xì)介紹了Android學(xué)習(xí)之SharedPerference存儲的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08
kotlin中的數(shù)據(jù)轉(zhuǎn)換方法(示例詳解)
這篇文章介紹了Kotlin中將數(shù)字轉(zhuǎn)換為字符串和字符串轉(zhuǎn)換為數(shù)字的多種方法,包括使用`toString()`、字符串模板、格式化字符串、處理可空類型等,同時,也詳細(xì)講解了如何安全地進行字符串到數(shù)字的轉(zhuǎn)換,并處理了不同進制和本地化格式的字符串轉(zhuǎn)換,感興趣的朋友一起看看吧2025-03-03
一文理解Android系統(tǒng)中強指針的實現(xiàn)
因為Android中很多地方代碼是用C++編寫,為了能夠保證C++中指針能夠被正確的釋放,于是Android引入了其實在C++中已經(jīng)有的智能指針技術(shù)2021-10-10

