Handler源码分析

0、目录

一、说明

二、源码分析

       2.1、使用Handler.sendMessage()方式发送消息

       2.2、使用Handler.post()方式发送消息

三、总结

四、感谢

一、说明

本人也是菜鸟,跟着大神的脚步,第一次尝试分析源码,希望自己终有一天也能成为大神。

本文直接进行源码相关的介绍,如果您对Handler相关的使用和工作原理还不是太熟悉,建议您先阅读《Handler使用方法详解(含实例)》和《Handler原理解析》,熟悉相关使用和工作原理后再看相关源码。

二、源码分析

Handler的使用方式因为发送消息的方式不同而不同,总共可以分为两种,Handler.sendMessage()和Handler.post(Runnable r)。

下面的源码分析将根据Handler的这两种使用方式,以及Hander的具体使用步骤进行解析。

2.1、使用Handler.sendMessage()方式发送消息

使用步骤:

使用匿名Handler子类
步骤1、在主线程中通过匿名内部类创建Handler类对象
    Handler mhandler =  new Handler(){
        //重写handleMessage()方法,执行相关的UI操作
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //执行的UI操作 
        }
    };
步骤2、在子线程中创建需要发送的消息对象
    Message msg = Message.obtain();
    msg.what = 1;
步骤3、在子线程中通过Hander发送消息到消息队列
    mhandler .sendMessage(msg);
步骤4、启动子线程

下面将根据每一步进行分析

步骤1、在主线程中通过匿名内部类创建Handler类对象

//使用方法
Handler mhandler =  new Handler(){
        //重写handleMessage()方法,执行相关的UI操作
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //执行的UI操作 
        }
    };

  //源码分析:
  public Handler() {
        this(null, false);
        //this(null, false) = Handler(null, false)
    }

    public Handler(Callback callback, boolean async){
        //仅贴出关键代码

        //1、获取当前线程的Looper对象,也就是把Hander与该Looper对象绑定
         mLooper = Looper.myLooper();
        //public static Looper myLooper() {
        //        return sThreadLocal.get();//即返回sThreadLocal中存储的Looper对象
        //    }
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        //如果Looper对象为空,则抛出异常
        //也就是说当前线程中没有创建Looper对象,则不能创建Handler对象,
        //即要想创建Handler对象必须先创建Looper对象
        //创建Looper对象方法,主线程中开启应用自动创建,子线程中需要手动调用Looper.prepare()方法

        //2、获取Looper对象的消息队列,也就把Handler对象与该消息队列绑定
        mQueue = mLooper.mQueue;
}

通过上面的源码我们可以看到,创建Handler对象的时候,会自动关联到当前线程的Looper对象和对应的消息队列上,从而绑定到了实现创建Handler对象操作的这个线程上。

在上面源码中我们直接使用了Looper对象和消息队列,我们并没有创建他们,那么他们是在什么地方创建的,又是如何创建的呢?

步骤1前的隐式操作1、创建Looper对象和MessageQueue对象

创建Looper对象的方法主要分是在主线程还是在子线程中,分别调用Looper.prepareMainLooper()和Looper.prepare(),创建一个Looper对象的同时也会自动创建 一个对应的消息队列对象。两者的区别是,主线程中创建Looper对象在打开应用时自动调用,而在子线程中必须手动调用Looper.prepare()方法来创建Looper对象。

源码分析 Looper.prepareMainLooper()
//作用:为主线程创建一个Looper对象,同时也创建一个MessageQueue对象
//注:该方法在主线程中自动调用,不需要手动调用
//在Android应用进程启动时,会默认创建一个主线程(ActivityThread),
//创建时,会自动调用主线程的main()方法(该方法就是应用程序的入口)
public static void main(String[] args) {
    //仅贴出关键代码

    //1、为主线程创建一个Looper对象,同时生成一个MessageQueue对象
    Looper.prepareMainLooper();-->>分析1 
    //2、创建主线程
    ActivityThread thread = new ActivityThread(); 
    //3、开启消息循环。后面详细介绍
    Looper.loop();  
    //4、消息循环是无限循环,如果退出了该循环,则抛出异常
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

//分析1:Looper.prepareMainLooper()分析:
    public static void prepareMainLooper() {
        //1、也就是调用Looper.prepare()方法,-->>分析2
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                //2、sMainLooper 是一个Looper类型的变量,存放当前Looper对象
                //如果其不为空,表示重复创建Looper对象,则抛出异常
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            //3、获取主线程的Looper对象赋值给sMainLooper 
            sMainLooper = myLooper();
        }
    }

分析2 源码分析:Looper.prepare()
    //作用:在子线程中创建一个Looper对象,同时生成一个消息对象
    //必须在子线程中手动调用Looper.prepare()去创建Looper对象
    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        //1、static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
        //通过定义可以看到sThreadLocal 是一个存放Looper对象的ThreadLocal 
        //即判断sThreadLocal是否为空,是否存在Looper对象,不为空抛出异常
        //也就是说一个线程中只能有一个Looper对象,即Looper.prepare()不能被调用两次。
        //扩展:ThreadLocal是线程局部变量,当前线程所独有。

       sThreadLocal.set(new Looper(quitAllowed));-->>分析3
       //2、运行到这,说明是首次创建Looper对象
       //新建Looper对象,并存入sThreadLocal中
    }

