標籤:url blank 等等 介紹 延遲 listen class ui組件 rem
前言
Android的訊息傳遞機制是另外一種形式的“事件處理”,這種機制主要是為瞭解決Android應用中多線程的問題,在Android中不允許Activity新啟動的線程訪問該Activity裡的UI組件,這樣會導致新啟動的線程無法改變UI組件的屬性值。但實際開發中,很多地方需要在背景工作執行緒中改變UI組件的屬性值,比如下載網狀圖片、動畫等等。本篇部落客要介紹Handler是如何發送與處理線程上傳遞來的訊息,並講解Message的幾種傳遞資料的方式,最後均會以小Demo來示範。
Handler
Handler,它直接繼承自Object,一個Handler允許發送和處理Message或者Runnable對象,並且會關聯到主線程的MessageQueue中。每個Handler具有一個單獨的線程,並且關聯到一個訊息佇列的線程,就是說一個Handler有一個固有的訊息佇列。當執行個體化一個Handler的時候,它就承載在一個線程和訊息佇列的線程,這個Handler可以把Message或Runnable壓入到訊息佇列,並且從訊息佇列中取出Message或Runnable,進而操作它們。
Handler主要有兩個作用:
- 在背景工作執行緒中發送訊息。
- 在UI線程中擷取、處理訊息。
上面介紹到Handler可以把一個Message對象或者Runnable對象壓入到訊息佇列中,進而在UI線程中擷取Message或者執行Runnable對象,所以Handler把壓入訊息佇列有兩大體系,Post和sendMessage:
- Post:Post允許把一個Runnable對象入隊到訊息佇列中。它的方法有:post(Runnable)、postAtTime(Runnable,long)、postDelayed(Runnable,long)。
- sendMessage:sendMessage允許把一個包含訊息資料的Message對象壓入到訊息佇列中。它的方法有:sendEmptyMessage(int)、sendMessage(Message)、sendMessageAtTime(Message,long)、sendMessageDelayed(Message,long)。
從上面的各種方法可以看出,不管是post還是sendMessage都具有多種方法,它們可以設定Runnable對象和Message對象被入隊到訊息佇列中,是立即執行還是順延強制。
Post
對於Handler的Post方式來說,它會傳遞一個Runnable對象到訊息佇列中,在這個Runnable對象中,重寫run()方法。一般在這個run()方法中寫入需要在UI線程上的操作。
在Handler中,關於Post方式的方法有:
- boolean post(Runnable r):把一個Runnable入隊到訊息佇列中,UI線程從訊息佇列中取出這個對象後,立即執行。
- boolean postAtTime(Runnable r,long uptimeMillis):把一個Runnable入隊到訊息佇列中,UI線程從訊息佇列中取出這個對象後,在特定的時間執行。
- boolean postDelayed(Runnable r,long delayMillis):把一個Runnable入隊到訊息佇列中,UI線程從訊息佇列中取出這個對象後,延遲delayMills秒執行
- void removeCallbacks(Runnable r):從訊息佇列中移除一個Runnable對象。
下面通過一個Demo,講解如何通過Handler的post方式在新啟動的線程中修改UI組件的屬性:
1 package com.bgxt.datatimepickerdemo; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.os.Handler; 6 import android.view.View; 7 import android.widget.Button; 8 import android.widget.TextView; 9 10 public class HandlerPostActivity1 extends Activity {11 private Button btnMes1,btnMes2;12 private TextView tvMessage;13 // 聲明一個Handler對象14 private static Handler handler=new Handler();15 16 @Override17 protected void onCreate(Bundle savedInstanceState) {18 super.onCreate(savedInstanceState);19 setContentView(R.layout.message_activity); 20 21 btnMes1=(Button)findViewById(R.id.btnMes1);22 btnMes2=(Button)findViewById(R.id.btnMes2);23 tvMessage=(TextView)findViewById(R.id.tvMessage);24 btnMes1.setOnClickListener(new View.OnClickListener() {25 26 @Override27 public void onClick(View v) {28 // 新啟動一個子線程29 new Thread(new Runnable() { 30 @Override31 public void run() {32 // tvMessage.setText("...");33 // 以上操作會報錯,無法再子線程中訪問UI組件,UI組件的屬性必須在UI線程中訪問34 // 使用post方式修改UI組件tvMessage的Text屬性35 handler.post(new Runnable() { 36 @Override37 public void run() {38 tvMessage.setText("使用Handler.post在背景工作執行緒中發送一段執行到訊息佇列中,在主線程中執行。"); 39 }40 }); 41 }42 }).start();43 }44 });45 46 btnMes2.setOnClickListener(new View.OnClickListener() {47 48 @Override49 public void onClick(View v) {50 new Thread(new Runnable() { 51 @Override52 public void run() {53 // 使用postDelayed方式修改UI組件tvMessage的Text屬性值54 // 並且延遲3S執行55 handler.postDelayed(new Runnable() {56 57 @Override58 public void run() {59 tvMessage.setText("使用Handler.postDelayed在背景工作執行緒中發送一段執行到訊息佇列中,在主線程中延遲3S執行。"); 60 61 }62 }, 3000); 63 }64 }).start();65 66 }67 });68 }69 }
Android--多線程之Handler