Android 彻底掌握 Handler 看这里就够了

}

sThreadLocal.get()

public T get() {

Thread t = Thread.currentThread();

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

}

可以看出,myLooper 通过一个线程本地变量中的存根,然后 mQueue 是 Looper 中的一个全局变量,类型是 MessageQueue 类型。

MessageQueue:保存要由 Looper 调度的消息列表。 Message不是直接添加到 MessageQueue 的,而是通过与 Looper 关联的 Handler 对象添加的。你可以使用 Looper.myQueue() 检索当前线程的 MessageQueue。

Looper 介绍

=========

默认情况下,线程没有与之关联的消息循环;要创建一个,在运行循环的线程中调用 prepare ,然后循环让它处理消息,直到循环停止。

大多数与消息循环的交互是通过 Handler 类进行的。

这是一个Looper线程实现的典型例子,利用prepare和loop的分离,创建了一个初始Handler与Looper进行通信。

class LooperThread extends Thread {

public Handler mHandler;

public void run() {

Looper.prepare();

mHandler = new Handler(Looper.myLooper()) {

public void handleMessage(Message msg) {

// 在这里处理传入的消息

}

};

Looper.loop();

}

}

启动一个 java 程序的入口函数是 main 方法,但是当 main 函数执行完毕之后此程序停止运行,也就是进程会自动终止。

但是当我们打开一个 Activity 之后,只要我们不按下返回键 Activity 会一直显示在屏幕上,也就是 Activity 所在进程会一直处于运行状态。实际上 Looper 内部维护一个无限循环,保证 App 进程持续进行。

Looper初始化


Activity.attach() 方法中会传入一个ActivityThread,ActivityThread 的 main 方法是一个新的 App 进程的入口。

ActivityThread.main()


public static void main(String[] args) {

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “ActivityThreadMain”);

// 安装选择性系统调用拦截

AndroidOs.install();

// 禁止CloseGuard

CloseGuard.setEnabled(false);

Environment.initForCurrentUser();

//确保 TrustedCertificateStore 查找 CA 证书的正确位置

final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());

TrustedCertificateStore.setDefaultUserDirectory(configDir);

// 调用每个进程的主线模块初始化。

initializeMainlineModules();

Process.setArgV0(“”);

//重点:注释1

//初始化当前进程的 Looper 对象

Looper.prepareMainLooper();

ActivityThread thread = new ActivityThread();

thread.attach(false, startSeq);

if (sMainThreadHandler == null) {

sMainThreadHandler = thread.getHandler();

}

//重点:注释2

//调用 Looper 的 loop 方法开启无限循环。

Looper.loop();

throw new RuntimeException(“Main thread loop unexpectedly exited”);

}

注释1:就初始化当前进程的 Looper 对象;

注释2:调用 Looper 的 loop 方法开启无限循环(具体下面讲到)。

Looper.prepareMainLooper()


public static void prepareMainLooper() {

//注释1:创建一个Looper

//下面把方法贴出来

prepare(false);

//加个同步方法对象锁

synchronized (Looper.class) {

if (sMainLooper != null) {

throw new IllegalStateException(“The main Looper has already been prepared.”);

}

//这个要等prepare执行完再看

//注释1

sMainLooper = myLooper();

}

}

Looper.prepare()

private static void prepare(boolean quitAllowed) {

//判断是否绑定过 Looper 对象

if (sThreadLocal.get() != null) {

throw new RuntimeException(“Only one Looper may be created per thread”);

}

sThreadLocal.set(new Looper(quitAllowed));

}

Looper.prepare 方法其实就是new 一个 Looper。核心之处在于将 new 出的 Looper 设置到了线程本地变量 sThreadLocal.set(looper) 中。也就是说创建的 Looper 与当前线程发生了绑定。

**注意:**在创建 Looper 对象之前,会判断 sThreaLocal 中是否已经绑定过 Looper 对象,如果是则抛出异常。这行代码的目的是确保在一个线程中 Looper.prepare() 方法只能被调用 1 次。

new Looper()

private Looper(boolean quitAllowed) {

mQueue = new MessageQueue(quitAllowed);

mThread = Thread.currentThread();

}

Looper在构造方法中初始化了消息队列 MessageQueue 对象。

prepare 方法执行完之后,会在 Looper.prepareMainLooper 中处调用 myLooper() 方法,从 sThreadLocal 中取出 Looper 对象并赋值给 sMainLooper 变量。

Looper.prepare() 只能被调用1次

从上面代码可以看出Activity在被创建时已经在 Looper.prepareMainLooper()中调用了一次Looper.prepare(),我决定在onCreate()里面再调用一次Looper.prepare(),祝福我吧。 我现在我准备在MainActivity中加一行代码

@Override

public void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

Looper.prepare();

}

结果惨兮兮:

注意:

  • 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方法
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

结语

由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!以下是目录截图:

由于整个文档比较全面,内容比较多,篇幅不允许,下面以截图方式展示 。

再附一部分Android架构面试视频讲解:

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

sg);

}

}

咱先看看handleCallback方法
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-X3jG8wru-1713144376168)]

[外链图片转存中…(img-Jkk1ZROL-1713144376168)]

[外链图片转存中…(img-iKyik3rH-1713144376168)]

[外链图片转存中…(img-l9hoXrLX-1713144376169)]

[外链图片转存中…(img-wgQryE6r-1713144376169)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

结语

由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!以下是目录截图:

[外链图片转存中…(img-0XYZh65S-1713144376169)]

由于整个文档比较全面,内容比较多,篇幅不允许,下面以截图方式展示 。

再附一部分Android架构面试视频讲解:

[外链图片转存中…(img-w5yjOhvH-1713144376169)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值