Handler学习记

258 阅读6分钟
Handler总结

Android几乎就是Handler消息传递: 那么是怎么创建的? Handler的用途是干什么的? 在android 中Handler 用于线程间的切换(子线程到主线程, 子线程到子线程)都可以发送消息

创建过程(是怎么创建的? 怎么进行消息发送? Handler、Looper、MessageQueue、Message之间存在什么样的关系?)

Android 启动时运行ActivityThread 类里面的 Main方法:

public static void main(String[] args) {
    //....省略代码
    // Looper.prepareMainLooper 就是Android 创建Handler 的入口
    
    Looper.prepareMainLooper();

    //....省略代码
    
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);

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

    if (false) {
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    }

    // End of event ActivityThreadMain.
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    Looper.loop();

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

**Looper.prepareMainLooper 就是Android 创建Handler 的入口, 并且对应的 Looper.loop()。 可以看出prepareMainLooper() 函数 是准备Looper, loop() 就是一个循环, **


prepareMainLooper函数

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

prepareMainLooper() -》 prepare()调用下面方法 加入 ThreadLocal()中一个Looper()实例

// sThreadLocal.get() will return null unless you've called prepare().
@UnsupportedAppUsage
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
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));
}

加入Looper 实例后 Looper()构造函数里创建了 MessageQueue() 和 获取当前线程

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

总结1:一个线程里面只有一个Looper,一个MessageQueue,可以有多个Handler

总结2:如果要在线程中创建 Looper ,那么一定会有Looper.prepareLooper() 和 Looper.loop() 两个对应

总结3:每个线程 创建 Looper 流程: (创建前 Looper 准备好prepare() ) ->加入Looper()(构造方法里面 创建 MessageQueue) -> (创建多个Handler 接收、发送消息)-> 调用Looper.loop()

准备好Looper后 就是获取Handler:

    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

从ActivityThread 中 的 getHandler() 获取主线程的MainThreadHandler, getHandler()获取的又是 final H mH = new H(); 这个实例, class H extends Handler ,H 类继承Hnadler, 那么H 类是用来干嘛的?

看 H类的 handleMessage(也就是 Handler 回调的方法):

public void handleMessage(Message msg) {
        if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
        switch (msg.what) {
            case BIND_APPLICATION:
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                AppBindData data = (AppBindData)msg.obj;
                handleBindApplication(data);
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                break;
            case RECEIVER:
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp");
                handleReceiver((ReceiverData)msg.obj);
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                break;
            case CREATE_SERVICE:
                if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                            ("serviceCreate: " + String.valueOf(msg.obj)));
                }
                handleCreateService((CreateServiceData)msg.obj);
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                break;
                //....省略代码
            case DUMP_ACTIVITY:
                handleDumpActivity((DumpComponentInfo)msg.obj);
                break;
            case RELAUNCH_ACTIVITY:
                handleRelaunchActivityLocally((IBinder) msg.obj);
                break;
           //....省略代码
        }
        Object obj = msg.obj;
        if (obj instanceof SomeArgs) {
            ((SomeArgs) obj).recycle();
        }
        if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
    }
}

msg.what中看出 CREATE_SERVICE 是创建Service的, 也就是说我们Android 四大组件的管理都在此处进行。


上面是主线程创建Handler、 Looper、MessageQueue、Message过程,


Handler 使用分析创建过程

当我们在Activity创建Hnadler时 会 mQueue = mLooper.mQueue;赋值。( 获取 当前线程中Looper 创建的MessageQueue对象)。
当Handler发送消息时(不管调用什么方法)最终会到 sendMessageAtTime() 方法, 同时 获取实例 MessageQueue, 通过enqueueMessage()方法加入Message消息

public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    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);
}

将当前Handler赋值给Message的target,并调用MessageQueue 的enqueueMessage方法。(uptimeMillis 延迟发送时间)MessageQueue不是队列,而是单向链表, enqueueMessage方法如何把消息添加队列的?

