讀老羅的安卓之旅這本書的一些筆記及個人的理解

安卓開發積累了一段時間之後,對於常用的技術有一定的瞭解和理解。但做技術不能只是浮於表面,還應該深入的理解他們的原理。當前的移動開發再也不是你會你就有機會,而是要求你懂得更多,理解得更深。這裏是一篇看了 老羅的安卓之旅 這本書的讀書筆記,以及個人的一些想法,可能對於有些知識點理解還是不夠深刻,權做一個記錄,在以後重讀這本書的時候繼續做修正。


一:對於安卓框架的認識

      安卓這個系統的框架,大家都知道分爲這樣幾層(從上到下):應用層,framework層,運行時和擴展庫,硬件抽象層HAL(老羅把前邊的幾層分爲運行在用戶空間中的幾層),linux內核(進程的管理,內存的管理等,老羅把這層分爲運行在內核空間)。我們所做的應用開發絕大多數都是在應用層去做,當然使用的api肯定是基於framework層或者是更底層的。當然這裏說的就是我們做應用開發只是在這個系統上使用系統給我們提供的一些工具讓我們來實現產品需求這一系列的功能。(這個架構的認識最基本,理應有這個概念)


二:對安卓底層誇進程通信機制的理解

      安卓框架底層跨進程通信機制使用最多的是Binder技術。binder技術是基於共享內核內存實現的,相對其他跨進程通信方式,優點是只需要做一次數據拷貝,然後做地址映射。更加安全。binder技術的架構分爲這樣幾個部分:Client端, Server端, SystemManager(這三個部分是運行在用戶空間),binder驅動(運行在內核空間)。網上有這樣的一個比喻比較貼切: Client端郵寄包裹到Server端,首先Client端會把包裹發送給快遞公司(Binder驅動), 快遞公司就會去系統中查找(這個系統就是SystemManager,每一個Server端都會把服務註冊到SystemManager當中來,如果server端的服務沒有找到,SystemManager就會要求啓動Server端的服務,然後註冊到SystemManager當中來,SystemManager就會持有Server端的一個Binder代理),並且找到Server端。然後完成Client端的通信的消息到Server端。這就是一個簡單的Binder的通信,Binder跨進程通信技術傳遞數據的方式使用parcelable接口,並不是我們在網絡框架中使用比較頻繁的Serializable接口。


三:安卓應用啓動的入口及消息機制

     安卓系統使用的是Java語言,在寫java例子的時候入口是靜態的mian()方法,在安卓這裏邊的入口就是ActivityThread類的main()方法, ActivityThread是一個final的java類,在main方法中執行的東西比較簡單,但是在ActivityThread這個類中持有的屬性及其他方法還是很複雜的,至少你去看方法參數的個數還是讓人生畏的。不過沒關係,在main方法中代碼非常簡單,做了幾件事:創建了一個ActivityThread對象,調用attach方法(當然這個的方法裏邊就做了很多的事情,創建ApplicationThread這個binder,然後會將這個binder傳遞到ActivityManagerService當中去,發出啓動第一個Activity的消息,由H中進程處理),然後創建Looper,啓動looper的loop方法,循環消息。安卓當中涉及到UI的更新都是只能在主線程中執行的(因爲這個操作不是線程安全的,線程安全就是由於共享數據時,多個線程的操作導致數據結果不一致),多線程之間的通信使用的最多的是Handler,Handler技術就是擁有這種能力可以向主線程中的消息隊列發送消息。關於Handler的創建(一般創建就是在主線程中,如果在子線程中創建沒有沒有創建looper的法就會報錯),會關聯到當前線程的looper和消息隊列,可以參看Handler的源碼去分析一下他們之間的關係,有這樣的一個概念之後就發現跨線程通信這麼簡單,再去看EventBus 和 RxAndroid當中實現指定線程執行是多麼簡單。就是使用handler啊。


