استفاده از ViewBinding به‌جای FindViewById
ﺯﻣﺎﻥ ﻣﻄﺎﻟﻌﻪ: 7 دقیقه

استفاده از ViewBinding به‌جای FindViewById

در اندروید استودیوی 3.6، ویژگی جدید به نام ViewBinding اضافه شده است که به شما قابلیت تعویض findViewById را با شیء ایجاد شده برای ساده کردن کد، رفع bug و اجتناب از تکرار findViewById را می‌دهد.

بروزرسانی build.gradle برای فعال کردن ViewBinding

برای فعال کردن ViewBinding نیازی به کتابخانه‌های اضافه ندارید. این ویژگی در پلاگین Android Gradle در اندروید استودیوی نسخه‌ی 3.6 وجود دارد. برای فعال کردن آن کافیست تنظیمات زیر را در build.gradle سطح ماژول اضافه کنید:

// Available in Android Gradle Plugin 3.6.0
android {
    viewBinding {
        enabled = true
    }
}

در اندروید استودیوی نسخه‌ی 4.0، ViewBinding به buildFeature منتقل شده است و باید به صورت زیر عمل کنید:

// Android Studio 4.0
android {
    buildFeatures {
        viewBinding = true
    }
}

هنگامی که برای یک پروژه فعال شد، ViewBinding یک کلاس به صورت خودکار برای همه‌ی layoutهای شما ایجاد خواهد کرد. نیازی به تغییر XML ندارید، این کار به صورت خودکار برای همه‌ی layoutهای موجود انجام می‌شود.

می‌توانید هر زمان که یک layout را مانند fragment ,Activity یا حتی RecyclerView Adapter ،Inflate می‌کنید از کلاس ایجاد شده استفاده کنید.

استفاده از ViewBinding در اکتیویتی

اگر layout به نام activity_awesome.xml داشته باشید، که شامل یک دکمه و دو textView باشد، ViewBinding کلاس کوچکی به اسم ActivityAwesomeBinding برای آن می‌سازد که شامل صفاتی برای هر View با شناسه آن در layout است.

// Using view binding in an Activity
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val binding = ActivityAwesomeBinding.inflate(layoutInflater)

    binding.title.text = "Hello"
    binding.subtext.text = "Concise, safe code"
    binding.button.setOnClickListener { /* ... */ }

    setContentView(binding.root)
}

هنگام استفاده از ViewBinding نیاز به فراخوانی findViewById ندارید، در عوض فقط از خصوصیات ارائه شده برای ارجاع به هر view در layout با شناسه‌ی آن استفاده کنید.

عنصر ریشه‌ی layout همیشه در صفتی به نام root ذخیره می‌شود که به صورت خودکار برای شما تولید می‌شود. در متد onCreate، اکتیویتی شما باید root را به setContentView پاس بدهید، تا به اکتیویتی اطلاع دهید که از layout در شیء ایجاد شده استفاده کند.

صدا‌ زدن setContentView با شناسه‌ی layout به‌جای استفاده از شیء ایجاد شده اشتباهی است که ممکن است رخ دهد. این باعث می‌شود که layout دوبار inflate شود و listener بر روی شیء layout اشتباه اعمال شود.

