Android 线程 Looper.prepare()、Looper.loop() 使用

优化项目过程中发现了一个非常Low的问题,整理一下。备忘:
说问题之前先看下HandlerThread的定义
一个封装了looper的线程:  

Looper用于封装了android线程中的消息循环。默认情况下一个线程是不存在消息循环(message loop)的,须要调用Looper.prepare()来给线程创建一个消息循环,调用Looper.loop()来使消息循环起作用。从消息队列里取消息。处理消息。
注:写在Looper.loop()之后的代码不会被马上执行。当调用后mHandler.getLooper().quit()后。loop才会中止,其后的代码才干得以执行。

Looper对象通过MessageQueue来存放消息和事件。一个线程仅仅能有一个Looper。相应一个MessageQueue。


下面是Android API中的一个典型的Looper thread实现:

//Handler不带參数的默认构造函数:new Handler()。实际上是通过Looper.myLooper()来获取当前线程中的消息循环,
//而默认情况下。线程是没有消息循环的,所以要调用 Looper.prepare()来给线程创建消息循环,然后再通过。Looper.loop()来使消息循环起作用。
[java]  view plain copy
  1. class LooperThread extends Thread  
  2. {  
  3. public Handler mHandler;  
  4. public void run()   
  5. {  
  6. Looper.prepare();  
  7. mHandler = new Handler()   
  8. {  
  9. public void handleMessage(Message msg)   
  10. {  
  11. // process incoming messages here  
  12. }  
  13. };  
  14. Looper.loop();  
  15. }  

另,Activity的MainUI线程默认是有消息队列的。

所以在Activity中新建Handler时,不须要先调用Looper.prepare()。


那么遇到了有多Low的问题呢:

项目中重写了一个HandlerThread,然后定义了post方法。然后在主线程中例如以下实现:

        AsyncHandler.post(new Runnable() {
            @Override
            public void run() {
                try {
                    Looper.prepare();

   // 一坨要异步运行的代码******

                    Looper.loop();
                } catch (Exception e) {
                    // TODO: handle exception
                e.printStackTrace();
                }

那么明眼人一看就看出问题来了 ,这代码一跑异步代码肯定运行不到啊。为啥呢。且看下prepare的实现:



     /** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
    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));
    }

So,简单,却是问题~

转载于:https://www.cnblogs.com/liguangsunls/p/7216407.html

<think>我们正在查找Looper.prepare()的具体代码实现。根据引用[1]和引用[2]的内容,我们可以得到以下信息:引用[1]中提供了Looper.prepare()方法的代码片段:```javapublicstaticvoidprepare(){prepare(true);}privatestaticvoidprepare(booleanquitAllowed){if(sThreadLocal.get()!=null){thrownewRuntimeException("OnlyoneLoopermaybecreatedperthread");}sThreadLocal.set(newLooper(quitAllowed));}```这里,prepare()方法调用了私有的prepare(boolean)方法,传入true表示允许退出。在prepare(boolean)方法中,首先检查当前线程是否已经存在Looper(通过sThreadLocal.get()判断),如果已经存在则抛出异常(因为一个线程只能有一个Looper)。然后,创建一个新的Looper对象(传入quitAllowed参数)并设置到sThreadLocal中。引用[2]补充说明:prepare()方法在一个工作线程中只能调用一次,调用后就可以通过Looper.myLooper()获取当前线程Looper对象,也可以通过Looper.myQueue()获取消息队列。因此,Looper.prepare()的主要作用是为当前线程初始化一个Looper对象,并确保一个线程只有一个Looper。现在,我们按照要求生成相关问题。</think>### Looper.prepare() 源码实现分析 根据 Android 源码(以 Android 10 为例),`Looper.prepare()` 的核心实现如下: ```java // frameworks/base/core/java/android/os/Looper.java public final class Looper { private static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>(); public static void prepare() { prepare(true); // 默认允许退出 } private static void prepare(boolean quitAllowed) { // 检查当前线程是否已存在Looper if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } // 创建新Looper并绑定到当前线程 sThreadLocal.set(new Looper(quitAllowed)); } // Looper构造函数 private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); // 创建消息队列 mThread = Thread.currentThread(); // 绑定当前线程 } } ``` #### 关键实现解析: 1. **线程唯一性保证** 通过 `sThreadLocal.get() != null` 检查确保每个线程只能创建一个 `Looper` 实例,否则抛出运行时异常[^1]。 2. **消息队列初始化** 在 `Looper` 构造函数中创建 `MessageQueue` 对象,核心参数 `quitAllowed` 控制是否允许退出循环[^1]。 3. **线程绑定机制** 使用 `ThreadLocal` 存储 `Looper` 实例,实现线程隔离: ```java public static @Nullable Looper myLooper() { return sThreadLocal.get(); } ``` 4. **主线程特殊处理** 系统主线程初始化时调用 `prepareMainLooper()`,其内部设置 `quitAllowed=false` 禁止退出: ```java public static void prepareMainLooper() { prepare(false); // 主线程不允许退出 sMainLooper = myLooper(); } ``` #### 典型使用场景: 工作线程中必须显式调用: ```java new Thread(() -> { Looper.prepare(); // 初始化Looper Handler handler = new Handler(); Looper.loop(); // 启动消息循环 }).start(); ``` 若不调用 `prepare()` 直接创建 `Handler`,将触发 `"Can't create handler inside thread that has not called Looper.prepare()"` 异常[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值