Android的Handler
1. Handler是用于线程间通信,本质上是:
Handler调用发送方法,向与Looper绑定的消息队列写入消息,然后Looper.loop()会循环的从消息队列里拿出消息。并调用dispatchMessage处理消息。而需要此消息的线程会实现回调的handleMessage接口来处理消息。
2.举个例子:主线程调用子线程的Handler发送消息。
package com.android.car.myapplication;
import static java.lang.Thread.currentThread;
import static java.lang.Thread.sleep;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private TextView textView;
private Handler mainHandler;
private Handler backgroundHandler;
private Thread backgroundThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_carsetting);
textView = findViewById(R.id.textView);
// 主线程的 Handler,用于更新 UI
mainHandler = new Handler(Looper.getMainLooper());
// 创建子线程并启动它
backgroundThread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("childThread prepare");
Looper.prepare();
// 在子线程中创建一个 Handler
// 充当其他线程调用 backgroundHandler.sendMessage/backgroundHandler.post的接收端
backgroundHandler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(Message msg) {
if (msg.what == 1) {
System.out.println("childThread receive Msg 1");
}
}
};
System.out.println("childThread Looping");
Looper.loop();
}
});
backgroundThread.start();
// 等待线程跑起来
try {
sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Message message = backgroundHandler.obtainMessage(1);
backgroundHandler.sendMessage(message);
System.out.println("MainThread: sendMsg 1");
}
}
- 日志
2024-11-07 16:25:54.908 12880-12902 System.out com...myapplication I childThread prepare 2024-11-07 16:25:54.908 12880-12902 System.out com...myapplication I childThread Looping 2024-11-07 16:25:56.910 12880-12880 System.out com...myapplication I MainThread: sendMsg 1 2024-11-07 16:25:56.912 12880-12902 System.out com...myapplication I childThread receive Msg 1
3. Handler使用的源码解析
- 3.0 调用端使用sendMessage来发送消息
Message message = backgroundHandler.obtainMessage(1); backgroundHandler.sendMessage(message);
追sendMessage的调用栈,最终会调用到Handler.java的enqueueMessage函数
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, long uptimeMillis) { msg.target = this; // 。。。。。 return queue.enqueueMessage(msg, uptimeMillis); }
1)msg.target指定了this,即当前的Handler, 对应3.3中取出消息的地方msg.target为handler, 且这个Handler是backgroundHandler。
2)enqueueMessage将msg放入了消息队列。
- 3.1 Looper.prepare();
public static void prepare() { prepare(true); } 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)); }
- 3.2 Handler backgroundHandler = new Handler(Looper.myLooper())
public Handler(@NonNull Looper looper) { this(looper, null, false); } @UnsupportedAppUsage public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) { this(looper, callback, async, /* shared= */ false); } public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async, boolean shared) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; mIsShared = shared; }
- 3.3 Looper.loop(); 关键是loopOnce()从消息队列中循环拿消息,
假设现在调用了3.0中的sendMessage方法,此时消息队列中已经有了消息。
那么调用me.mQueue.next();即可拿到这条message.
再调用dispatchMessage处理消息。
private static boolean loopOnce(final Looper me, final long ident, final int thresholdOverride) { Message msg = me.mQueue.next(); // might block 。。。。 msg.target.dispatchMessage(msg); 。。。。。 msg.recycleUnchecked(); 。。。。。 return true; }
3.0 讲过了msg.target是backgroundHandler,再往下查看dispatchMessage的实现:
public void dispatchMessage(@NonNull Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); // 调用者overide 实现的 handleMessage函数 } }
会发现其中的handleMessage是在 2.当中实现的handleMessage方法。
4. nativePollOnce(ptr, nextPollTimeoutMillis);
nativePollOnce, 就是linux中的poll函数,可以让出线程对cpu的占用。
没有消息则线程进入空闲状态,不用一直调用来浪费cpu, 这种等待是非阻塞的。
5.总结:
在子线程中:
- Looper.prepare()初始化了MessageQueue,与当前线程绑定。
- Handler通过传入当前的Looper实现与Loop绑定,
- Handler通过override实现了handleMessage。
- 再通过Looper.loop()开启死循环来处理消息。
其他线程:
- 调用子线程的Handler的post/sendMessage方法,来向目标线程的MessageQueue写入消息。
子线程:
- 子线程调用Loop.loop()拿到消息,并调用dispatchMessage处理消息。
- 在调用子线程override的handleMessage方法来处理来自其他线程的消息。