如何快速閱讀並分析Android原始碼
很多時候為了解決一個問題必須先理解Android系統的執行原理,這時候就得閱讀應用層框架的原始碼。學會閱讀系統原始碼或者他人的程式碼,這是研發必備的技能之一,只有瞭解別人寫的東西才能在他之上更好的行事,同時也能去學習和借鑑他人優秀的程式碼思想。
那麼,如何閱讀並分析Android原始碼呢?
這裡我只講一些初級的、基礎的方法,很快就可以上手,不需要下載和編譯系統原始碼。
我們下載Android SDK的時候一般都會下載相應版本的原始碼(sdk/sources目錄下),在AS(Android Studio)上追蹤系統程式碼時會自動開啟原始碼檔案,如果沒有原始碼則會提示下載:
系統的原始碼一般多且複雜,雖然有不少註釋,但如果純靠閱讀去理解會相當吃力,很難把握整體流程。我們需要結合實際使用場景,通過debug去分析程式碼的執行邏輯。那麼SDK的版本有那麼多,應該檢視哪個版本的原始碼呢?這個根據需要,如果要檢視最新7.0的原始碼就檢視相應的。如果沒有指定的版本,一般你開啟的SDK自帶的虛擬機器的版本是多少就檢視相應版本的程式碼。我們可以通過在專案build.gradle檔案裡面配置compileSdkVersion為指定的版本
例如,一般情況下,我使用版本22的虛擬機器:
接著把專案的compileSdkVersion配置為22:
android {
compileSdkVersion 22
buildToolsVersion "22.0.0"
...
}
然後在AS上追蹤系統程式碼,或者通過雙擊shift鍵,輸入需要查詢的系統類:
我們可以看到這時候的原始碼版本都是android-22。
接下來我們就要根據使用場景,尋找一個入口的地方,打一個斷點,同時在其他覺得可疑的關鍵地方也打入斷點,進入debug模式,這樣邏輯就會在斷點的地方停止,這時候就可以檢視程式碼的執行邏輯,藉助AS強大的debug功能分析程式碼。debug一定要有耐心,而且要多嘗試設定可疑斷點,讓程式碼在關鍵地方停止。多運用幾次就可以快速閱讀和分析系統原始碼,明白其中的程式碼邏輯。
這裡給個建議,一開始只需要把握某一個功能的整體程式碼邏輯,設定幾個關鍵斷點,通過斷點閱讀程式碼,不要深入細節無法自拔。等理解了整體邏輯之後,再考慮從細節地方入手,一句句程式碼debug下去。
最後,我們通過一個實際場景運用上面的方法去分析"View的OnClickListener.onClick()方法是怎樣被觸發的"。
首先新建一個專案,build.gradle裡的配置如下:
android {
compileSdkVersion 22
...
}
建立一個頁面,裡面存在一個按鈕,設定了OnClickListener,啟動自帶的api版本為22的虛擬機器,執行專案,效果如下:
那麼接下來debug從哪裡入手呢?我們並不知道OnClickListener在哪裡被回撥,因此並不能預先在系統程式碼裡打斷點。這裡我們可以觀察呼叫view.setOnClickListener()的程式碼,然後檢視OnClickListener物件儲存在哪,什麼時候呼叫,然後在關鍵地方打入斷點。但其實還有更簡單的方法,我們採用逆向思維,直接在OnClikcListener.onClick()方法裡面打入斷點:
進入debug模式:
點選按鈕,然後程式碼會執行到斷點的地方,這個時候我們檢視左下角呼叫棧:
可以看到onClick方法是被View.performClick()方法呼叫,繼續下檢視呼叫棧發現performClick方法又是在PerformClick物件中執行:
PerformClick物件實現了Runnable,run()方法是在主執行緒訊息佇列執行的,所以接下來我們需要在View的原始碼裡追蹤程式碼,藉助AS強大的功能檢視PerformClick物件哪裡被建立和被呼叫:
從上面可以看出關鍵地方,PerformClick在View.onTouchEvent()方法被呼叫。想必接下來要分析"View的OnClickListener.onClick()方法是怎樣被觸發的"這個問題就知道如何下手了,比如我們可以在View.onTouchEvent()打入斷點,一步步程式碼檢視具體的程式碼邏輯:
整個的過程大概就這樣,當然不同問題要靈活處理,重要的是多實踐多操作,就會得出一套自己解決問題的方法。