Handler源码分析(超详细的)

这篇博客是一种入门级的但讲的很细,本人能力有限,希望看到大神,发现有不对的地方请联系我,也希望可以和大家在讨论区互动。

本文不管是从哪得到得信息,本人都认真的研究过和测试。包括代码所以说本人技术可能一般,但是都是总结别人和自己用心研究的成果。不喜勿喷..本文纯属抛砖引玉,先。谢谢大家的观看!不说废话了进入正题 


为什么使用Handler?

Android的UI要求更新只能在UI线程,因为安卓是单线程模型。如果任意线程都可以更新UI的话,线程安全问题处理起来会相当麻烦复杂,就会出现页面错乱。所以就规定了Android的是单线程模型,只允许在UI线程更新UI操作。

也就是在Android中更新Ui必须在主线程,在子线程更新Ui会报子线程不能修改UI异常。

你想想安卓的页面一会被这个线程修改,一会被别的线程更改。用户体验就会很差,给别人一种不可控制的感觉。

Handler是什么?

来自百度百科-----

主要用于异步消息的处理:当发出一个消息之后,首先进入一个消息队列,发送消息的函数即刻返回,而另外一个部分在消息队列中逐一将消息取出,然后对消息进行处理,也就是发送消息和接收消息不是同步的处理。 这种机制通常用来处理相对耗时比较长的操作。

简单说Handler就是谷歌的Android的为了开发人员封装的一套更新UI的机制,消息处理机制。就是为了方便开发者人员的。

Handler怎么使用?

1.创建Handler实例。

2.创建Message对象建议使用Message的静态方法obtain()构建。

3.给Message对象赋值。

4.Handler.sendMessage()方法把Message发送出去。

5.在Handler里重写它的handlerMessage方法,用来处理接收到的Message。

Handler机制:

Handler,looper,Message,MessageQueue。

Mssage:储存信息。

Handler:把Message添加到MssageQueue里,处理Looper发送过来的Message。

Looper:取出MessageQueue的Message,将Message发送到Handler。

MessageQueue:储存Handler发送过来的Message

简单说:

当一个应用启动时,会初始化一个UI线程,UI线程中又初始化了Looper,创建Looper的时候又创建了MessageQueue。当Handler把 Messgae发送到MessageQueue里,然后Looper循环的取出发给Handler,由Handler处理这个信息。

 

Handler源码分析:

这篇文章是先贴代码再说意思,害怕你不看源码,源码很重要,源码很重要,源码很重要!!!

一.首先从new  Handler开始

  private Handler handler=new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    };

这样new会报警告的,查看警告是:

This Handler class should be static or leaks might occur (anonymous android.os.Handler) less... Since this Handler is declared as an inner class, it may prevent the outer class from being garbage collected. If the Handler is using a Looper or MessageQueue for a thread other than the main thread, then there is no issue. If the Handler is using the Looper or MessageQueue of the main thread, you need to fix your Handler declaration, as follows: Declare the Handler as a static class; In the outer class, instantiate a WeakReference to the outer class and pass this object to your Handler when you instantiate the Handler; Make all references to members of the outer class using the WeakReference object.

翻译成中文是:

这个处理程序类应该是静态的,否则可能会发生泄漏(匿名的android.os.Handler)。

由于这个处理程序被声明为一个内部类,它可以防止外部类被垃圾收集。如果处理程序使用Looper或MessageQueue来处理主线程以外的线程,那么就没有问题了。如果处理程序使用主线程的Looper或MessageQueue,则需要修复处理程序声明,如下所示:将处理程序声明为静态类;在外部类中,实例化对外部类的WeakReference,并在实例化处理程序时将该对象传递给处理程序;使用WeakReference对象对外部类的所有成员进行引用。

说的很明显了,使用静态内部类来解决。   ---------------------------点击查看解决方案

我们接着第一步看继续看,怎么警告怎么来的。 new Handler直接调用的构造方法

  public Handler() {
        this(null, false);
    }

而这个构造又直接调用了(点击this查看),这里先仔细看看。

     /**
     * @hide
     */
    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

又调用了标有@hide的构造方法,为了讲的清楚,我附一个讲@hide的链接,不懂的可以看看。


    private static final boolean FIND_POTENTIAL_LEAKS = false;
    private static final String TAG = "Handler";
    private static Handler MAIN_THREAD_HANDLER = null;

