Handler详解(中)

Handler详解(上)

https://blog.csdn.net/weixin_37730482/article/details/72864047

 

本章节讲解Handler的源码分析。

 

一.发送消息 源码分析

上节讲到,Handler的几个常用的发送消息的方法最后都会不约而同的走到sendMessageAtTime(Message msg, long uptimeMillis)方法。那么我们的消息发送源码之旅就在这个方法开始吧。

 

常用方法调用关系流程图

 

 

源码之Handler类

 

sendMessageAtTime()方法源码

 /**
 * Enqueue a message into the message queue after all pending messages
 * before the absolute time (in milliseconds) <var>uptimeMillis</var>.
 * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
 * Time spent in deep sleep will add an additional delay to execution.
 * You will receive it in {@link #handleMessage}, in the thread attached
 * to this handler.
 * 
 * @param uptimeMillis The absolute time at which the message should be
 *         delivered, using the
 *         {@link android.os.SystemClock#uptimeMillis} time-base.
 *         
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.  Note that a
 *         result of true does not mean the message will be processed -- if
 *         the looper is quit before the delivery time of the message
 *         occurs then the message will be dropped.
 */
public boolean sendMessageAtTime(@NonNull 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);
}

 

该方法主要有两个工作

(1) 赋值MessageQueue对象

(2) 调用本类enqueueMessage()方法。enqueueMessage()方法稍后再看。

 

先看一下MessageQueue的赋值。

MessageQueue queue = mQueue;

那么这个mQueue对象是哪里来的呢?他又是在哪里赋值的呢?

final MessageQueue mQueue;

可见mQueue对象是Handler类的全局变量。哪里赋值的?源码发现Handler类里有两个地方赋值这个变量。

赋值处1

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


    
    //获取Looper对象
    mLooper = Looper.myLooper();



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


    //赋值MessageQueue对象   
    mQueue = mLooper.mQueue;
    

    mCallback = callback;
    mAsynchronous = async;
}

 

赋值处2

public Handler(Looper looper, Callback callback, boolean async) {
    
    //赋值Looper对象
    mLooper = looper;
    

    //赋值MessageQueue对象
    mQueue = looper.mQueue;
    

    mCallback = callback;
    mAsynchronous = async;
}

 

也就是说上述sendMessageAtTime()方法中的MessageQueue对象的赋值变量mQueue。是在Handler的构造方法里赋值的。Handler的构造方法了除了赋值MessageQueue对象还赋值了Looper对象。可是明明刚刚简单使用时创建Handler的时候,我用的是一个参数的构造方法。没有使用源码中两个参数和三个参数的构造方法呀。其实Handler的构造方法在Handler内部是互相调用的。如下。因为构造方法比较多。这里我们就列举两个和MessageQueue+Looper有关的构造方法。

 

无参构造方法 也就是上述 简单使用中的举例

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

内部调用 本类的两个参数构造方法。也就是 赋值处1 。不过要注意的是使用无参构造方法时。Looper对象因为没有传参,所以需要获取。

mLooper = Looper.myLooper();

如何获取,下面讲解。

接着看一个参数的构造方法。也就是上述 使用postDelayed方法在子线程延时更新UI的举例

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

内部调用 本类的三个参数的构造方法。也就是赋值处2 。因为Looper对象已通过参数传参,左移这里无需获取,直接使用传入的参数即可。

到这里,通过Handler的构造方法也可以看出。Handler是离不开MessageQueue和Looper的。

 

 

小结1

<1> sendMessageAtTime()方法中核心代码就两行。首先会赋值MessageQueue对象。

<2> 创建Handler时,可以使用的构造方法很多,如果没有传参Looper对象。则构造方法里默认获取(怎么获取下面讲)。如果传参Looper对象。则使用传参的Looper对象

<3> 创建Handler时,使用Looper对象获取MessageQueue对象

 

 

 

源码之Looper类

上面说到,在创建Handler对象时,如果没有传入Looper对象,系统会自己取Looper对象。那么Looper是怎么获取的呢?

mLooper = Looper.myLooper();

也就是,通过Looper的myLooper()方法。

myLooper()方法源码

/**
 * Return the Looper object associated with the current thread.  Returns
 * null if the calling thread is not associated with a Looper.
 */
public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

很明显,myLooper()方法是通过ThreadLocalget方法获取的Looper对象。sThreadLocal变量是Looper类的全局变量。因为既然可以使用sThreadLocal.get()方法获取Looper对象。那么什么时候set的呢?因为只有set了值,才可以get到值。

