Android在設計時引入了Handler消息機制,每個消息發送到主線路的消息隊列中,消息隊列遵循先進先出原則,發送消息不會阻塞線程,而接收線程會阻塞線程。Handler容許發送並處理Message消息,Message對象經過主線程的MessageQueue消息隊列相關聯的Message和Runnable對象進行存取。每一個Handler實例對Message消息發送和接收與對應主線程和主線程的消息隊列有關。當建立一個新的Handler時,Handler就屬於當前主線程,主線程MessageQueue消息隊列也同步建立,即Handler會綁定到建立該Handler的主線程/消息隊列上。而後,Handler就能夠經過主線程的消息隊列發送和接收Message消息對象了。java
Handler的特性android
1)Android裏沒有全局Message Queue消息隊列,每一個Activity主線程都有一個獨立的Message Queue消息隊列,消息隊列採用先進先出原則。不一樣APK應用不能經過Handler進行Message通訊,同一個APK應用中能夠經過Handler對象傳遞而進行Message通訊。app
2)每一個Handler實例都會綁定到建立它的線程中(通常位於主線程,即Activity線程),可是Handler實例能夠在任意線程中建立(能夠在主線程或子線程中建立)異步
3)Handler發送消息使用Message Queue消息隊列,每一個Message發送到消息隊列裏面;發送消息採用異步方式,因此不會阻塞線程。而接收線程則採用同步方式,因此會阻塞線程,因此當Handler處理完一個Message對象後纔會去取下一下消息進行處理。ide
下面咱們經過一個實例來加深一下對以上內容的理解,在這個實現中,經過四個Button的onClick事件,實現不一樣方式的Handler消息處理機制。函數
button_1:完成在主線程中傳遞Handler消息處理oop
button_2:在子線程中完成Handler消息處理this
button_3:在其它線程完傳入Handler對象並完成其消息處理spa
button_4:一個實驗,驗證在其它線程中更新ActivityUI時會拋出異常(這個我沒實現,感興趣的本身寫吧).net
話很少說,直接上源碼吧
1)activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" > <Button android:id="@+id/button_1" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="handle msg in main thread"/> <Button android:id="@+id/button_2" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="handle msg in sub thread"/> <Button android:id="@+id/button_3" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="handler comes from other thread"/> <Button android:id="@+id/button_4" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="refresh ActivityUI in other thread"/> </LinearLayout>
2)MainActivity.java
package cn.lion.handlertest; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; public class MainActivity extends Activity implements OnClickListener{ private Button button1 = null; private Button button2 = null; private Button button3 = null; //private Button button4 = null; private MyHandler mHandler = null; private Message msg = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button1 = (Button)findViewById(R.id.button_1); button2 = (Button)findViewById(R.id.button_2); button3 = (Button)findViewById(R.id.button_3); //button4 = (Button)findViewById(R.id.button_4); button1.setOnClickListener(this); button2.setOnClickListener(this); button3.setOnClickListener(this); //button4.setOnClickListener(this); } @Override public void onClick(View v) { dealOnClick(v.getId()); } /** * 自定義一個處理onClick事件的方法 * @param msgId */ private void dealOnClick(int msgId) { mHandler = new MyHandler(); //子線程和主線程均可以操做這個mHandler,固然也能夠在switch的具體case中才建立 switch(msgId){ case R.id.button_1: // 主線程中建立MyHandler對象,mHandler建立Handler消息類型爲一、消息對象爲字符串的Message對象 //mHandler = new MyHandler(); msg = mHandler.obtainMessage(1, (Object)"Main thread send message by Message Object"); msg.sendToTarget(); //Handler 發送消息 break; case R.id.button_2: InnerThread innerThread = new InnerThread(); innerThread.start(); //內部線程異步處理button_2的事件 break; case R.id.button_3: //mHandler = new MyHandler(); SubThread subThread = new SubThread(mHandler); //把主線程中建立的mHandler對象傳遞給子線程 subThread.start(); //子線程對象,用於異步處理Handler Message消息 break; } } /** * 自定義MyHandler,繼承自Handler,覆蓋父類的 handleMessage() 方法,msg.obj * 是Message對象傳遞過來的Object對象,本例中爲String對象 。 * @author lion * */ public class MyHandler extends Handler{ public MyHandler(Looper myLooper){ super(myLooper); //重寫構造方法,經過Looper建立MyHandler對象 } public MyHandler(){ } @Override public void handleMessage(Message msg){ String str = ""; switch(msg.what){ case 1: str = "1: " + msg.obj; break; case 2: str = "2: " + msg.obj; break; case 3: str = "3: " + msg.obj; break; } Toast toast = Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT); toast.show(); } } private class InnerThread extends Thread{ @Override public void run(){ //只能在Activity的主線程中使用不帶Looper對象的構造函數來建立Handler對象,因此此行會拋出異常 //mHandler = new MyHandler(); //Lopper.myLooper()獲取Looper爲null,因此此行會拋出異常 //mHandler = new MyHandler(Looper.myLooper()); //經過Looper.getMainLooper()獲取父類的looper能夠成功建立Handler對象並將Message了送到父類 mHandler = new MyHandler(Looper.getMainLooper()); Message msg = mHandler.obtainMessage(2, (Object)"Inner thread send message by Message Object"); msg.sendToTarget(); } } /** * 子線程經過Handler對象建立Message對象,並在子線程中發送Handler消息,這個消息將由主線程在handleMessage中接收並響應 * @author lion * */ public class SubThread extends Thread{ private Handler mHandler; public SubThread(Handler mHandler){ this.mHandler = mHandler; } @Override public void run(){ Message msg = mHandler.obtainMessage(3, (Object)"Other thread send message by myHandler"); msg.sendToTarget(); } } }
仔細分析一下Handler的做用:經過上面的實例能夠看出,Handler的主要做用是異步處理較費時的操做,優先將界面返回給用戶,異步處理完成後再去更新用戶界面。在Android中啓動應用程序時,Android首先會開啓一個主線程(即UI線程),主線程專門管理界面中的UI控件,對事件進行分發,如點擊一個Button,Android會分發事件到具體的Button上,以響應用戶的操做。
若是須要處理一個耗時的操做,以下載文件,那麼這種操做就絕對不應放到主線程中進行,不然界面會出現假死現象。咱們要把這種耗時的操做放到子線程中去處理,子線程處理完成後再根據處理結果決定是否通知主線程更新UI,注意在子線程中是沒法更新主線程的界面(UI)的。爲了解決這個問題,Android引入了Handler,因爲Handler運行在主線程中(即運行於Activity UI線程中),它與子線程能夠經過Message對象來傳遞數據。因此能夠利用Handler,從子線程中向主線程發送更新UI的消息,從而實現了UI的及時更新。
至於主線程和子線程如何通訊、Handler如何獲取Message等問題,見我上篇文章 android的消息處理機制——Looper,Handler,Message