天天看點

Android開發:Handler、Looper、MessageQueue

Android系統主要通過MessageQueue、Looper和Handler三個類來實作Android應用程式的處理消息機制。---參考羅升陽書集

MessageQueue:用來描述消息隊列。

Looper:用來建立消息隊列,以及進入消息循環。

Handler:用來發送消息和處理消息。//Handler在Android中很常用,或是用來更新UI,或是派發任務給子線程去執行,也可用來産生逾時效果,比如:用sendMessageDelayed(TASK_TIMEOUT, OUT_TIME)方法。

三者之間的關系,如下圖參考:http://blog.chinaunix.net/uid-20937170-id-4649821.html

Android開發:Handler、Looper、MessageQueue

Android應用程式的消息隊例是使用一個MessageQueue對象來描述的,可通過調用Looper類的靜态成員函prepareMainLooper或者prepare來建立,其中,prepareMainLooper為應用程式的主線程建立消息隊列(隻能在主線程中調用,主線程又稱作UI線程);

prepare為應用程式的其他子線程建立消息隊列。

A:建立線程消息對列:即分析Looper類的靜态成員函數prepareMainLooper和prepare的實作。

<1>A. 在Java層,用prepareMainLooper函數線上程中建立了一個Looper對象(同時建立一個消息對列MessageQueue),

這個Looper對象是用來進入消息循環的,它的内部有一個消息隊列MessageQueue對象mQueue;

      B. 在JNI層,建立了一個NativeMessageQueue對象,這個NativeMessageQueue對象儲存在Java層的消息隊列對象mQueue的成員變量mPtr中;

      C. 在C++層,建立了一個Looper對象,儲存在JNI層的NativeMessageQueue對象的成員變量mLooper中,這個對象的作用是,當Java層的消息隊列中沒有消息時,就使Android應用程式主線程進入等待狀态,而當Java層的消息隊列中來了新的消息後,就喚醒Android應用程式的主線程來處理這個消息。

      如下圖參考:http://www.cnblogs.com/angeldevil/p/3340644.html

  

Android開發:Handler、Looper、MessageQueue
Android開發:Handler、Looper、MessageQueue

<2>

 int wakeFds[2];

    result = pipe(wakeFds);//建立一個管道

    //将管道中的讀端、寫端檔案描述符儲存在C++層的Looper類的成員變量中

    mWakeReadPipeFd = wakeFds[0];

    mWakeWritePipeFd = wakeFds[1];

    這個管道在一個線程的消息循環過程中起到的作用非常大。首先,當一個線程沒有新的消息需要處理時,它就會睡眠在這個管道的讀端檔案描述符上,

    直到有新的消息需要處理為止;其次,當其他線程向這個線程的消息隊列發送了一個消息之後,其他線程就會通過這個管道的寫端檔案描述符往這個管道寫入一個資料,

    進而将這個線程喚醒,以便它可以對剛才發送到它的消息隊列中的消息進行處理。

  B:線程消息循環過程

  調用Looper.loop()函數進入到消息循環 -》 Message msg = queue.next()即MessageQueue.next函數擷取下一個要處理的消息 -》nativePollOnce(ptr, nextPollTimeoutMillis)傳回後看消息隊列有沒有消息:

  若有消息則,nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);若沒消息,則nextPollTimeoutMillis = -1;( -1表示下次調用nativePollOnce時,如果消息中沒有消息,就進入無限等待狀态中去)

C:線程消息發送過程

Handler發消息,直至調用到Jni層,喚醒線程讀寫IO事件。

public Handler(Callback callback, boolean async) {

//綁定Handler與Looper

mLooper = Looper.myLooper();

mQueue = mLooper.mQueue;

mCallback = callback;

mAsynchronous = async;

}

///如下是轉載部分

http://www.eoeandroid.com/viewthread.php?tid=49595&highlight=handler

一、幾個關鍵概念

1、MessageQueue:是一種 資料 結構,見名知義,就是一個消息隊列,存放消息的地方。每一個線程最多隻可以擁有一個MessageQueue資料結構。

建立一個線程的時候,并不會自動 建立其MessageQueue。通常使用一個Looper對象對該線程的MessageQueue進行管理。主線程建立時,會建立一

個預設的Looper對象,而Looper對象的建立,将自動建立一個Message Queue。其他非主線程,不會自動建立Looper,要需要的時候,通過調

用prepare函數來實作。

2、Message:消息對象,Message Queue中的存放的對象。一個Message Queue中包含多個Message。 

Message執行個體對象的取得,通常使用Message類裡的靜态方法obtain(),該方法有多個重載版本可供選擇;它的建立并不一定是直接建立一個新的執行個體,

