[android]深入理解findViewById原理
用的太多了,但是不知道原理。Xutils裡面捨棄了findViewById改用註解,當時也很不理解。一步步瞭解後,發現,相比註解的方式載入控制項,findViewById的效率是很低的。註解+反射載入執行個體的過程看上去效率更高。
從activity的onCreate()裡開始:
點進去看源碼進入Activity.class類裡的方法:
Activity.class
發現這個返回的是getWindow()的findViewById方法,這個getWindow()是什嗎?
Activity.class
返回的是一個Window對象,Window是個抽象類別,包含的抽象方法可以管理Activity的UI組件,先這麼理解,這次主要理解findViewById的原理。
既然Activity的findViewById,是調用getWindow()(即Window對象)的findViewById方法,進入Window尋找它的findViewById。
Window.class
返回的是getDecorView()的findViewById,前面說Window是個抽象類別,不能具體實現管理ActivityUI組件的方法,那麼這個getDecorView()就是返回的是一個具體的View對象,來管理Activity的UI組件。
這個getDecorView是個抽象類別,實現這個類,返回的View可以用來管理UI視圖。
然後Activity的findViewById方法,又通過getDecorView()(返回View)一步一步傳入到View的findViewById了。下面是View類。
View.class
邏輯很簡單了,直接調用findViewTraversal(),用mID跟傳入的id對比,如果存在就返回當前view,不存在就返回null。findViewTraversal從字面上理解,這個方法的意思是反覆尋找view的ID。
到這裡我有點沒有頭緒了,憑感覺,尋找mID應該是不斷+1比較,如果是ViewGroup,裡面還有View的話,還應該是一個遞迴的過程,從這裡看不出來。所以我看是找mID是如何設定的。
這是一個set方法,給子view控制項添加ID,用來標識view。這個ID可以在R檔案裡看到。
先把id給了mID,如果mID為空白(就是沒有加ID呢),而且不是作為標籤(不太懂),那麼就給他加一個ID,動態產生控制項的ID。
一個固定地址開始,一個一個找ID,設定的ID值似乎連續的。然後在後面的尋找中,找遞迴,找迴圈。。沒有找到類似的代碼。
看上去,要知道mID才能知道答案。但是這樣分析下去得不到結果。
原因:
請看LinearLayout,RelativeLayout等等layout的繼承結構:
在ViewGroup中,已經對View的findViewTraversal()方法進行重寫了!
點進去找很快找到答案。
這個是重寫的方法:可以非常清楚的看到,findViewById的原理,是從頭開始找,遇到有子控制項的,就遞迴接著找。先不考慮具體細節,到這裡,開始的猜想得到了證實。其中v.findViewById又調用View中的方法,而View的findViewById調用的findViewTraversal()。這樣實現了一個遞迴。
尊重作者註明出處:http://blog.csdn.net/bless2015/article/details/46618639
我在找findViewById的過程中,由於開始忽略子類ViewGroup對View方法的重寫,導致在View.class萬行代碼中陷入死迴圈,找不到想看到的方法。但是還是找到一些有趣的東西,有時間再整理下來。