三:四大組件及進程相關

      安卓當中四大組件在一開始接觸安卓時就已經知道了,當然這也是面試過程中必問的一個問題。你可以答得很簡單也可以分析得很深入。這個就看個人對安卓整體框架及四大組件的理解了。

     Activity,可以給用戶展示出來看的嘛。的確,activity就是幹這個的,就如同咱們程序員就是寫代碼的不是修電腦和修手機的(開玩笑啦,其實副業還是可以去修電腦和修手機的哈)。activity的生命週期大家肯定都知道,7個生命週期的方法,你也知道activity頁面被完全覆蓋之後會走暫停,然後新頁面走生命週期的方法,最後頁面纔會走停止方法。如果是深入一點,爲什麼有暫停和停止兩個方法。而不是一個方法,可以研究一下。Activity的啓動模式以及應用的場景。生命週期onRestart 走完之後會再走哪個生命週期的方法,newIntent()方法之後再走哪個生命週期的方法,onActivityResult()之後呢?

        activity的那些簡單的東西大家都知道,如何去啓動一個Activity的使用,大家也知道。但是在activity的啓動過程是怎樣的,底層做了那些事情,這個還是有必要去做一下了解和理解的。手機桌面去啓動一個應用也是通過調用StartActivity這種方式去啓動一個activity的。首先啓動一個activity,當前進程會跟ActivityManagerService進行通信,這是兩個進程,就涉及到binder跨進程通信,ActivityManagerService接收到這個消息之後,會通知當前進程暫停頁面的活動。然後去檢查啓動的這個activity所在的這個進程有沒有啓動,如果沒有啓動那麼就從Zygote進程fork一個新進程,然後設置相應的參數。然後去啓動這個進程的ActivityThread,然後在去啓動這個activity。啓動一個Activity,需要當前進程與Ams Wms Sm等系統進程之間進行通信,然後纔會創建一個頁面。(當然我上邊說的太簡單了,詳細的可以去拜讀老羅的安卓之旅,看看大神給我們分析的啓動Activity的35個步驟,膜拜一下)。安卓系統會給我們提供一個任務棧,每啓動一個應用,系統就會創建一個任務,然後在安卓系統中就會把這個任務壓入這個任務棧當中。可以通過adb 命令去查看當前系統啓動的那些任務,每個任務當中有哪些頁面 adb shell dumpsys activity. 可以看到棧底的應用就是luancher。一個任務中可以包含多個activity,即使這些activity的進程不是同一個。東西還是不少,當然activity其他生命週期也是通過當前進程與AMS服務進行通信來完成回調當前進程顯示頁面的生命週期的方法的。


       Service ,不需要給用戶展示,完成的工作。service的分類就有兩種service,普通的service和intentService.  intentService是繼承Service來完成的,不過是單開了線程而已。service的啓動方式大家也肯定知道,有兩種,正常啓動和綁定啓動。這些基本的東西就不說了。大家肯定是非常熟悉。那麼如何去啓動一個service呢?啓動的過程與啓動一個activity的過程類似(分了19個步驟,再膜拜一下),啓動過程也是當前進程與Ams,及Sm之間的跨進程通信來完成的。當然這樣分析太簡單了,都沒有深入嘛。確實,每一步做了什麼涉及到的東西太多了。還是推薦再去拜讀老羅的安卓之旅。啓動的Activity 以及Service 和 ContentProvider 都會在ActivityThread中存起來,以便以後調用。


      broadCast 廣播,兩種實現形式。靜態和動態。你肯定比我清楚多。當系統發出一個廣播時,就會去查找有哪些廣播接受者(這裏的接受者只是靜態註冊的和已經啓動的動態註冊的廣播接受者)。如果靜態註冊的廣播的進程沒有沒有啓動,那麼就會通知AMS去啓動這個進程,再去創建這個廣播的接受者。大家都知道四大組件的創建都是在主線程中創建的(所以你也知道handler在activity中創建,就是默認在主線程中創建的),在廣播接受者當中不能執行太長事件的動作,否則就會報ANR,這個ANR是如何產生的呢?看源碼可以分析得到,在處理每一個廣播時 系統都會通過handler發用一個延遲啓動的超時消息,如果廣播接受者在這個超時消息處理之前就完成了,那麼就會取消消息隊列中的這個超時消息,如果沒有在規定時間(10秒)內完成,那麼系統處理這個消息之後就會報ANR.  看看這個ANR的消息的發生就是這樣的一個簡單過程,使用的技術也是咱們在平時使用最多的handler發送消息的技術。


    ContentProvider,內容提供者。無論是對當前進程還是對其他進程提供數據的。在清單文件中配置contentprovider是否支持多進程,具體參數是mutiprocess,如果爲true,那麼每個使用到這個contentprovider的進程都會創建一個contentprovider對象並保存到當前進程中來,如果設置爲false,那麼各個使用到這個contentprovider的進程會共享一個進程,而這個進程就是contentprovider創建的這個進程。涉及到contentprovider 的創建,也會是當前進程與ActivityManagerService ContentService等各個進程的通信。大家也肯定使用觀察者模式,就是被觀察者會持有一個存放觀察者的容器,當被觀察者的某個事件被觸發時 就會通知各個觀察者。這是一個簡單的設計模式。在contentprovider中就有涉及。我們在監聽某個數據的改變,會用loadcallback 或者是使用到contentObserver(底層實現loadcallback也是使用的ContentObserver),然後通過getContentResolver().registerContentObserver()將觀察者註冊到被觀察者的容器中,在Rerolver中保存的各個觀察者是以列表的形式存放各種數據的監聽的觀察者,以樹的保存形式來存放同一類型數據的觀察者。然後在contentprovider中對數據庫的insert  update  delete這樣的操作就會通知各個監聽各個數據的變化的觀察者。使用的技術很簡單,就是一種觀察者模式,但是在開發過程中,可能沒有注意這裏就是已經使用到了這些模式。


   四大組件是安卓系統爲用戶提供基本功能的四類工具。整體來看,整個安卓系統就是一個工具,可以來操縱硬件,當然安卓系統這個工具當中也提供了四大組件這些工具,來共開發者使用。我們開發出來的應用也只是去表現一系列的數據的這樣的工具而已啦。其實都是使用工具的過程和創造工具的過程。