先说Handler类上的参数

 if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

第一行的if判断了是有没有泄露(FIND_POTENTIAL_LEAKS=找到潜在的泄漏)默认是false的所以if里面不用看。接下

 mLooper = Looper.myLooper();

Looper调用了自己的静态方法,看myLooper方法是干嘛的

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

myLooper它返回与当前线程关联的Looper对象。如果调用线程与一个循环程序没有关联就会返回为null。

怎么返回呢,点get()进去看看。

 public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

这个方法是,返回当前线程的此线程局部变量副本中的值。如果变量没有当前线程的值,则首先将其初始化为调用initialValue()方法返回的值。

第一行的  Thread t = Thread.currentThread();会调用c++的方法,如果你想简单了解一下。(在往下看就到ThreadLocal类了,我本来打算继续讲的,但是初心是为了大家都能看懂,就删了)

@FastNative
public static native Thread currentThread();

返回到Handler的构造方法

 if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }

这个简单如果Looper不存在的话抛异常。继续

  mQueue = mLooper.mQueue;
  mCallback = callback;
  mAsynchronous = async;

获取一些值,比如 mLooper.mQueue就是关联MessageQueue,实现了MessageQueue自动绑定。到此Handler的构造方法就结束。

自己总结一下Handler的构造干了什么。

  1. new Handler的时候判断了被new的时候有没有泄漏。
  2. myLooper它返回与当前线程关联的Looper对象接着判断looper是否为null。

休息一下吧!

 @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }

看完构造我们看看handleMessage方法。这个方法在Handler里,你只要实现它就可以拿到Message了。这个你先知道这些就好,下面会讲的。

二、获取Message

接下发送消息开始,发信息就需要Message,怎么获得Message呢,那先看看之前我是怎么写的

      Message message = new Message();
      message.arg1=1;
      Handler handler = new Handler();
      handler.sendMessage(message);

再看现在怎么写的代码

 Message message = Message.obtain();
 message.arg1=1;
 Handler handler = new Handler();
 handler.sendMessage(message);

为什么这样写,看源码。

  /**
     * Return a new Message instance from the global pool. Allows us to
     * avoid allocating new objects in many cases.
     */
    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;
            }
        }
        return new Message();
    }

判断sPoolSync有没有被创建,如果被创建了证明Message已经被实例过了,没有的话就new 一个Message。

就是从全局池返回一个新的Message实例,节约内存。

三、Handler发送Message

handler.sendMessage(message);

从Handler发送信息开始:

   public final boolean sendMessage(Message msg){
        return sendMessageDelayed(msg, 0);
    }

我们继续分析的sendMessage这个方法,点进去你会看到调用了sendMessageDelayed()方法

 public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

sendMessageDelayed判断了设置的时间是不是为小于0,小于0就有问题了,所以小于0就直接赋值为0.

然后一点注意,它调用sendMessageAtTime的时候,传入的值!!!

msg=看上面可以知道是Message对象

SystemClock.uptimeMillis+delayMillis是干嘛的呢?

 SystemClock.uptimeMillis是获取从开机到现在的毫秒数+延迟的时间,也就是说这个方法发送出去的参数。(重要)

有同学说了,我用的不是这个方法,慢慢看,别急.sendMessageDelayed也只是调用了方法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);
    }

sendMessageAtTime把的MessageQueue对象判断一下为不为空,为空就是一个异常。那么MessageQueue在哪来的呢。我们找找它在哪?

把mQueue赋值队列,那么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;
    }

看到这个方法了吗mQueue = mLooper.mQueue;也就是说MessageQueue是在Looper类里拿的。这里就不说了,我们返回来看。

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

