Handler源碼閱讀

1. Handler構(gòu)造方法

final Looper mLooper;
final MessageQueue 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;
}

2. 給Handler發(fā)送一個消息

該Message將會保存在Handler的Looper的MessageQueue的鏈表結(jié)構(gòu)里
2.1 sendMessage
public final boolean sendMessage(Message msg) {
  return sendMessageDelayed(msg, 0);
}
2.2 sendMessageDelayed
public final boolean sendMessageDelayed(Message msg, long delayMillis){
  if (delayMillis < 0) {
    delayMillis = 0;
  }
  return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
2.3 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);
}
2.4 enqueueMessage
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
  msg.target = this;  //Message.target設置為Handler
  if (mAsynchronous) {
    msg.setAsynchronous(true);
  }
  return queue.enqueueMessage(msg, uptimeMillis); //調(diào)用MessageQueue 的enqueueMessage方法
}
2.5 enqueueMessage
MessageQueue里面安裝時間順序他去,將msg存放在鏈表結(jié)構(gòu)里饱岸。

frameworks/base/core/java/android/os/MessageQueue.java

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

3 執(zhí)行鏈表的消息

3.1 Looper循環(huán)處理鏈表的的Message

frameworks\base\core\java\android\os\Looper.java

public static void loop() {
  final Looper me = myLooper();
  if (me == null) {
    throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
  }
  final MessageQueue queue = me.mQueue;

  // Make sure the identity of this thread is that of the local process,
  // and keep track of what that identity token actually is.
  Binder.clearCallingIdentity();
  final long ident = Binder.clearCallingIdentity();

  for (;;) {
    Message msg = queue.next(); // might block
    if (msg == null) {
      // No message indicates that the message queue is quitting.
      return;
    }
    try {
      msg.target.dispatchMessage(msg);
    } finally {
    }
    msg.recycleUnchecked();
  }
}
3.2 調(diào)用Handler的handleMessage方法

android\frameworks\base\core\java\android\os\Handler.java

public void dispatchMessage(Message msg) {
  if (msg.callback != null) {
    handleCallback(msg);
  } else {
    if (mCallback != null) {
      if (mCallback.handleMessage(msg)) {
        return;
      }
    }
    handleMessage(msg); //調(diào)用Handler的handleMessage方法
  }
}

4.Message的重用

讀取:從Message自身的緩存鏈表重用Message

frameworks/base/core/java/android/os/Message.java

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();
}
存入:Message處理完后慨绳,放入緩存鏈表
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) { //緩存?zhèn)€數(shù)最大值50
      next = sPool;
      sPool = this; //放入表頭 
      sPoolSize++;
    }
  }
}
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末爱榔,一起剝皮案震驚了整個濱河市被环,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌详幽,老刑警劉巖筛欢,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異唇聘,居然都是意外死亡版姑,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門迟郎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來剥险,“玉大人,你說我怎么就攤上這事宪肖”碇疲” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵控乾,是天一觀的道長么介。 經(jīng)常有香客問我,道長蜕衡,這世上最難降的妖魔是什么壤短? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上久脯,老公的妹妹穿的比我還像新娘蒜绽。我一直安慰自己,他們只是感情好桶现,可當我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鼎姊,像睡著了一般骡和。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上相寇,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天慰于,我揣著相機與錄音,去河邊找鬼唤衫。 笑死婆赠,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的佳励。 我是一名探鬼主播休里,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼赃承!你這毒婦竟也來了妙黍?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤瞧剖,失蹤者是張志新(化名)和其女友劉穎拭嫁,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抓于,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡做粤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了捉撮。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片怕品。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖呕缭,靈堂內(nèi)的尸體忽然破棺而出堵泽,到底是詐尸還是另有隱情,我是刑警寧澤恢总,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布迎罗,位于F島的核電站,受9級特大地震影響片仿,放射性物質(zhì)發(fā)生泄漏纹安。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望厢岂。 院中可真熱鬧光督,春花似錦、人聲如沸塔粒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卒茬。三九已至船老,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間圃酵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留俘陷,地道東北人岭洲。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像告私,于是被迫代替她去往敵國和親承桥。 傳聞我的和親對象是個殘疾皇子凶异,可洞房花燭夜當晚...
    茶點故事閱讀 45,055評論 2 355