Handler机制-Looper源码解析

Handler机制-Looper源码解析

一、介绍

安卓中Handler框架处理消息,其中Looper类用来循环从MessageQueue类中获取消息,然后调用Handler进行消费.本文将基于安卓9.0代码带分析Looper的实现.

二、Looper类主要成员变量

Looper类比较简单,其主要类成员变量比较少.

  • static final ThreadLocal sThreadLocal = new ThreadLocal();

    存放Looper的线程共享变量,每个线程的Looper是不同的.

  • final MessageQueue mQueue;

    消息队列

  • final Thread mThread;

    Looper绑定的线程

  • private static Looper sMainLooper;

    主线程Looper

三、Looper的构造函数

//构造方法是私有的,一般会有静态方法来常见实例.
private Looper(boolean quitAllowed) {
    //创建消息队列.
    mQueue = new MessageQueue(quitAllowed);
    //保存创建Looper的当前线程实例.
    mThread = Thread.currentThread();
}

在Looper中构造方法中,首先创建了消息队列MessageQueue实例保存到了成员变量mQueue中,其次将当前线程实例存放到mThead成员变量中,完成Looper和线程的绑定.
该构造方法有一个参数:quitAllowed,表示该Looper是否可以提出,通过后面的代码分析可以看到主线程的Looper是不认不能退出的,其他线程的Looper是可以退出的.
Looper只有一个私有的构造方法,所以不允许直接通过new方法创建一个Looper实例,需要通过Looper的提供的静态工厂方法创建实例.

四、创建Looper

Looper类中提供了三个静态工厂方法, 创建Looper实例.

  • prepareMainLooper()方法用于创建主线程的Looper,
  • prepare()方法用于创建子线程的Looper.
  • prepare(boolean quitAllowed)方法是真正的创建looper的方法,它是私有的,通过prepareMainLooper()和prepare()调用.

4.1 创建Looper实例-prepare(boolean quitAllowed)

//创建Looper.
private static void prepare(boolean quitAllowed) {
    //创建前先从本地线程变量sThreadLocal中获取Looper,如果取到就抛出异常,不能重复创建.
    //所以创建
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    //直接newLooper的实例,并将Looper保存到本地变量中.
    sThreadLocal.set(new Looper(quitAllowed));
}

在该方法中创建Looper实例,在创建以前调用sThreadLocal.get()获取当前线程的Looper,如果获取到就抛出异常"Only one Looper may be created per thread",该异常说明一个线程只能创建一个Looper,不能重复创建.

sThreadLocal.set(new Looper(quitAllowed));表明将创建的looper实例保存到sThreadLocal中,从而保证每个线程的Looper不被覆盖.

4.2 创建void prepareMainLooper()


//主线程的Looper不能退出的,只能创建一次,并且创建后保存到
public static void prepareMainLooper() {
    //直接调用perpare方法创建,传入参数false,表示不能退出.
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        //将主线程的Looper的保存到静态成员变量sMainLooper,方便在其他线程中获取主线程的Looper.
        sMainLooper = myLooper();
    }
}

创建主线程Looper的时候调用prepare(false);创建,传入的参数为false,说明不能退出.将创建好的Looper实例保存到sMainLooper成员变量中.

在Android的实际开发工作中,我们不会去调用prepareMainLooper()方法来创建Looper实例,因为App在一启动的时候就自动创建了Looper实例

public final class ActivityThread extends ClientTransactionHandler {
 ...
 public static void main(String[] args) {
    ...
    //创建主线程Looper.
    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    //启动Looper的死循环
    Looper.loop();
 }
}

4.3 创建子线程的Looper实例-prepare()

//子线程的创建的Looper都是可以退出的.
public static void prepare() {
    prepare(true);
}

通过调用prepare(true)方法在子线程中创建Looper实例,参数为true,表明子线程创建的Looper可以退出的.

五、获取Looper.

5.1 获取当前线程的Looper

public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

通过myLooper()方法,在线程本地变量中获取Looper.

5.2 获取主线程的Looper

在主线程中,直接调用Looper.myLooper()方法返回的就是主线程的Looper.
在其他线程中,需要使用Looper.getMainLooper()方法获取主线程的Looper.
所以一直建议使用Looper.getMainLooper()方法获取主进程的Looper.

public static Looper getMainLooper() {
    synchronized (Looper.class) {
        return sMainLooper;
    }
}

六、Looper.loop()循环获取消息

下面是loop()代码,删掉大量和核心逻辑无关的代码.

public static void loop() {
    //首先获取当前的Looper,如果不存在,就抛出异常.
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    //获取当前Looper关联的MessageQueue
    final MessageQueue queue = me.mQueue;
    
    //创建死循环获取消息.
    for (;;) {
        //获取下一条消息.
        Message msg = queue.next(); // might block
        //如果消息为null,就跳出循环,提出Looper.
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }

        ...
        //调用Handler的dispatchMessage方法处理消息.
        try {
            msg.target.dispatchMessage(msg);
        } finally {
        }
        ...
        msg.recycleUnchecked();
    }
}

Looper创建了一个死循环,从mQueue获取消息,获取到后调用Handler进行处理,如果获取的消息为null就退出Looper.

七、Looper的退出

Looper类提供了两个方法quit()和quitSafely()来退出Looper,通过方法名字就可以看出一个安全退出的,一个是非安全退出.

7.1、quit()-非安全退出

public void quit() {
    mQueue.quit(false);
}

调用该方法后,直接终止Looper,不处理任何的message.

7.2 quitSafely()

public void quitSafely() {
    mQueue.quit(true);
}

调用该方法可以安全退出Looper,它处理完所有的消息后在终止,调用该方法后不能在把Messag放到消息队列中.

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值