private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
        long uptimeMillis) {
    msg.target = this;
    msg.workSourceUid = ThreadLocalWorkSource.getUid();

    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

enqueueMessage方法如何把消息添加队列的:(enqueueMessage 中的 msg.next = p; 加入到单向链表)

boolean enqueueMessage(Message msg, long when) {
    //....省略代码

    synchronized (this) {
        //....省略代码
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        // 根据 when 进行顺序排序,将消息插入到其中
        if (p == null || when == 0 || when < p.when) {
            // New head, wake up the event queue if blocked.
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            // 找到 合适的节点
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            //插入数据
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }

        // We can assume mPtr != 0 because mQuitting is false.
        //唤醒 MessageQueue 的 next()方法 中的nativePollOnce()
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

消息添加成功后,怎么回调到Handler 的呢? 这时我们Looper 就派上了用场, 创建Looper时 会调用public static void loop() 这个方法来一直循环 MessageQueue 里面的 Message 消息内容:

public static void loop() {
    //获取当前Looper
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    if (me.mInLoop) {
        Slog.w(TAG, "Loop again would have the queued messages be executed"
                + " before this one completed.");
    }

    me.mInLoop = true;
    //获取当前Looper对应得MessageQueue
    final MessageQueue queue = me.mQueue;
    
    //确保该线程的标识是本地进程的标识,并跟踪该标识令牌实际上是什么。
    // Make sure the identity of this thread is that of the local process,
    // and keep track of what that identity token actually is.
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();

    // Allow overriding a threshold with a system prop. e.g.
    // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
    final int thresholdOverride =
            SystemProperties.getInt("log.looper."
                    + Process.myUid() + "."
                    + Thread.currentThread().getName()
                    + ".slow", 0);

    boolean slowDeliveryDetected = false;

    for (;;) {
        // (1)使用获取到得 MessageQueue 来取Message值,如果没有值就会停在这里等待值得到来
        //怎么取值得? 
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }

       //省略代码......
        long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
        try {
            //调用当前 msg 的 Handler(msg.target 就是一个Handler) 给 dispatchMessage(Handler)方法
            msg.target.dispatchMessage(msg);
            if (observer != null) {
                observer.messageDispatched(token, msg);
            }
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } catch (Exception exception) {
            if (observer != null) {
                observer.dispatchingThrewException(token, msg, exception);
            }
            throw exception;
        } finally {
            ThreadLocalWorkSource.restore(origWorkSource);
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
       //省略代码......

        msg.recycleUnchecked();
    }
}

msg.target.dispatchMessage(msg); 中 msg.target 就是Handler, 当Message msg = queue.next() 取到消息后就 调用 Handler 的 dispatchMessage 方法:

public void dispatchMessage(@NonNull Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}
dispatchMessage:(方法调用解释)

从中我们可以了解到对于Message消息,我们有三种处理方式:

1.通过Message对象的callback进行处理
2.通过Handler类的Callback 接口进行处理
3.通过重写Handler类的方法handleMessage进行处理 并且这三个是由顺序的,只要其中的任意一个队消息进行了处理,后面的方法对消息的处理都不会调用啦。那么问题来了,这三种方式怎么用呢?

第一种

    public static Message obtain(Handler h, Runnable callback) {
        Message m = obtain();
        m.target = h;
        m.callback = callback;

        return m;
    }

第二种

    public Handler(Callback callback) {
        this(callback, false);
    }
    public Handler(Looper looper, Callback callback) {
        this(looper, callback, false);
    }

第三种

    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            /*
             * 获取到消息之后,对message进行一些处理
             */
        }
    };

回到Looper.loop() 中,它通过无限循环获取消息 Message msg = queue.next(); // might block 当无消息时就会停在这里 一直等消息, 看queue.next() 函数:

@UnsupportedAppUsage
Message next() {
    //省略代码...
    for (;;) {
        //省略代码...
        //调用Native 的Epoll方法中。。。
        // 通过 epoll_wait 等待消息,等待 nextPollTimeoutMillis 时长
        nativePollOnce(ptr, nextPollTimeoutMillis);

        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) {
                // Stalled by a barrier.  Find the next asynchronous message in the queue.
                //问题:这个target == null 时 发送的什么消息?
                // 获得一个有效的消息
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                if (now < msg.when) {// 说明需要延迟执行,通过; nativePollOnce 的 timeout 来进行延迟
                    // 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 {// 立即执行的消息,直接返回
                    // Got a message.
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    //这个时候取到Msg 返回
                    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;
            }

           //省略代码...
        }

        //省略代码...
        // 如果执行了 idle handlers 的内容,现在消息可能已经到了执行时间,所以这个时候就不等待了,再去检查一下消息是否可以执行, nextPollTimeoutMillis 需要置为 0
        nextPollTimeoutMillis = 0;
    }
}

总结3:创建Handler 发送\接收消息 流程:

graph TD
handler的sendMessage --> sendMessageAtTime --> Handler的enqueueMessage --> 到MessageQueue的enqueueMessage --> msg.next给Message --> Looper.loop方法循环取值 --> MessageQueue的next循环返回值 --> Looper.loop取到msg后调用msg.target.dispatchMessage返回给Handler

总结4:Handler 怎么实现线程切换