四:關於linux啓動之後啓動的幾個系統級進程

      這個層次很深,現在想講這個,對於我整體的知識積累及知識的系統架構,肯定是相差很遠很遠。

     不過大體上我知道知道存在這樣幾個步驟:

      linux系統啓動,會啓動這樣幾個進程 zygote 進程,然後由zygote進程啓動System進程。由System進程啓動ActivityManagerService進程 WindowManagerService 進程,ContentService進程,PackageManagerService進程等。在啓動這些進程之後 這些服務進程都會向SystemManager進程進行註冊。這時候使用到的進程之間的通信有Socket 通信 也有Binder通信。

    系統服務進程啓動之後,packageManagerService就會去查找當前已經安裝那些應用,會從五個地方去查找(參考於老羅的安卓之旅):/system/framework、/system/app、/vendor/app (供應商APP)、 /data/app、 /data/app-private(受DRM保護的私有應用APP) ,packageManagerService回去解析每個應用的清單文件。

   啓動應用時那就是涉及到AMS 及 PMS之間的跨進程通信了。


五:安卓系統整體 及以後再看書的期望

      不只是安卓系統,其實應該說是每一個系統都是有很多的東西組成。這可不是短時間內就能學到和掌握的。所以在開發過程中需要的是持續的堅持和敢於探索的勇氣。

      老羅的博客在以前看時發現絕大部分看不懂,那的確是當時太low了(當然現在也還是low).現在再去看發現有些東西能看懂了。當然着都是需要一個積累過程。個人覺得老羅的書會比博客更詳細些,可能是對書的偏見。如果大家能讀這本書的法,還是非常建議的。當你拿上這本厚厚的書有看下去的勇氣和堅持時,你會發現就有些東西變得從容了。大家都不是在這個過程當中麼。

   


 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章