fwrite

fwrite

好好生活
twitter
github
email

Handler机制

概述#

说明
Handler真正处理事件的地方
Looper循环检查是否有要传输的事件,从 MessageQueue 中获取事件,并交给 Handler 处理(假如列队为空就进入休眠)
MessageQueue储存需要做的事情,一般来说只允许保存相同类型的 Object、Message 除存的数据结构队列
Message需要做的事件

一个 Thread 对应一个 Looper
一个 Looper 对应一个 MessageQueue
一个 MessageQueue 内有多个 Message
每个 Message 中最多对应一个 Handler 处理事件
Thread & Handler 是一对多的关系

Handler#

接受处理 Messgae
将 Message 存入 MessageQueue 中

// Handler.java

public class Handler {
    ...

    final Looper mLooper;
    final MessageQueue mQueue;
    final Callback mCallback;

    ...

     public interface Callback {
        boolean handleMessage(@NonNull Message msg);
    }

    // 通常用来给使用者 Override 处理事件
    public void handleMessage(@NonNull Message msg) {
    }

    // 分化,有三种方式
    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
}

在上面分发事件有三种方法,并且 这三种分发方式有先后顺序,只要前面被处理,就不会使用后面的方式处理
Message 本身的 callback
实现 Callback 接口
Override Handler#handleMessage Function
通过 Handler 把信息入队到 MessageQueue,方式有 Post & Send 两种系列,并且可以控制发送的时间
Post 系列:把零散信息转为 Message 再用 Send 传出

函数功能
boolean post(Runnable r)直接发出信息
boolean postAtTime(Runnable, long updatetimeMillis)在固定(规定)时间再发出该条信息
Send 系列:参数直接是 Message
函数功能
boolean sendEmptyMessage(int what)直接发送信息
boolean sendMessageArFrontOfQueue(Message msg)把消息发送到信息队列最前面
boolean sendMessageAtTime(int what, long updatetimeMillis)在固定(规定)时间再发出该条信息
boolean sendMessageDelayed(Message msg, long delayMillis)延迟几毫秒后发送该信息

Post 实现方式

// Handler.java

public class Handler {

    public final boolean post(@NonNull Runnable r) {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

    // 包装 callback 再传出
    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();        // 取得 Message 资源,避免不断创建,可以复用资源
        m.callback = r;        // 直接设定 Runnable 回调函数
        return m;
    }

    // 最后通过计算 当前时间 + 延长实现,之后就呼叫 sendMessageAtTime 函数
    public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

    // 在规定时间发送信息
    public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            // 若是该 Thread 并没有规定 MessageQueue 则会抛出错误
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

}

发送信息方法#

名称参数:回传解释
postRunnable : boolean接收一个 Runnable 对象作为 Message
postAtTimeRunnable, long : boolean接收一个 Runnable 对象作为 Message,并在等待的规定时间发送 Message
sendEmptyMessageint : boolean发送一个使用者规定的 int 信息,在由使用者自己处理
sendMessageAtTimeMessge, int : boolean发送一个使用者规定的 int 信息,在由使用者自己处理
sendMessageDelayedMessge, long : boolean在等待的规定时间后 (延迟) 发送 Message

Post & Send#

// Send ...
    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }
    
// Post ...
    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
    
    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }
    
// 最终都会 sendMessageAtTime
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {    // 1. 
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

处理 Message#

从 dispatchMessage 可看出它预设处理 Message 的顺序
msg.callback (Runnable)
mCallback (interface)
handleMessage (method)

public void handleMessage(Message msg) {
     // 使用者复写
 }
  
 /**
  * Handle system messages here.
  */
 public void dispatchMessage(Message msg) {
     // callback 优先级最高
     if (msg.callback != null) {		// msg.callback is Runnable
         handleCallback(msg);
     } else {
         if (mCallback != null) {
             if (mCallback.handleMessage(msg)) {
                 return;
             }
         }
         handleMessage(msg);
     }
 }

MessageQueue & Message#

如其名,它是一个队列 FIFO,它通过 本地方法 (Native) 内存指针创建 Queue

private native static long nativeInit();
    
MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();
    }

Queue 方法#

名称参数:回传解释
enqueueMessageMessage, long : boolean在指定时间内压入队列中
nextvoid : Message元素拉出队列
removeMessagesHandler, int, Object : void移除特定元素
removeMessagesHandler, Runnable, Object : void移除特定元素

MessageQueue#

MessageQueue 因为是 Queue 所以有所谓的 FIFO, 所以有队列的功能

MessageQueue(boolean quitAllowed) {
    mQuitAllowed = quitAllowed;
    mPtr = nativeInit();
}

private native static int nativeInit();

MessageQueue 创建#

连接于 Looper 的建构函数,当 Looper 创建时 MessageQueue 就一同创建

private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

Looper 通过 MessageQueue 取得 Message#