又回到了sendMssagerAtTime方法,讲过的就不说了。它调用了enqueueMessage方法

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {          
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

enqueueMessage这方法中msg.target = this;this就是Handler啦.target是标记的意思吧。翻译目标(目标),也就是说它把Handler关联起来了。

四、QueueMessage储存Message

接着就要调用这个enqueueMessage方法啦。而这个方法是queue调的,queue是参数传过来的就是说是的MessageQueue类的方法。我,们继续看啊。接下来代码多,但是一定要看一下,不用记住就好。

 boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

            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 {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                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;
            }

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

分开讲

 if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

首先判断了这个handler存在不,在继续,不在抛异常,判断消息有没有在使用在使用抛异常,没有继续。

 synchronized (this) {
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

这个方法上锁了,判断这个有没有向死线程上的处理程序发送消息,有抛异常,没有继续。

 public void recycle() {
        if (isInUse()) {
                if (gCheckRecycle) {
                    throw new IllegalStateException("This message cannot be recycled because it "
                            + "is still in use.");
                }
                return;
        }
        recycleUnchecked();
    }

就是说先检查在不在使用,在判断有没有回收,然后调用recycleUnchecked()方法

 void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = -1;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }

注释看到了吗?翻译一下

当消息保留在回收对象池中时,将其标记为正在使用。清除所有其他细节。懂了吧,我们返回继续看。

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 {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                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;
            }

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

这个方法很多内容吧,分开讲,建议你搞清楚。


              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 {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                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;

这个死循环就是根据 消息(Message)创建的时间 插入到队列中放到的MessageQueue里。

MessageQueue也就先到这了。

填坑

之前有同学说他一直用的是下面的方法

  handler.post(new Runnable() {
                    @Override
                    public void run() {
                        
                    }
                });

这个方法是吧,我这个小白要放大招了

                Message message = Message.obtain();
                message.arg1 = 1;
                Handler handler = new Handler();
                handler.sendMessage(message);
                handler.sendEmptyMessage(0);
                handler.sendEmptyMessageDelayed(1, 1000);
                handler.sendMessageAtTime(message, 1000);
                handler.sendMessageAtFrontOfQueue(message);
                handler.sendMessageDelayed(message, 1000);
                handler.post(new Runnable() {
                    @Override
                    public void run() {

                    }
                });
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {

                    }
                }, 1000);
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {

                    }
                },1000);
                handler.postAtTime(new Runnable() {
                    @Override
                    public void run() {

                    }
                },1000);

哈哈,是不是很简单了。不管怎么调它都会走到下面这个方法。

   private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

不相信你试试。我承认简单。别笑我这小白。

休息一下,我们要继续啦。我们回顾一下,从Handler发到MessageQueue里。

Handler调用sendMessage或者Post等以上发送Message的方法,都会发送到MessageQueue的enqueueMessage里。

四、Looper类

Looper类怎么来的呢?

看一下ActivityThread类

public static void main(String[] args) {
     

        //省略代码1
        Looper.prepareMainLooper();

        //省略代码2
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

        //省略代码3
        Looper.loop();

       
    }

继续看Looper.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();
        }
    }

里面有个 prepare(false);看这个:

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

它new Looper跟进去

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

创建主线程时,会自动调用ActivityThread的1个静态的main();而main()内则会调用Looper.prepareMainLooper()为主线程生成1个Looper对象,同时也会生成其对应的MessageQueue对象。

看ActivityThread的main方法中省略代码3下面:

 Looper.loop();

Looper调用了静态loop方法

  final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }

首先判断了looper是否存在,不存在就会抛异常说没有looper,让你调用prepare方法创建Looper

 public static void loop() {
         //省略

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

这个死循环会取出Message有就取。没有就结束

   msg.target.dispatchMessage(msg);

然后会调用这个方法,这个方法是Handler的,去Handler里看。msg.target证明了是那个Handler,证明了是那个Handler方法Message就是那个Handler处理Message。

 /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

这个方法,把Message发个Handler了。

handler.Callback的消息处理可以“覆盖”处理器自己的消息处理所以可以设置一个默认的消息处理注意:。返回值为true才“覆盖”默认的消息处理,如果都没有覆盖就是调用的handleMessage(MSG) ;方法啦这个方法就是你在处理程序重写的方法,消息方法一样。

    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            Toast.makeText(HomeActivity.this, "msg", Toast.LENGTH_SHORT).show();
        }
    };

这里的Message 就是你拿出来的,记住处理器只有一个。并且Handler在那个线程新就在那个线程

到此Handler的简单分析结束了。本来想写一篇详细的源码分析,由于能力和时间不够各位我尽力了。

谢了各位。如果喜欢请点个赞就好。如果看不懂,多看两遍,肯定没有问题。

大神有问题联系QQ在这:1441289824

参考文档:

http://www.cnblogs.com/dolphin0520/p/3920407.html

https://www.jianshu.com/p/b4d745c7ff7a

附一张我以前喜欢的三叶。。。

猜你喜欢

转载自blog.csdn.net/qq_41346910/article/details/82841518