黄色网页视频 I 影音先锋日日狠狠久久 I 秋霞午夜毛片 I 秋霞一二三区 I 国产成人片无码视频 I 国产 精品 自在自线 I av免费观看网站 I 日本精品久久久久中文字幕5 I 91看视频 I 看全色黄大色黄女片18 I 精品不卡一区 I 亚洲最新精品 I 欧美 激情 在线 I 人妻少妇精品久久 I 国产99视频精品免费专区 I 欧美影院 I 欧美精品在欧美一区二区少妇 I av大片网站 I 国产精品黄色片 I 888久久 I 狠狠干最新 I 看看黄色一级片 I 黄色精品久久 I 三级av在线 I 69色综合 I 国产日韩欧美91 I 亚洲精品偷拍 I 激情小说亚洲图片 I 久久国产视频精品 I 国产综合精品一区二区三区 I 色婷婷国产 I 最新成人av在线 I 国产私拍精品 I 日韩成人影音 I 日日夜夜天天综合

Android AsyncTask與handler

系統(tǒng) 2302 0

本文主要講解下AsyncTask的使用以及Handler的應用

首先,我們得明確下一個概念,什么是UI線程。顧名思義,ui線程就是管理著用戶界面的那個線程!

android的ui線程操作并不是安全的,并且和用戶直接進行界面交互的操作都必須在ui線程中進行才可以。這種模式叫做單線程模式。

我們在單線程模式下編程一定要注意: 不要阻塞ui線程、確保只在ui線程中訪問ui組件

當我們要執(zhí)行一個復雜耗時的算法并且最終要將計算結果反映到ui上時,我們會發(fā)現,我們根本沒辦法同時保證上面的兩點要求;我們肯定會想到開啟一個新的線程,讓這個復雜耗時的任務到后臺去執(zhí)行,但是執(zhí)行完畢了呢?我們發(fā)現,我們無法再與ui進行交互了。

為了解決這種情況,android為我們提供了很多辦法。

1)、handler和message機制:通過顯示的拋出、捕獲消息與ui進行交互;

2)、Activity.runOnUiThread(Runnable):如果當前線程為ui線程,則立即執(zhí)行;否則,將參數中的線程操作放入到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 啟動任務執(zhí)行的輸入參數,比如HTTP請求的URL

Progress 后臺任務執(zhí)行的百分比。

Result 后臺執(zhí)行任務最終返回的結果,比如String

用程序調用,開發(fā)者需要做的就是實現這些方法。

1) 子類化AsyncTask

2) 實現AsyncTask中定義的下面一個或幾個方法

onPreExecute() ,該方法將在執(zhí)行實際的后臺操作前被UI thread調用。可以在該方法中做一些準備工作,如在界面上顯示一個進度條。

doInBackground(Params…) ,將在onPreExecute 方法執(zhí)行后馬上執(zhí)行,該方法運行在后臺線程中。這里將主要負責執(zhí)行那些很耗時的后臺計算工作。可以調用 publishProgress方法來更新實時的任務進度。該方法是抽象方法,子類必須實現。

onProgressUpdate(Progress…) ,在publishProgress方法被調用后,UI thread將調用這個方法從而在界面上展示任務的進展情況,例如通過一個進度條進行展示。

onPostExecute(Result) ,在doInBackground 執(zhí)行完成后,onPostExecute 方法將被UI thread調用,后臺的計算結果將通過該方法傳遞到UI thread.

為了正確的使用AsyncTask類,以下是幾條必須遵守的準則:

1) Task的實例必須在UI thread中創(chuàng)建

2) execute方法必須在UI thread中調用

3) 不要手動的調用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)這幾個方法

4) 該task只能被執(zhí)行一次,否則多次調用時將會出現異常

    package cn.com.chenzheng_java;
 
import android.os.AsyncTask;
/**
 * 
 * @author chenzheng_java
 * @description 異步任務AcyncTask示例
 *    
 */
public class MyAsyncTask extends AsyncTask<String, Integer, Object> {
 
 /**
 * 該方法由ui線程進行調用,用戶可以在這里盡情的訪問ui組件。
 * 很多時候,我們會在這里顯示一個進度條啥的,以示后臺正在
 * 執(zhí)行某項功能。
 */
 @Override
 protected void onPreExecute() {
 super.onPreExecute();
 }
 
 /**
 * 該方法由后臺進程進行調用,進行主要的耗時的那些計算。
 * 該方法在onPreExecute方法之后進行調用。當然在執(zhí)行過程中
 * 我們可以每隔多少秒就調用一次publishProgress方法,更新
 * 進度信息
 */
 @Override
 protected Object doInBackground(String... params) {
 return null;
 }
 
 
 /**
 * doInBackground中調用了publishProgress之后,ui線程就會
 * 調用該方法。你可以在這里動態(tài)的改變進度條的進度,讓用戶知道
 * 當前的進度。
 */
 @Override
 protected void onProgressUpdate(Integer... values) {
 super.onProgressUpdate(values);
 }
 
 /**
 * 當doInBackground執(zhí)行完畢之后,由ui線程調用。可以在這里
 * 返回我們計算的最終結果給用戶。
 */
 @Override
 protected void onPostExecute(Object result) {
 super.onPostExecute(result);
 }
}
  


下面介紹最本質的多線程:hanlder和message機制:

為何需要多線程:

在日常應用中,我們通常需要處理一些“后臺,用戶不可見”的操作,例如說,我們需要下載一個音樂,要是你的應用必須等用戶下載完成之后才可以進行別的操作,那肯定讓用戶非常的不爽。這時候,我們通常的做法是,讓這些操作去后臺執(zhí)行,然后等后臺執(zhí)行完畢之后,再給用戶彈出相應的提示信息。這時候,我們就需要使用多線程機制,然后通過創(chuàng)建一個新的線程來執(zhí)行這些操作。

明白了,實現需求,我們就準備著手實現了。但是,經過進一步的了解,我們悲劇的發(fā)現,android中的線程機制是,只能在UI線程中和用戶進行交互。當我們創(chuàng)建了一個新線程,執(zhí)行了一些后臺操作,執(zhí)行完成之后,我們想要給用戶彈出對話框以確認,但是卻悲劇的發(fā)現,我們根本無法返回UI主線程了。 (UI線程就是你當前看到的這些交互界面所屬的線程)。

這時候,我們如果想要實現這些功能,我們就需要一個android為我們提供的handler和message機制。

先講解下編程機制:

我們通常 在UI線程中創(chuàng)建一個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的管理人員,它會不停的循環(huán)的遍歷隊列,然后將符合條件的message一個個的拿出來交給handler進行處理。

注意,handler是在UI線程中聲明的,如果我們直接用類似代碼執(zhí)行一個線程的話,實際上并沒有創(chuàng)建一個新的線程,因為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();
		
		// 創(chuàng)建一個包含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());		// 在新線程中執(zhí)行任務 
	}
    
	/** 主線程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發(fā)送消息,與UI控件交互顯示結果
			
			super.handleMessage(msg);
		}
	}
    
	
	// 構造Runnable,處理后臺業(yè)務邏輯,如下載
	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();
			}
		}
	}
}
  

運行結果:

Android AsyncTask與handler


示例代碼下載



轉載聲明:

Android之多線程工作-AsyncTask與handler

Android自用-----AsyncTask實現異步處理任務

android線程 Handler Message Queue AsyncTask


參考推薦:

java synchronized詳解

java中synchronized用法

Android實現計時與倒計時的幾種方法

java同步synchronized關鍵字用法示例

Android AsyncTask與handler


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

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

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論