sThreadLocal变量set值是在prepare()方法中。

 

prepare()方法源码

private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
     
    
    //sThreadLocal变量set值
    sTreadLocal.set(new Looper(quitAllowed));
}

注意:prepare()方法中 sThreadLocal变量set值时 首先会先get值,如果get值不为空,也就是说已经创建过Looper。会抛出异常。Only one Looper may be created per thread。也就是说一个线程只能有一个Looper对象。这也是面试的重点

prepare()方法是在哪里调用的呢?

 

调用处1

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

这个prepare()方法就是通过代码手动调用Looper.prepare()时。比如 子线程创建Handler对象

//来给线程创建一个消息循环
Looper.prepare();
                        
//来使消息循环起作用。
Looper.loop();

 

调用处2

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()方法是在哪里调用的呢?

public static void main(String[] args) {
        
        
    //调用prepareMainLooper()方法   
    Looper.prepareMainLooper();

       
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }


    if (false) {
        Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, "ActivityThread"));
    }

       
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

    Looper.loop();
}

也就是在ActivityThread类main方法中调用的。而ActivityThread类是APP运行时,默认为APP创建的主线程

 

注意刚刚 sThreadLocal变量set值时创建Looper对象

sThreadLocal.set(new Looper(quitAllowed));

也就是说,Looper的创建时机是在Looper类的prepare()方法中调用的。而上述也讲了。prepare()方法有两个地方调用。

1.主线程ActivityThread类中的main()方法系统默认调用。

2.子线程手动调用Looper.prepare();方法调用。

 

创建Looper时,做了两件事

1.创建MessageQueue对象。

2.将当前线程赋值给mThread对象。

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

 

注意,Looper的构造方法中创建MessageQueue时,传了一个布尔值。quitAllowed

而由上述源码可知。

ActivityThred类的main()方法调用Looper.prepareMainLooper();时传参是false

而手动调用Looper.prepare();时传参是true

那么这个参数有什么作用呢?

此参数当成参数传到MessageQueue的构造方法中

MessageQueue(boolean quitAllowed) {
    mQuitAllowed = quitAllowed;
    mPtr = nativeInit();
}

此变量什么时候使用

void quit(boolean safe) {
    if (!mQuitAllowed) {
        throw new IllegalStateException("Main thread not allowed to quit.");
    }


  ...

}

也就是,如果这个参数是false。则不让退出Looper循环。根据抛出的异常也可以看出Main thread not allowed to quit.。也就是说主线程默认开始的Looper是不允许退出的

 

 

 

小结2

<1> 发送消息,最后走到Handler类sendMessageAtTime方法。而该方法需要赋值一个MessageQueue对象。而MessageQueue对象是要Looper对象获取

<2> Looper对象获取两个途径

       (1) 使用Handler时,如果传Looper对象。则Looper对象就用传过来的参数即可。   

       (2) 使用Handler时,如果没有传Looper对象。则需要系统自己获取

<3> 系统获取Looper对象,最终通过ThreadLocal对象的get方法获取。ThreadLocal对象set的时机有两个。

        (1) ActivityThread类的main方法默认给APP创建主线程时调用Looper类的prepareMainLooper()方法。

        (2) 手动调用Looper类的Looper.prepare();方法 自己准备Looper对象。

<4> ThreadLocal对象set设置Looper对象时会创建Looper对象。创建Looper对象时会做两件事情。

        (1) 创建MessageQueue对象。

        (2) 获取当前线程给全局的Looper类的全局线程变量。

<5> 创建Looper时,有一个布尔类型的参数。此参数主线程默认创建调用时传的是false。而手动调用创建Looper时传的是true。这个参数又会当成参数在Looper构造方法中创建MessageQueue时,传给MessageQueue类。此布尔值在MessageQueue中的作用就是是否允许退出Looper循环。而上述也讲解过了。由于主线程传递的是false。所以主线程是不允许退出Looper循环的

<6> sThreadLocal.set(new Looper(quitAllowed));时,会先get值,如果get的值不为空,会抛出异常。也就是说一个线程只允许一个Looper存在。

 

 

源码之Handler类

下面接着sendMessageAtTime()方法 继续讲解

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
        
    return enqueueMessage(queue, msg, uptimeMillis);
}

MessageQueue的赋值已经讲解清楚了。下面看enqueueMessage()方法。

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

首先,将this对象赋值给Message的target。那么this代表什么呢?在Handler类里面this当然代表的Handler。也就是发送Message时使用的Handler对象

