在網上看見View.findViewById() 和 Activity.findViewById()執行效率不一樣
使用Activity.findViewById()如:
TextView tv_inner_1 = (TextView)this.findViewById(R.id.tv_inner_1); TextView tv_inner_2 = (TextView)this.findViewById(R.id.tv_inner_2);
使用View.findViewById() 如:
View layout_outer = this.findViewById(R.id.layout_outer); TextView tv_inner_1 = (TextView)layout_outer.findViewById(R.id.tv_inner_1); TextView tv_inner_2 = (TextView)layout_outer.findViewById(R.id.tv_inner_2);
他們都是針對下面同一個xml
<LinearLayout> <LinearLayout id="@+id/layout_outer"> <TextView id="@+id/tv_inner_1"/> <TextView id="@+id/tv_inner_2"/> </LinearLayout> </LinearLayout>
自從學習android的hello world開始
我們就知道了這樣一個函式findViewById(),他已經成為了家喻戶曉,坑蒙拐騙,殺人越貨必備的一個函式(好吧,這句是扯淡)
但一直用也沒細緻研究過它,直到寫程式的時候發現一個由這個函式引起的一個莫名其妙的bug,遂決定好好研究下次函式~
我們呼叫的findViewById()函式其實有兩種(目前我只看到兩種,不確定還有沒有其他的),一種是Activity類中findViewById()函式
另外一種是View類中定義的findViewById()函式
一般我們在oncreate()方法中使用的(**view)findViewById(R.id.**)既是呼叫的Activity中的findViewById()函式
而在其他情況寫出的***view.findViewById()中呼叫的是view類中的findViewById()
分別看一下原始碼中的實現方法及介紹
Activity類中定義的findViewById()
/** * Finds a view that was identified by the id attribute from the XML that * was processed in {@link #onCreate}. * * @return The view if found or null otherwise. */ public View findViewById(int id) { return getWindow().findViewById(id); } /** * Retrieve the current {@link android.view.Window} for the activity. * This can be used to directly access parts of the Window API that * are not available through Activity/Screen. * * @return Window The current window, or null if the activity is not * visual. */ public Window getWindow() { return mWindow; }
這裡可以看出這個函式是在尋找在xml中定義的指定id的物件
View類中的findViewById()
/** * Look for a child view with the given id. If this view has the given * id, return this view. * * @param id The id to search for. * @return The view that has the given id in the hierarchy or null */ public final View findViewById(int id) { if (id < 0) { return null; } return findViewTraversal(id); /** * {@hide} * @param id the id of the view to be found * @return the view of the specified id, null if cannot be found */ protected View findViewTraversal(int id) { if (id == mID) { return this; } return null; }
從這裡可以看出我們是從一個view的child view中尋找指定id的物件,所以即使幾個layout的XML檔案中的View的id號相同的話,只要他們沒有相同的父節點,或有相同的父親節點,但不在父節點及以上節點呼叫findViewById通過id來查詢他們就是沒有問題。(這句引用自這裡http://www.2cto.com/kf/201204/127404.html)
使用這個函式的常見問題:
1.既然Activity中的findViewById()是從R.java中尋找東西,那麼我們就要杜絕相同名字的控制元件
今天自己的bug就是因為這個產生的
說到控制元件的命名,今天還有一個小發現
仔細看下邊兩段程式碼程式碼
< ?xml version="1.0" encoding="utf-8"?> < LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/LinearLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > < /LinearLayout>
< ?xml version="1.0" encoding="utf-8"?> < LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > < /LinearLayout>
一段裡邊Layout沒有id這個引數,一段裡邊有id,雖然程式碼不同但在outline中顯示出來都是
這樣在第一種情況下R.id中可以找到LinearLayout這個控制元件,第二種是沒有的哈,這些也是以後要注意的細節
2.在呼叫view中的findViewById()一定要想好父View是誰!即**view.findViewById()中的**view要找對,如果沒有找對父View,返回基本都是null了