View 繫結   Android Jetpack 的一部分。

檢視區塊繫結功能可讓您更輕鬆地編寫與檢視區塊互動的程式碼。在模組中啟用檢視區塊繫結後,系統會為該模組中的每個 XML 版面配置檔案產生繫結類別。凡是在對應版面配置中具有 ID 的檢視區塊,繫結類別的例項都會包含指向這些檢視區塊的直接參照。

在大多數情況下,檢視畫面繫結會取代 findViewById

設定

檢視區塊繫結會依模組逐一啟用。如要在模組中啟用檢視畫面繫結,請在模組層級 build.gradle 檔案中將 viewBinding 建構選項設為 true,如以下範例所示:

Groovy

android {
    ...
    buildFeatures {
        viewBinding true
    }
}

Kotlin

android {
    ...
    buildFeatures {
        viewBinding = true
    }
}

如果您希望在產生繫結類別時忽略版面配置檔案,請將 tools:viewBindingIgnore="true" 屬性新增至該版面配置檔案的根檢視畫面:

<LinearLayout
        ...
        tools:viewBindingIgnore="true" >
    ...
</LinearLayout>

用量

如果為模組啟用檢視區塊繫結,系統會為模組包含的每個 XML 版面配置檔案產生繫結類別。每個繫結類別都包含根檢視區塊和所有具有 ID 的檢視區塊的參照。系統會透過以下方式產生繫結類別的名稱:將 XML 檔案的名稱轉換為 Pascal 命名法,並在結尾處加上字詞「Binding」。

舉例來說,假設名為 result_profile.xml 的版面配置檔案包含下列內容:

<LinearLayout ... >
    <TextView android:id="@+id/name" />
    <ImageView android:cropToPadding="true" />
    <Button android:id="@+id/button"
        android:background="@drawable/rounded_button" />
</LinearLayout>

產生的繫結類別稱為 ResultProfileBinding。這個類別有兩個欄位:名為 nameTextView,以及名為 buttonButton。版面配置中的 ImageView 沒有 ID,因此繫結類別中沒有對它的參照。

每個繫結類別也包含 getRoot() 方法,可為對應版面配置檔案的根檢視區塊提供直接參照。在這個範例中,ResultProfileBinding 類別中的 getRoot() 方法會傳回 LinearLayout 根檢視區塊。

以下各節將示範如何在活動和區塊中使用產生的繫結類別。

在活動中使用檢視繫結

如要設定繫結類別的例項,以便與活動搭配使用,請在活動的 onCreate() 方法中執行下列步驟:

  1. 呼叫產生繫結類別中包含的靜態 inflate() 方法。這會為活動建立繫結類別的例項。
  2. 呼叫 getRoot() 方法或使用 Kotlin 屬性語法,取得根檢視區塊的參照。
  3. 將根檢視區塊傳遞至 setContentView(),讓它成為螢幕上的有效檢視區塊。

相關步驟如以下範例所示:

Kotlin

private lateinit var binding: ResultProfileBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ResultProfileBinding.inflate(layoutInflater)
    val view = binding.root
    setContentView(view)
}

Java

private ResultProfileBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = ResultProfileBinding.inflate(getLayoutInflater());
    View view = binding.getRoot();
    setContentView(view);
}

您現在可以使用繫結類別的例項,參照任何檢視畫面:

Kotlin

binding.name.text = viewModel.name
binding.button.setOnClickListener { viewModel.userClicked() }

Java

binding.name.setText(viewModel.getName());
binding.button.setOnClickListener(new View.OnClickListener() {
    viewModel.userClicked()
});

在片段中使用檢視繫結

如要設定繫結類別的例項,以便與片段搭配使用,請在片段的 onCreateView() 方法中執行下列步驟:

  1. 呼叫產生繫結類別中包含的靜態 inflate() 方法。這會為片段建立繫結類別的例項。
  2. 呼叫 getRoot() 方法或使用 Kotlin 屬性語法,取得根檢視區塊的參照。
  3. onCreateView() 方法傳回根檢視區塊,將其設為螢幕上的有效檢視區塊。

Kotlin

private var _binding: ResultProfileBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    _binding = ResultProfileBinding.inflate(inflater, container, false)
    val view = binding.root
    return view
}

override fun onDestroyView() {
    super.onDestroyView()
    _binding = null
}

Java

private ResultProfileBinding binding;

