子线程和主线程创建使用Handler不同处的源码分析

子线程的Handler

在使用handler时,会有在子线程创建handler的场景,那我们从Looper.java的源码中摘抄下面一段创建Hander的代码段:

 class LooperThread extends Thread {
     public Handler mHandler;
     public void run() {
         Looper.prepare();
         mHandler = new Handler() {
             public void handleMessage(Message msg) {
                 // process incoming messages here
             }
         };
         Looper.loop();
     }
 }

上面是一般使用在子线程创建和使用Handler的代码段,我们对比以前在主线程创建和使用Handler的代码,可以发现基本差不多,但是有一点不一样,那就是在子线程中多了下面这两行代码:

Looper.prepare();
Looper.loop();

1.1 prepare

就是子线程需要prepare,可以直接理解为组要准备当前线程的looper。就是说子线程没有looper,那我们看看我们怎么准备looper的?

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

源码的注释也说得很清楚,就是创建handler需要先有looper。prepare()方法里面是调用了prepare(boolean quitAllowed)方法,后面这个方法比前面就多了个参数,这个参数【quitAllowed】看字面意思可以看出作用就是:允不允许looper退出,从代码中我们可以知道子线程的looper是可以退出的;然后在prepare(boolean quitAllowed)中首先检查时候已经存在looper了,如果已经含有了looper,那就报错,这下我们就知道了Android是怎么保证一个线程只有一个looper了,如果当前线程还不存在looper,那就直接new一个新的looper,然后将创建的looper塞进sThreadLocal中。

1.2 loop

那么子线程中loop()方法是什么呢?这个loop()方法就是在当前线程中运行消息队列,并切在结束时需要调用quit()方法.我们接着针对loop()看看源码里面做了什么:

/**
    * Run the message queue in this thread. Be sure to call
    * {@link #quit()} to end the loop.
    */
public static void loop() {
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;

    for (;;) {
        Message msg = queue.next(); // might block
        ...
        try {
            msg.target.dispatchMessage(msg);
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } 
        ....
        msg.recycleUnchecked();
    }
}

在loop()方法中主要就是从消息队列中获取消息,然后执行信息分发【这个具体先不深入,我们只要知道loop()的主要工作就行】,对比一下我们在主线程中使用Handler的情况,在子线程中使用Handler很像是条件不好人要自立更生艰苦奋斗,没有条件就自己创造条件。

主线程的Handler

我们看了子线程中如何使用Handle和相关源码分析,接下来再看看主线程中我们是怎么使用handler的?根据以前的经验,主线程创建使用Handler就是直接创建的,并没有其他的操作:

public Handler mHandler;
mHandler = new Handler() {
    public void handleMessage(Message msg) {
       // process incoming messages here
    }
};

相比子线程,使用时少了prepare()和loop();但是真的是主线程不需要调用这些方法吗?显然不是的,子线程有的主线程也不能少,那接下来我们看看是谁帮了我们的忙?

还记得之前在Android_Application启动梳理时,就发现了在ActivityThread的面main函数就有这么两行行代码:

public static void main(String[] args) {
    ...
    Looper.prepareMainLooper();
    ...
    Looper.loop();
}

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

这个prepareMainLooper()里面就是调用了prepare()方法,但是传入的参数和在子线程中不同,这里这传入的是false,也就是说主线程的looper是不允许退出的;到这里,我们知道prepareMainLooper将当前线程初始化为循环程序,将其标记为应用程序的主循环程序应用程序的主循环是由android环境创建的,因此用户不必自己调用此函数

2.2 loop

在prepareMainLooper()方法后也调用了loop()方法,看到这里,我们就明白了主线程在使用handler的条件在创建程序之初就已经具备,所以让用户在主线程中使用handler也方便很多。

 

总结

1.也可以在子线程创建handler,需要提前prepare looper和自己调用loop。

2.主线程和子线程的区别:主线程的looper创建完后不可以退出,子线程创建的looper是可以退出的,需要自己去prepare()和loop(),主线程的handler环境在进程启动的时候就创建好了。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值