視窗層級關系(浮窗是如何“浮”的)?
浮窗有哪些限制,如何越過使用者授權實作浮窗功能?
activity是如何接收到touch事件的?
前兩個問題在前兩篇文章中已經分析,在這篇文章中我們以第三個問題為切入點,簡單分析一下視窗與使用者輸入的關系。
正常的思路是直接去尋找activity 的dispatchtouchevent方法,我們看看activity的dispatchtouchevent()方法的調用棧,在方法中加入thread.dumpstack()來檢視調用棧。
輸出:
一條粗略的線索:
viewrootimpl-deliverinputevent ->view.dispatchpointerevent->phonewindow$decorview.dispatchtouchevent->mainactivity.dispatchtouchevent,讀者可以根據這個線索去跟蹤源碼。我們這裡先不深入其中細節,先來看看decorview 到 activity.dispatchtouchevent 是如何調用的?
再來看看decorview的 dispatchtouchevent方法:
decorview 是view的子類重寫了dispatchtouchevent方法,在這個方法中調用 callback,這個callback是window的一個靜态内部接口類,activity實作了這個接口,activity的dispatchtouchevent() 方法正是從callback繼承而來。
思路同上:dump出根視圖的dispatchtouchevent()方法調用棧:
添加到windowmanagerservice中管理。是以activity的dispatchtouchevent方法其實是view傳遞過來的。
我們可以猜測粗略線索是:touch事件-》硬體裝置-》某個服務-》 viewrootimpl --》view。
我們先來看看viewrootimpl和view到底有啥關系?首先,看看windowmanager的addview方法,windowmanager是個接口,我們看其實作類windowmangerimpl的源碼:
在來看看windowmanagerglobal的源碼:
在這裡建立了viewrootimpl對象,并且把傳單下來的view通過setview方法設定到其中的變量,來看看setview的源碼:
}
由此得到關系圖:
通過windowmanagerimpl.addview,最終把view添加指派到了viewrootimpl的變量mview。viewrootimpl是view(視窗)和windowmanagerservice協定的紐帶
從mvc的角度來看的話:可以認為view是v,viewrootimpl是controller,windowmanagerservice是model。view的繪制、重新整理都需要通過viewrootimpl與windowmanagerservice互動,另外view的輸入事件(鍵盤、觸摸)也是由viewrootimpl傳遞給view的,那麼viewrootimpl是如何監聽到使用者輸入事件的呢?
回憶下上文點到的windowinputeventreceiver,這是viewrootimpl的一個内部類,我們dump出來的dispatchtouchevent最初的地方就是源于這個類,再往下就是messagequeue、looper的資訊。由此可以推斷windowinputeventreceiver是viewrootimpl和底層某個服務進行ipc互動的關鍵,這個服務是什麼服務呢?
這部分涉及到anddroid系統的兩個重要的子產品:圖形視窗和使用者輸入,分别對應的服務是windowmanagerservice和inputmanagerservice。windowmanagerservice負責圖形視窗(view)的繪制、重新整理等事物、inputmanagerservice管理使用者輸入事件處理。
1、inputmanagerservice 管理者兩個角色inputreader和inputdispatcher 。
2、inputreader負責從硬體(eventhub)讀取輸入信号,轉化成為事件,傳遞給inputdispatcher。
3、inputdispatcher将inputreader傳遞過來的事件分發到對應的場景,例如将touch事件分發到viewrootimpl。
那麼inputmanagerservice(inputdispatcher)是如何将touch事件傳遞到viewrootimpl(windowinputeventreceiver)的呢?
使用者輸入事件處理模型是“生産者-消費者“模型,生産者發生在系統程序中,消費者發生在使用者程序中。傳遞過程由ipc互動,這裡的通訊是采用的socket通訊,消費者需要向生産者”注冊“通訊管道,registerinputchannel建立連接配接。在viewrootimpl的setview()方法中建立了windowinputeventreceiver,并通過windowmanagerservice向inputmanagerservice注冊inputchannel監聽輸入事件。
touchevent事件傳遞流程 :
<a href="http://www.cnblogs.com/samchen2009/p/3367496.html">《android 的視窗管理系統》</a>
<a href="http://www.cnblogs.com/samchen2009/p/3368158.html">《android的使用者輸入處理》</a>
<a href="http://blog.csdn.net/singwhatiwanna/article/details/50775201">《android中motionevent的來源和viewrootimpl》</a>