@Override
public View onCreateView (LayoutInflater inflater,
                          ViewGroup container,
                          Bundle savedInstanceState) {
    binding = ResultProfileBinding.inflate(inflater, container, false);
    View view = binding.getRoot();
    return view;
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    binding = null;
}

您現在可以使用繫結類別的例項,參照任何檢視畫面:

Kotlin

binding.name.text = viewModel.name
binding.button.setOnClickListener { viewModel.userClicked() }

Java

binding.name.setText(viewModel.getName());
binding.button.setOnClickListener(new View.OnClickListener() {
    viewModel.userClicked()
});

為不同設定提供提示

在多個設定中宣告檢視畫面時,有時會根據特定版面配置使用不同的檢視畫面類型。以下程式碼片段為這項操作的範例:

# in res/layout/example.xml

<TextView android:id="@+id/user_bio" />

# in res/layout-land/example.xml

<EditText android:id="@+id/user_bio" />

在這種情況下,您可能會預期產生的類別會公開 TextView 類型的欄位 userBio,因為 TextView 是常見的基礎類別。由於技術上的限制,視圖繫結程式碼產生器無法判斷這項資訊,因此會改為產生 View 欄位。這需要稍後使用 binding.userBio as TextView 轉換欄位。

為解決這項限制,檢視繫結支援 tools:viewBindingType 屬性,可讓您告知編譯器在產生的程式碼中使用哪種型別。在前述範例中,您可以使用這個屬性,讓編譯器將欄位產生為 TextView

# in res/layout/example.xml (unchanged)

<TextView android:id="@+id/user_bio" />

# in res/layout-land/example.xml

<EditText android:id="@+id/user_bio" tools:viewBindingType="TextView" />

舉另一個例子來說,假設您有兩個版面配置,一個包含 BottomNavigationView,另一個則包含 NavigationRailView。這兩個類別都會擴充 NavigationBarView,其中包含大部分的實作詳細資料。如果您的程式碼不需要確切知道目前版面配置中出現哪個子類別,您可以使用 tools:viewBindingType 將產生的類型設為兩個版面配置中的 NavigationBarView

# in res/layout/navigation_example.xml

<BottomNavigationView android:id="@+id/navigation" tools:viewBindingType="NavigationBarView" />

# in res/layout-w720/navigation_example.xml

<NavigationRailView android:id="@+id/navigation" tools:viewBindingType="NavigationBarView" />

檢視畫面繫結在產生程式碼時無法驗證這個屬性的值。為避免編譯和執行階段錯誤,值必須符合下列條件:

  • 值必須是從 android.view.View 沿用的類別。
  • 這個值必須是所放置標記的超類別。舉例來說,下列值無法使用:

      <TextView tools:viewBindingType="ImageView" /> <!-- ImageView is not related to TextView. -->
      <TextView tools:viewBindingType="Button" /> <!-- Button is not a superclass of TextView. -->
    
  • 最終類型必須在所有設定中一致。

與 findViewById 的差異

檢視繫結相較於使用 findViewById 有以下重要優點:

  • 空值安全性:由於檢視區塊繫結會建立對檢視區塊的直接參照,因此不會因為無效的檢視區塊 ID 而發生空值指標例外狀況。此外,如果檢視畫面只出現在版面配置的部分設定中,則繫結類別中含有其參照的欄位會標示為 @Nullable
  • 類型安全性:每個繫結類別中的欄位類型,都會與 XML 檔案中參照的檢視區塊相符。也就是說,不會發生類別轉換例外狀況。

這些差異表示版面配置和程式碼不相容,導致建構作業在編譯時間而非執行階段失敗。

與資料繫結的比較

檢視畫面繫結和資料繫結都會產生繫結類別,您可以使用這些繫結類別直接參照檢視畫面。不過,檢視區塊繫結可處理較簡單的用途,且相較於資料繫結,可提供下列優點:

  • 編譯速度更快:View 繫結不需要註解處理,因此編譯時間更快。
  • 使用簡便:檢視區塊繫結不需要特別標記的 XML 版面配置檔案,因此可更快速地在應用程式中採用。在模組中啟用檢視畫面繫結後,系統會自動將其套用至該模組的所有版面配置。

另一方面,與資料繫結相比,檢視繫結有下列限制:

基於這些考量,在某些情況下,建議您在專案中同時使用檢視繫結和資料繫結。您可以在需要進階功能的版面配置中使用資料繫結,也可以在不需要進階功能的版面配置中使用檢視畫面繫結。

其他資源

如要進一步瞭解 View Binding,請參閱下列其他資源:

網誌

影片