Android之Looper源码分析(第一篇:创建Looper对象)

前言

    Looper对象在Android的Handler机制中起到巨大的作用,可以说是核心对象了,今天一起分析Looper对象的创建,Looper类中定义了两个静态方法,均可用于创建Looper对象

    Looper的构造方法使用private修饰,无法通过正常途径使用构造方法创建Looper对象……所以接下来我们分析这两个创建Looper对象的静态方法,prepare()和prepareMainLooper()

 

静态方法prepareMainLooper()分析

    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

此方法只能在主线程(Ui线程)的执行代码中创建Looper对象,这个静态方法目前最常用在每个App架构的入口类ActivtyThread中的静态方法main()中,开发者可能永远用不到这个方法(如果你自己写App框架,也能用得着)接下来学习一下代码块中执行了哪些代码,就知道为什么我们不能手动调用该方法了……

1、调用静态方法prepare()

调用静态方法prepare(),并为其传入flase,false表示不允许Looper对象持有的MessageQueue对象退出(这样执行的线程就不会退出了),此处的静态方法prepare()会创建Looper对象, 稍后会详细该方法

2、创建完Looper对象,检查Looper类是否已经持有创建的Looper对象

当前线程需要持有Class对象锁(Looper类锁),才可以继续执行代码块中的代码,如果没有获得对象锁,将会被阻塞在代码块的入口处,静态方法prepareMainLooper()第一次执行的时候,Looper类持有的静态变量sMainLooper指向的是null,这里会检查静态变量sMainLooper是否已经指向一个Looper对象,如果sMainLooper不为null,说明其已经指向了一个Looper对象,那么针对这种情况会抛出一个异常IllegalStateException对象,用于告知调用者:The Main Looper has alrady been prepared. 表示在主线程中的Looper对象已经创建好了………………作为开发者,我们又在主线程中调用此静态方法,就会看到此异常。这就是为什么不能在任何线程调用这个方法的原因,作为Looper类,App框架在执行ActivityThread的main()方法时已经调用过Looper的静态方法prepareMainLooper(),由于又有对象锁控制代码块同一时刻只有一个线程可以访问,所以可以保证Looper类持有的sMainLooper指向的Looper对象,一定是在主线程中创建的Looper对象!

3、将Looper类持有的sMainLooper指向一个Looper对象

调用静态方法myLooper(),它会返回当前线程中持有的Looper对象,然后赋值给Looper类持有的sMainLooper,此时Looper类开始持有创建的Looper对象。(这处代码唯一可能执行的是,第一次在主线程中创建Looper对象的时候)

 

静态方法prepare()分析

    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));
    }

用于在线程中创建Looper对象的静态方法,传入的参数表示Looper对象持有的MessageQueue对象能否退出

1、检查ThreadLocal对象是否已经持有一个已经创建的Looper对象

通过ThreadLocal对象的get()方法可以获得一个以ThreadLocal对象为Key,获得的Looper对象,ThreadLocal确保在每一个线程对象中只有一个创建的Looper对象,如果在当前线程中再次创建Looper对象,因为ThreadLocal已经可以获得一个Looper对象,所以当你想在线程中创建多个Looper时,这里会抛出RuntimeException对象,用于提醒调用者:“Only one Looper may be created per thread”!!!表示每个线程中只能创建一个Looper对象

2、创建Looper对象,并保存到ThreadLocal对象中

如果是第一次创建Looper对象,为Looper的构造方法传入局部变量quitAllowed,创建的Looper对象再传入到ThreadLocal对象sThreadLocalset()方法中,由ThreadLocal对象负责保存创建的Looper对象

 

Looper构造方法分析

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

用于创建Looper对象的构造方法,传入的参数quitAllowed表示MessageQueue对象能否退出

1、创建MessageQueue对象,并赋值给Looper对象持有的实例变量mQueue中保存

传入的局部变量quitAllowd会直接传入到MessageQueue的构造方法中,新创建的MessageQueue对象会直接赋值给Looper对象持有的实例变量mQueue

2、获取当前的Thread对象

通过Thread的静态方法currentThread()可以获得表示当前线程的Thread对象,并赋值给Looper对象持有的实例变量mThread

 

静态方法myLooper()分析

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

用于获取当前线程中持有的线程局部变量(Looper对象),即每个线程中保存的唯一的Looper对象

1、Looper类持有的ThreadLocal对象sThreadLocal,通过它的get()方法即可获取到当前线程中保存的Looper对象

2、向调用者返回在线程中保存的Looper对象

 

静态方法prepare()分析

    public static void prepare() {
        prepare(true);
    }

用于创建一个MessageQueue可退出的Looper对象

1、调用静态方法prepare,并传入true

内部再调用静态方法prepare(),注意此时传入的参数是true,代表Looper对象持有的MessageQueue对象可以退出(这样线程就可以退出了)

 

重要字段介绍

private static final String TAG = "Looper"; //大佬打印日志用的TAG

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();   
//static修饰ThreadLocal,一是方便所有线程复用,二是ThreadLocalMap中的底层数组持有的元素对象Entry

//弱引用对象持有了ThreadLocal对象,不用static,ThreadLocal可能随时会被回收

private static Looper sMainLooper;  //Looper类持有的永远指向主线程相关的Looper对象

final MessageQueue mQueue; //Looper对象持有的MessageQueue对象

final Thread mThread;      //Looper对象持有的Thread对象(当前线程对象)


TAG:常量,作者用于打印日志

sThreadLocal:Looper类持有的静态变量,指向一个ThreadLocal对象

sMainLooper:Looper类持有的静态变量,sMainLooper永远指向的主线程中创建的Looper对象 

mQueue:Looper对象持有的MessageQueue对象

mThread:Looper对象持有的Thread对象,该Thread对象表示当前线程

 

总结

1、静态方法prepareMainLooper()用于在主线程创建Looper对象,每个App均在ActivityThread的静态方法main()中已经调用了该方法,所以导致开发者无法再次使用该方法创建Looper对象

2、静态方法prepare()是预留给开发者在工作线程中创建Looper对象用的,记住了哈

3、Looper对象持有一个MessageQueue对象

4、Looper对象持有一个Thread对象,表示当前线程

5、Looper类持有一个sMainLooper,它永远指向主线程中创建的Looper对象

6、Looper类持有一个ThreadLocal对象,它负责持有作为线程局部变量的Looper对象

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值