//分析3 Looper构造方法
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        //1、创建消息队列对象
        //从这里就能看出来,当创建Looper对象时,同时创建了一个对应的消息队列
       
        mThread = Thread.currentThread();
    }

总结:

1、创建主线程时,会自动调用主线程的main()方法,在main()方法内会调用Looper.prepareMainLooper()方法创建Looper对象,同时创建一个消息队列对象。

即在创建Looper对象时,在主线程中是自动创建的,而在子线程中,必须手动调用Looper.prepare()方法调用,若在子线程中没有Looper对象则不能创建Handler对象,也就是说在创建Handler对象前,必须先创建Looper对象。

2、Looper.prepareMainLooper()方法最终依然调用了Looper.prepare()方法。

3、创建完Looper和消息队列后,会自动进入消息循环Looper.loop(),这又是一个隐式操作。

步骤1前的隐式操作2:Looper.loop(),消息循环

源码分析:Looper.loop()
作用:消息循环,主要作用就是从消息队列中获取消息并分发消息到对应的Handler进行处理
public static void loop() {
    //仅贴出关键代码

    //1、获取当前线程的Looper对象
    final Looper me = myLooper(); 
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
    //如果Looper对象为空,则抛出异常。也就是说,在调用Looper.loop()前必须创建了Looper对象

    //2、获取Looper对象中的消息队列        
    final MessageQueue queue = me.mQueue;

     //3、消息循环
    for (;;) {
       //3.1从消息队列中取出消息对象,如果消息队列为空,则会阻塞.
            Message msg = queue.next(); // -->>分析1
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
             }
        //3.2 消息分发
        msg.target.dispatchMessage(msg);// -->>分析2
       //msg的target属性的值,就是发送该msg的Handler对象,
       //msg.target.dispatchMessage(msg); = Handler.dispatchMessage(msg);
 
        msg.recycle();//释放资源
             
    }
}

分析1:Message msg = queue.next();
    作用:从消息队列中取出消息
    Message next() {
        //仅贴出关键代码

        int nextPollTimeoutMillis = 0;
        //nextPollTimeoutMillis 用来判断消息队列中是否还有消息
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                 Binder.flushPendingCommands();
            }
             nativePollOnce(ptr, nextPollTimeoutMillis);
            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                //uptimeMillis() Returns milliseconds since boot, not counting time spent in deep sleep.也就是手机启动以来的时间
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
               	 if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (false) Log.v("MessageQueue", "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                 nextPollTimeoutMillis = 0;
            }
            ...
        }
        ...
    }

分析2:msg.target.dispatchMessage(msg);
    作用:消息分发,分发给发送该消息的Handler去处理
    public void dispatchMessage(Message msg) {
       //1、若msg.callback != null成立,则表示该消息的发送方式是Handler.post(Runnable r)
      //则执行 handleCallback(msg)方法,在后面分析Handler.post(Runnable r)方式时详细分析.
         if (msg.callback != null) {
            handleCallback(msg);
        } else {
            //2、当使用Handler(Callback callback, boolean async)或Handler(Looper looper, Callback callback, boolean async)构造函数
            //创建Handler对象时会传入callback对象,并会重写public boolean handleMessage(Message msg)方法,mCallback = callback;
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            //3、如果不是以上两种情况,就会运行这里,通常我们写的程序都是执行这里的
            handleMessage(msg);//-->>分析3
        }
    }


分析3: handleMessage(msg)源码分析
    /**
     * Subclasses must implement this to receive messages.
     */
    //可见该方法是一个空方法,创建Handler子类时要重写了该方法(用Handler.post()方法发送消息时则不需要)
    public void handleMessage(Message msg) {
    }

总结:

消息循环操作主要负责消息出队列和消息的分发

消息分发时,调用msg.target.dispatchMessage(msg)方法进行分发,最终回调重写的handleMessage()方法进行消息的处理。不过在消息分发的时,要进行相关的判断,进而做相应的处理。

步骤2、在子线程中创建需要发送的消息对象

源码分析:Message msg = Message.obtain();

//作用:创建消息对象
//创建消息对象有两种方法,直接new Message()或Message.obtain(),推荐使用第二种方法。
 public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            } 
            //sPool的声明为private static Message sPool,由此可知sPool是一个Message类型的变量
            //sPool就是Message内部维持的一个Message池,目的是为了Message的复用。
        }
        //如果Message池为空,则创建新的Message对象
        //从这里就能看出来,获取Message对象时最好使用Message.obtain(),如果Message池为空,依然会    new Message()。
        return new Message();
    }

总结:

