深入android
① 深入分析Android-Handler消息機制
Handler是Android消息機制的上層介面。通過它可以輕松地將一個任務切換到Handler所在的線程中去執行。通常情況下,Handler的使用場景就是 更新UI 。
在子線程中,進行耗時操作,執行完操作後,發送消息,通知主線程更新UI。
Handler消息機制主要包括: MessageQueue 、 Handler 、 Looper 這三大部分,以及 Message 。
從上面的類圖可以看出:
MessageQueue、Handler和Looper三者之間的關系: 每個線程中只能存在一個Looper,Looper是保存在ThreadLocal中的。 主線程(UI線程)已經創建了一個Looper,所以在主線程中不需要再創建Looper,但是在其他線程中需要創建Looper。 每個線程中可以有多個Handler,即一個Looper可以處理來自多個Handler的消息。 Looper中維護一個MessageQueue,來維護消息隊列,消息隊列中的Message可以來自不同的Handler。
在子線程執行完耗時操作,當Handler發送消息時,將會調用 MessageQueue.enqueueMessage ,向消息隊列中添加消息。 當通過 Looper.loop 開啟循環後,會不斷地從消息池中讀取消息,即調用 MessageQueue.next , 然後調用目標Handler(即發送該消息的Handler)的 dispatchMessage 方法傳遞消息, 然後返回到Handler所在線程,目標Handler收到消息,調用 handleMessage 方法,接收消息,處理消息。
從上面可以看出,在子線程中創建Handler之前,要調用 Looper.prepare() 方法,Handler創建後,還要調用 Looper.loop() 方法。而前面我們在主線程創建Handler卻不要這兩個步驟,因為系統幫我們做了。
初始化Looper :
從上可以看出,不能重復創建Looper,每個線程只能創建一個。創建Looper,並保存在 ThreadLocal 。其中ThreadLocal是線程本地存儲區(Thread Local Storage,簡稱TLS),每個線程都有自己的私有的本地存儲區域,不同線程之間彼此不能訪問對方的TLS區域。
開啟Looper
創建Handler :
發送消息 :
post方法:
send方法:
② 深入理解Android:SystemServer進程的作用
看了一段時間關於SystemServer進程的博客,有點小理解,寫一篇關於SystemServer的小筆記,然後走一遍過程。
ZygoteInit通過startSystemServer方法fork了一個SS進程。這個進程有啥作用呢。
handlerSystemServerProcess()方法只要是以下三個方法:
其中 applicationInit() 很有意思很重要。該方法中有一個,invokeStaticMain方法通過反射調用main方法:
run方法最終通過反射調用SystemServer的main方法,作用是:
通過以上分析其實main方法的主要作用是:
1、調整系統時間
2、設置屬性persist.sys.dalvik.vm.lib.2的值為當前虛擬機的運行庫路徑
3、裝載libandroid_servers.so庫,初始化native層service
4、初始化系統Context
5、創建SystemServiceManager對象
6、調用startBootstrapServices(),startCoreServices(),startOtherServices()啟動所有的java服務
另外也可以看到為什麼說handler默認是主線程,以及android 應用本身就是基於handler/Looper/Message的
startBootstrapServices():啟動java層的各種服務。framwork層的服務。例如AMS
startCoreServices:啟動核心服務:
startOtherServices也與上面一樣啟動各種服務。
總結下:SystemServer進程最終會執行到SystemServer類中的main方法中,初始化各種伺服器,其中第一個初始化的就是ActivityManagerService。當我們點擊啟動app的時候。Zygote會對這個消息進行處理,最終執行到applicationInit。那麼是在哪裡調用方法啟動應用的呢?
③ 深入理解ANDROID怎麼樣
《深入理解Android》是一本以情景方式對Android的源代碼進行深入分析的書。內容廣泛,以對Framework層的分析為主,兼顧Native層和Application層;分析深入,每一部分源代碼的分析都力求透徹;針對性強,注重實際應用開發需求,書中所涵蓋的知識點都是Android應用開發者和系統開發者需要重點掌握的。
全書共10章:
第1章介紹了閱讀本書所需要做的准備工作,主要包括對Android系統架構和源碼閱讀方法的介紹;
第2章通過對Android系統中的MediaScanner進行分析,詳細講解了Android中十分重要的JNI技術;
第3章分析了init進程,揭示了通過解析init.rc來啟動Zygote以及屬性服務的工作原理;
第4章分析了Zygote、SystemServer等進程的工作機制,同時還討論了Android的啟動速度、虛擬機HeapSize的大小調整、Watchdog工作原理等問題;
第5章講解了Android系統中常用的類,包括sp、wp、RefBase、Thread等類,同步類,以及Java中的Handler類和Looper類,掌握這些類的知識後方能在後續的代碼分析中做到游刃有餘;
第6章以MediaServer為切入點,對Android中極為重要的Binder進行了較為全面的分析,深刻揭示了其本質。
第7章對Audio系統進行了深入的分析,尤其是AudioTrack、AudioFlinger和AudioPolicyService等的工作原理。
第8章深入講解了Surface系統的實現原理,分析了Surface與Activity之間以及Surface與SurfaceFlinger之間的關系、SurfaceFlinger的工作原理、Surface系統中的幀數據傳輸以及LayerBuffer的工作流程。
第9章對Vold和Rild的原理和機制進行了深入的分析,同時還探討了Phone設計優化的問題;
第10章分析了多媒體系統中MediaScanner的工作原理。
本書適合有一定基礎的Android應用開發工程師和系統工程師閱讀。通過對本書的學習,大家將能更深刻地理解Android系統,從而自如應對實際開發中遇到的難題。
作者簡介 :
鄧凡平,資深Android開發工程師,熱衷於Android源代碼的研究,對Android的架構設計和實現原理有非常深刻的認識和理解,應用開發經驗也十分豐富。目前就職於國內一家領先的Android企業,負責Framework的開發和維護。樂於分享,活躍於CSDN等專業社區,撰寫的Android Framework源碼的系列文章深受讀者歡迎。此外,他對linux內核、C/C++/Python相關的技術,以及高性能網路伺服器和多核並行開發等也有一定的研究。
④ 深入理解android2-WMS,控制項
title: '深入理解android2-WMS,控制項-圖床版'
date: 2020-03-08 16:22:42
tags:
typora-root-url: ./深入理解android2-WMS-控制項
typora--images-to: ./深入理解android2-WMS-控制項
WMS主要負責兩個功能, 一是負責窗口的管理,如窗口的增加刪除,層級.二是負責全局事件的派發.如觸摸點擊事件.
先簡單介紹幾個重要的類
IWindowSession. 進程唯一的.是一個匿名binder.通過他向WMS請求窗口操作
surface 繪畫時,canvas會把內容繪制到surface里.surface是有surfaceFlinger提供給客戶端的.
WindowManager.LayoutParams 集成自ViewGroup.LayoutParams.用來指明client端的窗口的一些屬性.最重要的是type. 根據這屬性來對多個窗口進程ZOrder的排序.
windowToken.向WMS添加的窗口令牌.每個窗口都要有一個令牌.
IWindow. 是client提供給WMS的.繼承自binder.WMS通過IWindow對象來主動發起client端的事件.
窗口的本周就是進行繪制所使用的surface,客戶端向WMS添加窗口的過程,就是WMS為客戶端分配surface的過程.
ui框架層就是使用surface上繪制ui元素.及響應輸入事件
WMS負責surface的分配.窗口的層級順序
surfaceFlinger負責將多個Surface混合並輸出.
WMS有SystemServer 進程啟動.他和AMS其實是運行於一個進程中的.只是分別有各自的線程.
上邊傳入了兩個handler.這里就使用windowManager的handler來創建WMS.也就是在一個handerThread線程中創建
用來管理每個窗口的事件輸入.也就是把輸入事件轉發到正確的窗口
能獲取顯示系統的同步信號.用來驅動動畫的渲染
所有窗口動畫的總管,在mChoreographer的驅動下渲染所有動畫
只有PhoneWindowManager一個實現.定義了很多窗口相關的策略.是最重要的成員,比如負責窗口的zorder順序.
zorder就是各個窗口在z軸的值.越大越在屏幕上層.窗口就是根據zorder值一層一層堆在一起.
可以繪制的屏幕列表.默認是只有1個.
管理所以窗口的顯示令牌token,每個窗口都要屬於一個token.這里的IBinder 是
表示所有Activity的token. AppWindowToken是WindowToken的子類,這個list的順序和AMS中對mHistory列表中activity的順序是一樣的 .反應了系統中activity的疊加順序.也就是說.所有窗口都有WindowToken.而Activity對應的窗口則多了AppWindowToken.
每個窗口都對應一個WindowState.存儲改窗口的狀態信息(這就和AMS中對每個activity抽象成ActivityRecord一樣)
這里的iBinder 是IWIndow類.
Session 是WMS提供給客戶端來與WMS進行交互的,這是匿名binder.為了減輕WMS的負擔.客戶端通過IWindowManager.openSession 拿到他的代理.然後通過代理與WMS交互.每個進程唯一.
客戶端通過IWindowSession.add 來添加窗口. iWindowSession 是同aidl形成的.最終到了WMS.addWindow.
這里總的來說就是確立了客戶窗口的WindowToken.WindowState.和DisplayContent. 並都保存了起來.同時根據layoutparams.type進行了些窗口等級的判斷.
WindowToken將同一個應用組件的窗口安排在一起.一個應用組件可以是Activity,InputMethod.
WindowToken使應用組件在變更窗口時必須與自己的WindowToken匹配.
這里主要是為了處理窗口的層級關系而設立的.
只要是一個binder對象.都可以作為token向wms聲明.wms會把這個binder對應起一個WindowToken.其實就是把客戶端的binder和wms里的一個WindowToken對象進行了綁定.
因為Activity比較復雜,因此WMS為Activity實現了WindowToken的子類 appwindowtoken.同時在AMS啟動Activity的ActivityStack.startActivityLocked里聲明token.
然後在activityStack.realStartActivityLocked里在發給用戶進程,然後用戶在通過這個binder和WMS交互時帶過來.
activity則在 activityStack 線程的handleResumeActivity 里把Activity 對應的窗口,加入到wMS中
取消token 也是在AMS中 ,也就是說, AMS負責avtivity的token向WMS的添加和刪除.
當然.Activity的 r.appToken 是 IApplicationToken.Stub ,他里邊有一系列的窗口相關的通知回調.
這里總結下. AMS在創建Activity的ActivityRecord時,創建了他的appToken,有把appToken傳送給WMS.WMS對應匹配為APPWindowToken,最後還把這個appToken發送給activity.因此AMS就通過ActivityRecord就可有直接操作WMS對該窗口的繪制.如圖.
每個window在WMS里都抽象成了WindowState.他包含一個窗口的所有屬性.WindowState在客戶端對應的則是iWidow.stub類.iWidow.stub有很多窗口通知的回調.
WindowState被保存在mWindowMap里.這是整個系統所有窗口的一個全集.
HashMap<IBinder, WindowToken> mTokenMap .這里是 IApplicationToken(客戶端)和WindowToken的映射
HashMap<IBinder, WindowState> mWindowMap 這里是IWidow(客戶端)和WindowState的映射,並且WMS通過這個IWindow 來回調客戶端的方法.
上圖可以看出.每個activity 只有一個ActivityRecord.也只有一個AppToken,也就只有一個WindowToken.而一個acitvity可能有多個窗口.每個窗口對應一個WindowState.
WindowToken用來和AMS交換. 而WindowState對應的iWindow則是WMS來與客戶端交互的.
窗口顯示次序就是窗口在Z軸的排了.因為窗口是疊加在一起的.因此就需要知道哪些顯示在上邊,哪些在下邊.這個由WindowState構造時確定
可見.分配規則是由WindowManagerPolicy mPolicy來決定的.產生 mBaseLayer和mSubLayer. mBaseLayer決定該窗口和他的子窗口在所有窗口的顯示位置. mSubLayer決定子窗口在同級的兄弟窗口的顯示位置.值越高.顯示約靠上.
WindowState 產生了他自己這個窗口的layer值後.在添加窗口的時候就會把所有窗口按layer排序插入mWindows列表中,在通過 adjustWallpaperWindowsLocked();進行層級調整.
當客戶端通過IWindowsession.add後,客戶端還沒有獲得Surface.只有在執行IWindowsession.relayout後.客戶端才獲得了一塊Surface. IWindowsession.relayout根據客戶端提供的參數,為客戶端提供surface.具體實現是WMS.relayoutWindow
總的來說就是根據用戶傳入的參數,更新WindowState.然後遍歷所有窗口布局.在設置合適的Surface尺寸,在返回給用戶端
會循環調用6次.里邊的邏輯大概如下
這里主要下,因為之前加了鎖.requestTraversalLocked他又會重復執行();因此會重復循環執行布局.
布局這部分就記個原理吧
布局完成後.客戶端的尺寸和surface都得到了.就可以繪制 了.WMS會通知客戶端布局發送變化
總結,WMS 負責管理所有的窗口.包括系統窗口和APP窗口,而窗口必須有一個WindowToken所為標識符.同時WMS為每個窗口創建一個WindowState類,這是窗口在服務端的抽象.WindowState則綁定了一個客戶端的IWindow類,WMS通過這個IWindow 向APP發送消息.
AMS在啟動Activity的時候.把ActivityRecord.token 通過wms.addtoken 注冊到WMS.又把這個token發送到APP端.因此三方可以通過這個token正確找到對應的數據.
WMS負責給所以窗口按ZOrder排序,確定窗口的尺寸,提供繪畫用的surface.
Activity的窗口是先wms.addtoken 建立windowToken關系 . wms.addWindow. 添加串口, WMS.relayout獲取surface. 完成 .
一個windowToken對應一個Activity. 但是可能對應多個windowSatate.也就是對應多個窗口.
是view樹的根實現類是viewRootImpl.但是他不是view.他是用來和WMS進行交流的管理者.viewRootImpl內部有個IWindowSession,是WMS提供的匿名binder,同時還有個iWindow子類,用來讓WMS給viewr發消息. view通過ViewRoot向WMS發消息.WMS在通過IWIndow 向APP發消息. 每個View樹只有一個ViewRoot,每個Activity也只有一個ViewRoot. UI繪制,事件傳遞.都是通過ViewRoot.
.實現類是PhoneWindow . Activity和View的溝通就是通過Window.Activity實現window的各種回調.一個Activity也對應一個PhoneWindow.也對應一個View樹.
Docerview 就是View樹的根.這是一個View. 他由PhoneWindow管理. 下文的WindowManager也由phoneWindow管理.
他還管理window的屬性 WindowManager.layoutparams.
他是一個代理類.他集成自ViewManager.他的實現是WindowManagerImpl.這是每個Activity都有一個.但是他只是把工作委託給了 WindowManagerGlobal來實現. 他負責添加刪除窗口,更新窗口.並控制窗口的補件屬性WindowManager.Layoutparams.
是進程唯一的.負責這個進程的窗口管理.他里邊有三個集合.保存這個進程所有窗口的數據.這里的每個數據根據index得到的是同一個Activity屬性.所有的WindowManager的操作都轉到他這里來.
private final ArrayList<View> mViews 每個view是個跟節點
private final ArrayList<ViewRootImpl> mRoots view對應的viewRoot
private final ArrayList<WindowManager.LayoutParams> mParams 窗口的layoutparams屬性.每個窗口一個
對於一個acitivity對象永遠對應一個PhoneWindow,一個WindowManagerImpl,一個WMS端的APPWindowToken,一個AMS里的ActivityRecord(但是如果一個activity在棧里有多個對象,就有多個ActivityRecord和AppWindowToken),acitvity 的默認窗口的view樹是DocerView.
一個窗口 對應一個ViewRoot,一個View樹.一個WindowManager.LayoutParams,一IWindow(WMS回調app).一個WSM端的WindowSatate.
但是一個Activity可以有多個窗口,因此對應WMS里可能有多個WindowSatate.這些WindowState都對應一個AppWindowToken.
一個Activity可能被載入多次.因此在AMS中可能有多個ActivityRecord對應這個activit的多個對象.
但是一個進程則對應一個WindowManagerGlobal.一個ActivityThread(主線程).一個ApplicationThread(AMS調用app).一個iWindowSession(viewroot向WMS發消息)
這里的區別就是 app與AMS 的交互是以進程之間進行通信.而App與WMS的交互.則是以窗口作為通信基礎.
當Activity由AMS啟動時.ActivityThread 通過handleResumeActivity執行resume相關的操作.這個函數首先是執行activity.resume, 此時activity 對應的view樹已經建立完成(oncreate中建立,PhoneWindow也創建了).需要把activity的窗口添加到WMS中去管理.
這里的wm是WindowManager.是每個activity一個.他內部會調用WindowManagerGlobal.addView
WindowManagerGlobal.addView
這里會為窗口創建ViewRootImpl. 並把view.ViewRootImpl.WindowMa.LayoutParams都保存在WindowManagerGlobal中, 並通過ViewRootImpl向WMS添加窗口
如果這個窗口是子窗口(wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW)
就把子窗口的token設為父窗口的token否則就是所屬activity的token.
在來個圖
在這里我們看到.我們通過mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); 拿到的並不是遠程的WMS.而是本地的WindowManagerImpl. 他又把請求轉發給WindowManagerGlobal ,而WindowManagerGlobal作為進程單實例.又是吧請求轉給對應窗口的ViewRootImpl.ViewRootImpl通過WMS的IWindowSession 把數據發給WMS.
ViewRootImpl用來溝通View和WMS.並接受WMS的消息.這是雙向的binder通信.作為整個空間樹的根部,控制項的測量,布局,繪制,輸入時間的派發都由ViewRootImpl來觸發.
ViewRootImpl由WindowManagerGlobal創建,是在activityThread.handleResumeActivity時,先執行activity.resume.在調用wm.addView. 就會執行WindowManagerGlobal.addView里.創建ViewRootImpl,此時是在ui線程中.
ViewRootImpl里的mView屬性.host屬性,就是view樹
添加窗口時通過requestLayout();向ui線程發送消息.最後回調到ViewRootImpl.performTraversals.他是整個ui控制項樹,measure.layout.draw的集合.
這里分為五個階段.
預測量階段.進行第一次測量,獲得view.getMeasuredWitdh/Height,此時是控制項樹期望的尺寸.會執行View的onMeasure
布局階段,根據預測量的結果,通過IWindowSession.relayout向WMS請求調整窗口的尺寸這會使WMS對窗口重新布局,並把結果返回給ViewRootImpl.
最終測量階段, 預測量的結果是view樹期望的結果.WMS可能會進行調整,在這里WMS已經把結果通知了ViewRootImpl.因此這里會窗口實際尺寸performTraversals進行布局.view及子類的onMeasure會被回調
布局階段. 測量完成後獲得空間的尺寸,布局要確定控制項的位置,View及子類的onLayout會被回調.
繪制階段,使用WMS提供的surface.進行繪制,View及子類的onDraw會被回調.
通常我們看到的都是 先measure,在layout在draw. 這里看到.其實measure先得到期望值,在和WMS溝通.WMS在調整後,返回確定值,在根據確定值進行mesure.
measureHierarchy里會通過三次協商.執行performMeasure 來確認合適的尺寸.
performMeasure 會調用view 的measure 優會調用onMeasure. 我們可重寫onMeasure來實現測量.而measure 方法是final的.onMeasure 的結果通過setMeasuredDimension方法保存.
對於view. onMeasure.比較容易. 對於ViewGroup.則還要遍歷調用他所以子view的measure. 並且需要考慮padding和子view 的margin. padding是控制項外內邊距. margin 是控制項外邊距.
ViewGroup需要先測量完子view.在根據子view的測量值得到自己的寬高.舉例,如果只有一個子view.那麼ViewGroup的寬= 子view的寬+子view的margin+viewg的padding. 至少是這個值.
繼續回到performTraversals
這里就是提前測量了一下.得到控制項樹希望的尺寸大小,
通過relayoutWindow來布局窗口. ViewRootImpl 通過IWindowSession 來通知WMS進行窗口布局.
這里主要下. 調用WMS後.WMS會調整窗口的尺寸. 同時會生成surface返回給ViewRootImpl. 因此後續的繪畫就有了畫布了.可以看到最後的參數是mSurface.這是本地的surface. 這里會和wms的進行綁定.
接下來繼續performTraversals,綁定WMS返回的surface.然後更新尺寸.
最後進行最終測量. 上邊過程太亂了. 了解下就行.還是看常見的控制項繪制流程.
繪制由viewRootImpl.performTraversals觸發, 抽取出來後,就是這樣
就是直接調用view樹的根的measure方法. 傳入到View
該方法是final .意味著無法重寫.這里又會調用onMeasure.
因此.對於view.在onMeasure中調整好高度,通過setMeasuredDimension設置好自己的測量寬高就可以了.
對應ViewGroup.則在onMeasure中,先要遍歷子view.調用他們的measure(注意一定是調用子類的measure,measure又會調用onMeasure), 子view寬高都知道後,在根據子view的寬高來設置自己.也就是ViewGroup的寬高受子view影響.
可以看到view的measure又調用了onMeasure, 如果是view 則可以直接重新onMeasure來設定大小.而對於ViewGroup, 則需要重寫onMeasure來先遍歷子view.設定大小.然後再設定viewGroup的大小. ViewGroup並沒有重寫onMeasure.因為每個ViewGroup要實現的效果不同,需要自己完成.但ViewGroup提供了幾個方法供ViewGroup的繼承類來遍歷子view.
view的寬高由自己的layoutParams和父view提供的 widthMeasureSpec|heightMeasureSpec共同決定.
View 自己的寬高,是保存在LayoutParams中對,以寬舉例 LayoutParams.width 有三種情況,精確值(就是指定大小),MATCH_PARENT. WRAP_CONTENT,模式則有fuview提供.有 unspecified,exactly,at_most三種.
匹配如下.
其實這個很好理解. 如果子view自己指定了寬高.就用他的值就可以.如果子view是match_parent.那就使用父view提供的寬高. 如果子view是wrap_content,那就不能超過父view的值.
看下ViewGroup為子view繪制而提供的方法,可以看到.ViewGroup會減去padding和margin,來提供子view的寬高.
上步measure過程未完成後,整個view書的 測量寬高都得到了.也就是view.getMeasuredWidth()和getMeasuredHeight()
performLayout中會調用mView.layout. 這樣就把事件從ViewRootImpl傳遞到了view.而layout中又會調用onLayout.ViewGroup需要重寫onLayout為子view進行布局,遍歷調用子view的layout.因此就完成整個view樹的laylut過程.
豎向的實現, 豎向的就行把view從上到下一次排開
這里注意區分.measure過程是先得到子view的測量值,在設定父ViewGroup的值.而layout過程則是先傳入父view的左上右下值,來計運算元view的左上右下的位置值.這里應該具有普遍性.但不知道是否絕對.
performDraw 中的調用draw.又調用mView.draw.然後就進入view樹的繪制了.
view的draw 又會調用onDraw ,viewGroup又調用dispatchDraw()把draw分發到子view里 繪制的畫布就是canvas. 這是從surface.lockCanvas中獲得的一個區域.
而在ViewGroup.dispatchDraw中.重要的一點是getChildDrawingOrder 表示子view的繪制順序.默認是與ziview的添加順序一樣.我們也可以改變他.最後繪制的會顯示在最上邊,而這也影響view的事件傳遞順序.
view.draw. 就是一層一層的畫內容.先畫北京,在onDraw.在畫裝飾什麼的.
canvas.translate(100,300)通過平移坐標系.使之後的內容可以直接在新坐標系中繪制.
這就是ViewGroup在向子view傳遞canvas的時候.方便多了. 會之前先對其ziview的左上角.那麼子view就可以直接從自己坐標軸的(0,0)開始繪制, 繪制完成後ViewGroup在還原原有坐標系.
canvas.save. canvas.restore 用來保存還原坐標系.
view.invalidate.
當某個view發送變化需要重繪時,通過view.invalidate向上通知到ViewRootImpl.從這個view到ViewRootImpl的節點都標記為藏區域.dirty area. ViewRootimpl再次從上到下重繪時,只繪制這些臟區域.效率高.
本來安卓兼容使用鍵盤,也支持,觸摸.二者的輸入事件派發不一樣.使用鍵盤時會有個控制項處於獲得焦點狀態.處於觸摸模式則由用戶決定. 因此控制項分為兩類.任何情況下都能獲得焦點.如輸入文本框.只有在鍵盤操作時才能獲得焦點.如菜單,按鈕.
安卓里有觸摸模式.當發送任意觸摸時進入觸摸模式.當發送方向鍵和鍵盤或者執行View.requestRocusFromTouch時,退出觸摸模式.
獲取焦點. view.request.
先檢查是否能獲取焦點,
然後設置獲取簡單的標記,
向上傳遞到ViewRootimpl.保證只能有一個控制項獲取焦點.
通知焦點變化的監聽者.
更新view的drawable狀態,
requestChildFocus會把焦點事件層層上報取消原來有焦點的控制項.最後的效果就是從viewrootimpl中.到最終有焦點的view.構成一條 mFoucued 標識的鏈條.來個圖就明白了.每個view的mFocused總是指向他的直接下級.
獲取focus的傳遞是從底層view到頂層的ViewRootImpl.而取消focus測試從頂層的ViewRootimpl到底層原來那個獲得焦點的view.
而如果是ViewGroup請求獲取焦點,會根據FLAG_MASK_FOCUSABILITY特性來做不同方式,分別有先讓自己獲取焦點,或者安卓view的索引遞增或者遞減來匹配view.
ViewRootImpl 中的.WindowInputEventReceiver接受輸入事件.他會把事件包裝成一個QueuedInputEvent.然後追加到一個單鏈表的末尾.接著重頭到尾的處理輸入事件,並通過deliverInputEvent完成分發.這里會把單鏈表所有事件都處理完.
deliverInput中又會把觸摸事件執行到通過 ViewPreImeInputStage.processKeyEvent. 轉入mView.dispatchPointerEvent(event).這里又進入 dispatchTouchEvent
MotionEvent是觸摸事件的封裝.getAction可以拿到動作的類型和觸控點索引號.
getX(),getY().拿到動作的位置信息.通過getPointID拿到觸控點的id. 動作以down 開頭.跟多個move.最後是up.
,當事件返回true.表示事件被消費掉了.
⑤ 如何深入學習android開發
Android開發,需要掌握以下知識:
android以java為基礎的,所以前提要學好Java基礎知識,比如基本類型、集合等。
android api,學習基本的Activity、service、intent等基本的知識,可以開發一些界面。
計算機網路基本知識。
Linux命令、C編程基礎、Android Java編程、Google Android Linux操作系統具體操作等
安卓系統開發的方法,簡單來說分成四層:
第一層,以Inventor為代表的繪圖工具,是Google推出的簡單開發工具,主要是針對初級玩家的玩意兒,操作起來確實容易,一個不懂程序開發的用戶就可以通過拖拽搞出一個能在安卓平台上跑的應用來,有點像做PPT,但任何事情都有兩面性,這種容易上手的繪圖工具,無法實現業務邏輯,運行效率也比較低。
第二層,以Rexsee為代表的無線中間件,這種方法就不是玩家用的了,必須是工程師來用,但對技術門檻的要求很低,會用HTML和JS的技術員就可以方便的使用,在技術要求大幅度降低的同時,基礎功能的封裝也是一大亮點,這些中間件已經把所有應用需要的基礎功能封裝好,程序員直接使用JS去調用就可以了,不再需要吭哧吭哧從零開始寫代碼,比如你想調用個GPS,本來要編幾千行的代碼,用中間件只需一行JS代碼即可搞定,難怪說做中間件的廠商都說:「用了我的東西,你的程序已經做了一大半啦!」此言不虛。
第三層,基於JAVA的JDK JDK(Java Development Kit),目前絕大部分應用都是用這種方式來開發,對程序員的要求比較高,首先要有比較好的JAVA底子,然後要對Android平台本身有很深的研究,門檻不算低。
第四層,基於C++的NDK( Native Development Kit),很多大型游戲是用這種方法開發的,相對於JDK,這種方法的門檻就更高了,目前使用的比較少,畢竟現在是智能手機的時代,硬體和網速都大幅提升,沒必要動不動就Touch底層。
⑥ 求《深入理解Android卷1》全文免費下載百度網盤資源,謝謝~
《深入理解Android卷1》網路網盤pdf最新全集下載:
鏈接:https://pan..com/s/1gi-_FG90fh2sfWnkAphZnw
簡介: 這是一本以情景方式對Android的源代碼進行深入分析的書。內容廣泛,以對Framework層的分析為主,兼顧Native層和Application層;分析深入,每一部分源代碼的分析都力求透徹;針對性強,注重實際應用開發需求,書中所涵蓋的知識點都是Android應用開發者和系統開發者需要重點掌握的。
⑦ Android啟動過程深入解析
當按下Android設備電源鍵時究竟發生了什麼?
Android的啟動過程是怎麼樣的?
什麼是Linux內核?
桌面系統linux內核與Android系統linux內核有什麼區別?
什麼是引導裝載程序?
什麼是Zygote?
什麼是X86以及ARM linux?
什麼是init.rc?
什麼是系統服務?
當我們想到Android啟動過程時,腦海中總是冒出很多疑問。本文將介紹Android的啟動過程,希望能幫助你找到上面這些問題的答案。
Android是一個基於Linux的開源操作系統。x86(x86是一系列的基於intel 8086 CPU的計算機微處理器指令集架構)是linux內核部署最常見的系統。然而,所有的Android設備都是運行在ARM處理器(ARM 源自進階精簡指令集機器,源自ARM架構)上,除了英特爾的Xolo設備(http://xolo.in/xolo-x900-features)。Xolo來源自凌動1.6GHz x86處理器。Android設備或者嵌入設備或者基於linux的ARM設備的啟動過程與桌面版本相比稍微有些差別。這篇文章中,我將解釋Android設備的啟動過程。深入linux啟動過程是一篇講桌面linux啟動過程的好文。
當你按下電源開關後Android設備執行了以下步驟。
此處圖片中step2中的一個單詞拼寫錯了,Boot Loaeder應該為Boot Loader(多謝@jameslast 提醒)
第一步:啟動電源以及系統啟動
當電源按下,引導晶元代碼開始從預定義的地方(固化在ROM)開始執行。載入引導程序到RAM,然後執行。
第二步:引導程序
引導程序是在Android操作系統開始運行前的一個小程序。引導程序是運行的第一個程序,因此它是針對特定的主板與晶元的。設備製造商要麼使用很受歡迎的引導程序比如redboot、uboot、qi bootloader或者開發自己的引導程序,它不是Android操作系統的一部分。引導程序是OEM廠商或者運營商加鎖和限制的地方。
引導程序分兩個階段執行。第一個階段,檢測外部的RAM以及載入對第二階段有用的程序;第二階段,引導程序設置網路、內存等等。這些對於運行內核是必要的,為了達到特殊的目標,引導程序可以根據配置參數或者輸入數據設置內核。
Android引導程序可以在找到。
傳統的載入器包含的個文件,需要在這里說明:
init.s初始化堆棧,清零BBS段,調用main.c的_main()函數;
main.c初始化硬體(鬧鍾、主板、鍵盤、控制台),創建linux標簽。
更多關於Android引導程序的可以在這里了解。
第三步:內核
Android內核與桌面linux內核啟動的方式差不多。內核啟動時,設置緩存、被保護存儲器、計劃列表,載入驅動。當內核完成系統設置,它首先在系統文件中尋找」init」文件,然後啟動root進程或者系統的第一個進程。
第四步:init進程
init是第一個進程,我們可以說它是root進程或者說有進程的父進程。init進程有兩個責任,一是掛載目錄,比如/sys、/dev、/proc,二是運行init.rc腳本。
init進程可以在/system/core/init找到。
init.rc文件可以在/system/core/rootdir/init.rc找到。
readme.txt可以在/system/core/init/readme.txt找到。
對於init.rc文件,Android中有特定的格式以及規則。在Android中,我們叫做Android初始化語言。
Action(動作):動作是以命令流程命名的,有一個觸發器決定動作是否發生。
語法
1
2
3
4
5
; html-script: false ]
on <trigger>
<command>
<command>
<command>
Service(服務):服務是init進程啟動的程序、當服務退出時init進程會視情況重啟服務。
語法
1
2
3
4
5
; html-script: false ]
service <name> <pathname> [<argument>]*
<option>
<option>
...
Options(選項)
選項是對服務的描述。它們影響init進程如何以及何時啟動服務。
咱們來看看默認的init.rc文件。這里我只列出了主要的事件以及服務。
Table
Action/Service
描述
on early-init
設置init進程以及它創建的子進程的優先順序,設置init進程的安全環境
on init
設置全局環境,為cpu accounting創建cgroup(資源控制)掛載點
on fs
掛載mtd分區
on post-fs
改變系統目錄的訪問許可權
on post-fs-data
改變/data目錄以及它的子目錄的訪問許可權
on boot
基本網路的初始化,內存管理等等
service servicemanager
啟動系統管理器管理所有的本地服務,比如位置、音頻、Shared preference等等…
service zygote
啟動zygote作為應用進程
在這個階段你可以在設備的屏幕上看到「Android」logo了。
第五步
在Java中,我們知道不同的虛擬機實例會為不同的應用分配不同的內存。假如Android應用應該盡可能快地啟動,但如果Android系統為每一個應用啟動不同的Dalvik虛擬機實例,就會消耗大量的內存以及時間。因此,為了克服這個問題,Android系統創造了」Zygote」。Zygote讓Dalvik虛擬機共享代碼、低內存佔用以及最小的啟動時間成為可能。Zygote是一個虛擬器進程,正如我們在前一個步驟所說的在系統引導的時候啟動。Zygote預載入以及初始化核心庫類。通常,這些核心類一般是只讀的,也是Android SDK或者核心框架的一部分。在Java虛擬機中,每一個實例都有它自己的核心庫類文件和堆對象的拷貝。
Zygote載入進程
載入ZygoteInit類,源代碼:/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
registerZygoteSocket()為zygote命令連接注冊一個伺服器套接字。
preloadClassed 「preloaded-classes」是一個簡單的包含一系列需要預載入類的文本文件,你可以在/frameworks/base找到「preloaded-classes」文件。
preloadResources() preloadResources也意味著本地主題、布局以及android.R文件中包含的所有東西都會用這個方法載入。
在這個階段,你可以看到啟動動畫。
第六步:系統服務或服務
完成了上面幾步之後,運行環境請求Zygote運行系統服務。系統服務同時使用native以及java編寫,系統服務可以認為是一個進程。同一個系統服務在Android SDK可以以System Services形式獲得。系統服務包含了所有的System Services。
Zygote創建新的進程去啟動系統服務。你可以在ZygoteInit類的」startSystemServer」方法中找到源代碼。
核心服務:
啟動電源管理器;
創建Activity管理器;
啟動電話注冊;
啟動包管理器;
設置Activity管理服務為系統進程;
啟動上下文管理器;
啟動系統Context Providers;
啟動電池服務;
啟動定時管理器;
啟動感測服務;
啟動窗口管理器;
啟動藍牙服務;
啟動掛載服務。
其他服務:
啟動狀態欄服務;
啟動硬體服務;
啟動網路狀態服務;
啟動網路連接服務;
啟動通知管理器;
啟動設備存儲監視服務;
啟動定位管理器;
啟動搜索服務;
啟動剪切板服務;
啟動登記服務;
啟動壁紙服務;
啟動音頻服務;
啟動耳機監聽;
啟動AdbSettingsObserver(處理adb命令)。
第七步:引導完成
一旦系統服務在內存中跑起來了,Android就完成了引導過程。在這個時候「ACTION_BOOT_COMPLETED」開機啟動廣播就會發出去。
⑧ 如何深入學習android
就是多做項目,在做項目中你會遇到各種問題,各種需求。就會自動提升自己的能力。
⑨ 《深入理解Android:WiFi,NFC和GPS卷》pdf下載在線閱讀全文,求百度網盤雲資源
《深入理解Android:WiFi,NFC和GPS卷》網路網盤pdf最新全集下載:
鏈接:https://pan..com/s/1inU9q9tp3SkEq9LSo87w7Q
簡介:本書從實際應用的需求出發,適合所有Android系統工程師、Android應用開發工程師和BSP開發工程師閱讀。本書是經典暢銷書「深入理解Android」系列的新作,由資深Android系統專家鄧凡平先生撰寫,全志和高通等公司資深專家擔任技術審校並強烈推薦。從通信專業知識和Android系統代碼實現的角度,對Netd、Wi-Fi、NFC和GPS等模塊的代碼進行深入的剖析,旨在深刻揭示其實現原理和工作流程。其中涉及大量通信相關的專業知識,因此特意邀請全志和高通等著名晶元公司的資深專家擔任技術審校。