本文主要講解下AsyncTask的使用以及Handler的應用
首先,我們得明確下一個概念,什么是UI線程。顧名思義,ui線程就是管理著用戶界面的那個線程!
android的ui線程操作并不是安全的,并且和用戶直接進行界面交互的操作都必須在ui線程中進行才可以。這種模式叫做單線程模式。
我們在單線程模式下編程一定要注意: 不要阻塞ui線程、確保只在ui線程中訪問ui組件
當我們要執行一個復雜耗時的算法并且最終要將計算結果反映到ui上時,我們會發現,我們根本沒辦法同時保證上面的兩點要求;我們肯定會想到開啟一個新的線程,讓這個復雜耗時的任務到后臺去執行,但是執行完畢了呢?我們發現,我們無法再與ui進行交互了。
為了解決這種情況,android為我們提供了很多辦法。
1)、handler和message機制:通過顯示的拋出、捕獲消息與ui進行交互;
2)、Activity.runOnUiThread(Runnable):如果當前線程為ui線程,則立即執行;否則,將參數中的線程操作放入到ui線程的事件隊列中,等待執行。
3)、View.post(Runnable):將操作放入到message隊列中,如果放入成功,該操作將會在ui線程中執行,并返回true,否則返回false
4)、View.postDelayed(Runnable, long)跟第三條基本一樣,只不過添加了一個延遲時間。
5)、android1.5以后為我們提供了一個工具類來搞定這個問題AsyncTask.
AsyncTask是抽象類 ,定義了三種泛型類型 Params,Progress,Result。
Params 啟動任務執行的輸入參數,比如HTTP請求的URL
Progress 后臺任務執行的百分比。
Result 后臺執行任務最終返回的結果,比如String
用程序調用,開發者需要做的就是實現這些方法。
1) 子類化AsyncTask
2) 實現AsyncTask中定義的下面一個或幾個方法
onPreExecute() ,該方法將在執行實際的后臺操作前被UI thread調用。可以在該方法中做一些準備工作,如在界面上顯示一個進度條。
doInBackground(Params…) ,將在onPreExecute 方法執行后馬上執行,該方法運行在后臺線程中。這里將主要負責執行那些很耗時的后臺計算工作。可以調用 publishProgress方法來更新實時的任務進度。該方法是抽象方法,子類必須實現。
onProgressUpdate(Progress…) ,在publishProgress方法被調用后,UI thread將調用這個方法從而在界面上展示任務的進展情況,例如通過一個進度條進行展示。
onPostExecute(Result) ,在doInBackground 執行完成后,onPostExecute 方法將被UI thread調用,后臺的計算結果將通過該方法傳遞到UI thread.
為了正確的使用AsyncTask類,以下是幾條必須遵守的準則:
1) Task的實例必須在UI thread中創建
2) execute方法必須在UI thread中調用
3) 不要手動的調用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)這幾個方法
4) 該task只能被執行一次,否則多次調用時將會出現異常
package cn.com.chenzheng_java; import android.os.AsyncTask; /** * * @author chenzheng_java * @description 異步任務AcyncTask示例 * */ public class MyAsyncTask extends AsyncTask<String, Integer, Object> { /** * 該方法由ui線程進行調用,用戶可以在這里盡情的訪問ui組件。 * 很多時候,我們會在這里顯示一個進度條啥的,以示后臺正在 * 執行某項功能。 */ @Override protected void onPreExecute() { super.onPreExecute(); } /** * 該方法由后臺進程進行調用,進行主要的耗時的那些計算。 * 該方法在onPreExecute方法之后進行調用。當然在執行過程中 * 我們可以每隔多少秒就調用一次publishProgress方法,更新 * 進度信息 */ @Override protected Object doInBackground(String... params) { return null; } /** * doInBackground中調用了publishProgress之后,ui線程就會 * 調用該方法。你可以在這里動態的改變進度條的進度,讓用戶知道 * 當前的進度。 */ @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); } /** * 當doInBackground執行完畢之后,由ui線程調用。可以在這里 * 返回我們計算的最終結果給用戶。 */ @Override protected void onPostExecute(Object result) { super.onPostExecute(result); } }
下面介紹最本質的多線程:hanlder和message機制:
為何需要多線程:
在日常應用中,我們通常需要處理一些“后臺,用戶不可見”的操作,例如說,我們需要下載一個音樂,要是你的應用必須等用戶下載完成之后才可以進行別的操作,那肯定讓用戶非常的不爽。這時候,我們通常的做法是,讓這些操作去后臺執行,然后等后臺執行完畢之后,再給用戶彈出相應的提示信息。這時候,我們就需要使用多線程機制,然后通過創建一個新的線程來執行這些操作。
明白了,實現需求,我們就準備著手實現了。但是,經過進一步的了解,我們悲劇的發現,android中的線程機制是,只能在UI線程中和用戶進行交互。當我們創建了一個新線程,執行了一些后臺操作,執行完成之后,我們想要給用戶彈出對話框以確認,但是卻悲劇的發現,我們根本無法返回UI主線程了。 (UI線程就是你當前看到的這些交互界面所屬的線程)。
這時候,我們如果想要實現這些功能,我們就需要一個android為我們提供的handler和message機制。
先講解下編程機制:
我們通常 在UI線程中創建一個handler,handler相當于一個處理器 ,它主要負責處理和綁定到該handler的線程中的message。每一個handler都必須關聯一個looper,并且兩者是一一對應的,注意,這點很重要哦!此外,looper負責從其內部的messageQueue中拿出一個個的message給handler進行處理。因為我們這里handler是在UI線程中實現的,所以經過這么一個handler、message機制,我們就可以回到UI線程中了。
handler: 處理后臺進程返回數據的工作人員。
message: 后臺進程返回的數據,里面可以存儲bundle等數據格式
messageQueue: 是線程對應looper的一部分,負責存儲從后臺進程中拋回的和當前handler綁定的message,是一個隊列。
looper: looper相當于一個messageQueue的管理人員,它會不停的循環的遍歷隊列,然后將符合條件的message一個個的拿出來交給handler進行處理。
注意,handler是在UI線程中聲明的,如果我們直接用類似代碼執行一個線程的話,實際上并沒有創建一個新的線程,因為handler已經跟默認的UI線程中的looper綁定了。
如果有興趣的話,可以去看下Handler的默認空構造函數便知道原因了,里面直接綁定了當前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(); // 創建一個包含Looper的線程,這里如果沒有HandlerThread的調用,會直接將后邊的MyRunnable放到UI線程隊列(myHandler.post(new MyRunnable())) HandlerThread handlerThread = new HandlerThread("handler_thread"); handlerThread.start(); // 啟動自定義處理線程 myHandler = new MyHandler(handlerThread.getLooper()); // 將handler綁定到新線程 myHandler.post(new MyRunnable()); // 在新線程中執行任務 } /** 主線程Handler,可以與UI控件交互 */ Handler mainHanlder = new Handler(){ @Override public void handleMessage(Message msg) { if(msg.what == 0) { tvTXT.setText(returnMsg.toString()); // 與主線程控件打交道(直接訪問) } } }; /** 構造Hanlder,不可與UI控件直接交互 */ private MyHandler myHandler = null; private class MyHandler extends Handler{ /** * 使用默認的構造函數,會將handler綁定當前UI線程的looper。 * 如果想使用多線程這里是不能使用默認的構造方法的。 */ public MyHandler(){ super(); } /** 構造函數,自定義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); // 保存要顯示的結果 mainHanlder.sendEmptyMessage(0); // 向主線程mainHanlder發送消息,與UI控件交互顯示結果 super.handleMessage(msg); } } // 構造Runnable,處理后臺業務邏輯,如下載 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發送消息 Thread.sleep(3000); } catch (Exception e) { Log.i("", "Runnable send msg error..."); e.printStackTrace(); } } } }
運行結果:
轉載聲明:
Android之多線程工作-AsyncTask與handler
Android自用-----AsyncTask實現異步處理任務
android線程 Handler Message Queue AsyncTask
參考推薦:
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
