View binding یک ویژگی است که نوشتن کدی را که با نماها در تعامل است را آسانتر میکند. هنگامی که view binding در یک ماژول فعال می شود، یک کلاس binding برای هر فایل طرح بندی XML موجود در آن ماژول ایجاد می کند. یک نمونه از یک کلاس binding شامل ارجاع مستقیم به تمام نماهایی است که دارای شناسه در طرح مربوطه هستند.
در بیشتر موارد، view binding جایگزین findViewById
می شود.
View binding به صورت ماژول به ماژول فعال است. برای فعال کردن view binding در یک ماژول، همانطور که در مثال زیر نشان داده شده است، گزینه viewBinding
build را در فایل build.gradle
سطح ماژول روی true
تنظیم کنید:
android { ... buildFeatures { viewBinding true } }
android { ... buildFeatures { viewBinding = true } }
اگر میخواهید هنگام تولید کلاسهای binding، یک فایل layout نادیده گرفته شود، ویژگی tools:viewBindingIgnore="true"
به نمای ریشه آن فایل طرحبندی اضافه کنید:
<LinearLayout
...
tools:viewBindingIgnore="true" >
...
</LinearLayout>
اگر view binding برای یک ماژول فعال باشد، یک کلاس binding برای هر فایل طرح بندی XML که ماژول حاوی آن است ایجاد می شود. هر کلاس binding شامل ارجاعاتی به نمای ریشه و تمام نماهایی است که دارای شناسه هستند. نام کلاس binding با تبدیل نام فایل XML به حروف پاسکال و افزودن کلمه Binding به انتهای آن ایجاد می شود.
به عنوان مثال، یک فایل layout به نام 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
در layout هیچ شناسه ای ندارد، بنابراین هیچ مرجعی به آن در کلاس binding وجود ندارد.
هر کلاس binding همچنین شامل یک متد getRoot()
است که یک مرجع مستقیم برای نمای ریشه فایل layout مربوطه ارائه می دهد. در این مثال، متد getRoot()
در کلاس ResultProfileBinding
نمای ریشه LinearLayout
را برمی گرداند.
بخش های زیر استفاده از کلاس های اتصال تولید شده در فعالیت ها و قطعات را نشان می دهد.
برای تنظیم یک نمونه از کلاس binding برای استفاده با یک اکتیویتی، مراحل زیر را در متد onCreate()
اکتیویتی انجام دهید:
- متد static
inflate()
موجود در کلاس binding تولید شده را فراخوانی کنید. این یک نمونه از کلاس binding برای فعالیت ایجاد می کند. - با فراخوانی متد
getRoot()
یا با استفاده از نحو ویژگی Kotlin، به نمای ریشه ارجاع دهید. - نمای root را به
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 برای ارجاع به هر یک از view ها استفاده کنید:
binding.name.text = viewModel.name binding.button.setOnClickListener { viewModel.userClicked() }
binding.name.setText(viewModel.getName()); binding.button.setOnClickListener(new View.OnClickListener() { viewModel.userClicked() });
برای تنظیم نمونه ای از کلاس binding برای استفاده با یک قطعه، مراحل زیر را در متد onCreateView()
قطعه انجام دهید:
- متد static
inflate()
موجود در کلاس binding تولید شده را فراخوانی کنید. این یک نمونه از کلاس binding را برای استفاده از قطعه ایجاد می کند. - با فراخوانی متد
getRoot()
یا با استفاده از نحو ویژگی Kotlin، به نمای ریشه ارجاع دهید. - نمای ریشه را از متد
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 برای ارجاع به هر یک از view ها استفاده کنید:
binding.name.text = viewModel.name binding.button.setOnClickListener { viewModel.userClicked() }
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" />
در این مورد، ممکن است انتظار داشته باشید که کلاس تولید شده یک فیلد userBio
از نوع TextView
را نشان دهد، زیرا TextView
کلاس پایه رایج است. به دلیل محدودیتهای فنی، مولد کد پیوندی view نمیتواند این را تعیین کند و به جای آن یک فیلد View
ایجاد میکند. این مستلزم فرستادن فیلد بعداً با binding.userBio as TextView
.
برای رفع این محدودیت، view binding از ویژگی 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" />
View binding نمی تواند ارزش این ویژگی را هنگام تولید کد تأیید کند. برای جلوگیری از خطاهای زمان کامپایل و زمان اجرا، مقدار باید دارای شرایط زیر باشد:
- مقدار باید کلاسی باشد که از
android.view.View
به ارث می برد. مقدار باید یک سوپرکلاس از برچسبی باشد که روی آن قرار می گیرد. به عنوان مثال، مقادیر زیر کار نمی کنند:
<TextView tools:viewBindingType="ImageView" /> <!-- ImageView is not related to TextView. --> <TextView tools:viewBindingType="Button" /> <!-- Button is not a superclass of TextView. -->
نوع نهایی باید به طور مداوم در تمام تنظیمات حل شود.
View binding مزایای مهمی نسبت به استفاده از findViewById
دارد:
- ایمنی تهی: از آنجایی که binding view ارجاع مستقیم به نماها ایجاد می کند، به دلیل شناسه نمای نامعتبر، خطر استثنای اشاره گر تهی وجود ندارد. علاوه بر این، زمانی که یک view فقط در برخی از تنظیمات یک طرحبندی وجود دارد، فیلد حاوی مرجع آن در کلاس binding با
@Nullable
علامتگذاری میشود. - نوع ایمنی: فیلدهای هر کلاس binding دارای انواعی هستند که با نماهایی که در فایل XML به آنها ارجاع می دهند مطابقت دارند. این بدان معنی است که هیچ خطری برای استثناء بازیگران کلاس وجود ندارد.
این تفاوت ها به معنای ناسازگاری بین طرح و کد شما است که منجر به شکست ساخت شما در زمان کامپایل و نه در زمان اجرا می شود.
View binding و data binding هر دو کلاس های binding را ایجاد می کنند که می توانید از آنها برای ارجاع مستقیم به نماها استفاده کنید. با این حال، view binding برای رسیدگی به موارد استفاده سادهتر در نظر گرفته شده است و مزایای زیر را نسبت به دادهها ارائه میکند:
- کامپایل سریعتر: اتصال مشاهده نیازی به پردازش حاشیه نویسی ندارد، بنابراین زمان کامپایل سریعتر است.
- سهولت استفاده: مشاهده صحافی به فایلهای طرحبندی XML با برچسبگذاری خاص نیاز ندارد، بنابراین در برنامههای شما سریعتر اجرا میشود. هنگامی که View binding را در یک ماژول فعال میکنید، به طور خودکار برای همه طرحبندیهای آن ماژول اعمال میشود.
از طرف دیگر، view binding در مقایسه با data binding دارای محدودیتهای زیر است:
- View binding از متغیرهای طرحبندی یا عبارات طرحبندی پشتیبانی نمیکند، بنابراین نمیتوان از آن برای اعلام محتوای پویا UI مستقیماً از فایلهای طرحبندی XML استفاده کرد.
- View binding از اتصال دو طرفه داده پشتیبانی نمی کند.
به دلیل این ملاحظات، در برخی موارد بهتر است از هر دو view binding و data binding در پروژه استفاده شود. میتوانید در طرحبندیهایی که نیاز به ویژگیهای پیشرفته دارند، از اتصال دادهها استفاده کنید و در طرحبندیهایی که نیازی به ویژگیهای پیشرفته ندارند، از پیوند مشاهده استفاده کنید.
برای کسب اطلاعات بیشتر در مورد مشاهده binding، به منابع اضافی زیر مراجعه کنید:
- توجه: وقتی جاوا اسکریپت خاموش است، متن پیوند نمایش داده می شود
- از Kotlin synthetics به Jetpack view binding مهاجرت کنید
- چیدمان ها و عبارات الزام آور
- معماری برنامه: لایه UI - شروع به کار - توسعه دهندگان اندروید