Android 彻底掌握 Handler 看这里就够了,大厂Android高级多套面试专题整理集合

  • prepare 方法在一个线程中只能被调用 1 次
  • Looper 的构造方法在一个线程中只能被调用 1 次
  • MessageQueue 在一个线程中只会被初始化 1 次

结论:也就是说 UI 线程中只会存在 1 个 MessageQueue 对象,后续我们通过 Handler 发送的消息都会被发送到这个 MessageQueue 中。

Looper 干啥的?


总结 Looper 做的事情就是:不断从 MessageQueue 中取出 Message,然后处理 Message 中指定的任务。

回到原点,在 ActivityThread 的 main 方法中,除了调用 Looper.prepareMainLooper 初始化 Looper 对象之外,还调用了 Looper.loop 方法开启无限循环,Looper 的主要功能就是在这个循环中完成的。

Looper.loop()


public static void loop() {

//取出 Looper 对象并赋值给 me

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;

final MessageQueue queue = me.mQueue;

//下面这个死循环,进去就甭想出来了。

for (; {

//注释1

//调用 MessageQueue 的 next 方法取出 Message

Message msg = queue.next(); // might block

if (msg == null) {

// No message indicates that the message queue is quitting.

return;

}

try {

//注释2

//msg不为null,进行处理

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();

}

}

上面代码表示 loop 方法中执行了一个死循环,这也是一个 Android App 进程能够持续运行的原因。

注释1:不断地调用 MessageQueue 的 next 方法取出 Message。

注释2:如果 message 不为 null,则处进行后续处理。具体就是从 Message 中取出 target 对象,然后调用其 dispatchMessage 方法处理 Message 自身。target是谁?

Message.target

public final class Message implements Parcelable {

@UnsupportedAppUsage

@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)

public long when;

/package/ Bundle data;

@UnsupportedAppUsage

/package/ Handler target;

@UnsupportedAppUsage

/package/ Runnable callback;

// sometimes we store linked lists of these things

@UnsupportedAppUsage

/package/ Message next;

/** @hide */

public static final Object sPoolSync = new Object();

private static Message sPool;

private static int sPoolSize = 0;

}

查看后其实就是个Handler。那咱们再看看Handler 的 dispatchMessage 方法

Handler.dispatchMessage()

/**

* Handle system messages here.

* 在这里处理系统消息。

*/

public void dispatchMessage(@NonNull Message msg) {

if (msg.callback != null) {

handleCallback(msg);

} else {

if (mCallback != null) {

if (mCallback.handleMessage(msg)) {

return;

}

}

handleMessage(msg);

}

}

/**

* Subclasses must implement this to receive messages.

* 子类必须实现它才能接收消息。

*/

public void handleMessage(@NonNull Message msg) {

}

可以看出,在 dispatchMessage 方法中会调用一个空方法 handleMessage,而这个方法也正是我们创建 Handler 时需要覆盖的方法。那么 Handler 是何时将其设置为一个 Message 的 target 的呢?

Handler.sendMessage()


Handler 有几个重载的 sendMessage 方法,但是基本都大同小异。咱使用最普通的 sendMessage 方法来分析,代码具体如下:

public final boolean sendMessage(@NonNull Message msg) {

return sendMessageDelayed(msg, 0);

}

Handler.sendMessageDelayed()

public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {

if (delayMillis < 0) {

delayMillis = 0;

}

return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);

}

Handler.sendMessageAtTime()

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);

}

经过几层调用之后,在这里我们拿到了在 ActivityThread 的 main 方法中通过 Looper 创建的 MessageQueue。

并且最后调用 enqueueMessage 方法将 Message 插入到消息队列 MessageQueue 中。

Handler.emqueueMessage()

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);

}

注释:将 Handler 自身设置为 Message的target(Handler) 对象。下来咱们看看 MessageQueue 的 enqueueMessage 方法。因此后续 Message 会调用此 Handler 的 dispatchMessage  方法来处理。

MessageQueue.enqueueMessage()

boolean enqueueMessage(Message msg, long when) {

//注释1,非空判断

if (msg.target == null) {

throw new IllegalArgumentException(“Message must have a target.”);

}

synchronized (this) {

if (msg.isInUse()) {

throw new IllegalStateException(msg + " This message is already in use.");

}

if (mQuitting) {

IllegalStateException e = new IllegalStateException(

msg.target + " sending message to a Handler on a dead thread");

Log.w(TAG, e.getMessage(), e);

msg.recycle();

return false;

}

msg.markInUse();

//注释2,从这朝下都蛮重要的

msg.when = when;

Message p = mMessages;

boolean needWake;

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.

if (needWake) {

nativeWake(mPtr);

}

}

return true;

}

注释1:会判断msg.target == null 没有设置,则直接抛出异常;

