android-handler、looper、messageQueue、message

  Handler创建,必须有个一个Looper,主线程自己创建了。其他线程需要自己创建,默认是没有的。创建方法

  1. 这种方法是先创建一个系统定义好的HandlerThread,这个是跑在非UI线程中的,已经创建好了looper,直接用就可以了.创建handler有多个构造函数,具体看源码

    HandlerThread threadhandler = new HandlerThread("1111");
    threadhandler.start();
    myhandler = new myHandler(threadhandler.getLooper());

   2. 自己创建一个新的线程,在线程中调用Looper.prepare();然后写处理message回调方法,接着还要调用looper.loop();
  class LooperThread extends Thread {
   public Handler mHandler;
  
  public void run() {
Looper.prepare();

mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};

Looper.loop();
}
}
  为什么一定要有一个Looper呢?
  因为handler的无参数构造函数里需要looper,如果为空就抛异常。
  如何设置looper?
调用Looper.prepare();这里会判断当前的线程是不是已经有looper了,有的话会抛异常,这就是说一个线程只能有一个looper。
Message是什么,有什么用?
存放消息的用的,它有很多属性。特别说明target,表示的就是处理它的handler,next属性,这就是利用了链表结构来构造的消息队列,message.next表示着当前消息的下一个,是按照时间来的,只能顺序不能反过来,他没有prev属性。
  这里需要说一下他的Spool静态属性,这是一个消息池,Spool自己就是一个Message对象,刚开始的时候他是null的,什么时候它有东西的呢?
  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++;
  }
  }
  }
  看这个方法,这个方法是looper中循环处理完一个message之后做的事情,它回收了这个message,并且将这个被回收的message和已有的Spool链接起来,再将Spool指向这个回收的message,利用这种方法将回收的message都给串了起来。
  message -> spool -> null
  spool(被回收的message)-> message(旧的spool) -> null
  消息池怎么被使用的?
  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();
  }
  利用obtain的方法得到一个消息池中的第一个空message,并且spool指向第二个元素,剩余的空消息数-1;

MessageQueue是什么,有什么用?
用来操作messages,例如handler发送消息过来,他需要把消息按照顺序串起来。还有处理完消息后他需要把消息从消息队列中删除等等。
handler有什么用?
发送和处理消息。handler通过sendmessage等方法发送消息,最终都是通过sendMessageAtTime(这里最终是调用了enqueueMessage方法,其中uptimeMillis参数是SystemClock.uptimeMillis() + delayMillis,所以想要优先处理runable,就是要让时间戳在所有message之前,利用
sendMessageAtFrontOfQueue方法,这个参数会传递0,这样就会优先处理了)来处理发送给MessageQueue。然后通过looper回调函数msg.target.dispatchMessage(msg)-->handler的handleMessage()方法具体处理。
   handler还可以使用post方法将runnable传给消息队列message有callback属性,在looper的dispatchMessage()方法中,如果是runnable就直接run()了;

最后有个疑问:到底是什么样的机制可以让looper循环去处理message?

   while (true) {  

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

     if (msg != null) {  

    if (msg.target == null) {    

      return;  

            }  

    if (me.mLogging!= null) me.mLogging.println(  ">>>>> Dispatching to " + msg.target + " "  

     + msg.callback + ": " + msg.what   );  

    msg.target.dispatchMessage(msg);  

    if (me.mLogging!= null) me.mLogging.println(  "<<<<< Finished to    " + msg.target + " "  

     + msg.callback);  

      msg.recycle();  

    }  

  看到Message msg = queue.next(); // might block 这句话,获得待处理的message,这里可能会堵塞,没有message的时候就循环等待,直到messageQueue退出
  
  现在再看看queue.next方法
  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());
  }
  这部分代码进入条件是target是null,那么什么时候target会是null呢,首先我们要明确,我们只有2种方法往messageQueue的mMessages里插入message---enqueueMessage(sendMessage等最终都是走的它)和enqueueBarrier。我们用handler在setMessage的时候enqueueMessage方法已经
  msg.target = this;
  而且如果我们使用的是带参数的Message中的obtain方法也会设置target。
  那么无疑就是enqueueBarrier方法,这个方法只有一个入口,就是Looper的postSyncBarrier(),它会返回一个int值,用于之后的removeSyncBarrier(int)。
  int enqueueSyncBarrier(long when) {
   // Enqueue a new sync barrier token.
   // We don't need to wake the queue because the purpose of a barrier is to stall it.
    synchronized (this) {
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();//这里返回一个target为null的Message
msg.markInUse();
msg.when = when;
msg.arg1 = token;
    .....
    }
  }
  然后接着看queue.next,如果是阻断msg,那么就一直找到msg是isAsynchronous的,然后接着处理,这个isAsynchronous有2种设置方法,一个是handler构造参数里面传的,那么所有的sendMessage都会打上异步标签。还有一种就是单独调用一个message的setAsynchronous。
  这样的话,当阻断的时候就会跳过普通的message,找到异步message去执行。
  接着往下看next();
  // Got a message.
  mBlocked = false;
  if (prevMsg != null) {
   prevMsg.next = msg.next;//如果阻断的话,这里prevMsg就不是空,那么就会直接把标签是异步的message的上一个message的next直接指向标签是异步的message的下一个message,其实就是把异步message从消息队列中给抽出去了
  } else {
   mMessages = msg.next;//这里就是普通message的处理步骤,消息队列少了第一个元素
  }
  msg.next = null;
  if (false) Log.v("MessageQueue", "Returning message: " + msg);
  return msg;
  到这里,阻断message还是在消息队列中,下次循环还是依照这个顺序执行。除非我们手动调用removeSyncBarrier方法才能正常处理普通的message。
  这里得到个结论,mMessages的第一个元素不一定就是本次待处理的message。

 这个阻断在源码中有地方使用:scheduleTraversals这个方法,这个方法是view的measure,layout,draw三部曲的入口。

void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().postSyncBarrier();//这里,使用了阻断,此时只有message是异步的才可以被执行。
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
}
}

mTraversalRunnable这个Runnable执行的代码是

void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);//已经开始执行了,就把阻断remove掉,view展示完毕后继续正常处理普通的message

if (mProfile) {
     ....
     }  
    }  
}
优点快速展示,想了半天,为啥他不使用sendMessageAtFrontOfQueue这个方法优先执行mTraversalRunnable呢?可能原因,我们也可以主动调用改方法,那么岂不是就有可能我们的runnable优先与系统展示view了?使用阻断,他内部还是按照时间戳顺序执行的,就保证了view展示优先执行~!!!!!

 



  接着看next();
  
// 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("MessageQueue", "IdleHandler threw exception", t);
}

if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
这里还有代码,这是干嘛的?这这个就是执行idle handlers的,当之前的message,一个都找不到的时候,说明空闲,这个时候就可以执行IdleHandler了
使用方法就是调用MessageQueue的addIdleHandler方法。
posted @ 2015-05-19 20:27  saki_god  阅读(352)  评论(0编辑  收藏  举报