Android 消息机制 - Looper(Looper 静态方法、Looper 静态方法注意事项、Looper 实例方法、Looper 实例方法注意事项)

一、Looper 概述

  1. Looper 是 Android 消息机制的核心组件之一,它为线程创建并管理消息循环,让线程能够持续处理消息队列中的消息

  2. 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()
  1. prepare 方法用于为当前线程创建 Looper(含 MessageQueue),一个线程只能调用一次
java 复制代码
public static Looper myLooper()
  1. myLooper 方法用于获取当前线程的 Looper 实例
java 复制代码
public static void loop()
  1. 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 静态方法注意事项

  1. 在主线程中调用 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
  1. 一个线程只能调用一次 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 实例方法注意事项

  1. 在主线程中调用 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.
  1. 在主线程中调用 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.
相关推荐
MY_TEUCK1 小时前
【Java 后端】SpringBoot 登录认证与会话跟踪实战(JWT + Filter/Interceptor)
java·开发语言·spring boot
今天长肉了吗2 小时前
银行风控项目踩坑实录:指标跑了6小时,风险评分全挂了
java
随读手机2 小时前
多式联运信息交互平台完整方案(2026版)
java·ai·eclipse·云计算·区块链
许彰午3 小时前
03-二叉树——从递归遍历到非递归实现
java·算法
nj01283 小时前
Spring 循环依赖详解:三级缓存、早期引用、AOP 代理与懒加载
java·spring·缓存
野生技术架构师3 小时前
2026年最全Java面试题及答案汇总(建议收藏,面试前看这篇就够了)
java·开发语言·面试
百锦再4 小时前
Auto.js变成基础知识学习
开发语言·javascript·学习·sqlite·kotlin·android studio·数据库开发
一只叫煤球的猫4 小时前
ThreadForge 源码解读一:ThreadScope 如何把并发任务放进清晰边界?
java·面试·开源
洛_尘4 小时前
Python 5:使用库
java·前端·python
程序员小假5 小时前
HTTP3 性能更好,为什么内网微服务依然多用 HTTP2?HTTP2 内网优势是什么?
java·后端