View binding   بخشی از Android Jetpack.

اتصال نما ویژگی‌ای است که نوشتن کد تعاملی با نماها را آسان‌تر می‌کند. وقتی اتصال نما در ماژولی فعال شود، کلاس اتصال برای هر فایل طرح‌بندی XML موجود در آن ماژول تولید می‌کند. یک نمونه از کلاس اتصال حاوی ارجاع‌های مستقیم به همه نماهایی است که شناسه‌ای در چیدمان مربوطه دارند.

در بیشتر موارد، اتصال نما جایگزین findViewById می‌شود.

راه‌اندازی

اتصال نما به‌صورت واحدبه‌واحد فعال می‌شود. برای فعال کردن اتصال نما در یک ماژول، گزینه ساخت viewBinding را روی true در سطح ماژول فایل build.gradle تنظیم کنید، همان‌طور که در مثال زیر نشان داده شده است:

شیک

android {
    ...
    buildFeatures {
        viewBinding true
    }
}

کاتلین

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

اگر می‌خواهید هنگام تولید کلاس‌های اتصال، فایل چیدمان نادیده گرفته شود، مشخصه tools:viewBindingIgnore="true" را به نمای ریشه آن فایل چیدمان اضافه کنید:

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

کاربرد

اگر اتصال نما برای پیمانه‌ای فعال باشد، کلاس اتصال برای هر فایل چیدمان XML که پیمانه حاوی آن است تولید می‌شود. هر کلاس اتصال حاوی ارجاع‌هایی به نمای ریشه و همه نماهایی است که شناسه دارند. نام کلاس اتصال با تبدیل نام فایل XML به حالت پاسکال و افزودن کلمه «اتصال» به انتهای آن تولید می‌شود.

برای مثال، فایل چیدمانی به‌نام 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 نامیده می‌شود. این کلاس دو فیلد دارد: یک TextView به‌نام name و یک Button به‌نام button. ‫ImageView در چیدمان شناسه‌ای ندارد، بنابراین هیچ ارجاعی به آن در کلاس اتصال وجود ندارد.

هر کلاس اتصال شامل یک روش getRoot() نیز می‌شود که مرجع مستقیمی برای نمای ریشه فایل چیدمان مربوطه ارائه می‌دهد. در این مثال، روش getRoot() در کلاس ResultProfileBinding نمای ریشه LinearLayout را برمی‌گرداند.

بخش‌های زیر استفاده از کلاس‌های اتصال تولیدشده را در فعالیت‌ها و قطعات نشان می‌دهد.

استفاده از اتصال نما در فعالیت‌ها

برای راه‌اندازی نمونه‌ای از کلاس اتصال برای استفاده با یک فعالیت، مراحل زیر را در روش onCreate() فعالیت انجام دهید:

  1. روش inflate() ایستا را که در کلاس اتصال تولیدشده گنجانده شده است فراخوانی کنید. این کار نمونه‌ای از کلاس اتصال را برای استفاده فعالیت ایجاد می‌کند.
  2. با فراخوانی روش getRoot() یا استفاده از نحو ویژگی Kotlin ، مرجعی به نمای ریشه دریافت کنید.
  3. نمای ریشه را به setContentView() منتقل کنید تا به نمای فعال در صفحه تبدیل شود.

این مراحل در مثال زیر نشان داده شده است:

کاتلین

private lateinit var binding: ResultProfileBinding

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

جاوا

private ResultProfileBinding binding;

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

اکنون می‌توانید از نمونه کلاس اتصال برای ارجاع به هریک از نماها استفاده کنید:

کاتلین

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

جاوا

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

استفاده از اتصال نما در قطعه‌ها

برای راه‌اندازی نمونه‌ای از کلاس اتصال برای استفاده با قطعه، مراحل زیر را در روش onCreateView() قطعه انجام دهید:

  1. روش inflate() ایستا را که در کلاس اتصال تولیدشده گنجانده شده است فراخوانی کنید. این کار نمونه‌ای از کلاس اتصال برای قطعه ایجاد می‌کند تا از آن استفاده کند.
  2. با فراخوانی روش getRoot() یا استفاده از نحو ویژگی Kotlin ، مرجعی به نمای ریشه دریافت کنید.
  3. نمای ریشه را از روش onCreateView() برگردانید تا به نمای فعال در صفحه تبدیل شود.

کاتلین

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
}

جاوا

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;
}

اکنون می‌توانید از نمونه کلاس اتصال برای ارجاع به هریک از نماها استفاده کنید:

کاتلین

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

جاوا

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

ارائه راهنمایی برای پیکربندی‌های مختلف

When you declare views across multiple configurations, it occasionally makes sense to use a different view type depending on the particular layout. تکه‌کد زیر نمونه‌ای از این را نشان می‌دهد:

# in res/layout/example.xml

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

# in res/layout-land/example.xml

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

در این مورد، ممکن است انتظار داشته باشید که کلاس تولیدشده فیلد userBio از نوع TextView را نمایش دهد، زیرا 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 مزایای مهمی دارد:

  • ایمنی تهی: ازآنجایی‌که اتصال نما ارجاع‌های مستقیم به نماها ایجاد می‌کند، هیچ خطری برای استثنای اشاره‌گر تهی به‌دلیل شناسه نمای نامعتبر وجود ندارد. علاوه‌براین، وقتی نمایی فقط در برخی پیکربندی‌های چیدمان وجود دارد، فیلد حاوی مرجع آن در کلاس اتصال با @Nullable علامت‌گذاری می‌شود.
  • ایمنی تایپی: فیلدهای هر کلاس اتصال دارای انواع مطابق با نماهایی هستند که در فایل XML به آن‌ها ارجاع می‌دهند. این یعنی خطر استثنای تبدیل کلاس وجود ندارد.

این تفاوت‌ها به این معنی است که ناسازگاری بین چیدمان و کد شما منجر به شکست ساخت شما در زمان ترجمه می‌شود تا در زمان اجرا.

مقایسه با ترابست داده‌ها

اتصال نما و اتصال داده هر دو کلاس‌های اتصالی تولید می‌کنند که می‌توانید از آن‌ها برای ارجاع مستقیم به نماها استفاده کنید. بااین‌حال، اتصال نما برای رسیدگی به موارد استفاده ساده‌تر درنظر گرفته شده است و مزایای زیر را نسبت به اتصال داده ارائه می‌دهد:

  • ترجمه سریع‌تر: اتصال نما به پردازش حاشیه‌نویسی نیاز ندارد، بنابراین زمان ترجمه سریع‌تر است.
  • سهولت استفاده: اتصال نما به فایل‌های چیدمان XML با برچسب خاص نیاز ندارد، بنابراین سریع‌تر در برنامه‌هایتان پذیرفته می‌شود. وقتی اتصال نما را در یک واحد فعال کنید، به‌طور خودکار برای همه چیدمان‌های آن واحد اعمال می‌شود.

ازسوی دیگر، اتصال نما درمقایسه با اتصال داده محدودیت‌های زیر را دارد:

به‌دلیل این ملاحظات، در برخی موارد بهتر است از هر دو اتصال داده و اتصال نما در یک پروژه استفاده شود. می‌توانید از اتصال داده در چیدمان‌هایی استفاده کنید که به ویژگی‌های پیشرفته نیاز دارند و از اتصال نما در چیدمان‌هایی استفاده کنید که به این ویژگی‌ها نیاز ندارند.

منابع بیشتر

برای کسب اطلاعات بیشتر درباره View Binding، منابع تکمیلی زیر را ببینید:

وبلاگ‌ها

ویدیوها