一、Looper 概述
-
Looper 是 Android 消息机制的核心组件之一,它为线程创建并管理消息循环,让线程能够持续处理消息队列中的消息
-
Looper 是实现主线程(UI 线程)消息循环、Handler 跨线程通信的基础
二、Looper 静态方法
1、prepareMainLooper 方法
java
public static void prepareMainLooper()
- prepareMainLooper 方法用于给主线程初始化 Looper,开发者禁止手动调用,否则抛出异常
2、getMainLooper 方法
(1)基本介绍
java
public static Looper getMainLooper()
- getMainLooper 方法用于在任意线程获取主线程 Looper,它是跨线程更新 UI 的核心
(2)演示
java
Looper mainLooper = Looper.getMainLooper();
3、prepare 方法、myLooper 方法、loop 方法
(1)基本介绍
java
public static void prepare()
- prepare 方法用于为当前线程创建 Looper(含 MessageQueue),一个线程只能调用一次
java
public static Looper myLooper()
- myLooper 方法用于获取当前线程的 Looper 实例
java
public static void loop()
- myLooper 方法用于启动消息循环,无限读取 MessageQueue 中的消息并分发,会阻塞当前线程,直到调用 quit 方法或者 quitSafely 方法
(2)演示
java
public class MyLooperThread extends Thread {
public static final String TAG = MyLooperThread.class.getSimpleName();
private Handler handler;
@Override
public void run() {
Log.i(TAG, "创建 Looper");
Looper.prepare();
handler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
Log.i(TAG, "处理消息:" + msg.what + " " + msg.obj);
}
};
Log.i(TAG, "开启 Looper 循环");
Looper.loop();
Log.i(TAG, "终止 Looper 结束");
}
public Handler getHandler() {
return handler;
}
}
java
MyLooperThread myLooperThread = new MyLooperThread();
myLooperThread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Handler handler = myLooperThread.getHandler();
Message message = Message.obtain();
message.what = 100;
message.obj = "hello";
handler.sendMessage(message);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.getLooper().quitSafely();
# 输出结果
创建 Looper
开启 Looper 循环
处理消息:100 hello
终止 Looper 结束
4、myQueue 方法
(1)基本介绍
java
public static MessageQueue myQueue()
- myQueue 方法用于获取当前线程的 Looper 实例关联的 MessageQueue 实例
(2)演示
java
MessageQueue messageQueue = Looper.myQueue();
三、Looper 静态方法注意事项
- 在主线程中调用 prepareMainLooper 方法,会抛出异常
java
Looper.prepareMainLooper();
# 输出结果
FATAL EXCEPTION: main
Process: com.my.handler, PID: 8553
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.my.handler/com.my.handler.MainActivity}: java.lang.RuntimeException: Only one Looper may be created per thread
- 一个线程只能调用一次 prepare 方法,否则会抛出异常
java
public class TestThread extends Thread {
public static final String TAG = TestThread.class.getSimpleName();
private Handler handler;
@Override
public void run() {
Log.i(TAG, "调用 Looper.prepare()");
Looper.prepare();
Log.i(TAG, "再次调用 Looper.myLooper()");
Looper.prepare();
handler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
Log.i(TAG, "处理消息:" + msg.what + " " + msg.obj);
}
};
Log.i(TAG, "开启 Looper 循环");
Looper.loop();
Log.i(TAG, "终止 Looper 结束");
}
public Handler getHandler() {
return handler;
}
}
java
TestThread testThread = new TestThread();
testThread.start();
# 输出结果
FATAL EXCEPTION: Thread-2
Process: com.my.handler, PID: 26512
java.lang.RuntimeException: Only one Looper may be created per thread
四、Looper 实例方法
1、getThread 方法
(1)基本介绍
java
public Thread getThread()
- getThread 方法用于获取当前 Looper 绑定的线程
(2)演示
java
Looper mainLooper = Looper.getMainLooper();
Thread thread = mainLooper.getThread();
Log.i(TAG, thread.getName());
# 输出结果
main
2、getQueue 方法
(1)基本介绍
java
public MessageQueue getQueue()
- getQueue 方法用于获取当前 Looper 关联的 MessageQueue 实例
(2)演示
java
Looper mainLooper = Looper.getMainLooper();
MessageQueue messageQueue = mainLooper.getQueue();
3、isCurrentThread 方法
(1)基本介绍
java
public boolean isCurrentThread()
- isCurrentThread 方法判断当前调用线程是否是 Looper 绑定的线程
(2)演示
java
Looper mainLooper = Looper.getMainLooper();
Log.i(TAG, String.valueOf(mainLooper.isCurrentThread()));
# 输出结果
true
4、dump 方法
(1)基本介绍
java
public void dump(@NonNull Printer pw, @NonNull String prefix)
- dump 方法用于将当前 Looper 的关键状态输出到指定流
(2)演示
java
Looper mainLooper = Looper.getMainLooper();
Printer printer = new Printer() {
@Override
public void println(String x) {
Log.i("LooperDump", x);
}
};
mainLooper.dump(printer, "mainLooper: ");
# 输出结果
mainLooper: Looper (main, tid 1) {2176923}
mainLooper: Message 0: { when=-1s265ms what=159 obj=android.app.servertransaction.ClientTransaction@8382 target=android.app.ActivityThread$H }
mainLooper: Message 1: { when=-853ms what=149 obj=android.os.BinderProxy@442a3a8 target=android.app.ActivityThread$H }
mainLooper: Message 2: { when=-204ms callback=android.app.-$$Lambda$ActivityThread$A4ykhsPb8qV3ffTqpQDklHSMDJ0 target=android.app.ActivityThread$H }
mainLooper: Message 3: { when=-70ms callback=androidx.core.content.res.ResourcesCompat$FontCallback$$ExternalSyntheticLambda0 target=android.os.Handler }
mainLooper: Message 4: { when=+4s422ms what=1000 target=android.graphics.AwareBitmapCacher$MyHandler }
mainLooper: (Total messages: 5, polling=false, quitting=false)
5、quitSafely 方法
(1)基本介绍
java
public void quitSafely()
- quitSafely 方法用于安全终止 Looper 消息循环,处理完已就绪消息后终止
(2)演示
java
public class DelayThread extends Thread {
public static final String TAG = DelayThread.class.getSimpleName();
private Handler handler;
@Override
public void run() {
Log.i(TAG, "创建 Looper");
Looper.prepare();
handler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
Log.i(TAG, "开始处理消息:" + msg.what + " " + msg.obj);
try {
Thread.sleep(2 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(TAG, "消息处理完成");
}
};
Log.i(TAG, "开启 Looper 循环");
Looper.loop();
Log.i(TAG, "终止 Looper 结束");
}
public Handler getHandler() {
return handler;
}
}
java
DelayThread delayThread = new DelayThread();
delayThread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Handler handler = delayThread.getHandler();
Message message1 = Message.obtain();
message1.what = 1;
message1.obj = "hello 1";
handler.sendMessage(message1);
Message message2 = Message.obtain();
message2.what = 2;
message2.obj = "hello 2";
handler.sendMessage(message2);
Message message3 = Message.obtain();
message3.what = 3;
message3.obj = "hello 3";
handler.sendMessage(message3);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.getLooper().quitSafely();
# 输出结果
创建 Looper
开启 Looper 循环
开始处理消息:1 hello 1
消息处理完成
开始处理消息:2 hello 2
消息处理完成
开始处理消息:3 hello 3
消息处理完成
终止 Looper 结束
6、quit 方法
(1)基本介绍
java
public void quit()
- quit 方法用于立即终止 Looper 消息循环,清空消息队列
(2)演示
java
public class DelayThread extends Thread {
public static final String TAG = DelayThread.class.getSimpleName();
private Handler handler;
@Override
public void run() {
Log.i(TAG, "创建 Looper");
Looper.prepare();
handler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
Log.i(TAG, "开始处理消息:" + msg.what + " " + msg.obj);
try {
Thread.sleep(2 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(TAG, "消息处理完成");
}
};
Log.i(TAG, "开启 Looper 循环");
Looper.loop();
Log.i(TAG, "终止 Looper 结束");
}
public Handler getHandler() {
return handler;
}
}
java
DelayThread delayThread = new DelayThread();
delayThread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Handler handler = delayThread.getHandler();
Message message1 = Message.obtain();
message1.what = 1;
message1.obj = "hello 1";
handler.sendMessage(message1);
Message message2 = Message.obtain();
message2.what = 2;
message2.obj = "hello 2";
handler.sendMessage(message2);
Message message3 = Message.obtain();
message3.what = 3;
message3.obj = "hello 3";
handler.sendMessage(message3);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.getLooper().quit();
# 输出结果
创建 Looper
开启 Looper 循环
开始处理消息:1 hello 1
消息处理完成
终止 Looper 结束
7、setMessageLogging 方法
(1)基本介绍
java
public void setMessageLogging(@Nullable Printer printer)
- setMessageLogging 方法用于监听消息分发全流程,为 Looper 实例设置一个 Printer ,Looper 会在消息分发前、分发后分别调用
(2)演示
java
public class MyLooperThread extends Thread {
public static final String TAG = MyLooperThread.class.getSimpleName();
private Handler handler;
@Override
public void run() {
Log.i(TAG, "创建 Looper");
Looper.prepare();
handler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
Log.i(TAG, "处理消息:" + msg.what + " " + msg.obj);
}
};
Log.i(TAG, "开启 Looper 循环");
Looper.loop();
Log.i(TAG, "终止 Looper 结束");
}
public Handler getHandler() {
return handler;
}
}
java
MyLooperThread myLooperThread = new MyLooperThread();
myLooperThread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Handler handler = myLooperThread.getHandler();
Looper looper = handler.getLooper();
looper.setMessageLogging(new Printer() {
@Override
public void println(String s) {
Log.i("LooperMessage", s);
}
});
Message message1 = Message.obtain();
message1.what = 1;
message1.obj = "hello 1";
handler.sendMessage(message1);
Message message2 = Message.obtain();
message2.what = 2;
message2.obj = "hello 2";
handler.sendMessage(message2);
Message message3 = Message.obtain();
message3.what = 3;
message3.obj = "hello 3";
handler.sendMessage(message3);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.getLooper().quit();
# 输出结果
创建 Looper
开启 Looper 循环
>>>>> Dispatching to Handler (com.my.handler.MyLooperThread$1) {2176923} null: 1
处理消息:1 hello 1
<<<<< Finished to Handler (com.my.handler.MyLooperThread$1) {2176923} null
>>>>> Dispatching to Handler (com.my.handler.MyLooperThread$1) {2176923} null: 2
处理消息:2 hello 2
<<<<< Finished to Handler (com.my.handler.MyLooperThread$1) {2176923} null
>>>>> Dispatching to Handler (com.my.handler.MyLooperThread$1) {2176923} null: 3
处理消息:3 hello 3
<<<<< Finished to Handler (com.my.handler.MyLooperThread$1) {2176923} null
终止 Looper 结束
五、Looper 实例方法注意事项
- 在主线程中调用 quit 方法,会抛出异常
java
Looper mainLooper = Looper.getMainLooper();
mainLooper.quit();
# 输出结果
FATAL EXCEPTION: main
Process: com.my.handler, PID: 11860
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.my.handler/com.my.handler.MainActivity}: java.lang.IllegalStateException: Main thread not allowed to quit.
- 在主线程中调用 quitSafely 方法,会抛出异常
java
Looper mainLooper = Looper.getMainLooper();
mainLooper.quitSafely();
# 输出结果
FATAL EXCEPTION: main
Process: com.my.handler, PID: 13300
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.my.handler/com.my.handler.MainActivity}: java.lang.IllegalStateException: Main thread not allowed to quit.