注释2:会按照 Message 的时间 when 来有序得插入 MessageQueue 中,可以看出 MessageQueue 实际上是一个有序队列,只不过是按照 Message 的执行时间来排序。

后续就是通过 ActivityThread 的 main 方法中 Looper 创建的 MessageQueue。Looper 从 MessageQueue 中取出 Message 之后,会调用 dispatchMessage 方法进行处理。

至此 Handler 的发送消息和消息处理流程已经介绍完毕。

重点关注

====

Handler 的 post(Runnable) 与 sendMessage(Message msg) 有什么区别


样例:

public class HandlerActivity extends ActivityBase{

ActivityHandlerBinding binding ;

private Handler handler = new Handler(new Handler.Callback() {

@Override

public boolean handleMessage(@NonNull Message msg) {

switch (msg.what){

case 1:

binding.tvTotle.setText(String.format(“哈哈哈哈考了%d”,msg.arg1));

break;

}

return false;

}

});

@Override

protected void onCreate(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

binding = ActivityHandlerBinding.inflate(getLayoutInflater());

setContentView(binding.getRoot());

binding.btnSendMessage.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

Message msg = new Message();

msg.what=1;

msg.arg1=100;

handler.sendMessage(msg);

}

});

binding.btnPost.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

handler.post(new Runnable() {

@Override

public void run() {

binding.tvTotle.setText(String.format(“哈哈哈哈考了%d”,80));

}

});

}

});

}

}

Handler.post()

public final boolean post(@NonNull Runnable r) {

return  sendMessageDelayed(getPostMessage®, 0);

}

然后调用 getPostMessage() 传入 Runnable ,咱看看这个是干嘛的?

Handler.getPostMessage()

private static Message getPostMessage(Runnable r) {

Message m = Message.obtain();

m.callback = r;

return m;

}

在这个方法中你会发现getPostMessage()会将 Runnable 赋值到 Message 的 callback 变量中,返回一个Message。并调用 sendMessageDelayed 方法。

Handler.sendMessage()

public final boolean sendMessage(@NonNull Message msg) {

return sendMessageDelayed(msg, 0);

}

对比发现他们都调用 sendMessageDelayed() ,只不过生成的Message方式不同。 sendMessageDelayed() 上文已经讲到了就不多描述了。可以向上翻翻。

可以看出,经过几层调用之后,sendMessageDelayed() 最终会调用 enqueueMessage() 方法将 Message 插入到消息队列 MessageQueue 中。而这个消息队列就是我们刚才分析的在 ActivityThread 的 main 方法中通过 Looper 创建的 MessageQueue

Looper 通过 loop() 方法从 MessageQueue 中取出 Message ,Message.target(Handrle) 会调用 dispatchMessage 方法进行处理。下面咱再看看它的源码。

Handrle.dispatchMessage()

/**

* Handle system messages here.

* 在这里处理系统消息。

*/

public void dispatchMessage(@NonNull Message msg) {

//注释1

if (msg.callback != null) {

handleCallback(msg);

} else {

//注释2

if (mCallback != null) {

if (mCallback.handleMessage(msg)) {

return;

}

}

handleMessage(msg);

}

}

咱先看看handleCallback方法

Handrle.handleCallback()

private static void handleCallback(Message message) {

message.callback.run();

}

很明显,dispatchMessage 分两种情况:

注释1msg.callback != null,一般为通过 post(Runnabl) 方式,会直接执行 Runnable 的 run 方法。因此这里的 Runnable 实际上就是一个回调接口,跟线程 Thread 没有任何关系。

注释2msg.callback == null,这种一般为 sendMessage 的方式,则会调用 Handler 的 hanlerMessage 方法进行处理。

Looper.loop() 为什么不会阻塞主线程


刚才我们了解了,Looper 中的 loop 方法实际上是一个死循环。但是我们的 UI 线程却并没有被阻塞,反而还能够进行各种手势操作,这是为什么呢?在 MessageQueue 的 next 方法中.

MessageQueue.next()

