1. 程式人生 > >[Android個人理解(六)]使用include標籤的注意事項

[Android個人理解(六)]使用include標籤的注意事項

我們在使用include標籤時是為了提高部分程式碼的重用性,同時增加程式碼的層次性和條理性。
但是在我們實際使用的時候,往往就會由於include的屬性和include的原理不夠清楚,而產生bug。
1、首先,我們說明include標籤所在佈局檔案a和include所包含的佈局檔案b的關係
必須明確a和b通過使用include連線,與其說是包含,更像是拼接。Include不是View類,自然與其內的佈局物件,不是巢狀關係。
我們都清楚,我們可以將a中的include標籤刪去,直接複製貼上b的程式碼,這樣是可以的。但是我們在使用的時候往往會出現,無法直接根據id找到b下的元件或者在一些元件中比如DrawerLayout無法識別b的元件等問題,但這些我們都可以當做對include理解的煙霧。上述原因是系統通過include標籤識別xml檔案的機制由於繞了一個圈,自然會出現當某些部分被重寫後,直接呼叫的方法就失效的情況。(PS:個人理解,看不到include的原始碼,不知道include的具體實現)
2、然後由上,我們由拼接關係,我們就可以理解merge標籤的必要性。
是告訴系統b佈局檔案是include下的一個合法的佈局檔案,可以直接拼接,以使b檔案內的元件和a中include標籤所在的附近元件是平級關係。平級關係的目的是優化UI結構,減少結點冗餘。因為xml巢狀越多,系統需要遍歷的次數也就越多。
3、問題又來了,既然是拼接關係,那麼include的屬性的作用是什麼?
include的屬性的意義是重寫他包含的的根元件的屬性,不僅僅是id,更多的是重寫layout屬性。Android開發的官方網站的說明這樣提到:
“Similarly, you can override all the layout parameters. This means that any android:layout_* attribute can be used with the tag.”
意思是任何android:layout_*屬性都可以應用在標籤中。含義有兩層,一是必須同時過載layoutwidth和layoutheight熟悉,其他的layout_*屬性才會起作用,否這都會被忽略掉。另一層是隻能在include屬性寫layout_*屬性。因為還是上面的原因,include沒有實際意義,重寫的屬性的目的就是確定b佈局檔案的拼接位置。
同時我們也很容易明白,因為重寫了根佈局的屬性,b檔案下的根佈局的layout就不起作用了。
4、還是由上個問題,我們引出include標籤的id屬性。不僅僅如果include指定了id的話,就不能直接把它裡面的控制元件當成主xml中的控制元件來直接獲得了,必須先獲得這個xml佈局檔案,再通過佈局檔案findViewById來獲得其子控制元件。當沒有指定id的時候,只能直接this. findViewById來獲得其子控制元件。至於原因,我們還是歸因於對include下的佈局檔案的呼叫機制。

在實際運用中,我因為include出現過兩次bug,在這裡分享一下。
Bug1:DrawerLayout對內容佈局如果使用include標籤,但沒有宣告width和height屬性的話,元件不識別。這類似於對左抽屜和右抽屜的xml屬性要求大致相同,必須有android:layout_gravity=”start”和android:layout_width或者end一樣。
原始碼如下:

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" > <include layout="@layout/flame_layout" android:layout_width="match_parent" android:layout_height="match_parent" /> <LinearLayout android:id="@+id/left_drawer"
android:layout_width="240dp" android:layout_height="match_parent" android:layout_gravity="start" > <include layout="@layout/drawer_left" /> </LinearLayout> </android.support.v4.widget.DrawerLayout>

Bug2:自定義weight的使用時無響應。
事實上是因為我們沒有選中對應的元件,有時會報NullPointExceptiom,有時就是自定義元件的監聽無響應,當時我們推測的原因有OnClik和Ontouch傳值的問題,自定義元件內部的監聽事件等,實際上只是include是否指定id,和findViewById方法的物件選擇問題。而像include這樣的細節問題往往是最難發現的。

最後我其實想過,如果在include標籤外加一個layout標籤,以上的問題就不需要考慮了,這篇文章也就沒有必要了。但是這就回到了上面問題2,儘量的減少佈局的巢狀,這也是Android中 merge的用心所在。