最后调用MessageQueue类的enqueueMessage()方法。显然,enqueueMessage()方法是MessageQueue对象调用的。也就是说走到这里已经脱离了Handler类。而到了MessageQueue类。

 

 

小结3

<1> 发送消息Handler类里的最后一个方法enqueueMessage方法

<2> Handler类的enqueueMessage方法中,赋值Message对象的target属性为this。也就是说到这里 每个发出去的Message都持有把它发出去的Handler的引用。而Message又存放到MessageQueue中,如果需要延时可能在MessageQueue中的位置还可能靠后。这就是使用Handler时如果使用不当可能造成内存泄漏的原因。

 

 

 

源码之MessageQueue

消息发送 Handler类enqueueMessage方法 最后走到 MessageQueue类enqueueMessage()方法 走到这里相当于 消息入消息队列(MessageQueue 看代码可知其实是个单链表)

 

enqueueMessage()方法源码

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

方法中,如果Message的target为空,或者正在被使用直接抛出异常。继续

同步代码块中 如果正在退出,将Message回收,然后return false。结束。否则 继续

mMessage是消息队列中的第一条消息。

//消息在使用状态
msg.markInUse();

//消息延时时间
msg.when = when;

//消息队列中的头部消息mMessages赋值给p
Message p = mMessages;

大致的意思就是:将传进来要发送的消息对象变成在使用状态+传进来的延时时间赋值给传进来的消息。然后将头部消息赋值给p

 

if (p == null || when == 0 || when < p.when) {
               
    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;
}

 

否则 For循环中就是当前消息队列不为空,或者 当前传参消息延时时间比头部消息延时时间大,将参数的Message对象插入消息队列中等待执行插入位置和延时时间相关

 

 

小结4

<1> 消息发送 走到MessageQueue类的enqueueMessage()方法。相当于入消息队列(MessageQueue其实是一个单链表)

<2> 传进来要发送的消息在MessageQueue中位置,与其延时时间以及队列中是否有其他消息有关。

 

 

源码之Message类

Message类部分源码

public final class Message implements Parcelable {


  ...


  Handler target;

  Runnable callback;

  Message next;


  ...

}

也就是说,Message类其实是一个实现了Parcelable接口的实体类。上述Handler类的enqueueMessage()方法发送消息时将Handler的对象赋值给Message的target对象,其实就是赋值给Message类中的Handler变量。通俗一点将就是 每个发出去的Message对象都会持有Handler对象的引用。这也就是使用Handler时容易造成内存泄漏的原因。具体原因下一章节讲解。

 

注意

创建Message的方式。在使用Handler进行线程通讯时,必不可少的要创建Message,而为了内存优化在创建Message时,最好不要new一个Message。

正确的写法

Message msg = Message.obtain();
msg.what = 2;
msg.arg1 = 33;
msg.arg2 = 44;
msg.obj = "Message发送的消息";

正确的写法

Message msg = handler.obtainMessage();
msg.what = 2;
msg.arg1 = 33;
msg.arg2 = 44;
msg.obj = "Message发送的消息";

备注

handler.obtainMessage();内部调用了Message.obtain();

如下

/**
 * Returns a new {@link android.os.Message Message} from the global message pool. More efficient than
 * creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this).
 *  If you don't want that facility, just call Message.obtain() instead.
 */
@NonNull
public final Message obtainMessage(){
    return Message.obtain(this);
}

 

错误的写法

Message msg = new Message();
msg.what = 2;
msg.arg1 = 33;
msg.arg2 = 44;
msg.obj = "Message发送的消息";

即,创建Message使用Message的缓存池。

 

Message的obtain()方法源码

