[Android源碼]Message分析

一,Message源碼分析

首先介紹message使用分析,再介紹Message源碼內容分析。本文重點分析,Message類中節省內存的代碼設計。

1.1 基本構造方式

創建使用一個對象,最常用最普通的方式爲New一個新的對象,Message msg = new Message();通過new 一個新的對象,在內存中保留了該對象的引用消耗了內存空間。

Message源碼也建議不通過new一個Message的對象的方式來創建一個新的Message對象。而是使用Message.obtain()的方式來創建。

    /** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
    */
    public Message() {
    }

1.2 使用Message.obtain()方式

使用Message  msg = Message.obtain();

方式獲取msg對象。該方式相比較使用new創建一個新的對象有什麼優勢呢?

跟蹤源碼:

    <p class="p1">    <span class="s1">/*package*/</span> Message <span class="s2">next</span>;</p>    private static final Object sPoolSync = new Object();
    private static Message sPool;
    private static int sPoolSize = 0;

    private static final int MAX_POOL_SIZE = 10;
    /**
     * Return a new Message instance from the global pool. Allows us to
     * avoid allocating new objects in many cases.
     */
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }
    /**
     * Return a Message instance to the global pool.  You MUST NOT touch
     * the Message after calling this function -- it has effectively been
     * freed.
     */
    public void recycle() {
        clearForRecycle();// 將Message對象的成員屬性賦值爲null

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }
        Message.obtain函數:有多個obtain函數{Message.obtain(),Message.obtain(what)},主要功能一樣,只是參數不一樣。作用是從Message Pool中取出一個Message,如果Message Pool中已經沒有Message可取,則新建一個Message返回,同時用對應的參數給得到的Message對象賦值。 
        Message Pool:消息池最大值爲10個;消息池爲一個鏈表結構。一個新的消息的添加採用的是頭插法。通過Message.mPool->(Message並且Message.next)-> (Message並且Message.next)-> (Message並且Message.next)...構造一個Message Pool。Message Pool的第一個元素直接new出來,然後把Message.mPool(static類的static變量)指向它。其他的元素都是使用完的 Message通過Message的recycle函數清理後放到Message Pool(通過Message Pool最後一個Message的next指向需要回收的Message的方式實現)。下圖爲Message Pool的結構: 

 

      使用Message.obtain()方式構建Message對象與直接分配一個新的對象。在許多情況下,它能避免分配新的對象,減少內存的開支。

1.3 Message成員屬性

   Message中下面幾種參數比較常用:

public int what;// 消息身份標識
public int arg1;// 
public int arg2;// 
public Object obj;// 需要攜帶的對象參數
Bundle data;// 攜帶Bundle類型參數
long when;
  我們使用Message來封裝攜帶一些需要傳遞的參數。可以攜帶基本參數arg1、arg2,可以攜帶對象obj,可以攜帶bundle(android最常用的攜帶數據的容器,類似於Map)。如果我們需要攜帶的數據類型比較簡單,例如只攜帶int類型數據,可以優先使用Message.arg1和Message.arg2來傳遞信息,這比用Bundle更省內存。

Demo源碼:

public class MainActivity extends Activity  
{
    private final int WHAT = 100;
    private TextView mTextTitle;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextTitle = (TextView) findViewById(R.id.textview1);
        new Thread(runnable).start();
    }
 
    Runnable runnable = new Runnable(){
        @Override
        public void run() {
            int count = 0;
            for (int i = 0; i < 10; i++) {
                count ++;
            }
            Message msg = handler.obtainMessage();
            msg.what = WHAT;
            msg.arg1 = count;
            handler.sendMessage(msg);
        }
    };
    Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what) {
                case WHAT:
                    int count = msg.arg1;
                    mTextTitle.setText("總共人數:" + count);
                break;
            }
            return false;
        }
    });
}


至此:Message的分析完畢;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章