创建消息对象的方法有两个,直接new Message()或Message.obtain(),而者使用了Message池,以便Message的复用,如果Message池,则依然会new Message(),所以创建消息对象时直接使用Message.obtain()即可。

步骤3、在子线程中通过Hander发送消息到消息队列

 

源码分析: mhandler .sendMessage(msg); 
    作用:将消息发送到消息队列中
    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);//-->>分析1
    }

//分析1
  public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);//-->>分析2
        //SystemClock.uptimeMillis()  Returns milliseconds since boot, not counting time spent in deep sleep.
        //也就是这个时间是手机从启动到现在的时间,而不是系统时间,需要注意。
    }

//分析2
     public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        //1、获取对应的消息队列
        MessageQueue queue = mQueue;
        //2、如果消息队列为空,则抛出异常
        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);//-->>分析3
    }

//分析3
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        //1、这里就是把当前的Handler对象赋值给Message的target属性。
        //msg.target在这里赋值,以便在Looper.loop()方法中,
        //分发消息时使用:msg.target.dispatchMessage(msg);
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);//-->>分析4
    }

分析4、MessageQueue下的enqueueMessage()方法
    boolean enqueueMessage(Message msg, long when) {
        //仅贴出关键代码
        ...
        synchronized (this) {
            ...
            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            //判断消息队列有无信息,若无,则当前插入的信息作为队头
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else { 
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                //队列有信息
                for (;;) {
                    prev = p;
                    p = p.next;//链表向后移动,直到最后一个
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
                //消息msg插入
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
    }
    return true;
}

总结:

到此,消息入队列完成,之后Looper对象就会不断从消息队列中读取消息并分发给相应的Handler去处理。

Handler发送消息的关键,Message的target对象绑定到当前发送该消息的Handler,只有这样才能够在分发的时候直到应用分发给哪个Handler处理。

到这里,使用Hander.sendMessage()方法发送消息的源码就分析完成了。

一些总结如下:

2.2、使用Handler.post()方式发送消息

使用步骤:

步骤1、在主线程中创建Handler实例
    private Handler mhandler = new Handler();
步骤2、在子线程中使用Handler.post()
     mhandler.post(new Runnable() {
                                @Override
                            public void run() {
                                 //执行的UI操作 
                            }
                        });

步骤3、启动子线程

实际Handler.post()方法和Handler.sendMessage()方法大体是一样的,我们仅介绍不同的地方。

下面根据步骤详细分析:

步骤1、在主线程中创建Handler实例

private Handler mhandler = new Handler();

该方式和Handler.sendMessage()方式相同,不同的是这里直接new Handler(),并没有复写handlerMessage().

步骤2、在子线程中使用Handler.post()

//使用方法 
mhandler.post(new Runnable() {
                                @Override
                            public void run() {
                                 //执行的UI操作 
                            }
                        });
源码分析
  public final boolean post(Runnable r)
    {
        return  sendMessageDelayed(getPostMessage(r), 0);
        //sendMessageDelayed()方法和方式Handler.sendMessage()中的相同
        //下面详细分析getPostMessage(r)
    }
  private static Message getPostMessage(Runnable r) {
        //1、创建一个消息对象 
        Message m = Message.obtain();
        //2、把Runnable 直接赋值给了Message的callback属性
        m.callback = r;
        return m;
    }

总结:

通过这里,我们可以看到,Handler.post(Runnable r)方式中,仅仅是把Runnable对象封装到Message对象中去了,而消息的发送,和Handler.sendMessage()方式相同

另外一个重要的区别的地方,就是在分发的时候。

public void dispatchMessage(Message msg) {
        //有前面分析我们直到,msg.callback就是Handler.post(Runnable r)中的Runnable对象,
        //所以这里不为空,msg.callback != null条件满足,后面执行 handleCallback(msg);
        if (msg.callback != null) {
            handleCallback(msg); //-->>分析1
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

//分析1:
     private static void handleCallback(Message message) {
        message.callback.run();
        //msg.callback就是Handler.post(Runnable r)中的Runnable对象
        //message.callback.run() = r.run()
        //即回调Handler.post(Runnable r)中Runnable 对象复写的run()方法。
    }

总结:

Handler.post(Runnable r)的分析也完成了,通过分析我们可以看到,和Handler.sendMessage()方法主要有两个方面的不同

1、不需要创建任何消息对象,而是直接传入Runnable对象,并把该Runnable对象封装到消息对象中

2、消息的处理方式不同,没有复写handlMessage()方法,而是执行的Runnable对象中的run()方法。

三、总结

以上就是本人对Handler源码相关的分析,对消息发送的两种方式,Handler.sendMessage()和Handler.post(Runnable r),根据每种方式使用步骤进行了详细分析。

四、感谢

第一次尝试分析源码,虽然之前看过很多遍,但真正让自己写出来的时候,特别难,在这里要特别感谢Carson_Ho,读他的文章受益匪浅。

本文参考了https://www.jianshu.com/p/b4d745c7ff7a

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值