美文网首页
Hanlder异步消息自总结

Hanlder异步消息自总结

作者: 别忘了你曾经也是 | 来源:发表于2016-11-04 10:11 被阅读0次

    由于在UI线程中不能做耗时长的操作,所以系统提供了Handler和AsyncTask来进行异步消息处理和任务;

    异步消息处理机制Handler

    Android中的异步消息处理主要由四个部分组成,Message、Handler、MessageQueue和Looper。

    Message

    Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。

    Handler

    Handler顾名思义也就是处理者的意思,它主要是用于发送和处理消息的。发送消息一般是使用Handler的sendMessage()或者post()方法,而发出的消息经过一系列地辗转处理后,最终会传递到Handler的handleMessage()方法中。

    MessageQueue

    MessageQueue是消息队列的意思,它主要是用于存放所有的Handler发送的消息。这部分消息会一直存在于消息队列中,等待被处理。每个线程中只有一个MessageQueue对象。

    Looper

    Looper调用Looper的loop()方法后,就会进入到一个无限循环当中,然后每当发现MessageQueue中存在一条消息,就会将它取出,并传递到Handler的handleMessage()方法中。每个线程中也只会有一个Looper对象。

    Handler源码分析:

    Handler的构造函数

    Handler的定义属性:

    finalMessageQueuemQueue;

    finalLoopermLooper;

    finalCallbackmCallback;

    finalbooleanmAsynchronous;

    IMessengermMessenger;

    在Handler中定义了7个构造函数,分别是:Handler()、Handler(Callback callback)、Handler(Looper

    looper)、Handler(Looper looper, Callback callback)、Handler(boolean

    async)、Handler(Callback callback, boolean async)、Handler(Looper

    looper, Callback callback, boolean async);在上面我们已经说过Handler异步消息机制主要包含MessageQueue、Looper和Message三个部分,那么首先要分析的这三个属性怎么赋值;

    构造方法一:

    public Handler(Looper looper, Callback callback, boolean async) {

    mLooper = looper;

    mQueue = looper.mQueue;//在Looper中进行分析

    mCallback = callback;

    mAsynchronous = async;

    }

    构造方法二:

    publicHandler(Callback callback, boolean async) {

    if (FIND_POTENTIAL_LEAKS) {

    final Class 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();//在looper中分享

    if (mLooper == null) {

    throw new RuntimeException(

    "Can't create handlerinside thread that has not called Looper.prepare()");

    }

    mQueue = mLooper.mQueue;

    mCallback = callback;

    mAsynchronous = async;

    }

    下面看下我们在使用Handler是常用的空参构造函数的调用

    public Handler() {

    this(null, false);//调用Handler(Callback callback, booleanasync)

    }

    可以看到最终会在构造函数中进行对mLooper和mQueue的赋值;

    Handler消息初始化

    在Handler中对消息的初始化主要是重载了5个obtainMessage()方法;分别是

    publicfinalMessageobtainMessage()

    {

    returnMessage.obtain(this);

    }

    publicfinalMessageobtainMessage(intwhat)

    {

    returnMessage.obtain(this, what);

    }

    publicfinalMessageobtainMessage(intwhat, Object obj)

    {

    returnMessage.obtain(this, what,obj);

    }

    publicfinalMessageobtainMessage(intwhat,intarg1,intarg2)

    {

    returnMessage.obtain(this, what,arg1, arg2);

    }

    publicfinalMessageobtainMessage(intwhat,intarg1,intarg2, Object obj)

    {

    returnMessage.obtain(this, what,arg1, arg2, obj);

    }

    可以看到在创建消息Message时会传进去一个参数this即当前Handler,这点很重要,我们知道在消息处理时要找到对应的处理消息的Handler;

    Handler中的send方法

    当handler在分线程进行完耗时的操作后并完成消息创建及配置,那么下面就进消息的发送;在handler中主要有:

    空消息:

    sendEmptyMessage(int what)

    sendEmptyMessageDelayed(int what, long

    delayMillis)

    sendEmptyMessageAtTime(int what, long

    uptimeMillis)

    非空消息:

    sendMessage(Message

    msg)发送一个普通的消息。即延时为零的消息;’

    sendMessageDelayed(Message

    msg, long delayMillis)发送一个延时消息;

    sendMessageAtFrontOfQueue(Message

    msg);

    sendMessageAtTime(Message

    msg, long uptimeMillis);

    上述方法最终会调用Handler中的enqueueMessage(MessageQueue

    queue, Message msg, long uptimeMillis)方法,enqueueMessage()又会调用MessageQueue的enqueueMessage(msg,

    uptimeMillis)方法,最终将消息send到消息队列中;

    Handler中的Post方法

    在Hanlder中处理定义了对消息的send方法之外,还定义了针对Runnable的post方法;相关方法:

    post(Runnable r)调用方法sendMessageDelayed(getPostMessage(r),

    0);

    postAtTime(Runnable r, long uptimeMillis)调用sendMessageAtTime(getPostMessage(r),

    uptimeMillis);

    postAtTime(Runnable r, Object token, long

    uptimeMillis) sendMessageAtTime(getPostMessage(r, token),

    uptimeMillis);sendMessageAtTime(getPostMessage(r, token), uptimeMillis);

    postDelayed(Runnable r, long delayMillis)调用sendMessageDelayed(getPostMessage(r),

    delayMillis);

    postAtFrontOfQueue(Runnable r)调用sendMessageAtFrontOfQueue(getPostMessage(r));

    可以发现Handler的post方法最终是调用了相关send方法,但是所有的post方法同时调用的一个getPostMessage(r)来对消息的创建;实现如下

    privatestaticMessagegetPostMessage(Runnable r) {

    Message m = Message.obtain();

    m.callback = r;

    returnm;

    }

    可以看到在该方法中主要是通过将Runnable复制给m.callback来实现;这将在对消息的分析是详细介绍;

    Handler中的消息处理过程

    我们知道,Handler消息机制中只要消息队列中存在消息,那么looper就不停的取出去消息并且将其交给Handler进行处理。这里我们暂时不关注looper是如何取出消息及分配消息,我们只关注消息是如何处理的;在Handler中对消息的处理只要一个方法:

    publicvoiddispatchMessage(Message msg) {

    if(msg.callback !=null) {

    handleCallback(msg);

    }else{

    if(mCallback!=null){

    if(mCallback.handleMessage(msg)) {

    return;

    }

    }

    handleMessage(msg);

    }

    }

    在该方法中首先要判断msg.callback !=null,而在上面我们已经分析过了只有在使用post相关的方法时msg.callback会被赋值;当msg.callback !=null时会调用handleCallback(msg):privatestaticvoidhandleCallback(Message message) {

    message.callback.run();//即调用Runable的run方法

    }

    当msg.callback==null时首先要判断的时mCallback!=null;在这里说明一下什么是mCallback:在Handler中定义这样的一个final属性:final Callback mCallback,那么什么是Callback呢?

    publicinterfaceCallback {

    public boolean handleMessage(Messagemsg);

    }

    在Handler中定义这样一个接口,官方的定义是:

    Callback interface you can use when

    instantiating a Handler to avoid having to implement your own subclass of

    Handler.

    当mCallback!=null不为空时,如果public boolean handleMessage(Message

    msg)方法返回的true,那么表示当前的message被处理,return;如果放回的丝false,那么在执行完public boolean handleMessage(Message

    msg)方法后会继续执行handleMessage(msg)方法,完成对数据的处理;

    Handler中的消息撤回和消息队列的判断

    Handler中定义的消息撤回的方法:

    removeMessages(int what)根据what来撤回消息;

    removeMessages(int what, Object object)根据what和object来撤回消息;

    removeCallbacksAndMessages(Object token)根据token撤回message和callbacks,当token是null是撤回消息队列的所有消息;

    同时,handler中还定义了对消息队列进行查询的方法:

    hasMessages(int what)

    hasMessages(int what, Object object)

    hasCallbacks(Runnable r)

    Looper的实现

    我们都知道handler的主要的任务就是进行线程间的通信,实现分线程和UI线程通信界面更新,但是我们发现在整个的handler中没有关于UI线程相关的东西;那么下面我们继续分析looper,希望能够找到着相关的东西;和Handler分析过程一样,我们首先看一下looper的构造函数和定义的属性:

    Looper定义的相关的熟悉如下

    staticfinalThreadLocalsThreadLocal=newThreadLocal();

    privatestaticLoopersMainLooper;// guarded by Looper.class

    finalMessageQueuemQueue;

    finalThreadmThread;

    然后查找Looper的构造函数,结果发现了:

    privateLooper(booleanquitAllowed) {

    mQueue=newMessageQueue(quitAllowed);//在消息队列中分析

    mThread= Thread.currentThread();

    }

    私有的构造函数,有一种单例的感觉;接着却找到了这样一个方法prepare(),

    publicstaticvoidprepare(){

    prepare(true);

    }

    privatestaticvoidprepare(booleanquitAllowed) {

    if(sThreadLocal.get() !=null) {

    thrownewRuntimeException("Only one Looper may be created per thread");

    }

    sThreadLocal.set(newLooper(quitAllowed));

    }

    可以new Looper的,接着分析,什么是sThreadLocal,找到ThreadLocal中的set和get方法,其中set()的作用是Sets the value of this variable for the

    current thread,即将looper与sThreadLocal当前线程绑定;通过prepare克可以创建looper,同时Looper中还定义了myLooper()方法获取当前线程的looper;

    publicstaticLoopermyLooper() {

    returnsThreadLocal.get();

    }

    接下来就该从消息队列中获取消息了,即调用loop()方法;

    publicstaticvoidloop() {

    final Looper me = myLooper();

    finalMessageQueue queue = me.mQueue;

    …..

    for(;;) {

    Message msg = queue.next();// might block

    if(msg ==null) {

    // No message indicates that the

    message queue is quitting.

    return;

    }

    ……

    msg.target.dispatchMessage(msg);

    ……

    }

    }

    主要是通过一个死循环不停的从消息队列中取出消息,然后执行msg.target.dispatchMessage(msg)方法即handler. dispatchMessage(msg)方法,由handler去完成消息的处理;

    同时,除了消息的获取之外,Looper还定义了两个退出的方法quit()和quitSafely();这两个方法都调用了Messagequeue的quit()方法,,这两个方法的区别会在下面解析

    Messagequeue时进行说明

    publicvoidquit() {

    mQueue.quit(false);

    }

    publicvoidquitSafely() {

    mQueue.quit(true);

    }

    主线程Looper的问题,我们在UI使用Handler进行线程通信时没有手动的创建Loop而是由于主线的looper系统已经为我们创建好;

    消息队列的实现

    老规矩首先分析一下MessageQueue的构造函数,发现

    // True if the message queue can be quit.

    privatefinalbooleanmQuitAllowed;

    MessageQueue(booleanquitAllowed) {

    mQuitAllowed= quitAllowed;

    mPtr=nativeInit();

    }

    结合MessageQueue和Looper的构造函数和prepare()方法,我们可以知道我们自己创建的MessageQueue都是可以quit,但是在Looper中还定义这么一个方法:

    publicstaticvoidprepareMainLooper(){

    prepare(false);//这个地方为false;

    synchronized(Looper.class) {

    if(sMainLooper!=null) {

    thrownewIllegalStateException("The main Looper has already been prepared.");

    }

    sMainLooper=myLooper();

    }

    }

    下面分析一下MessageQueue的enqueueMessage()方法和next();

    booleanenqueueMessage(Message msg,longwhen) {

    …….

    msg.when = when;

    Message p =mMessages;

    booleanneedWake;

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

    }

    if(needWake) {

    nativeWake(mPtr);

    }

    }

    returntrue;

    }

    消息队列消息的添加主要是进行相应的判断并且循环整个消息队列来进行按照时间的插入;

    Message next() {

    intpendingIdleHandlerCount = -1;// -1 only during

    first iteration

    intnextPollTimeoutMillis = 0;

    for(;;) {

    if(nextPollTimeoutMillis != 0) {

    Binder.flushPendingCommands();

    }

    // We

    can assume mPtr != 0 because the loop is obviously still running.

    // The

    looper will not call this method after the loop quits.

    nativePollOnce(mPtr, nextPollTimeoutMillis);

    synchronized(this) {

    //Try to retrieve the next message.Returnif found.

    finallongnow = SystemClock.uptimeMillis();

    Message prevMsg =null;

    Message msg =mMessages;

    if(msg !=null&& msg.target ==null) {

    //Stalled by a barrier.Find the nextasynchronous message in the queue.

    do{

    prevMsg = msg;

    msg = msg.next;

    }while(msg !=null&& !msg.isAsynchronous());

    }

    if(msg !=null) {

    if(now < msg.when) {

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

    returnmsg;

    }

    }else{

    //

    No more messages.

    nextPollTimeoutMillis = -1;

    }

    //

    Process the quit message now that all pending messages have been handled.

    if(mQuitting) {

    dispose();

    returnnull;

    }

    if(pendingIdleHandlerCount < 0

    && (mMessages==null|| now

    pendingIdleHandlerCount =mIdleHandlers.size();

    }

    if(pendingIdleHandlerCount <= 0) {

    mBlocked=true;

    continue;

    }

    if(mPendingIdleHandlers==null) {

    mPendingIdleHandlers=newIdleHandler[Math.max(pendingIdleHandlerCount, 4)];

    }

    mPendingIdleHandlers=mIdleHandlers.toArray(mPendingIdleHandlers);

    }

    for(inti = 0; i

    finalIdleHandleridler =mPendingIdleHandlers[i];

    mPendingIdleHandlers[i]=null;//

    release the reference to the handler

    booleankeep =false;

    try{

    keep = idler.queueIdle();

    }catch(Throwable t) {

    Log.wtf("MessageQueue","IdleHandler threw exception", t);

    }

    if(!keep) {

    synchronized(this) {

    mIdleHandlers.remove(idler);

    }

    }

    }

    pendingIdleHandlerCount = 0;

    nextPollTimeoutMillis = 0;

    }

    }

    voidquit(booleansafe) {

    if(!mQuitAllowed) {

    thrownewRuntimeException("Main thread not allowed to quit.");

    }//主线程不可退出

    synchronized(this) {

    if(mQuitting) {

    return;

    }

    mQuitting=true;

    if(safe) {

    removeAllFutureMessagesLocked();//处理完所有的消息后提出

    }else{

    removeAllMessagesLocked();//直接退出,不再关注消息队列是否处理完

    }

    // We

    can assume mPtr != 0 because mQuitting was previously false.

    nativeWake(mPtr);

    }

    }

    Message的实现

    对于message的分析,主要是关注两点

    Handlertarget;

    Runnablecallback;

    Message的创建主要是调用了其静态方法obtain():

    * Return a newMessage instance from the global pool. Allows us to

    avoidallocating new objects in many cases.

    publicstaticMessageobtain() {

    synchronized(sPoolSync) {

    if(sPool!=null){

    Message m =sPool;

    sPool= m.next;

    m.next=null;

    sPoolSize--;

    returnm;

    }

    }

    returnnewMessage();

    }

    从整个Messge池中返回一个新的Message实例,在许多情况下使用它,因为它能避免分配新的对象

    在上面我们已经知道在handler进行消息初始化的时候会调用obtain(Handler h)等方法其最终会通过obtain()进行消息返回并且对消息的target进行赋值;这也就是是在Loop()方法中进行消息分配的原因;Handler中的其他消息的初始化大家可以自己对应源码去看一下;

    我们在Handler的分配的时候曾经有过这样一个判断

    if(msg.callback !=null) {

    handleCallback(msg);

    }

    下面我们看一下msg.callback,在消息初始化的时候,当我们传入一个Runnable时,

    callback

    Runnable that will execute when the message is handled.也就是说再消息发送出去后会在执行。

    publicstaticMessageobtain(Handler h, Runnable callback) {

    Message m =obtain();

    m.target= h;

    m.callback= callback;

    returnm;

    }

    相关文章

      网友评论

          本文标题:Hanlder异步消息自总结

          本文链接:https://www.haomeiwen.com/subject/grgiuttx.html