現建立了一個Android開發水友圈,圈內會不定時更新一些Android中高級的進階資料,歡迎你們帶着技術問題來討論,共同成長進步!(包含資深UI工程師,Android底層開發工程師,Android架構師,原生性能優化及混合優化,flutter專精);但願有技術的大佬加入,水圈內解決的問題越多得到的權利越大!
1. mvc mvp mvvm三種架構模式java
Android系統架構分爲5層,從下到上依次爲 Linux內核層,硬件抽象層,系統運行庫層(Native),應用框架層,應用層。android
1.)傳統的IPC通訊方式算法
Android系統是基於Linux內核的,Linux提供了管道、消息隊列、共享內存和socket等IPC機制。那爲何Android還要提供Binder來實現IPC呢?主要是基於性能、穩定性和安全性方面的考慮。數據庫
性能:socket做爲通用接口,傳輸效率低,開銷大,主要用到跨網絡進程通訊。消息隊列、共享內存和管道採用存儲-轉發模式,數據拷貝至少須要兩次,共享內存雖然無需拷貝,可是控制複雜,難以使用。而binder只須要拷貝一次,性能上只次於共享內存。緩存
穩定性:Binder 基於 C/S 架構,客戶端(Client)有什麼需求就丟給服務端(Server)去完成,架構清晰、職責明確又相互獨立,天然穩定性更好。安全
安全性:Android 爲每一個安裝好的 APP 分配了本身的 UID,故而進程的 UID 是鑑別進程身份的重要標誌。傳統的 IPC 只能由用戶在數據包中填入 UID/PID,但這樣不可靠,容易被惡意程序利用。可靠的身份標識只有由 IPC 機制在內核中添加。其次傳統的 IPC 訪問接入點是開放的,只要知道這些接入點的程序均可以和對端創建鏈接,無論怎樣都沒法阻止惡意程序經過猜想接收方地址得到鏈接。性能優化
2.)傳統IPC通訊原理網絡
一般的作法是消息發送方將要發送的數據存放在內存緩存區中,經過系統調用進入內核態。而後內核程序在內核空間分配內存,開闢一塊內核緩存區,調用 copy_from_user() 函數將數據從用戶空間的內存緩存區拷貝到內核空間的內核緩存區中。一樣的,接收方進程在接收數據時在本身的用戶空間開闢一塊內存緩存區,而後內核程序調用 copy_to_user() 函數將數據從內核緩存區拷貝到接收進程的內存緩存區。這樣數據發送方進程和數據接收方進程就完成了一次數據傳輸,咱們稱完成了一次進程間通訊。多線程
一次數據傳遞須要經歷:內存緩存區 --> 內核緩存區 --> 內存緩存區,須要 2 次數據拷貝架構
接收數據的緩存區由數據接收進程提供,可是接收進程並不知道須要多大的空間來存放將要傳遞過來的數據,所以只能開闢儘量大的內存空間或者先調用 API 接收消息頭來獲取消息體的大小,這兩種作法不是浪費空間就是浪費時間。
3.)Binder IPC實現
Binder IPC 機制中涉及到的內存映射經過 mmap() 來實現,mmap() 是操做系統中一種內存映射的方法。內存映射簡單的講就是將用戶空間的一塊內存區域映射到內核空間。映射關係創建後,用戶對這塊內存區域的修改能夠直接反應到內核空間;反以內核空間對這段區域的修改也能直接反應到用戶空間。
synchronized
在用法上,它是java的關鍵字,通常咱們不太須要關注他的鎖的釋放,代碼執行完畢或者報錯會自動釋放鎖,而且沒法判斷鎖的狀態。
lock
是一個接口,咱們使用ReentrantLock 比較多,有多個獲取鎖的方式,能夠trylock直接返回獲取成功或者失敗,線程不用一直等待。在finally中必需要釋放該鎖。
爲何要有事件分發
Android中的view是樹形結構的,view可能會重疊在一塊兒,當咱們點擊的地方有多個view的時候,這個時間該給誰,這就是爲何要有事件分發。
先來看看view的樹形結構:
上面多出來兩個東西是phonewindow和decorview,其中,主題顏色和標題欄內容等主要就是decorview來負責顯示的,那PhoneWindow是作什麼的呢?
PhoneWindow 繼承window,而且是window惟一的實現類,window是一個抽象類,是全部視圖的最頂層容器,視圖的外觀和行爲都歸他管,不管是背景顯示,標題欄仍是事件處理都是他管理的範疇,它其實就像是View界的太上皇。
`DecorView` 是 `PhoneWindow` 的一個內部類,其職位至關於小太監,就是跟在 `PhoneWindow` 身邊專業爲 `PhoneWindow` 服務的,除了本身要幹活以外,也負責消息的傳遞,`PhoneWindow` 的指示經過 `DecorView` 傳遞給下面的 View,而下面 View 的信息也經過 `DecorView` 回傳給 `PhoneWindow`
事件分發、攔截、消費
類型 相關方法 Activity ViewGroup View 事件分發 dispatchTouchEvent √ √ √ 事件攔截 onInterceptTouchEvent X √ X 事件消費 onTouchEvent √ √ √
Activity做爲原始的事件分發者,不須要攔截事件,若是須要這個事件不分發下去就好了。
一樣的,view在事件傳遞的最末端,也不須要攔截事件,不處理回傳回去就好了。
事件在收集以後最早傳遞給Activity,而後依次向下傳遞:
Activity -> PhoneWindow -> DectorView -> ViewGroup -> ... -> view
若是沒有任何View消費掉事件,那麼這個事件會按照反方向回傳,最終傳回給Activity,若是最後 Activity 也沒有處理,本次事件纔會被拋棄 :
Activity <- PhoneWindow <- DecorView <- ViewGroup <- ... <- View
上面的模式是一個很是經典的責任鏈模式
注:參考連接
在activity的attach方法裏面,會建立一個PhoneWindow。
在onCreate中調用setContentView,setContentView是window的一個抽象方法,真正實現類是PhoneWindow:
@Override public void setContentView(int layoutResID) { if (mContentParent == null) { //1.初始化 //建立DecorView對象和mContentParent對象 ,並將mContentParent關聯到DecorView上 installDecor(); } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) { mContentParent.removeAllViews();//Activity轉場動畫相關 } //2.填充Layout if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) { final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID, getContext()); transitionTo(newScene);//Activity轉場動畫相關 } else { //將Activity設置的佈局文件,加載到mContentParent中 mLayoutInflater.inflate(layoutResID, mContentParent); } //讓DecorView的內容區域延伸到systemUi下方,防止在擴展時被覆蓋,達到全屏、沉浸等不一樣體驗效果。 mContentParent.requestApplyInsets(); //3. 通知Activity佈局改變 final Callback cb = getCallback(); if (cb != null && !isDestroyed()) { //觸發Activity的onContentChanged方法 cb.onContentChanged(); } mContentParentExplicitlySet = true; }
核心方法就兩個:installDecor() 和 mLayoutInflater.inflate(layoutResID, mContentParent) ;
installDecor會建立一個DecorView 對象,該對象將做爲整個應用窗口的根視圖。而後配置不一樣窗口修飾屬性(style theme等)。
mLayoutInflater.inflate就是解析xml,深度優先地遞歸解析xml,一層層添加到root view上,最終返回root view.解析的部分大體包含兩點:1.解析出View對象,2.解析View對應的Params,並設置給View。
有四種狀況會形成ANR發生:
如何避免:
儘可能避免在主線程中作耗時操做。 多線程==>引出如何實現多線程,線程池的使用
如何分析ANR:
flutter
一步手機的刷新率爲60hz,當一幀圖像繪製完畢後準備繪製下一幀時,顯示器會發出一個垂直同步信號(如VSync), 60Hz的屏幕就會一秒內發出 60次這樣的信號。而這個信號主要是用於同步CPU、GPU和顯示器的。
通常地來講,計算機系統中,CPU、GPU和顯示器以一種特定的方式協做:CPU將計算好的顯示內容提交給 GPU,GPU渲染後放入幀緩衝區,而後視頻控制器按照同步信號從幀緩衝區取幀數據傳遞給顯示器顯示。