/**
 * 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();
}
//全局静态消息对象,相当于消息池
private static Message sPool;


//消息池中的消息数量 Message.obtain()执行 此数-1 表示消息池中有一个消息被重复使用 Looper.loop取消息时,会清空使用过的消息 此数+1 表示消息池中又多了一个可以被重复使用的消息 具体+1操作 消息接收模块讲解
private static int sPoolSize = 0;


//消息池中的消息最大个数 具体使用 消息接收模块讲解
private static final int MAX_POOL_SIZE = 50;

 

大致可以这样理解。通过Message缓存池方式获取Message对象时,首先判断缓存池中有没有Message,如果有就直接取出使用,然后消息池中可被重复使用的消息个数-1。如果没有这时才new一个Message。默认消息池消息数量为50。

 

到这里消息发送就讲解完了。那么发送的消息是怎么到达消息接收的地方呢?下面继续讲解

 

 

 

 

 

 

二.消息接收 源码分析

上面讲到了消息发送最终会走到MessageQueue类的enqueueMessage(Message msg, long when)方法。按照消息队列中是否有消息当前消息延时时间,将传进来的消息对象插到消息队列的相应位置。那么 发送的消息 怎么到 消息接收 的方法呢?

比如 postDelayed方法 怎么到run()方法呢?

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

   }
},500);

比如 匿名内部类创建Handler 怎么到handleMessage()方法呢?

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

    }
};

答案就在Looper类的loop()方法。那我们的消息接收源码之旅就在这个方法开始吧。

 

源码之Looper类

loop()方法源码


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.");
    }
        
    if (me.mInLoop) {
        Slog.w(TAG, "Loop again would have the queued messages be executed"
                    + " before this one completed.");
    }

    me.mInLoop = true;

    //核心代码2处 使用Looper对象获取MessageQueue对象     
    final MessageQueue queue = me.mQueue;

      
    final long ident = Binder.clearCallingIdentity();

        
    boolean slowDeliveryDetected = false;

    for (;;) {

        //核心代码3处 使用MessageQueue的next()方法获取Message对象。
        Message msg = queue.next(); // might block
        

        //核心代码4处 如果MessageQueue中取出的Message对象为空 则退出无限循环。
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }

           
        final Observer observer = sObserver;

        final long traceTag = me.mTraceTag;
        long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
        long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
        if (thresholdOverride > 0) {
            slowDispatchThresholdMs = thresholdOverride;
            slowDeliveryThresholdMs = thresholdOverride;
        }
        
        final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
        final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

        final boolean needStartTime = logSlowDelivery || logSlowDispatch;
        final boolean needEndTime = logSlowDispatch;

        if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
            Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
        }

        final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
        final long dispatchEnd;
        Object token = null;
        if (observer != null) {
            token = observer.messageDispatchStarting();
        }
            
        long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
        try {

            //核心代码5处 msg.target就是发送消息的时候传入的Handler对象,即发送消息的Handler
            msg.target.dispatchMessage(msg);


            if (observer != null) {
                observer.messageDispatched(token, msg);
            }
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } catch (Exception exception) {
            if (observer != null) {
                observer.dispatchingThrewException(token, msg, exception);
            }
            throw exception;
        } finally {
            ThreadLocalWorkSource.restore(origWorkSource);
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
            

            
        //核心代码6处 调用Message类的recycleUnchecked方法回收消息,将Message对象放到消息池中
        msg.recycleUnchecked();
    }
}

此方法,按照标记有六处要点。

<1> 获取Looper对象。上面已经讲过,这里就不赘述了

//核心代码1处 获取Looper对象     
final Looper me = myLooper();

 

<2> 使用Looper对象获取MessageQueue对象

//核心代码2处 使用Looper对象获取MessageQueue对象     
final MessageQueue queue = me.mQueue;

 

<3> 在For循环(无限循环)中用MessageQueue的next方法取出MessageQueue中的Message对象 MessageQueue的next()方法还是挺复杂的下面讲解

//核心代码3处 使用MessageQueue对象获取Message对象。
Message msg = queue.next(); // might block

 

<4> 如果从MessageQueue中取出的Message对象为空,也就是说消息队列中暂时没有消息了。则退出For循环(无限循环)

//核心代码4处 如果MessageQueue中取出的Message对象为空 则退出无限循环。
if (msg == null) {
    // No message indicates that the message queue is quitting.
    return;
}

 

<5> 调用Handler的dispatchMessage()方法发布消息

//核心代码4处 msg.target就是发送消息的时候传入的Handler对象,即发送消息的Handler
msg.target.dispatchMessage(msg);

此处的msg.target就是发送消息时的Handler对象。上面已经讲过,这里就不赘述了

 

<6> 该方法的最后调用Message类的recycleUnchecked方法回收消息,将Message对象放到消息池中。

//核心代码5处 调用Message类的recycleUnchecked方法回收消息,将Message对象放到消息池中
msg.recycleUnchecked();

 

 

小结1

<1> Looper类的loop()方法,里面有一个For循环(无限循环)。用来循环的取出MessageQueue中的Message。当从MessageQueue中取出的Message为空时,即消息队列暂时没有消息时,会退出For循环(无限循环)。

<2> Looper类的loop()方法走到最后,就到了Handler类的dispatchMessage()方法。来做消息发布。也就是说Looper类的loop方法,是用来循环取出MessageQueue中的Message的。而真正的消息发布走的是Handler类的dispatchMessage()方法。

<3> Looper类的loop()方法哪里调用呢?前面也讲过了

(1) 主动调用 APP默认的主线程ActivityThread类的main方法中调用。

Looper.prepareMainLooper();

(2) 子线程手动调用

Looper.loop();

 

 

 

源码之MessageQueue类

上述Looper类的loop()方法取出MessageQueue中的Message时,调用了MessageQueue类的next方法。

next()方法源码

Message next() {
    // Return here if the message loop has already quit and been disposed.
    // This can happen if the application tries to restart a looper after quit
    // which is not supported.
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }

    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    int nextPollTimeoutMillis = 0;
    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();
            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 (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    return msg;
                }
            } else {
                // No more messages.
                nextPollTimeoutMillis = -1;
            }

            // Process the quit message now that all pending messages have been handled.
            if (mQuitting) {
                dispose();
                return null;
            }

            // If first time idle, then get the number of idlers to run.
            // Idle handles only run if the queue is empty or if the first message
            // in the queue (possibly a barrier) is due to be handled in the future.
            if (pendingIdleHandlerCount < 0
                    && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                // No idle handlers to run.  Loop and wait some more.
                mBlocked = true;
                continue;
            }

            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }

        // Run the idle handlers.
        // We only ever reach this code block during the first iteration.
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; // release the reference to the handler

            boolean keep = false;
            try {
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }

            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }

        // Reset the idle handler count to 0 so we do not run them again.
        pendingIdleHandlerCount = 0;

        // While calling an idle handler, a new message could have been delivered
        // so go back and look again for a pending message without waiting.
        nextPollTimeoutMillis = 0;
    }
}

MessageQueue类的next方法,源码比较多。而且里面好多native的方法。这里就不赘述了,主要看Java层的代码。大致的意思就是取出MessageQueue中的消息。因为发送消息入队列时是按照Message的延时时间确定的位置。那么取出MessageQueue中的Message时也是一样。按照延时时间取。即取出延时时间较短(入消息队列时放在前面的消息)。

 

 

小结2

取出MessageQueue中的消息时,用的是next()方法。根据延时时间,取出急需发送的消息。

 

 

源码之Message类

上述Looper类的loop()方法 最后一行 消息发出后 调用了Message类的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++;
        }
    }
}

 

小结3

<1> Looper类的loop()方法发布消息后。会执行Message类的recycleUnchecked()方法。

<2> 该方法就是回收消息,将消息变成可被重复使用的消息,然后放到消息池中。

<3> 具体的回收就是  将Message的flags置成可使用状态  将Message的what属性 arg1属性 arg2属性 obj属性 when属性 target属性等等都置成默认初始的值。然后如果当前消息池中的消息数量小于MAX_POOL_SIZE即小于50。将当前消息赋值给消息池对象sPool 然后消息池中可被重复使用的消息数+1。

 

 

 

源码之Handler类

上述Looper类的loop()方法,最后的消息发布是执行的Handler类的dispatchMessage()方法。

dispatchMessage()方法源码

public void dispatchMessage(@NonNull Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

此方法,有两个重点。

<1> 如果Message的callback对象不为空。执行handleCallback(msg);方法。

那么Message的callback对象是啥呢

Runnable callback;

即,使用post方法或者postDelayed方法传参的Runnable对象。如下。

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

   }
},500);

然后handleCallback(msg);实际是

private static void handleCallback(Message message) {
    message.callback.run();
}

即,调用Runnable对象的run方法。此时上述postDelayed方法的run()方法就会执行了。

 

<2> 否则如果mCallback不为空 则

if (mCallback.handleMessage(msg)) {
     return;
}

mCallback对象是哪里来的呢 是在Handler的构造方法中传过来的

mCallback = callback;

此种方式的回调

public interface Callback {
    /**
     * @param msg A {@link android.os.Message Message} object
     * @return True if no further handling is desired
     */
    boolean handleMessage(@NonNull Message msg);
}

即 这个mCallback是创建Handler的时候可以选择传一个CallBack回调,里面依然是handleMessage方法。 调用自己接口的回调方法,一般不使用。

 

<3> 前两种情况都不满足走到下面的方法

handleMessage(msg);
public void handleMessage(@NonNull Message msg) {


}

即。一般创建Handler的时候重写的handleMessgae()方法。

 

 

小结4

消息发送,从Looper类的loop()方法到Handler类的dispatchMessage()方法。完成了消息的发布。

 

到这里消息接收就讲解完了。消息发送&消息接收。全部的源码就基本讲述完成。

 

 

 

 

 

附:Handler+Message+MessageQueue+Looper图表


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值