Android Handler之Looper有几个(四)

续上篇
有关Handler你想要的都在这里了(一)
有关Handler你想要的都在这里了(二)
有关Handler你想要的都在这里了(三)
Handler、Looper、MessageQueue协同工作的示意图
在这里插入图片描述
读者应该对着流程图,看着我的帖子,跟着我的思路,翻着源码,去一步一步理解这个Handler机制的工作流程,不用妄想看一眼就懂,除非你原来就懂。
请带着脑子看帖子
下面我将尝试使用文字来描述这个工作的过程
一、我们使用Handler发送一个消息的时候,这个流程最终调用了MessageQueue的enqueueMessage()方法,这个方法的作用是将一个消息插入到消息队列中
那么我们不禁要问,MessageQueue是什么时候初始化的?
仔细看流程图中的sendMessageAtTime()方法

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

仔细看这个方法中的第一行,就是将一个全局变量mQueue赋值给一个局部变量,然后再调用了enqueueMessage()方法,那么mQueue是什么时候赋值的呢?
聪明的人应该已经猜到了,就是构造方法中

  public Handler(Callback callback, boolean async) {
 
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
*/
    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

上面是Handler的两大类构造方法,源码我已经贴出来了,mQueue对象的初始化都是在构造方法中,具体来讲是在构造方法中从Looper中取的值,Looper的初始化我们先放下。
到这里我们再来回顾一下:

Handler中有一个成员变量mQueue,这个成员变量在Handler的构造方法中会初始化。
当我们发送一个消息的时候,这个消息最终通过调用了mQueue的enQueueMessage()方法,通过这个方法将一个消息存放到了消息队列中
Looper会通过loop()方法从消息队列中一条一条的取出消息,并且调用发送该消息的Handler的dispatchMessage()方法,从而这个消息就回到了发送该Message的Handler中
Handler的dispatchMessage()方法会调用自身的handleMessage()方法,handleMessage()方法就是我们处理消息的方法

到这里后,一条消息的发送—>处理流程就完成了。
我们再仔细看看Handler的空参的构造方法,这也是我们经常使用的方法。你也不要太懒,自己往下点着看看。

//空参的构造方法会调用这个构造方法
   public Handler(Callback callback, boolean async) {
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

上面的构造方法第二行代码就是验证Looper是否为空,这就解释了我们在有关Handler你想要的都在这里了(一)第四部分怎么从主线程发送消息到子线程?(虽然这种应用场景很少)中的示例代码为什么要手动初始化一个Looper了,而且是要在Handler初始化之前初始化Looper

现在我们来看Looper的初始化

//Looper暴露出的静态初始化方法
//这个方法会调用下面的私有静态方法
  public static void prepare() {
        prepare(true);
    }
//Looper私有的静态方法
   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));
    }
//私有的构造方法,禁止外界调用
  private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

解释一下上面三个方法

我们只能通过Looper.prepare()方法去初始化一个Looper
Looper.prepare(boolean)方法的逻辑是一个线程中只能有一个Looper对象,否则在第二次尝试初始化Looper的时候,就会抛出异常。
以线程为单位存储Looper的主要逻辑是通过ThreadLocal实现的
私有的构造方法,进制外界任意new出一个Looper

通过这段逻辑我们可以看出,一个线程中最多有一个Looper。
接着看Looper的构造方法,里面有一行代码

mQueue = new MessageQueue(quitAllowed);

是的,我们的MessageQueue是随着Looper的初始化而初始化的。那么,MessageQueue能不能随意的被new出来呢?

//MessageQueue的构造方法
 MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();
    }

可以看到,MessageQuede的构造方法是default的,也就是说,只有跟MessageQueue同一个包下才可以实例化MessageQueue,换句话说,我们用户是无法直接new一个MessageQueue对象出来的。而因为Looper在一个线程中只能有一个,从而导致MessageQueue也只能有一个。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值