Message next() {

// mPtr :used by native code

final long ptr = mPtr;

if (ptr == 0) {

return null;

}

//-1:仅在第一次迭代期间

int pendingIdleHandlerCount = -1;

//下一个Poll超时时间

int nextPollTimeoutMillis = 0;

for (; {

if (nextPolAndroid 彻底掌握 Handler 看这里就够了,大厂Android高级多套面试专题整理集合_第1张图片
lTimeoutMillis != 0) {

//将当前线程中挂起的所有 Binder 命令刷新到内核驱动程序。

//在执行可能会阻塞很长时间的操作之前调用这会很有用,

//以确保任何挂起的对象引用都已被释放,以防止进程持有对象的时间超过它所需的时间。

Binder.flushPendingCommands();

}

//注释:重点来了。

nativePollOnce(ptr, nextPollTimeoutMillis);

}

}

MessageQueue.nativePollOnce()

/non-static for callbacks/

private native void nativePollOnce(long ptr, int timeoutMillis);

nativePollOnce 方法是一个 native 方法,当调用此 native 方法时,主线程会释放 CPU 资源进入休眠状态,直到下条消息到达或者有事务发生,通过往 pipe 管道写端写入数据来唤醒主线程工作,这里采用的 epoll 机制。下面是关于 nativePollOnce 的部分分析,参考了nativePollOnce函数分析,感兴趣的可以去自己看看,有点懵。等我再努力努力再来看这些吧。

epoll机制:提供了Linux平台上最高效的I/O复用机制。 从调用方法上看,epoll的用法和select/poll非常类似,其主要作用就是I/O复用,即在一个地方等待多个文件句柄的I/O事件。

nativePollOnce的实现函数是android_os_MessageQueue_nativePollOnce

android_os_MessageQueue_nativePollOnce

frameworks/base/core/jni/android_os_MessageQueue.cpp

static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,

jlong ptr, jint timeoutMillis) {

NativeMessageQueue* nativeMessageQueue = reinterpret_cast(ptr);

//取出NativeMessageQueue对象,并调用它的pollOnce

nativeMessageQueue->pollOnce(env, obj, timeoutMillis);

}

pollOnce()

frameworks/base/core/jni/android_os_MessageQueue.cpp

void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {

mPollEnv = env;

mPollObj = pollObj;

//重任传递到Looper的pollOnce函数

mLooper->pollOnce(timeoutMillis);

mPollObj = NULL;

mPollEnv = NULL;

if (mExceptionObj) {

env->Throw(mExceptionObj);

env->DeleteLocalRef(mExceptionObj);

mExceptionObj = NULL;

}

}

pollOnce()

system/core/libutils/include/utils/Looper.h

/**

* 等待事件可用,以毫秒为单位可选超时。

* 为发生事件的所有文件描述符调用回调。

* 如果超时为零,则立即返回而不阻塞。

* 如果超时为负,则无限期等待直到事件出现。

* 如果之前使用wake() 唤醒轮询,则返回POLL_WAKE

* 超时到期,没有调用回调,也没有其他文件

* 描述符已准备就绪。

* 如果调用了一个或多个回调,则返回 POLL_CALLBACK。

* 如果在给定之前没有数据等待超时,则返回 POLL_TIMEOUT。

* 如果等待过程中发生错误,则返回 POLL_ERROR。

* 如果文件描述符有数据,则返回一个 >= 0 包含标识符的值

* 并且它没有回调函数(这里需要调用者来处理它)。

* 在这个(并且只有这个)情况下,outFd、outEvents 和 outData 将包含投票

* 与 fd 关联的事件和数据,否则它们将被设置为 NULL。

* 此方法在完成调用适当的回调之前不会返回

* 用于所有已发出信号的文件描述符。

*/

int pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);

inline int pollOnce(int timeoutMillis) {

//timeOutMillis参数为超时等待时间。如果为-1,则表示无限等待,直到有事件发生为止。如果值为0,则无需等待立即返回。

return pollOnce(timeoutMillis, nullptr, nullptr, nullptr);

}

mPollObj = NULL;

mPollEnv = NULL;

if (mExceptionObj) {

env->Throw(mExceptionObj);

env->DeleteLocalRef(mExceptionObj);

mExceptionObj = NULL;

}

}

pollOnce()

system/core/libutils/include/utils/Looper.h

/**

* 等待事件可用,以毫秒为单位可选超时。

* 为发生事件的所有文件描述符调用回调。

* 如果超时为零,则立即返回而不阻塞。

* 如果超时为负,则无限期等待直到事件出现。

* 如果之前使用wake() 唤醒轮询,则返回POLL_WAKE

* 超时到期,没有调用回调,也没有其他文件

* 描述符已准备就绪。

* 如果调用了一个或多个回调,则返回 POLL_CALLBACK。

* 如果在给定之前没有数据等待超时,则返回 POLL_TIMEOUT。

* 如果等待过程中发生错误,则返回 POLL_ERROR。

* 如果文件描述符有数据,则返回一个 >= 0 包含标识符的值

* 并且它没有回调函数(这里需要调用者来处理它)。

* 在这个(并且只有这个)情况下,outFd、outEvents 和 outData 将包含投票

* 与 fd 关联的事件和数据,否则它们将被设置为 NULL。

* 此方法在完成调用适当的回调之前不会返回

* 用于所有已发出信号的文件描述符。

*/

int pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);

inline int pollOnce(int timeoutMillis) {

//timeOutMillis参数为超时等待时间。如果为-1,则表示无限等待,直到有事件发生为止。如果值为0,则无需等待立即返回。

return pollOnce(timeoutMillis, nullptr, nullptr, nullptr);

}

你可能感兴趣的:(程序员,架构,移动开发,android)