当在A线程中创建handler的时候,同时创建了MessageQueue与Looper,Looper在A线程中调用loop进入一个无限的for循环从MessageQueue中取消息,当B线程调用handler发送一个message的时候,会通过msg.target.dispatchMessage(msg);将message插入到handler对应的MessageQueue中,Looper发现有message插入到MessageQueue中,便取出message执行相应的逻辑,因为Looper.loop()是在A线程中启动的,所以则回到了A线程,达到了从B线程切换到A线程的目的。

3cb22976cc1541217ae844afdaf4bc24.png

Handler 还有一个重要的功能就是发送消息屏障(Message)


为什么需要发送屏障消息? Message 可分为3种:
1.普通消息
2.屏障消息
3.异步消息
首先看 发送屏障消息的方式
@UnsupportedAppUsage
@TestApi
public int postSyncBarrier() {
    return postSyncBarrier(SystemClock.uptimeMillis());
}

private int postSyncBarrier(long when) {
    // Enqueue a new sync barrier token.
    // We don't need to wake the queue because the purpose of a barrier is to stall it.
    synchronized (this) {
        final int token = mNextBarrierToken++;
        final Message msg = Message.obtain();
        msg.markInUse();
        msg.when = when;
        msg.arg1 = token;

        Message prev = null;
        Message p = mMessages;
        if (when != 0) {
            while (p != null && p.when <= when) {
                prev = p;
                p = p.next;
            }
        }
        if (prev != null) { // invariant: p == prev.next
            msg.next = p;
            prev.next = msg;
        } else {
            msg.next = p;
            mMessages = msg;
        }
        return token;
    }
}

可以去看 Hnadler 发送Message 时(Handler的 enqueueMessage 方法里面)

msg.target = this;

这么重要的一个赋值操作,但是屏障消息的 target = null 所以在消息loop() 的时候,MessageQueue next()取值是先判断

if (msg != null && msg.target == null) {//2、遇到屏障 msg.target == null
    // Stalled by a barrier.  Find the next asynchronous message in the queue.
    do {
        prevMsg = msg;
        msg = msg.next;
    } while (msg != null && !msg.isAsynchronous());//3、遍历消息链表找到最近的一条异步消息
}

这是先取消息屏障,再获取里面的异步消息,加入Message链表。这就完成了消息屏障 的 发送 和 取值。
屏障消息就是为了确保异步消息的优先级,设置了屏障后,只能处理其后的异步消息,同步消息会被挡住,除非撤销屏障。 同步屏障为Handler消息机制增加了一种简单的优先级机制
根据发送同步屏障的方法我们可以看出 :再ViewRootImpl中的方法

void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        //发送一个消息屏障
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        //发送一个异步消息? 那么这个消息再干什么呢
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        notifyRendererOfFramePending();
        pokeDrawLockIfNeeded();
    }
}

跟随方法 到类 Choreographer 中:最终调用了postCallbackDelayedInternal 这个方法

@UnsupportedAppUsage
@TestApi
public void postCallback(int callbackType, Runnable action, Object token) {
    postCallbackDelayed(callbackType, action, token, 0);
}
@UnsupportedAppUsage
@TestApi
public void postCallbackDelayed(int callbackType,
        Runnable action, Object token, long delayMillis) {
    if (action == null) {
        throw new IllegalArgumentException("action must not be null");
    }
    if (callbackType < 0 || callbackType > CALLBACK_LAST) {
        throw new IllegalArgumentException("callbackType is invalid");
    }

    postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}

private void postCallbackDelayedInternal(int callbackType,
        Object action, Object token, long delayMillis) {
    if (DEBUG_FRAMES) {
        Log.d(TAG, "PostCallback: type=" + callbackType
                + ", action=" + action + ", token=" + token
                + ", delayMillis=" + delayMillis);
    }

    synchronized (mLock) {
        final long now = SystemClock.uptimeMillis();
        final long dueTime = now + delayMillis;
        mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

        if (dueTime <= now) {
                //
            scheduleFrameLocked(now);
        } else {
            //发送一个异步消息 最终还是走到 Handler的sendMessageAtTime方法
            Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
            msg.arg1 = callbackType;
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, dueTime);
        }
    }
}

(Choreographer这个是界面刷新需要的 比如 60HZ 屏幕刷新只需要 16.7ms)学了UI 绘制流程才来学习这个


面试常问题

  1. Handler 的基本原理
  2. 子线程中怎么使用 Handler
  3. MessageQueue 获取消息是怎么等待
  4. 为什么不用 wait 而用 epoll 呢?
  5. 线程和 Handler Looper MessageQueue 的关系
  6. 多个线程给 MessageQueue 发消息,如何保证线程安全
  7. Handler 消息延迟是怎么处理的
  8. View.post 和 Handler.post 的区别
  9. Handler 导致的内存泄漏
  10. 非 UI 线程真的不能操作 View 吗 引用外面其他博主答案