日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android中的消息机制

發布時間:2024/4/14 Android 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android中的消息机制 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Android 中的消息機制其實就是指的是 Handler 消息機制以及附帶的 Looper 和 MessageQueue 的工作流程。

1.Android 為什么提供Handler?

  • 解決子線程不能訪問 UI 的問題 在 ViewRootImpl 中有一個checkThread() 方法:
void checkThread() {if (mThread != Thread.currentThread()) {throw new CalledFromWrongThreadException("Only the original thread that created a view hierarchy can touch its views.");}} 復制代碼

2. 為什么子線程不能訪問UI呢?

  • Android 的 UI 控件不是線程安全的,如果在多線程中并發訪問 UI 控件會導致 UI 控件處于不可預期的狀態

3.那為什么不給UI控件加上鎖機制呢?

  • 加鎖會增加UI邏輯復雜性
  • 鎖機制會降低線程訪問UI的效率

4.Handler 的工作原理

5.ThreadLocal

Looper.java

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));} 復制代碼

ThreadLocal.java

class Thread{/* ThreadLocal values pertaining to this thread. This map is maintained* by the ThreadLocal class. */ThreadLocal.ThreadLocalMap threadLocals = null; }復制代碼

threadLocals 屬于 Thread 里的一個變量

ThreadLocalMap getMap(Thread t) {return t.threadLocals;} 復制代碼void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue);} 復制代碼public void set(T value) {//獲取當前的線程對象Thread t = Thread.currentThread();//getMap(t) 我們就知道了就是獲取當前線程里的 //threadLocals 變量 ,//類型是ThreadLocal.ThreadLocalMap類型ThreadLocalMap map = getMap(t);//判斷取出的是否為空,第一次應該為空if (map != null)//第二次不為空,將key:ThreadLocal;value:Looper存入map.set(this, value);else//為null時,創建ThreadLocalMap對象,并且將值與線程存入createMap(t, value);} 復制代碼

那么我們需要知道 ThreadLocalMap 是如何存儲的?

//ThreadLocal 靜態內部類 static class ThreadLocalMap {static class Entry extends WeakReference<ThreadLocal<?>> {/** The value associated with this ThreadLocal. */Object value;Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}}/*** The initial capacity -- MUST be a power of two.*/private static final int INITIAL_CAPACITY = 16;/*** The table, resized as necessary.* table.length MUST always be a power of two.*/private Entry[] table;xxx ....ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {table = new Entry[INITIAL_CAPACITY];int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);table[i] = new Entry(firstKey, firstValue);size = 1;setThreshold(INITIAL_CAPACITY);}/*** Set the value associated with key.** @param key the thread local object* @param value the value to be set*/private void set(ThreadLocal<?> key, Object value) {// We don't use a fast path as with get() because it is at// least as common to use set() to create new entries as// it is to replace existing ones, in which case, a fast// path would fail more often than not.Entry[] tab = table;int len = tab.length;//取出那個下標int i = key.threadLocalHashCode & (len-1);for (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {ThreadLocal<?> k = e.get();if (k == key) {e.value = value;return;}if (k == null) {replaceStaleEntry(key, value, i);return;}}tab[i] = new Entry(key, value);int sz = ++size;if (!cleanSomeSlots(i, sz) && sz >= threshold)rehash();} }復制代碼

6. 主線程 的 Looper 是何時創建的?

在 ActivityThread 的 main 方法中創建的,一起來看下:

public static void main(String[] args) {Looper.prepareMainLooper();xxx....Looper.loop(); } 復制代碼

Looper.prepareMainLooper();

public static void prepareMainLooper() {prepare(false);synchronized (Looper.class) {if (sMainLooper != null) {throw new IllegalStateException("The main Looper has already been prepared.");}sMainLooper = myLooper();}}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));} 復制代碼

prepare 方法中又創建threadLocal與Looper的關聯 , 而且加了判斷,說明一個線程只能有一個Looper,而后創建了 Looper 的實例。 Looper 構造方法

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

創建了 MessageQueue 實例,獲取當前的線程。

而在Handler 的創建構造函數中:

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());}}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--mLooper 和 Looper 中的 MessageQueue 對象。后面就是發消息,消息入隊,Looper取出消息,進而調用 handler 的 handleMessage 方法。

看書,隨筆記。如有問題,可指出。

總結

以上是生活随笔為你收集整理的Android中的消息机制的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。