国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Android 消息隊(duì)列模型詳解及實(shí)例

2019-10-23 18:30:13
字體:
供稿:網(wǎng)友

Android 消息隊(duì)列模型詳解及實(shí)例

Android系統(tǒng)的消息隊(duì)列和消息循環(huán)都是針對具體線程的,一個(gè)線程可以存在(當(dāng)然也可以不存在)一個(gè)消息隊(duì)列(Message Queue)和一個(gè)消息循環(huán)(Looper)。Android中除了UI線程(主線程),創(chuàng)建的工作線程默認(rèn)是沒有消息循環(huán)和消息隊(duì)列的。如果想讓該線程具有消息隊(duì)列和消息循環(huán),并具有消息處理機(jī)制,就需要在線程中首先調(diào)用Looper.prepare()來創(chuàng)建消息隊(duì)列,然后調(diào)用Looper.loop()進(jìn)入消息循環(huán)。如以下代碼所示:

class LooperThread extends Thread {   public Handler mHandler;    public void run() {    Looper.prepare();     mHandler = new Handler() {     public void handleMessage(Message msg) {      // process incoming messages here     }    };     Looper.loop();   }  } 

      這樣該線程就具有了消息處理機(jī)制了。如果不調(diào)用Looper.prepare()來創(chuàng)建消息隊(duì)列,會(huì)報(bào)"Java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()"的錯(cuò)誤。 

       通過下圖可以清晰顯示出UI Thread, Worker Thread, Handler, Massage Queue, Looper之間的關(guān)系:

 Android,消息隊(duì)列模型,消息隊(duì)列詳解

       解釋上圖中的幾個(gè)基本概念: 

       1.Message

       消息對象,顧名思義就是記錄消息信息的類。這個(gè)類有幾個(gè)比較重要的字段:

       a.arg1和arg2:我們可以使用兩個(gè)字段用來存放我們需要傳遞的整型值,在Service中,我們可以用來存放Service的ID。
       b.obj:該字段是Object類型,我們可以讓該字段傳遞某個(gè)多項(xiàng)到消息的接受者中。
       c.what:這個(gè)字段可以說是消息的標(biāo)志,在消息處理中,我們可以根據(jù)這個(gè)字段的不同的值進(jìn)行不同的處理,類似于我們在處理Button事件時(shí),通過switch(v.getId())判斷是點(diǎn)擊了哪個(gè)按鈕。

       在使用Message時(shí),我們可以通過new Message()創(chuàng)建一個(gè)Message實(shí)例,但是Android更推薦我們通過Message.obtain()或者Handler.obtainMessage()獲取Message對象。這并不一定是直接創(chuàng)建一個(gè)新的實(shí)例,而是先從消息池中看有沒有可用的Message實(shí)例,存在則直接取出并返回這個(gè)實(shí)例。反之如果消息池中沒有可用的Message實(shí)例,則根據(jù)給定的參數(shù)new一個(gè)新Message對象。通過分析源碼可得知,Android系統(tǒng)默認(rèn)情況下在消息池中實(shí)例化10個(gè)Message對象。 

       2.MessageQueue

       消息隊(duì)列,用來存放Message對象的數(shù)據(jù)結(jié)構(gòu),按照“先進(jìn)先出”的原則存放消息。存放并非實(shí)際意義的保存,而是將Message對象以鏈表的方式串聯(lián)起來的。MessageQueue對象不需要我們自己創(chuàng)建,而是有Looper對象對其進(jìn)行管理,一個(gè)線程最多只可以擁有一個(gè)MessageQueue。我們可以通過Looper.myQueue()獲取當(dāng)前線程中的MessageQueue。 

       3.Looper

       MessageQueue的管理者,在一個(gè)線程中,如果存在Looper對象,則必定存在MessageQueue對象,并且只存在一個(gè)Looper對象和一個(gè)MessageQueue對象。倘若我們的線程中存在Looper對象,則我們可以通過Looper.myLooper()獲取,此外我們還可以通過Looper.getMainLooper()獲取當(dāng)前應(yīng)用系統(tǒng)中主線程的Looper對象。在這個(gè)地方有一點(diǎn)需要注意,假如Looper對象位于應(yīng)用程序主線程中,則Looper.myLooper()和Looper.getMainLooper()獲取的是同一個(gè)對象。 

       4.Handler

       消息的處理者。通過Handler對象我們可以封裝Message對象,然后通過sendMessage(msg)把Message對象添加到MessageQueue中;當(dāng)MessageQueue循環(huán)到該Message時(shí),就會(huì)調(diào)用該Message對象對應(yīng)的handler對象的handleMessage()方法對其進(jìn)行處理。由于是在handleMessage()方法中處理消息,因此我們應(yīng)該編寫一個(gè)類繼承自Handler,然后在handleMessage()處理我們需要的操作。 

       另外,我們知道,Android UI操作并不是線程安全的,所以無法在子線程中更新UI。但Andriod提供了幾種方法,可以在子線程中通知UI線程更新界面: 

  1. Activity.runOnUiThread( Runnable )
  2. View.post( Runnable )
  3. View.postDelayed( Runnable, long )
  4. Handler

       比較常用的是通過Handler,用Handler來接收子線程發(fā)送的數(shù)據(jù),并用此數(shù)據(jù)配合主線程更新UI。那么,只要在主線程中創(chuàng)建Handler對象,在子線程中調(diào)用Handler的sendMessage方法,就會(huì)把消息放入主線程的消息隊(duì)列,并且將會(huì)在Handler主線程中調(diào)用該handler的handleMessage方法來處理消息。  

package com.superonion;  import android.app.Activity; import android.os.Bundle; import android.os.Message; import android.util.Log; import android.os.Handler;  public class MyHandler extends Activity {   static final String TAG = "Handler";   Handler h = new Handler(){     public void handleMessage (Message msg)     {       switch(msg.what)       {       case HANDLER_TEST:         Log.d(TAG, "The handler thread id = " + Thread.currentThread().getId() + "/n");         break;       }     }   };    static final int HANDLER_TEST = 1;   /** Called when the activity is first created. */   @Override   public void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     Log.d(TAG, "The main thread id = " + Thread.currentThread().getId() + "/n");      new myThread().start();     setContentView(R.layout.main);   }    class myThread extends Thread   {     public void run()     {       Message msg = new Message();       msg.what = HANDLER_TEST;       h.sendMessage(msg);       Log.d(TAG, "The worker thread id = " + Thread.currentThread().getId() + "/n");     }   } }  

        以上代碼中,Handler在主線程中創(chuàng)建后,子線程通過sendMessage()方法就可以將消息發(fā)送到主線程中,并在handleMessage()方法中處理。

 感謝閱讀,希望能幫助大家,謝謝大家對本站的支持!


注:相關(guān)教程知識(shí)閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 探索| 米脂县| 南宫市| 禹州市| 西丰县| 浏阳市| 云浮市| 永川市| 双桥区| 英德市| 灌阳县| 广东省| 鹰潭市| 唐海县| 新龙县| 庆元县| 改则县| 连州市| 玛曲县| 黄山市| 泸州市| 伊金霍洛旗| 定陶县| 紫阳县| 景洪市| 民勤县| 阿合奇县| 仪征市| 芦溪县| 长垣县| 兰溪市| 肇东市| 尚义县| 洛南县| 巴楚县| 大悟县| 科尔| 东山县| 桑日县| 嘉定区| 合江县|