而是先從Message Pool(消息池)中看有沒有可用的Message執行個體,存在則直接取出傳回這個執行個體。如果Message Pool中沒有可用的Message執行個體,

則才用給定的參數建立一個Message對象。調用removeMessages()時,将Message從Message Queue中删除,同時放入到Message Pool中。除了上面這

種方式,也可以通過Handler對象的obtainMessage()擷取 一個Message執行個體。

3、Looper: 

是MessageQueue的管理者。每一個MessageQueue都不能脫離Looper而存在,Looper對象的建立是通過prepare函數來實作的。同時每一個Looper對象

和一個線程關聯。通過調用Looper.myLooper()可以獲得目前線程的Looper對象

建立一個Looper對象時,會同時建立一個MessageQueue對象。除了主線程有預設的Looper,其他線程預設是沒有MessageQueue對象的,是以,不能

接受Message。如需要接受,自己定義 一個Looper對象(通過prepare函數),這樣該線程就有了自己的Looper對象和MessageQueue資料結構了。

Looper從MessageQueue中取出Message然後,交由Handler的handleMessage進行處理。處理完成後,調用Message.recycle()将其放入Message Pool中。

4、Handler: 

消息的處理者,handler 負責将需要傳遞的資訊封裝成Message,通過調用handler 對象的obtainMessage()來實作;

将消息傳遞給Looper,這是通過handler 對象的sendMessage()來實作的。繼而由Looper将Message放入MessageQueue中。

當Looper對象看到MessageQueue中含有Message,就将其廣播出去。該handler 對象收到該消息後,調用相應的handler對象的handleMessage()方法

對其進行處理。

二、線程之間的消息如何進行傳遞 

1、主線程給自己發送Message 

package test.message; 

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.widget.Button;

import android.widget.TextView ;

public class MainActivity extends Activity { 

    private Button btnTest;

    private TextView textView;

    private Handler handler ;

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        btnTest = (Button)this.findViewById(R.id.btn_01);

        textView = (TextView)this.findViewById(R.id.view_01);

        btnTest.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View arg0) {

                Looper looper = Looper.getMainLooper(); //主線程的Looper對象

                //這裡以主線程的Looper對象建立了handler ,

                //是以,這個handler 發送的Message會被傳遞給主線程的MessageQueue。

                handler = new MyHandler(looper);

                handler .removeMessages(0);

                //建構Message對象

                //第一個參數:是自己指定的message代号,友善在handler 選擇性地接收

                //第二三個參數沒有什麼意義

                //第四個參數需要封裝的對象

                Message msg = handler .obtainMessage(1,1,1,"主線程發消息了");

                handler .sendMessage(msg); //發送消息

            }

        });

    }

    class MyHandler extends Handler{

        public MyHandler(Looper looper){

            super(looper);

        }

        public void handleMessage(Message msg){

            super.handleMessage(msg);

            textView.setText("我是主線程的Handler,收到了消息:"+(String)msg.obj);

        }

    }

}

2、其他線程給主線程發送Message 

package test.message; 

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.widget.Button;

import android.widget.TextView;

public class MainActivity extends Activity { 

    private Button btnTest;

    private TextView textView;

    private Handler handler ;

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        btnTest = (Button)this.findViewById(R.id.btn_01);

        textView = (TextView)this.findViewById(R.id.view_01);

        btnTest.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View arg0) {

                //可以看出這裡啟動了一個線程來操作消息的封裝和發送的工作

                //這樣原來主線程的發送就變成了其他線程的發送,簡單吧?呵呵

                new MyThread().start();    

            }

        });

    }

    class MyHandler extends Handler{

        public MyHandler(Looper looper){

            super(looper);

        }

        public void handleMessage(Message msg){

            super.handleMessage(msg);

            textView.setText("我是主線程的Handler,收到了消息:"+(String)msg.obj);

        }

    }

    //加了一個線程類

    class MyThread extends Thread{

        public void run(){

            Looper looper = Looper.getMainLooper(); //主線程的Looper對象

            //這裡以主線程的Looper對象建立了handler ,

            //是以,這個handler 發送的Message會被傳遞給主線程的MessageQueue。

            handler = new MyHandler(looper);

            //建構Message對象

            //第一個參數:是自己指定的message代号,友善在handler 選擇性地接收

            //第二三個參數沒有什麼意義

            //第四個參數需要封裝的對象

            Message msg = handler .obtainMessage(1,1,1,"其他線程發消息了");

            handler .sendMessage(msg); //發送消息            

        }

    }

}

