2020年10月29日 星期四

[Android] Activity Layout 層級與 DecorView

我們為 activity 編寫的 layout 層級都在 android.id.content 這個 Android 內建的 layout id 之下,那 android.id.content 是不是 Activity 的 頂層 view 了呢?其實並不是的,它只是我們編寫的 layout 的 parent view 而已,當我們呼叫 setContentView 的時候,API 內部就將傳入的參數 layout id 放在 android.id.content 之下。

實際上 activity 的頂層 view 是一個叫 Decorview 的 FrameLayout,可以通過 API 取得。

  1. protected void onCreate(Bundle savedInstanceState) {
  2. View decorView = getWindoe().getDecorView();
  3. }

Decorview 會在 Activity initialize 的時候被創建出來,不過它也不是被 Activity 直接持有,而是 Activity 的 Window 成員持有 Decorview,看下面這張圖會比較清楚它們之間的關係。

雖然近來 Android 不斷提倡將 layout 層級扁平化以改善效能,但是你可以看到,就算我們寫的 layout 沒有任何嵌套,它也已經是第三層了,上面還有 android.id.content 和 Decorview 呢。

關於減少 layout 嵌套層級,在這裡順便提到使用 Fragment 時的一個小技巧,網路上很多範例,會在 activity layout xml 中放一個 FrameLayout 當成 fragment container。

  1. FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:id="@+id/fragment_container"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent" />

然後在 activity 中將 fragment 放入 container。

  1. import android.os.Bundle;
  2. import android.support.v4.app.FragmentActivity;
  3.  
  4. public class MainActivity extends FragmentActivity {
  5. @Override
  6. public void onCreate(Bundle savedInstanceState?) {
  7. super.onCreate(savedInstanceState);
  8. setContentView(R.layout.main_activity);
  9.  
  10. HeadlinesFragment firstFragment = new HeadlinesFragment();
  11. // Add the fragment to the 'fragment_container' FrameLayout
  12. getSupportFragmentManager().beginTransaction()
  13. .add(R.id.fragment_container, firstFragment).commit();
  14. }
  15. }

其實並不需要自己再建立一個 FrameLayout 當作 container,android.id.content 已經是一個 FrameLayout,直接將 fragment 放到 android.id.content 就好,這樣可以減少一層 layout 嵌套。

  1. import android.os.Bundle;
  2. import android.support.v4.app.FragmentActivity;
  3.  
  4. public class MainActivity extends FragmentActivity {
  5. @Override
  6. public void onCreate(Bundle savedInstanceState?) {
  7. super.onCreate(savedInstanceState);
  8. setContentView(R.layout.main_activity);
  9.  
  10. HeadlinesFragment firstFragment = new HeadlinesFragment();
  11. // Add the fragment to the 'fragment_container' FrameLayout
  12. getSupportFragmentManager().beginTransaction()
  13. .add(android.id.content, firstFragment).commit();
  14. }
  15. }

沒有留言:

張貼留言