Handler

1,119 阅读4分钟

未完待续!!!!!!

Handler

看电视剧的时候突然有感而发。可以把Handler机制,和机场传送带结合起来(我这个传送带比较高级,有行李的时候就转动,没有行李的时候就待机)。

  • Looper.loop() :比作传送带的机器(动力来源)。
  • MessageQueue:比作传送带。
  • Handler:比作 分拣员,负责向传送带放行李取行李。
  • Message:比作行李框(有的机场防止行李变脏)。
  • Message对象的内容:比作 行李。

为了方便记忆和学习,假设:主线程MessageQueue没有Message导致主线程block,这时一个Activity执行mHandler.sendMessage();

将这个过程分为 5步:

  • 1:通电(Looper.loop()),block(nativePollOnce()).
  • 2:放行李(mHandler.sendMessage() -> nativeWake()).
  • 3:传送带转起来.
  • 4:取行李 Handler.dispatch().
  • 5:循环使用 Message.recycleUnchecked().

1:通电

frameworks\base\core\java\android\app\ActivityThread.java

    // 1:main方法入口
    public static void main(String[] args) {
        ...
        // 2:
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);
        ...
        // 8:
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

frameworks\base\core\java\android\os\Looper.java

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();//进程内唯一

// 构造方法private,只能通过 prepare创建Looper对象
private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
}

public static void prepare() {
        prepare(true);
}

// 4:
//保证一个线程对应一个Looper,一个Looper对应一个MessageQueue。
private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        // 5:
        sThreadLocal.set(new Looper(quitAllowed));
}
// 3:
public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
}

// 9:
public static void loop() {
        final Looper me = myLooper();// sThreadLocal.get()
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;
        for (;;) {
            // 10:
            Message msg = queue.next(); // might block
...
            msg.target.dispatchMessage(msg);//这是handler内存泄漏的原因,target是Handler对象
        }
 }    

libcore\ojluni\src\main\java\java\lang\ThreadLocal.java

// 6:
 public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value); 
        else
            createMap(t, value);
    }

static class ThreadLocalMap {
	// 7:
     private void set(ThreadLocal<?> key, Object value) {
            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);//这里使用当前threadlocal哈希做下标。
            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();
                if (k == key) {
                    e.value = value;
                    return;
                }
                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }
            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
      }
}

frameworks\base\core\java\android\os\MessageQueue.java

Message next() { 
...
        for (;;) {
...          // 12: 没消息时阻塞
            nativePollOnce(ptr, nextPollTimeoutMillis);//阻塞操作
...
}
boolean enqueueMessage(Message msg, long when) { 
        ...
         nativeWake(mPtr); 

        return true;
}

2:放行李

Handler.java

    // 1:sendMessage 最终调用
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;//Message引用Handler.
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        // 2:
        return queue.enqueueMessage(msg, uptimeMillis);
    }

MessageQueue.java

Message next() { 
...
        for (;;) {
...         
            nativePollOnce(ptr, nextPollTimeoutMillis);//阻塞操作
...
}
// 3:
boolean enqueueMessage(Message msg, long when) { 
        ...
        // 4:
         nativeWake(mPtr); 

        return true;
}

3:传送带动起来

4:取行李

Looper.java

public static void loop() {
        final Looper me = myLooper();// sThreadLocal.get()
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;
        for (;;) {
            Message msg = queue.next(); // might block
...
            // 1:
            msg.target.dispatchMessage(msg);//这是handler内存泄漏的原因,target是Handler对象
            ...
            msg.recycleUnchecked();
        }
 }

Handler.java

    // 2:  链式调用
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

5:循环使用 Message

Looper.java

public static void loop() {
        final Looper me = myLooper();// sThreadLocal.get()
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;
        for (;;) {
            Message msg = queue.next(); // might block
            ...
            msg.target.dispatchMessage(msg);//这是handler内存泄漏的原因,target是Handler对象
            ...
            // 1:
            msg.recycleUnchecked();
        }
 }

Message.java

    // 2: 
    void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = -1;
        when = 0;
        target = null;
        callback = null;
        data = null;
        
        // 享元设计模式   Message池容量 50 ,超过50直接丢弃,等待GC
        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {  //MAX_POOL_SIZE = 50  
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }

如何保证一个线程只有一个looper

  • 1:Looper构造方法私有化
  • 2:只提供prepare()创建Looper对象
  • 3:使用 static final 保证 ,当前进程只有一个 sThreadLocal。

一个Thread对应一个ThreadLocal.ThreadLocalMap存储 ThreadLocal数据. 一个Thread对应多个ThreadLocal。一个ThreadLocal只能存储一个数据。

  • 4:sThreadLocal.set(new Looper(quitAllowed)).使用

Looper.java

    //3:使用 static final 保证 ,当前进程只有一个 sThreadLocal。
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

    //1:构造方法私有化
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
    //2:只提供prepare()创建Looper对象
    public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

ThreadLocal.java

  • Java标准库提供了一个特殊的ThreadLocal,它可以在一个线程中传递同一个对象。
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);//最终返回 Thread.java 的 ThreadLocal.ThreadLocalMap threadLocals;
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
    
    static class ThreadLocalMap {
    
        static class Entry extends WeakReference<ThreadLocal<?>> {
            Object value;
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
        
        private Entry[] table;
        
        private void set(ThreadLocal<?> key, Object value) {
            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);
            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();
                if (k == key) {
                    e.value = value;
                    return;
                }
                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }
            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }
      
    }

线程切换

线程切换 本质就是 线程切换执行 共享的资源。

  • 1:在主线程 Handler mHandler = new Handler(); 得到mHandler.mQueue MessageQueue
  • 2:在子线程 mHandler.sendMessage();

Handler.java

    //  2: 子线程
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue; // 共享的 MessageQueue
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }
    
    // 1:主线程 Handler 实例化
    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();//主线程已经 main() ->prepare()
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue; // 共享的 MessageQueue
        mCallback = callback;
        mAsynchronous = async;
    }