راه‌‌حل: وقتی از Viewbinding در اکتیویتی استفاده می‌کنید، باید همیشه layout را از شیء ایجاد شده پاس بدهید، با این روش: (setContentView(binding.root .

کد بی‌خطر با استفاده از شیء ایجاد شده

findViewById منبع بسیاری از bugهایی است که کاربر با آن روبرو می‌شود. پاس دادن id که در layout وجود ندارد آسان است، اما باعث تولید null و crash می‌شود. و از آنجا که هیچ type-safety در آن وجود ندارد به آسانی می‌توانfindViewById<TextView>  R.id.image را صدا زد. ViewBinding یک جایگزین امن و مختصر برای findViewById.

ویژگی‌های ViewBinding

  • Type-Safety: چون صفات همیشه به‌طور صحیح براساس نوع view در layout هستند. بنابراین اگر TextView در layout قرارا دهید، ViewBinding یک صفت از نوع TextView به نمایش می‌گذارد.
  • Null-safe: برای layout‌هایی که چند پیکربندی مخطلف دارند. ViewBinding تشخیص می‌دهد که view فقط در برخی از پیکربندی‌ها نمایش داده می‌شود و یک صفت Nullable@ می‌سازد.

از آنجا که کلاس‌های ایجاد شده کلاس‌های معمولی جاوا با حاشیه‌نویس مناسب برای کاتلین هستند، می‌توانید ViewBinding را هم برای زبان جاوا و هم برای کاتلین استفاده کنید.

چه کدهایی تولید می‌شود؟

ViewBinding کدهایی را تولید می‌کند که نیاز شما به findViewById را رفع می‌کند. یک کلاس برای هر Layout شما تولید می‌کند که نام کلاس براساس نام layout انتخاب می‌شود بنابراین activity_awesome.xml تبدیل به ActivityAwesomeBinding.java می‌شود.

هنگام ویرایش layout در اندروید استودیو، کدها‌ی تولید شده با بروزرسانی شیء وابسته به فایل xml بهینه می‌شود، که اینکار برای سریع‌تر شدن در حافظه انجام می‌شود. این بدان معنی است که تغییرات ایجاد شده در شیء سریعا در ویرایشگر در دسترس قرار می‌گیرد و نیازی به بازسازی کامل کدهای ایجاد شده نیست.

بیایید از کد تولید شده برای layout xml مثال قبل استفاده کنیم تا ببینیم ViewBinding چه چیزی تولید می‌کند.

public final class ActivityAwesomeBinding implements ViewBinding {
  @NonNull
  private final ConstraintLayout rootView;
  @NonNull
  public final Button button;
  @NonNull
  public final TextView subtext;
  @NonNull
  public final TextView title;

ViewBinding یک صفت با نوع صحیح برای هر view با id خاص تولید می‌کند. همچنین یک صفت با نام rootView که باgetter ، getroot در دسترس است تولید می‌کند. ViewBinding هیچ منطقی انجام نمی‌دهد فقط viewهای شما را در شیء ایجاد شده به نمایش می‌گذارد، بنابراین می‌توانید از آن‌ها بدون خطاهای ایجاد شده برای findViewById استفاده کنید. که این فایل ایجاد شده را ساده نگه می‌دارد(و از کند شدن تولید آن جلوگیری می‌کند).

اگر از کاتلین استفاده می‌کنید، این کلاس با قابلیت همکاری بهینه‌سازی شده است. از آنجا که همه‌ی صفت‌ها باNullable@ وNonNull@ حاشیه‌گذاری شده است، کاتلین می‌داند که چگونه همه‌ی آن‌ها را به صورت null-safe type نمایش دهد. برای اطلاعات بیشتر در مورد ارتباط بین زبان‌ها این مستند را بررسی کنید calling java from kotlin.

private ActivityAwesomeBinding(@NonNull ConstraintLayout rootView, @NonNull Button button,
      @NonNull TextView subtext, @NonNull TextView title) { … }
  
  @NonNull
  public static ActivityAwesomeBinding inflate(@NonNull LayoutInflater inflater) {
    /* Edited: removed call to overload inflate(inflater, parent, attachToParent) */
    View root = inflater.inflate(R.layout.activity_awesome, null, false);
    return bind(root);
  }

در ActivityAwesomeBinding.java، ViewBinding یک متد عمومی inflate ایجاد می‌کند. که به آرگومان آن به‌عنوان view والد، null پاس داده می‌شود و به والد متصل نمی‌شود. ViewBinding همچنین سه نسخه‌ی دیگر از inflate را به نمایش می‌گذارد که به شما اجازه می‌دهد پارامترهای parent و attachToParent را هنگامی که نیاز شد پاس بدهید.

صدا زدن bind زمانی است که جادو اتفاق می‌افتد. که layout ،inflate شده را می‌گیرد و همه‌ی صفات را متصل می‌کند، که یک سری بررسی خطا به پیام خطای قابل خواندن تولید شده اضافه می‌شود.

 @NonNull
  public static ActivityAwesomeBinding bind(@NonNull View rootView) {
    /* Edit: Simplified code – the real generated code is an optimized version */
    Button button = rootView.findViewById(R.id.button);
    TextView subtext = rootView.findViewById(R.id.subtext);
    TextView title = rootView.findViewById(R.id.title);
    if (button != null && subtext != null && title != null) {
      return new ActivityAwesomeBinding((ConstraintLayout) rootView, button, subtext, title);
    }
    throw new NullPointerException("Missing required view […]");
  }

متد bind پیچیده‌ترین کد در شیء تولید شده است، که با فراخوانی findViewById برای هر view انجام می‌شود. و اینجا می‌توانید جادو را ببینید، از آنجا که کامپایلر می‌تواند نوع و پتانسیل null بودن صفات را مستقیما در layout xml بررسی کند، بنابراین می‌تواند با خیال راحت findViewById را صدا بزند.

توجه داشته باید، که کد تولید شده برا ی متد bind طولانی است و از labled break برای بهینه‌سازی bytecode استفاده می‌کند. برای اطلاعات بیشتر در مورد این بهینه‌سازی به این پست مراجعه کنید.

در هر کلاس، ViewBinding سه تابع عمومی ثابت برای ساخت شیء اتصال به نمایش می‌گذارد، که به صورت زیر است:

  • (Inflate (inflater: از این تابع در onCreate ،Activity هنگامی که هیچ view والدی وجود ندارد که به شیء پاس بدهیم استفاده می‌شود.
  • (Inflate (inflate, parent, attachToParent: از این در فرگمنت یا در آداپتور RecyclerView، جایی که نیاز به پاس دادن parent و viewGroup به شیء است استفاده کنید.
  • (Bind (rootView: از این زمانی استفاده کنید که view قبلا inflate شده است و فقط می‌خواهید از ViewBinding برای اجتناب از findViewById استفاده کنید. این برای زمانی مناسب است که می‌خواهید ViewBinding را به زیرساخت موجود اتصال دهید و هنگامی که کد برای استفاده از ViewBinding تغییر کرده است.

چگونه از Layoutهای include شده استفاده کنیم

برای هر layout.xml در ماژول یک شیء تولید می‌شود. این حتی در زمانی که در داخل یک layout دیگر include شده است هم صدق می‌کند.

<!-- activity_awesome.xml -->
<androidx.constraintlayout.widget.ConstraintLayout>
    <include android:id="@+id/includes" layout="@layout/included_buttons"
</androidx.constraintlayout.widget.ConstraintLayout>
  
<!-- included_buttons.xml -->
<androidx.constraintlayout.widget.ConstraintLayout>
    <Button android:id="@+id/include_me" />
</androidx.constraintlayout.widget.ConstraintLayout>

در موردی که layout ،include شده است، ViewBinding یک ارجاع به آن layout قرار می‌دهد.

توجه داشته باشید که تگ include باید شناسه داشته باشد مانند: android:id="@+id/includes". این برای ViewBinding مهم است تا بتواند برای آن یک صفت تولید کند(مانند یک view عادی).

public final class ActivityAwesomeBinding implements ViewBinding {
  ...

  @NonNull
  public final IncludedButtonsBinding includes;

ViewBinding یک ارجاع به شیء IncludeButtonBinding در ActivityAwesomeBinding تولید می‌کند.

استفاده از ViewBinding و DataBinding

ViewBinding فقط یک جایگزین برای findViewById است. اگر می‌خواهید به صورت خودکار داده‌ها به Viewهای داخل فایل xml اتصال داده شوند باید از کتابخانه‌ی databinding استفاده کنید. هر دو کتابخانه را می‌توان در همان ماژول اعمال کرد و با هم کار کنند.

وقتی هر دو فعال هستند، layoutهایی که از تگ <layout> استفاده می‌کنند از DataBinding برای تولید شیء استفاده می‌کنند و همه‌ی layoutهای دیگر از ViewBinding استفاده می‌کنند.

ViewBinding برای این توسعه داده شد که چون بسیاری از توسعه‌دهندگان بازخوردهایی ارائه داده‌اند که یک راه‌حل سبک تر برای جایگزین findViewById ارائه شود.

ViewBinding و Kotlin Synthetics یا ButterKnife

یکی از متداول‌ترین سوالاتی که در مورد ViewBinding دیده می‌شود این است که "آیا باید از ViewBinding به‌جای kotlin synthetics یا butterKnife استفاده شود؟" هر دوی این کتابخانه ها توسط بسیاری از اپلیکیشن‌های موفق استفاده می‌شود و مشکل را نیز حل می‌کنند.

برای اکثر برنامه‌ها توصیه می‌شود که از ViewBinding به‌جای این کتابخانه‌ها استفاده شود، زیرا امن‌تر و دقیق‌تر است.

استفاده از ViewBinding به‌جای FindViewById

برای اطلاعات بیشتر در مورد VeiwBinding وبسایت رسمی آن را بررسی کنید.

منبع

چه امتیازی برای این مقاله میدهید؟

خیلی بد
بد
متوسط
خوب
عالی
در انتظار ثبت رای

/@pouryasharifi78
پوریا شریفی
توسعه‌دهنده‌ی اندروید

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

دیدگاه و پرسش

برای ارسال دیدگاه لازم است وارد شده یا ثبت‌نام کنید ورود یا ثبت‌نام

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

در حال دریافت نظرات از سرور، لطفا منتظر بمانید