文章目录
- 前言
- 一、两种用法
- 1.使用 post 方法
- 2.使用 sendMessage 方法
- 二、原理
- Message
- MessageQueue
- Looper
- Handler
前言
Handler 用于在线程间进行通信。主要用法就是在非UI线程中更新UI组件。当创建一个Handler的时候,该Handler就绑定了当前创建Hanlder的线程。
一、两种用法
1.使用 post 方法
class MainActivity : AppCompatActivity() {
private val handler = Handler()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener {
Toast.makeText(this, "hello", Toast.LENGTH_SHORT).show()
}
thread {
val runnable = Runnable {
tv_main_test.text = "5s"
}
Thread.sleep(3000)
handler.post(runnable)//将一个Runnable对象通过post方法传入到了Handler中,Handler会在合适的时候让主线程执行Runnable中的代码
}
}
}
2.使用 sendMessage 方法
class MainActivity : AppCompatActivity() {
private lateinit var textView: TextView
class MyHandler(activity: MainActivity): Handler() {
private val mWeakReference = WeakReference<MainActivity>(activity) // 弱引用 activity 避免内存泄漏
override fun handleMessage(msg: Message) {
val mainActivity = mWeakReference.get()
when (msg.what) {
1 -> {
mainActivity?.textView?.text = "hello"
}
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
textView = tv_main_text
val mHandler = MyHandler(this)
thread {
val msg = Message.obtain()
msg.what = 1
mHandler.sendMessage(msg)
}
}
}
二、原理
Message
Message是Handler接收与处理的消息对象。
- Message有两个重要的成员变量,分别为target 和callback,target 指的是处理此Message 的 Handler,callback 变量如果不为 null ,最终在 Handler 处理消息时执行 run 方法中的逻辑。
- Message 中有 4 个携带信息的成员变量,分别是 what,标识信息的来源;arg1,arg2,携带 int 类型的数据;obj,携带复杂类型的数据。Message 对象只是一个载体,重要的是它携带的信息。
- 一般使用 obtain() 方法获取 Message 对象。Message 内部有一个消息池,该消息池是一个链表结构,如果消息池不为 null,则从链表头部获取 Message,如果为空则 new Message()。
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool; // sPool表示链表头部
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
- 同时如果 Message 处理完毕会在Looper.loop() 方法中调用 recycleUnchecked() 方法回收 Message,放入链表头部。
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 = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null; // 清空 Message 数据
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
MessageQueue
一个线程内部只有一个 MessageQueue。
- MessageQueue实质是一个单向链表,Message对象有个next字段保存列表中的下一个,MessageQueue中的mMessages保存链表的第一个元素。
- 其中 enqueueMessage(Message msg, long when) 方法用于向链表中插入消息,具体来说,when 值越小的 Message 存放在链表的越前面,如果 when 是 0,则插入链表表头,when = 当前时间 + 指定的延迟毫秒数。
boolean enqueueMessage(Message msg, long when) { // when = SystemClock.uptimeMillis() + delayMillis,其中 SystemClock.uptimeMillis() 表示系统开机到当前的时间总数,单位是毫秒。
synchronized (this) {
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 {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
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;
}
Looper
一个线程只有一个唯一的 Looper,同时一个 Looper 只对应一个线程。
- Looper用来循环读取MessageQueen中的消息,读到消息之后就把消息交给Handler去处理。
- 默认情况下当我们创建一个新的线程的时候,这个线程里面是没有消息队列MessageQueue的。为了能够让线程能够绑定一个消息队列,我们需要借助于Looper。首先我们要调用Looper的prepare方法,该方法中调用了Looper 的构造方法,生成了线程的MessageQueue。同时也调用了ThreadLocal的 set() 方法,为Thread 的 ThreadLocalMap 成员变量添加了一个key = mThreadLocal,value = Looper 的键值对,即将线程与Looper绑定。
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare(); // 让线程绑定 Looper,同时生成线程的 MessageQueue
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop(); // 处理消息队列中的消息
}
}
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private Looper(boolean quitAllowed) { // 构造函数
mQueue = new MessageQueue(quitAllowed); // new 消息队列
mThread = Thread.currentThread(); // 获得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)); // ThreadLocal 能让每个线程都访问到自己的 Looper,往线程的ThreadLocalMap 中添加 value
}
- 关于ThreadLocal:每个线程内部都有一个自己的ThreadLocalMap,Map的key值为 ThreadLocal,value 为自己添加的值。ThreadLocal 能为每个线程添加自己的 Looper 到 Map 中,这样多个线程访问Looper就不会造成冲突。
- 在调用了Looper.prepare()方法之后,当前线程和Looper就进行了双向的绑定,这时候我们就可以调用Looper.loop()方法循环读取MessageQueen中的消息了。
Looper.java
public static void loop() { // 部分代码
final Looper me = myLooper(); // 获取线程绑定的Looper
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue; // 获取构造函数中 new 出来的消息队列,即当前线程所关联的 MessageQueue
for (;;) { // 不断循环
Message msg = queue.next(); // might block,如果此时消息队列中有Message,那么next方法会立即返回该Message,如果此时消息队列中没有Message,那么next方法就会阻塞式地等待获取Message。
// 具体如何阻塞?就是for 循环不断从MessageQueue 中获取消息
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
try {
msg.target.dispatchMessage(msg); // msg 的targe属性是Handler,让msg所关联的Handler,处理Message
}
msg.recycleUnchecked();
}
}
Handler
一个线程可以有多个 Handler,一个 Handler 只能对应一个线程。
- Handler 主要用于向 MessageQueue 中传入 Message 以及处理 Message。
- 通过sendMessageXXX系列方法可以向消息队列中添加消息,
所有的sendMessageXXX方法和sendEmptyMessageXXX最终都调用了sendMessageAtTime方法。
Handler.java
public boolean sendMessageAtTime(@NonNull 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); // 调用 Handler 的 enqueueMessage 方法
}
Handler.java
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this; // 将当前 handler 赋值给 Message.target,即将 Message 与 Handler 关联起来
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis); // 调用 MessageQueue 的 enqueueMessage 方法,将 Message 放入消息队列中
}
- 再来看看post方法,会发现post方法在其内部又调用了对应的sendMessage方法。post依赖sendMessage,post方法可以通过sendMessage方法向消息队列中传入消息,只不过通过post方法向消息队列中传入的消息都携带有callback对象。
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m; // 返回一个带有callback的message
}
- 在Looper.loop() 中,Looper一直在不断的从消息队列中通过MessageQueue的next方法获取Message,然后通过代码msg.target.dispatchMessage(msg)让该msg所绑定的Handler(Message.target)执行dispatchMessage方法以实现对Message的处理。
final Callback mCallback;
// 首先尝试让postXXX中传递的Runnable执行,其次尝试让Handler构造函数中传入的Callback的handleMessage方法处理,最后才是让Handler自身的handleMessage方法处理Message。
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) { // 如果是 post 方法添加的消息,则msg.callback!=null
handleCallback(msg);
} else {
if (mCallback != null) { // 如果 mCallback 在Handler构造函数中被初始化,则!= null
if (mCallback.handleMessage(msg)) { // 调用 callback 的 handlerMessage 方法
return;
}
}
handleMessage(msg); // 否则就调用重写的 handleMessage 方法
}
}
private static void handleCallback(Message message) {
message.callback.run(); // 调用 callback 的run方法处理信息
}