3、主線程給其他線程發送Message 

package test.message; 

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.widget.Button;

import android.widget.TextView;

public class MainActivity extends Activity { 

    private Button btnTest;

    private TextView textView;

    private Handler handler ;

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        btnTest = (Button)this.findViewById(R.id.btn_01);

        textView = (TextView)this.findViewById(R.id.view_01);

        //啟動線程

        new MyThread().start();    

        btnTest.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View arg0) {

                //這裡handler 的執行個體化線上程中

                //線程啟動的時候就已經執行個體化了

                Message msg = handler .obtainMessage(1,1,1,"主線程發送的消息");

                handler .sendMessage(msg);

            }

        });

    }

    class MyHandler extends Handler{

        public MyHandler(Looper looper){

            super(looper);

        }

        public void handleMessage(Message msg){

            super.handleMessage(msg);

            textView.setText("我是主線程的Handler,收到了消息:"+(String)msg.obj);

        }

    }

    class MyThread extends Thread{

        public void run(){

            Looper.prepare(); //建立該線程的Looper對象,用于接收消息

            //注意了:這裡的handler 是定義在主線程中的哦,呵呵,

            //前面看到直接使用了handler 對象,是不是在找,在什麼地方執行個體化的呢?

            //現在看到了吧???呵呵,開始的時候執行個體化不了,因為該線程的Looper對象

            //還不存在呢。現在可以執行個體化了

            //這裡Looper.myLooper()獲得的就是該線程的Looper對象了

            handler = new ThreadHandler(Looper.myLooper());

            //這個方法,有疑惑嗎?

            //其實就是一個循環,循環從MessageQueue中取消息。

            //不經常去看看,你怎麼知道你有新消息呢???

            Looper.loop(); 

        }

        //定義線程類中的消息處理類

        class ThreadHandler extends Handler{

            public ThreadHandler(Looper looper){

                super(looper);

            }

            public void handleMessage(Message msg){

                //這裡對該線程中的MessageQueue中的Message進行處理

                //這裡我們再傳回給主線程一個消息

                handler = new MyHandler(Looper.getMainLooper());

                Message msg2 = handler .obtainMessage(1,1,1,"子線程收到:"+(String)msg.obj);

                handler .sendMessage(msg2);

            }

        }

    }

}

4、其他線程給自己發送Message 

package test.message; 

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.widget.Button;

import android.widget.TextView;

public class MainActivity extends Activity { 

    private Button btnTest;

    private TextView textView;

    private Handler handler ;

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        btnTest = (Button)this.findViewById(R.id.btn_01);

        textView = (TextView)this.findViewById(R.id.view_01);

        btnTest.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View arg0) {

                //啟動線程

                new MyThread().start();    

            }

        });

    }

    class MyHandler extends Handler{

        public MyHandler(Looper looper){

            super(looper);

        }

        public void handleMessage(Message msg){

            super.handleMessage(msg);

            textView.setText((String)msg.obj);

        }

    }    

    class MyThread extends Thread{

        public void run(){

            Looper.prepare(); //建立該線程的Looper對象

            //這裡Looper.myLooper()獲得的就是該線程的Looper對象了

            handler = new ThreadHandler(Looper.myLooper());

            Message msg = handler .obtainMessage(1,1,1,"我自己");

            handler .sendMessage(msg);

            Looper.loop(); 

        }

        //定義線程類中的消息處理類

        class ThreadHandler extends Handler{

            public ThreadHandler(Looper looper){

                super(looper);

            }

            public void handleMessage(Message msg){

                //這裡對該線程中的MessageQueue中的Message進行處理

                //這裡我們再傳回給主線程一個消息

                //加入判斷看看是不是該線程自己發的資訊

                if(msg.what == 1 && msg.obj.equals("我自己")){

                    handler = new MyHandler(Looper.getMainLooper());

                    Message msg2 = handler .obtainMessage(1,1,1,"禀告主線程:我收到了自己發給自己的Message");

                    handler .sendMessage(msg2);                

                }

            }

        }

    }

}

附注: 

上面四個例子的布局檔案 是同一個檔案main.xml

<?xml version="1.0" encoding="utf-8"?> 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android

Android開發:Handler、Looper、MessageQueue

 rientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

<TextView  android:id="@+id/view_01"

    android:layout_width="fill_parent" 

    android:layout_height="wrap_content" 

    android:text="@string/hello "

    />

<Button android:id="@+id/btn_01" 

    android:layout_width="fill_parent" 

    android:layout_height="wrap_content" 

    android:text="測試消息" />

</LinearLayout>

繼續閱讀