Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 詳細講解Android中的Message的源碼

詳細講解Android中的Message的源碼

編輯:關於Android編程

相信大家對於Android中的Handler是在為熟悉不過了,但是要知道,Handler就其本身而言只是一個殼子,真正在內部起到作用的是Message這個類,對於Message這個類,相信大家也不會陌生,正如大家經常用到的Message.obtain()的方法一樣。但是大家又是否知道obtain()方法裡面為我們做了哪些操作了,下面我就帶領大家進行Message的王國,去一探究竟吧。

首先映入眼簾的是這樣的一行代碼:

 

public final class Message implements Parcelable

不用多說,Message實現了Parcelable的接口,也就是說經過Message封裝的數據,可以通過Intent與IPC進行傳輸。既然實現了Parcelable接口,那麼在Message方法中必不可少這三個方法:1)writeToParcel 2)describeContents 3)createFromParcel。

 

下面我們需要關注的四個成員變量分別是:

1)public int what

2)public int arg1

3)public int arg2

4)public Object obj


我們經常是用到這樣的幾個參數,但是其真實的含義是否真正的理解呢?只要google的內部的注釋才是真正的可靠的。

1)用戶定義消息的識別碼,以便於系統識別出當前的消息是關於什麼的。由於每一個Handle對於自己的消息的識別碼都有自己的命名空間。所以我們也就不用擔心各個不同的Handler之間會存在沖突的情況。

2)其中第二個參數與第三個參數的意義是一樣的,注釋上是這樣說明的,這兩個參數,如果用戶只是需要傳輸簡單的int類型的數據,相比較於setData(Bundle bundle),代價更低。

3)第四個參數,按照注釋上的說明,是這樣理解的:這是一個發送給接受者的一個隨意的數據,如果使用Messager來進行發送數據進行跨進程的通信,那麼當前的obj如果實現了Parcelable就一定不能夠為空指針,對於其他的數據的傳輸,我們一般使用setData方法就可以了。但是需要注意的是,對於高於android.os.Build.VERSION_CODES#FROYO的版本,這裡的Parcelable對象是不支持的。


上面的變量講完了以後,接下來,我們還需要講解另外的一組常量的定義:

 

private static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;
//池塘裡最大的尺寸
private static final int MAX_POOL_SIZE = 50;

乍一看,大家可能不理解上面四個變量的定義,如果我提醒一下大家,Android中的Message是可以重用的,那麼相信大家就能夠大致猜測到這四個變量的含義了。

 

1、第一個變量其實就是充當鎖的作用,避免多線程爭搶資源,導致髒數據

2、sPool這個變量可以理解為消息隊列的頭部的指針

3、sPoolSize是當前的消息隊列的長度

4、定義消息隊列緩存消息的最大的長度。

 

Ok,到這裡,Message的成員變量已經講解完畢,接下來主要是講解其中的Api方法。

第一個方法就是大家經常用到的obtain方法,而且不帶任何的參數:

 

public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                sPoolSize--;
                return m;
            }
        }
        return new CustomMessage();
    }www.2cto.com
首先為了避免多線程進行爭搶資源,給sPoolSync進行加鎖。首先判斷當前的隊列的指針是否為空,如果當前的指針已經不為空,當前的隊列的頭部的消息就是可以重用並且被取出,那麼當前的隊列的頭指針指向當前的消息的下一個消息,也就是m.next,同時把取出的消息的尾部指針置為null,隊列的長度減1.

 

第二個方法:

 

public static Message obtain(Message orig) {
        Message m = obtain();
        m.what = orig.what;
        m.arg1 = orig.arg1;
        m.arg2 = orig.arg2;
        m.obj = orig.obj;
        m.replyTo = orig.replyTo;
        if (orig.data != null) {
            m.data = new Bundle(orig.data);
        }
        m.target = orig.target;
        m.callback = orig.callback;
        return m;
    }
我們可以看到,這個方法相對於上面的方法多了一個orig的參數,從上面的代碼我們可以看到,首先從隊列中取出Message的對象,然後對其中的參數的對象的各個數據進行逐一的拷貝,並最終返回對象。

 

第三個方法如下:

 

public static Message obtain(Handler h) {
        Message m = obtain();
        m.target = h;
        return m;
    }
不用多說,這個函數中為當前創建的消息指定了一個Handler對象,因為我們知道Handler是Message的最終的目的地。

 

 

public static Message obtain(Handler h, Runnable callback) {
        Message m = obtain();
        m.target = h;
        m.callback = callback;
        return m;
    }
相對於上面的方法,這裡面多了一行m.callback = callback,按照注釋上面的說明,當一些消息真正的被執行的時候,callback這個Runnbale方法將會被觸發執行的。

 

接下來有一系列的方法的邏輯是差不多的,我們取其中的一個進行講解:

 

public static Message obtain(Handler h, int what, int arg1, int arg2) {
        Message m = obtain();
        m.target = h;
        m.what = what;
        m.arg1 = arg1;
        m.arg2 = arg2;
        return m;
    }
也就是說創建一個Message的時候,順便可以為這個Message提供一些邏輯上需要的參數。

 

消息有創建,那麼就必然存在回收的概念,下面我們一起來看一下:

 

public void recycle() {
        clearForRecycle();
        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }
void clearForRecycle() { flags = 0; what = 0; arg1 = 0; arg2 = 0; obj = null; replyTo = null; when = 0; target = null; callback = null; data = null; }


 


在clearForRecycle這個函數中,是做一些回收的預處理的操作,該置為0的參數置為0,該置為null的參數置為null。在recycle的函數中,只要當前的緩存的隊列的長度沒有超過上限,將當前的消息添加到隊列的尾部。

 

下面的方法是關於實現Parcelable所需要的方法:

 

public static final Parcelable.Creator CREATOR
            = new Parcelable.Creator() {
        public Message createFromParcel(Parcel source) {
            Message msg = Message.obtain();
            msg.readFromParcel(source);
            return msg;
        }
        
        public Message[] newArray(int size) {
            return new Message[size];
        }
    };
        
    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel dest, int flags) {
        if (callback != null) {
            throw new RuntimeException(
                "Can't marshal callbacks across processes.");
        }
        dest.writeInt(what);
        dest.writeInt(arg1);
        dest.writeInt(arg2);
        if (obj != null) {
            try {
                Parcelable p = (Parcelable)obj;
                dest.writeInt(1);
                dest.writeParcelable(p, flags);
            } catch (ClassCastException e) {
                throw new RuntimeException(
                    "Can't marshal non-Parcelable objects across processes.");
            }
        } else {
            dest.writeInt(0);
        }
        dest.writeLong(when);
        dest.writeBundle(data);
        Messenger.writeMessengerOrNullToParcel(replyTo, dest);
    }

    private void readFromParcel(Parcel source) {
        what = source.readInt();
        arg1 = source.readInt();
        arg2 = source.readInt();
        if (source.readInt() != 0) {
            obj = source.readParcelable(getClass().getClassLoader());
        }
        when = source.readLong();
        data = source.readBundle();
        replyTo = Messenger.readMessengerOrNullFromParcel(source);
    }

 

Ok,Message的內核源碼的剖析就講解到這裡,相信大家以後再用到這個類的時候會有更深的理解啦。
 

 

 

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved