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;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_carsetting);textView = findViewById(R.id.textView);// 主线程的 Handler,用于更新 UImainHandler = new Handler(Looper.getMainLooper());// 创建子线程并启动它backgroundThread = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("childThread prepare");Looper.prepare();// 在子线程中创建一个 Handler// 充当其他线程调用 backgroundHandler.sendMessage/backgroundHandler.post的接收端backgroundHandler = new Handler(Looper.myLooper()) {@Overridepublic 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);}@UnsupportedAppUsagepublic 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方法来处理来自其他线程的消息。