UI更新——消息處理massage
對於安卓內部消息得處理,實現對界面UI得更新操作,不能在線程中直接更新ui。至於為什么不能,在學習安卓開發的時候,在線程中操作會使程序崩潰。
為什么,可以看看諸多大神們的詳細介紹。
安卓內部處理數據更新UI都是耗時的操作,這些耗時操作系統不允許在Activity主線程中進行,必須在其他線程中操作,然后通過發消息的形式通知主線程更新UI,那么我們就要用多線程處理了,massage 消息處理機制。
下面我們一起分享郭霖Android多線程中消息處理更新UI的介紹。
通過一個具體的例子來驗證一下吧。新建一個 AndroidThreadTest 項目,然后修改 activity_main.xml 中的代碼,如下所示:
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 android:layout_width="match_parent" 3 android:layout_height="match_parent" > 4 <Button 5 android:id="@+id/change_text" 6 android:layout_width="match_parent" 7 android:layout_height="wrap_content" 8 android:text="Change Text" /> 9 <TextView 10 android:id="@+id/text" 11 android:layout_width="wrap_content" 12 android:layout_height="wrap_content" 13 android:layout_centerInParent="true" 14 android:text="Hello world" 15 android:textSize="20sp" /> 16 </RelativeLayout>
布局文件中定義了兩個控件,TextView 用於在屏幕的正中央顯示一個 Hello world 字符串,Button 用於改變 TextView 中顯示的內容,我們希望在點擊 Button 后可以把 TextView中顯示的字符串改成 Nice to meet you。接下來 MainActivity 中的代碼,如下所示:
1 public class MainActivity extends Activity implements OnClickListener { 2 public static final int UPDATE_TEXT = 1; 3 private TextView text; 4 private Button changeText; 5 private Handler handler = new Handler() { 6 public void handleMessage(Message msg) { 7 switch (msg.what) { 8 case UPDATE_TEXT: 9 // 在這里可以進行UI 操作 10 text.setText("Nice to meet you"); 11 break; 12 default: 13 break; 14 } 15 } 16 }; 17 …… 18 19 @Override 20 public void onClick(View v) { 21 switch (v.getId()) { 22 case R.id.change_text: 23 new Thread(new Runnable() { 24 @Override 25 public void run() { 26 Message message = new Message(); 27 message.what = UPDATE_TEXT; 28 handler.sendMessage(message); // 將Message 對象發送出去 29 } 30 }).start(); 31 break; 32 default: 33 break; 34 } 35 } 36 }
這里我們先是定義了一個整型常量 UPDATE_TEXT,用於表示更新 TextView這個動作。然后新增一個 Handler 對象,並重寫父類的 handleMessage 方法,在這里對具體的 Message進行處理。如果發現 Message 的 what 字段的值等於 UPDATE_TEXT,就將 TextView顯示的內容改成 Nice to meet you。下面再來看一下hange Text 按鈕的點擊事件中的代碼。可以看到,這次我們並沒有在子線程里直接進行 UI 操作,而是創建了一個 Message(android.os.Message)對象,並將它的 what 字段的值指定為 UPDATE_TEXT,然后調用 Handler 的 sendMessage()方法將這條Message 發送出去。很快,Handler 就會收到這條 Message,並在 handleMessage()方法中對它進行處理。注意此時 handleMessage()方法中的代碼就是在主線程當中運行的了,所以我們可以放心地在這里進行 UI 操作。接下來對 Message 攜帶的 what 字段的值進行判斷,如果等於UPDATE_TEXT,就將 TextView顯示的內容改成 Nice to meet you。現在重新運行程序,可以看到屏幕的正中央顯示着 Hello world。然后點擊一下 ChangeText按鈕,顯示的內容着就被替換成 Nice to meet you,如圖:
使用Massage消息機制處理ui線程,簡單操作。接下來解析異步消息處理機制的到底是如何工作的。
Android 中的異步消息處理主要由四個部分組成,Message、Handler、MessageQueue和Looper。其中Message和Handler在上一小節中我們已經接觸過了,而MessageQueue和Looper對於你來說還是全新的概念,下面我就對這四個部分進行一下簡要的介紹。
1. MessageMessage 是在線程之間傳遞的消息,它可以在內部攜帶少量的信息,用於在不同線程之間交換數據。上一小節中我們使用到了 Message 的 what 字段,除此之外還可以使用 arg1 和 arg2 字段來攜帶一些整型數據,使用 obj字段攜帶一個 Object 對象。
2. HandlerHandler 顧名思義也就是處理者的意思,它主要是用於發送和處理消息的。發送消息一般是使用 Handler的SendMessage()方法,而發出的消息經過一系列地輾轉處理后,最終會傳遞到 Handler的 handleMessage()方法中。
3. MessageQueueMessageQueue是消息隊列的意思,它主要用於存放所有通過 Handler發送的消息。這部分消息會一直存在於消息隊列中,等待被處理。每個線程中只會有一個 MessageQueue對象。
4. LooperLooper是每個線程中的 MessageQueue的管家,調用 Looper的 loop()方法后,就會進入到一個無限循環當中,然后每當發現 MessageQueue 中存在一條消息,就會將它取出,並傳遞到 Handler 的 handleMessage()方法中。每個線程中也只會有一個 Looper對象。
了解了 Message、Handler、MessageQueue 以及 Looper的基本概念后,我們再來對異步消息處理的整個流程梳理一遍。首先需要在主線程當中創建一個 Handler 對象,並重寫handleMessage()方法。然后當子線程中需要進行 UI 操作時,就創建一個 Message 對象,並通過 Handler 將這條消息發送出去。之后這條消息會被添加到 MessageQueue 的隊列中等待被處理,而 Looper 則會一直嘗試從 MessageQueue 中取出待處理消息,最后分發回 Handler的 handleMessage()方法中。由於 Handler是在主線程中創建的,所以此時 HandleMessage()方法中的代碼也會在主線程中運行,於是我們在這里就可以安心地進行 UI 操作了。整個異步消息處理機制的流程示意圖:
一條 Message 經過這樣一個流程的輾轉調用后,也就從子線程進入到了主線程,從不能更新 UI 變成了可以更新 UI,整個異步消息處理的核心思想也就是如此。
下面分享自己的所學所做關於安卓中的一些消息處理,信息的傳遞。bundle傳遞object對象。