国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

android線程消息機制之Handler詳解

2019-10-22 18:25:07
字體:
供稿:網(wǎng)友

android線程消息機制主要由Handler,Looper,Message和MessageQuene四個部分組成。平常在開發(fā)中,我們常用來在子線程中通知主線程來更新,其實整個安卓生命周期的驅(qū)動都是通過Handler(ActivityThread.H)來實現(xiàn)的。

首先我們先介紹這四個類的作用:

Handler:消息的發(fā)送者。負責將Message消息發(fā)送到MessageQueue中。以及通過Runnable,Callback或者handleMessage()來實現(xiàn)消息的回調(diào)處理

Looper:是消息的循環(huán)處理器,它負責從MessageQueue中取出Message對象進行處理。(Looper含有MessageQueue的引用)

Message:是消息載體,通過target來指向handler的引用。通過object來包含業(yè)務(wù)邏輯數(shù)據(jù)。其中MessagePool為消息池,用于回收空閑的Message對象的。

MessageQueue:消息隊列,負責維護待處理的消息對象。

android,線程消息機制,Handler

通過上面的圖,我們可以比較清楚地知道他們的作用以及關(guān)系。接下來,我們從源碼角度來分析這種關(guān)系是如何建立的。

public Handler(Looper looper, Callback callback, boolean async) {  mLooper = looper;  mQueue = looper.mQueue;  mCallback = callback;  mAsynchronous = async;}

hander的其它構(gòu)造方法可以自己去查看,通過這個構(gòu)造方法,我們知道,handler持有MessageQueue的引用。所以可以方便地將Message加入到隊列中去。

通過源碼我們發(fā)現(xiàn),sendMessage->sendMessageDelayed->sendMessageAtTime->enqueueMessage

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

都是通過enqueueMessage將message將加入到MessageQueue中。

接下來,我們看Message是如何構(gòu)造的。通過Message的構(gòu)造方法。

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是通過obtain的靜態(tài)方法從消息池sPool中拿到的。這樣可以做到消息的復用。

public static Message obtain(Handler h) {  Message m = obtain();  m.target = h;  return m;}

其中有一個重載方法中m.target = h;這段代碼非常重要,便于后面找到消息的目標handler進行處理。

接下來,我們來看Looper。我們知道Looper通過過Looper.loop來進入循環(huán)的,而循環(huán)是通過線程的run方法的驅(qū)動的。

首先我們知道,我們在創(chuàng)建Handler的時候,都沒有去創(chuàng)建Looper,那么Looper哪里來的呢?

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

再看看Looper.myLooper()

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

ThreadLocal是線程創(chuàng)建線程局部變量的類。表示此變量只屬于當前線程。

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

我們看到了sThreadLocal.get()的方法實際是取當前線程中的Looper對象。

那么我們主線程的Looper到底在哪里創(chuàng)建的呢?
而我們清楚地知道,如果在子線程中創(chuàng)建handler調(diào)用,則需要使用Looper.prepare方法。

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

我們看到此方法中,如果此線程中沒有Looper對象,則創(chuàng)建一個Looper對象。接下來我們在源碼中看到一個熟悉的方法。

  public static void prepareMainLooper() {    prepare(false);    synchronized (Looper.class) {      if (sMainLooper != null) {        throw new IllegalStateException("The main Looper has already been prepared.");      }      sMainLooper = myLooper();    }  }


此方法單獨的創(chuàng)建了一個sMainLooper用于主線程的Looper。這個prepareMainLooper到底在哪里調(diào)用呢?

高過引用指向發(fā)現(xiàn),我們在ActivityThread.main()方法中發(fā)現(xiàn)

  public static void main(String[] args) {    ...    Looper.prepareMainLooper();    ActivityThread thread = new ActivityThread();    thread.attach(false);    if (sMainThreadHandler == null) {      sMainThreadHandler = thread.getHandler();    }    if (false) {      Looper.myLooper().setMessageLogging(new          LogPrinter(Log.DEBUG, "ActivityThread"));    }    // End of event ActivityThreadMain.    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);    Looper.loop();    throw new RuntimeException("Main thread loop unexpectedly exited");  }

而ActivityThread.main()是程序的入口方法。這樣我們就非常清楚了,主線程的Looper在程序的啟動過程中就已經(jīng)創(chuàng)建并循環(huán)。

那么如果在子線程中創(chuàng)建Looper該如何正確調(diào)用呢?

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.loop()的執(zhí)行方法

public static void loop() {    final Looper me = myLooper();//拿到當前線程的looper    if (me == null) {      throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");    }    final MessageQueue queue = me.mQueue;//拿到當前l(fā)ooper的消息隊列    // 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 (;;) {//死循環(huán)遍歷消息體。如果為null,則休眠。      Message msg = queue.next(); // might block      if (msg == null) {        // No message indicates that the message queue is quitting.        return;      }      // This must be in a local variable, in case a UI event sets the logger      final Printer logging = me.mLogging;      if (logging != null) {        logging.println(">>>>> Dispatching to " + msg.target + " " +            msg.callback + ": " + msg.what);      }      final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;      final long traceTag = me.mTraceTag;      if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {        Trace.traceBegin(traceTag, msg.target.getTraceName(msg));      }      final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();      final long end;      try {        msg.target.dispatchMessage(msg);//此處是真正的分發(fā)消息。此處的target即是handler對象        end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();      } finally {        if (traceTag != 0) {          Trace.traceEnd(traceTag);        }      }      if (slowDispatchThresholdMs > 0) {        final long time = end - start;        if (time > slowDispatchThresholdMs) {          Slog.w(TAG, "Dispatch took " + time + "ms on "              + Thread.currentThread().getName() + ", h=" +              msg.target + " cb=" + msg.callback + " msg=" + msg.what);        }      }      if (logging != null) {        logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);      }      // Make sure that during the course of dispatching the      // identity of the thread wasn't corrupted.      final long newIdent = Binder.clearCallingIdentity();      if (ident != newIdent) {        Log.wtf(TAG, "Thread identity changed from 0x"            + Long.toHexString(ident) + " to 0x"            + Long.toHexString(newIdent) + " while dispatching to "            + msg.target.getClass().getName() + " "            + msg.callback + " what=" + msg.what);      }      msg.recycleUnchecked();    }  }

最后我們看下dispatchMessage的處理方法。

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

我們看到,dispatchMessage是優(yōu)化處理msg.callback,然后就是實現(xiàn)的Callback接口,最后才是handleMessage方法。

重點說明:

1、handler在實例化的時候,持有Looper的引用。是通過ThreadLocal與Handler進行關(guān)聯(lián)的。

2、Message在實例化的過程中,通過target 持有Handler的引用。

3、通常一個線程對應一個Looper.一個Looper可以屬于多個Handler。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網(wǎng)。


注:相關(guān)教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 库车县| 彭阳县| 犍为县| 会泽县| 衡南县| 曲沃县| 鄄城县| 泸水县| 松桃| 社会| 梁平县| 清新县| 万安县| 博野县| 隆回县| 大宁县| 台安县| 平武县| 阿克苏市| 法库县| 习水县| 芒康县| 江口县| 遂溪县| 林口县| 石柱| 湖南省| 扬中市| 休宁县| 潜江市| 青河县| 涿鹿县| 墨竹工卡县| 岳阳市| 嘉禾县| 庆元县| 启东市| 东台市| 自贡市| 台湾省| 泰州市|