㈠ android View 事件分發機制
Android 事件機制包含系統啟動流程、輸入管理(InputManager)、系統服務和 UI 的通信(WindowManagerService + ViewRootImpl + Window)、事件分發等一系列的環節。
Android 系統中將輸入事件定義為 InputEvent,根據輸入事件的類型又分為了 KeyEvent(鍵盤事件) 和 MotionEvent(屏幕觸摸事件)。這些事件統一由系統輸入管理器 InputManager 進行分發。
在系統啟動的時候,SystemServer 會啟動 WindowManagerService,WMS 在啟動的時候通過 InputManager 來負責監控鍵盤消息。
InputManager 負責從硬體接收輸入事件,並將事件通過 ViewRootImpl 分發給當前激活的窗口處理,進而分發給 View。
Window 和 InputManagerService 之間通過 InputChannel 來通信,底層通過 socket 進行通信。
Android Touch 事件的基礎知識:
KeyEvent 對應了鍵盤的輸入事件;MotionEvent 就是手勢事件,滑鼠、筆、手指、軌跡球等相關輸入設備的事件都屬於 MotionEvent。
InputEvent 統一由 InputManager 進行分發,負責與硬體通信並接收輸入事件。
system_server 進程啟動時會創建 InputManagerService 服務。
system_server 進程啟動時同時會啟動 WMS,WMS 在啟動的時候就會通過 IMS 啟動 InputManager 來監控鍵盤消息。
App 端與服務端建立了雙向通信之後,InputManager 就能夠將產生的輸入事件從底層硬體分發過來,Android 提供了 InputEventReceiver 類,以接收分發這些消息:
Window 和 IMS 之間通過 InputChannel 通信。InputChannel 是一個 pipe,底層通過 socket 進行通信。在 ViewRootImpl.setView() 過程中注冊 InputChannel。
Android 事件傳遞機制是 先分發再處理 ,先由外部的 View 接收,然後依次傳遞給其內層的 View,再從最內層 View 反向依次向外層傳遞。
三個方法的關系如下:
分發事件:
應用了樹的 深度優先搜索演算法 (Depth-First-Search,簡稱 DFS 演算法),每個 ViewGroup 都持有一個 mFirstTouchTarget, 當接收到 ACTION_DOWN 時,通過遞歸遍歷找到 View 樹中真正對事件進行消費的 Child,並保存在 mFirstTouchTarget 屬性中,依此類推組成一個完整的分發鏈。在這之後,當接收到同一事件序列的其它事件如 ACTION_MOVE、ACTION_UP 時,則會跳過遞歸流程,將事件直接分發給下一級的 Child。
ViewGroup 分發事件的主要的任務是找一個 Target,並且用這個 Target 處理事件,主要邏輯如下 :
為什麼倒序查找 TouchTarget?
如果按添加順序遍歷,當 View 重疊時(FrameLayout),先添加的 View 總是能消費事件,而後添加的 View 不可能獲取到事件。
攔截事件:
[1] Android 事件分發機制的設計與實現
[2] Android 事件攔截機制的設計與實現
㈡ 詳解Android消息機制之Message
在分析Message這個類之前,有必要先看看它的類注釋其中有這么一段話:
從這段話得知,盡管Message本身的構造方式是公共的,但實現Message對象的最好方法確實是通過Message.obtain()函數返回,或者通過Handler.obtainMessage()方法,查看其最終還是調用了obtain函數。
如果使用new來實現我們初步的推測,應該是會構建大量的Message對象,對內存有一定的影響。
在這還是先看一下谷歌給這個函數的注釋:
從obtain函數的注釋中也能看出其作用就是用避免大量的構建Message對象,但它是究竟是如何處理的呢?帶著疑問查看obtain函數:
實現很簡單:
但看到這里還是很模糊,雖然sPool看上去像一個消息池,但再仔細看居然是一個Message對象,這樣真的就能避免多次構建Message對象嗎?繼續看會發現一個next欄位,再看它的注釋 sometimes we store linked lists of these things ,Message的消息池原來是一個鏈表,如下圖所示 。
每一個Message 對象通過next指向下一個Message(最後一個Message的next為null)形成一個鏈表,Message對象就成了一個可用的Message池。
到這終於知道Message對象原來是從鏈表中獲取的,但還有一個疑問:Message對象是什麼時候放入鏈表中的呢?從obtain函數並沒有看見存儲Message的操作。這時候又要回到文章開頭的那段類注釋的最後一句話: which will pull them from a pool of recycled objects。
消息池是一些回收的對象,也就是說Message對象是在回收的時候將其添加到鏈表中的。通過查看在Message中有個recycle方法:
在recycleUnchecked函數中會先清空該消息的各個欄位,並且把flags設置為FLGA_IN_USE,表明該消息已經被使用了。然後判斷是否要將消息回收到消息池中,如果池的大小小於MAX_POOL_SIZE,就將自身添加到鏈表的表頭,sPoolSize++。
例如最開始的開始的時候鏈表中沒有任何消息,將第一個Message對象添加到表中,此時的sPool為空,因此next也為空,sPool又指向this,這時sPool就指向當前這個被回收的Message對象,sPoolSize加1。我們把這個Message命名為m1,這時的鏈表應該如下:
如果再次插入一個名為m2的Message,那麼m2將被插入表頭,sPool指向m2,這時sPool的鏈表中結構如下:
對象池默認的大小為50,如果池的大小小於50,被回收的消息將會被插入到鏈表頭部。
如果池中有元素,這時候再調用obtain函數時,實際上是就獲取鏈表中表頭的元素,也就是sPool。再把sPool指針往後移動一個。在obtain漢中,首先會聲明一個Message對象m,並且讓m指向sPool.sPool實際上指向了m2,因此m實際上指向的也是m2,這里相當於保持了m2這個元素。下一步是sPool指向m2的下一個元素,也就是m1。sPool也完成後移之後此時把m.next置空,也就相當於m2.next變成了null。最後就是m指向了m2元素,m2的next為空,sPool從原來的表頭m2指向了下一個元素m1,最後將對象的元素減1,這樣m2就順利的脫離了消息池隊伍,就返回給了調用obtain函數的。
㈢ Android的handler機制的原理
Android的handler機制的原理分為非同步通信准備,消息發送,消息循環,消息處理。
1、非同步通信准備
在主線程中創建處理器對象(Looper)、消息隊列對象(Message Queue)和Handler對象。
2、消息入隊
工作線程通過Handler發送消息(Message) 到消息隊列(Message Queue)中。
3、消息循環
消息出隊: Looper循環取出消息隊列(Message Queue) 中的的消息(Message)。
消息分發: Looper將取出的消息 (Message) 發送給創建該消息的處理者(Handler)。
4、消息處理
處理者(Handler) 接收處理器(Looper) 發送過來的消息(Message),根據消息(Message) 進行U操作。
handler的作用
handler是android線程之間的消息機制,主要的作用是將一個任務切換到指定的線程中去執行,(准確的說是切換到構成handler的looper所在的線程中去出處理)android系統中的一個例子就是主線程中的所有操作都是通過主線程中的handler去處理的。
Handler的運行需要底層的 messagequeue和 looper做支撐。
㈣ Android消息推送原理
產品的角度:功能需要,比如說資訊類產品的新聞推送、工具類產品的公告推送等等
運營的角度:活動運營需要,比如說電商類產品的促銷活動;召回用戶 / 提高活躍度等等
作為開發者,不要有需求就接,應該多思考、多理解用戶 / 功能的使用場景,有助於我們更好地去選擇合適的開發方式
系統級別:任何時候都可以推送給用戶,且不會被系統殺死
Android的消息推送服務稱為:C2DM(Cloudto Device Messaging)
消息推送的本質是:App將伺服器更新的信息推送給用戶,即App獲取伺服器信息,再推送給用戶
App從伺服器獲取最新消息的基本方式(原理)有3種:Push、Pull 和 SMS
經總結,Android中實現消息推送的有7種主流解決方案,接下來將一一介紹。
4.1 C2DM
定義:Cloud to Device Messaging,雲端推送
Android系統級別的消息推送服務-Google出品
原理:基於Push方式,C2DM服務負責處理諸如消息排隊等事務,並向運行於目標設備上的應用程序分發這些消息。如下圖:
定義:輕量級的消息發布/訂閱協議
原理:基於Push方式,wmqtt.jar 是IBM提供的MQTT協議的實現,原理如下圖:
其他三種:
客戶端
通信能夠在這三者的任意兩個之間雙向發生。
原理流程
現今主流的推送平台分為
手機廠商類:小米推送、華為推送。
第三方平台類:友盟推送、極光推送、雲巴(基於MQTT)
BAT大廠的平台推送:阿里雲移動推送、騰訊信鴿推送、網路雲推送