Android消息機制使用注意事項,防止泄漏

      在Android的線程通訊當中,使用頻率最多的就是Android的消息處理機制(Handler.send()、View.post()、Asynctask.excute()等等都使用到了消息處理機制)。Android中UI線程默認實現了該機制,其它工做線程要想跟UI線程同樣擁有該機制,就必須人爲去實現該機制,該機制的實現也至關簡單暫且忽略。對於Android裏的消息處理,涉及到Handler,Looper,Message,Message Queue等概念。java

  • Message:消息,其中包含了what(消息ID),obj(消息處理對象,這是引發泄漏的主要緣由,下面會談到)以及其它處理的數據(arg1,arg2,messenger),由MessageQueue統一列隊,終由Handler處理。
  • Handler:線程消息管理者,負責Message的發送及處理。使用Handler時,須要實現handleMessage(Message msg)方法來對特定的Message進行處理,例如更新UI等。
  • MessageQueue:線程的消息隊列,用來存放Handler發送過來的消息,並按照FIFO規則執行。固然,存放Message並不是實際意義的保存,而是將Message以鏈表的方式串聯起來的,等待Looper的抽取。
  • Looper:一個線程只能夠產生一個Looper對象,用來管理MessageQueue,它就像一個消息泵,不斷地從MessageQueue中抽取Message執行。所以,一個MessageQueue須要一個Looper。

     爲了便於理解Message泄漏,首先看一段Message的源代碼:android

// sometimes we store linked lists of these things
    /*package*/ Message next;

    private static final Object sPoolSync = new Object();
    private static Message sPool;
    private static int sPoolSize = 0;

    private static final int MAX_POOL_SIZE = 50;

    /**
     * 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();
    }

 

      從以上代碼能夠看到Message類有一個全局的消息池,池的大小爲50,用於存放Message對象。Message引發泄漏的問題就出在這個全局的消息池。咱們知道Java的回收是由GC來進行的,而當咱們強引用着一個對象時,GC是不會將這個對象回收的。正好這個全局的消息池,裏面存儲的Message必然是一個強引用。形成Message泄漏的一個最大的根源是Message的obj字段,這個字段是Object類型的,所以obj的byte數是能夠很大的。安全

      有些人可能會說,那我對obj這個參數作弱引用讓GC可以回收好不就得了。這個方法雖然能解決GC的回收,可是有一個致命的問題,就是弱應用是極不安全的,GC想要何時回收弱應用對象就何時回收。因此咱們應該換一個解決方方法,處理完一個Message就從全局當中移除一個。對於這個實現,Android的Handler有三個暴露的方法可供使用,removeMessages(int what)、removeMessages(int what, Object object)和removeCallbacksAndMessages(Object token)。具體使用可見以下代碼:ide

        @Override
        public void handleMessage(android.os.Message msg) {
            if (msg == null) {
                return;
            }
            removeXXXXX();
     
            }
        }

removeMessages(int what)和removeMessages(int what, Object object)會調用MessageQueue的removeMessages(Handler h, int what, Object object),該方法源碼以下:oop

void removeMessages(Handler h, int what, Object object) {
        if (h == null) {
            return;
        }

        synchronized (this) {
            Message p = mMessages;

            // Remove all messages at front.
            while (p != null && p.target == h && p.what == what
                   && (object == null || p.obj == object)) {
                Message n = p.next;
                mMessages = n;
                p.recycle();
                p = n;
            }

            // Remove all messages after front.
            while (p != null) {
                Message n = p.next;
                if (n != null) {
                    if (n.target == h && n.what == what
                        && (object == null || n.obj == object)) {
                        Message nn = n.next;
                        n.recycle();
                        p.next = nn;
                        continue;
                    }
                }
                p = n;
            }
        }
    }

 removeCallbacksAndMessages(Object token)會調用MessageQueue的removeCallbacksAndMessages(Handler h, Object object)方法,該方法源碼以下:post

void removeCallbacksAndMessages(Handler h, Object object) {
        if (h == null) {
            return;
        }

        synchronized (this) {
            Message p = mMessages;

            // Remove all messages at front.
            while (p != null && p.target == h
                    && (object == null || p.obj == object)) {
                Message n = p.next;
                mMessages = n;
                p.recycle();
                p = n;
            }

            // Remove all messages after front.
            while (p != null) {
                Message n = p.next;
                if (n != null) {
                    if (n.target == h && (object == null || n.obj == object)) {
                        Message nn = n.next;
                        n.recycle();
                        p.next = nn;
                        continue;
                    }
                }
                p = n;
            }
        }
    }
相關文章
相關標籤/搜索