Handler訊息傳遞機制淺析
本節引言
前兩節中我們對Android中的兩種事件處理機制進行了學習,關於回應的事件回應就這兩種;本節告訴大家的 是Activity中UI元件中的訊息傳遞Handler,相信很多朋友都知道,Android為了執行緒安全,並不允許我們在UI執行緒外操作UI;很多時候我們做介面刷新都需要透過Handler來通知UI元件更新!除了用Handler完成介面更新外,還可以使用runOnUiThread()來更新,甚至更高級的事務總線,當然,這裡我們只講解Handler,什麼是Handler,執行流程,相關方法,子線程與主線程中使用Handler的區別等!
學習路線圖:
#2.Handler類別的引入:
#3.Handler的執行流程圖:
#流程圖解析:相關名詞
- UI執行緒:就是我們的主執行緒,系統在建立UI執行緒的時候會初始化一個Looper物件,同時也會建立一個與其關聯的MessageQueue;
- Handler:作用就是傳送與處理訊息,如果希望Handler正常運作,在目前執行緒中要有一個Looper物件
- Message: Handler接收與處理的訊息物件
- MessageQueue:訊息佇列,先進先出管理Message,在初始化Looper物件時會建立一個與之關聯的MessageQueue;
- Looper:每個執行緒只能夠有一個Looper,管理MessageQueue,不斷地從中取出Message分發給對應的Handler處理!
簡單說:
#當我們的子執行緒想要修改Activity中的UI元件時,我們可以新建一個Handler物件,透過這個物件傳送訊息給主執行緒;而我們傳送的訊息會先到主執行緒的MessageQueue進行等待,由Looper按先入先出順序取出,再根據message物件的what屬性分發給對應的Handler進行處理!
4.Handler的相關方法:
- void handleMessage(Message msg):處理訊息的方法,通常是用於被重寫!
- sendEmptyMessage(int what):發送空訊息
- sendEmptyMessageDelayed(int what,long delayMillis):指定延時多少毫秒後傳送空白訊息
- sendMessage(Message msg):立即傳送訊息
- sendMessageDelayed(Message msg):指定延時多少毫秒後傳送訊息
- final boolean hasMessage(int what):檢查訊息佇列中是否包含what屬性為指定值的訊息 如果是參數為(int what,Object object):除了判斷what屬性,還需要判斷Object屬性是否為指定物件的訊息
5.Handler的使用範例:
1)Handler寫在主執行緒中
在主執行緒中,因為系統已經初始化了一個Looper物件,所以我們直接建立Handler物件,就可以進行訊息的傳送與處理了!
程式碼範例:簡單的一個定時切換圖片的程式,透過Timer定時器,定時修改ImageView顯示的內容,從而形成幀動畫
#執行效果圖:
#實作程式碼:
xmlns:tools="http://schemas.android.com/tools" ##oroidand : @+id/RelativeLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="match_parent"
android:layout_height="match_parent"
jay.example. handlerdemo1.MainActivity" >
#
<ImageView
android
android:layout_height="wrap_content"
and?
MainActivity.java:
//已定義切換的圖片的陣列id
able.s_1, R .drawable.s_2,R.drawable.s_3,
R.drawable.s_4,R.drawable.s_5,R.draw R.drawable.s_4,R.drawable.s_5,R.draw } ;
int imgstart = 0;
final Handler myHandler = new Han //重寫handleMessage方法,根據msg中what的值判斷是否執行後續操作
public void handleMessage(Message msg) {
## imgchange.setImageResource(imgids[imgstart++ % 8]);
## }
};
#
@Override 1 super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main );
final ImageView imgchange = (ImageView) findViewById(R.id.imgchange); 00毫秒讓handler發送一個空訊息
new Timer() .schedule(new TimerTask() {
##myHandler.sendEmptyMessage(0x123);
00);
}
}
#2)Handler寫在子執行緒中如果是Handler寫在了子執行緒中的話,我們就需要自己建立一個Looper物件了!建立的流程如下:
##1 )直接呼叫Looper.prepare()方法即可為目前執行緒建立Looper物件,而它的建構器會建立配套的MessageQueue;2 )建立Handler物件,重寫handleMessage( )方法就可以處理來自於其他執行緒的資訊了!3 )呼叫Looper.loop()方法啟動Looper
使用範例: 輸入一個數,計算後透過Toast輸出在這個範圍內的所有質數
#實作程式碼:
main.xml:<LinearLayout
and ">
<EditText
android:id="@+id/etNum"
_width="match_parent"
android:layout_height= 「wrap_content"
android:hint="請輸入上限」/>
<Button
android:layout_height="wrap_content"
android:onClick ="cal"
android:text="計算"/>
</LinearLayout>
#
MainActivity.java:
{
static final String UPPER_NUM = "upper
// 定義一個執行緒類別
# # class CalThread extends Thread
名詞 {
public # {
# Looper.prepare();
## {
//
public void handleMessage(Message msg)
if(msg.what == 0x123)
# int upper = msg.getData().getInt(UP) List<Integer> nums = new ArrayList<Integer>eger();
outer:
for (int i = 2 ; i <= upper ; i++)
我int j = 2 ; j < ;= Math.sqrt(i) ; j++)
// != 2 && i % j == 0)
continue outer;
}
}
nums.add(i);
}
// 使用Toast顯示統計出來的所有質數
Toast.make , Toast.LENGTH_LONG).show ();
}
## };
Looper.loop();
} #1 onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState); # setContentView(R.layout.main);
etNum = (EditText)findViewById
// 啟動新執行緒
calThread. start();
}
// 為按鈕的點選事件提供事件處理函數
public void 訊息
Message msg = new Message();
msg.what = 0x123;
Bundle NUM ,
Integer.parseInt(etNum.getText().toString()) );
msg.setData(bundle);
##// 傳送訊息給新執行緒中的Handler
calThread.mHandler.sendMessage(msg);
}
##1 ~
本節小結
本節對Android中的Handler事件傳遞進行了簡單的分析,要分清楚Handler,Message,MessageQueue, Loop的概念,以及Handler寫在主線程中以及子線程中的區別!