亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Android AsyncTask與handler

系統 1938 0

本文主要講解下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與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元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 99热播在线观看 | 亚洲欧美日韩高清一区二区一 | 四虎影视国产在线观看精品 | 国产精品国产精品国产专区不卡 | 国产nv精品你懂得 | 中文线码中文高清播放中 | 国产日韩欧美精品在线 | 97影院网 | 婷综合 | 一级特黄aaa大片大全 | 久久国产美女免费观看精品 | 亚洲欧美综合一区二区三区四区 | 国产精品福利在线 | 国内自拍一二三四2021 | 久久爱www| 四虎家庭影院 | 欧美日韩一区二区三区久久 | 亚洲欧美日韩第一页 | 国产福利91精品一区二区 | 国产成人亚洲精品无广告 | 青青青爽国产在线视频 | 国产乱子伦一级毛片 | 91免费国产高清观看 | 九九视频高清视频免费观看 | 亚洲成人免费看 | 四虎4hu永久免费视频大全 | 98色花堂国产精品首页 | 看欧美的一级毛片 | 色涩网站在线观看 | 黄色综合| 日产一二三四五六七区麻豆 | 五月天婷婷网址 | 国产免费一区二区三区在线 | 精品亚洲成a人在线观看 | 日本成人不卡 | 久久精品国产99国产精品免费看 | 性做久久 | 日本一区不卡视频 | 精品一区二区三区在线视频观看 | 久热精品在线 | 80s成年女人毛片免费观看观看 |