// MessageQueue.java

    Message next() {

        // 若已经被 depose mPtr 就会被设定为 0
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration

        // 下一个信息的时间
        int nextPollTimeoutMillis = 0;

        // 进入无限循环,也就是说 next 会导致 block
        for (;;) {
            ... 省略部分

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();

                Message prevMsg = null;    // 上一个信息
                Message msg = mMessages;    // 当前信息

                if (msg != null && msg.target == null) {    // target 就是 Handler

                    // 找到一个可发送的 Message
                    do {
                        prevMsg = msg;
                        msg = msg.next;    // 切换到下一个 Message
                    } while (msg != null && !msg.isAsynchronous());
                }

                // 再次判断 Message
                if (msg != null) {

                    // 判断时间
                    if (now < msg.when) {    // 该信息的时间还没到
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        // 计算剩余时间
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // 时间到,并且有 Message
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;    // 上一个 Message 就是当前 Message
                        } else {
                            mMessages = msg.next;    //切换到下一个要用的 Message
                        }

                        // 断开连接 !! 好让 GC 侦测到后回收 !!! (可达性分析)
                        msg.next = null;

                        ... debug 訊息

                        msg.markInUse();    // 标记该 Message 已经被使用过
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {        // 检查是否退出
                    dispose();
                    return null;
                }

                ... 省略 IdleHandler
            }

            ... 省略部分
        }

IdleHandler#

IdleHandler 是 MessageQueue 内的一个 interface,它可以在 MessageQueue 没有消息时让使用者知道,并决定如何处理

// MessageQueue.java

    public static interface IdleHandler {
        // 返回true,会让你设定的接口继续存在
		// 返回false则会移除你设定的接口
        boolean queueIdle();
    }

同样分析 next 方法,可以看到一个 MessageQueue 最多设定 4 个 IdleHandler

// MessageQueue.java

    Message next() {

        // 若已经被depose mPtr就会被设定为0
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration

        // 下一个信息的时间
        int nextPollTimeoutMillis = 0;

        // 进入无限循环,也就是说next会导致block
        for (;;) {
            ... 省略部分

            synchronized (this) {

                ... 省略部分

                // 检查是否有设置IdleHandler
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();


                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    continue;
                }

                // 最多设置4个Idle Handler
                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            
            // 循环
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // release the reference to the handler

                boolean keep = false;
                try {
                    // 当没有信息时通知接口
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }

                // 返回 false 就移除
                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            ... 省略部分
        }
    }

Looper#

它是组成消息的重要关键(Handler、Message、MessageQueue),它的角色是驱动

名称参数:回传解释
myLoopervoid : Looper以当前线程为主,取得当前 Thread 的 Looper
getMainLoopervoid : Looper取得主线程的 Looper

Looper - ThreadLocal#

最后 Looper 则是让整个 Hanler 机制循的动力,有 Looper 的推动 Handler 才能正常接收、发送信息
Looper 中包含了一个 MessageQueue(在构造函数中建构的)

// ava/android/os/Looper.java

public final class Looper {

    // 私有函数
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

}

当你每创建一个线程就必须为这个线程准备 Looper,否则在 Handler 发送消息时就会 crush(上面有说到会检查),创建主要有以下步骤
Looper 准备工作(prepare 函数)
创建 Handler 发送&接收消息
Looper 开始运作(loop 函数)

class LooperThread extends Thread {

    private Handler handler;

    public void run() {
        // 1
        Looper.prepare();

        // 2.
        handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                //... 处理 Message
            }

        }

        // 3.
        Looper.loop();
    }

}

ThreadLocal 这里大概提及,ThreadLocal 也就是线程隔离,使用线程 Thread 作为 Key 储存,而 Value 就是你要拷贝到每个线程的数据(每个子线程都持有一个数据)

//android/os/Looper.java

public final class Looper {

    // 拷贝线程的数据是Looper
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

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

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null)     // 一个线程只能prepare一次
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        // 为当前Thread设定Looper
        sThreadLocal.set(new Looper(quitAllowed));
    }
}

当你建立一个 Handler 时,在 Handler construct 就会透过当前的线程取得 Looper

// Handler

    public Handler(@Nullable Callback callback, boolean async) {
        ...
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }


// -----------------------------------------------------------------
// Looper 

    public static @Nullable Looper myLooper() {
        // sThreadLocal是静态的,会透过当前Thread作为Key取得Looper
        return sThreadLocal.get();
    }

Looper & Handler#

Looper 跟 Handler 的关系可以从 new Handler()这个构造函数中看出,它是透过 myLooper 方法,透过目前的线程在 ThreadLocal 中取得该当前线程所拥有的 Looper

// Handler construct
    public Handler() {
        this(null, false);
    }
    
    public Handler(Callback callback, boolean async) {
        ... 忽略

        // 取得当前线程的 Loop
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
    
//Looper...
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

Looper & UI Thread#

Android 中 Activity 的主线程是 ActivityThread’s main ()

public static void main(String[] args) {
        ...

        Looper.prepareMainLooper(); //"1. "

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {    
            //"2. "
            sMainThreadHandler = thread.getHandler();
        }

        ...

        // End of event ActivityThreadMain.
        ...
        
        Looper.loop();

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

主线程的 Looper 是不可以关闭的,并且使用类同步

public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

// 属性...
    private static Looper sMainLooper;  // guarded by Looper.class

Looper#loop,首先取得目前线程所拥有的 Looper,再取出 Looper 内部有的 MessageQueue,最后无限循环整个消息对列

// Looper.java

public static void loop() {
        final Looper me = myLooper();

        ...

        final MessageQueue queue = me.mQueue;

        ...

        for (;;) {
            // 
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            ...
            try {
            // 解决是谁再呼叫dispatchMessage,target为MessageQueue中的Handler
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            ...

            msg.recycleUnchecked();
        }
    }

ThreadLocal#

ThreadLocal 的功能主要是做到线程隔离(用线程隔离数据),简单来说可以把 ThreadLocal 当作一个 Map(但实际来说它并不是 Map),它的 Key 是 Thread,Value 是一个泛型

// 前面Looper.prepare()内部就有使用到set()方法
    public void set(T value) {
        Thread t = Thread.currentThread();    //"1. "
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }


// 前面Handler()构造函数内部就有使用到get()方法
public T get() {
        Thread t = Thread.currentThread();    //"2. "
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

它使用目前呼叫它的 Thread.currentThread 作为 Key 存入,Value 是泛型
依照当前线程(currentThread),取的 Value

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。