پروژه سایت آژانس هواپیمایی با asp
پروژه سایت آژانس هواپیمایی با Asp.Net
2020-04-29
آموزش آداپتور های بایندینگ (Binding adapters)
آموزش آداپتور های بایندینگ (Binding adapters)
2020-05-03
کلاس های تولید شده توسط دیتا بایندینگ

کلاس های تولید شده توسط دیتا بایندینگ

کلاس های تولید شده توسط دیتا بایندینگ ، کلاس های binding تولید شده توسط کتابخانه دیتا بایندینگ که در پست های پیشین تجاری اپ بسیار درباره آنها توضیح دادیم .برای دسترسی به view ها و variable های درون لایه استفاده می شوند و ما در این پست از تجاری اپ قصد داریم نحوه ایجاد و سفارشی کردن کردن این کلاس ها را به شما آموزش دهیم.

کلاس های binding تولید شده توسط دیتا بایندینگ

کلاس های تولید شده توسط کتابخانه دیتا بایندینگ ،درواقع به متغیر ها (variable) و view های درون لایه لینک می شوند و به عبارتی می توان از طریق این کلاس های تولید شده به تمام المان های درون لایه بدون نیاز به تعریف هرکدام ،دسترسی پیدا کرد به این خاطر که تمامی این المان ها درون کلاس تولید شده توسط خود کتابخانه دیتا بایندینگ تعریف شده اند.

کلاس بایندینگ برای تمام لایه ها به صورت جدا ایجاد میشود.به صورت پیشفرض نامی که برای کلاس بایندینگ درنظر گرفته می شود براساس نام لایه ست.بدین صورت که نام لایه را به صورت Pascal case در نظر گرفته و به عنوان نام کلاس بایندینگ انتخاب میشود بدین صورت که اگر نام لایه activity_main.xml بود ، نام لایه بایندینگ تولید شده ActivityMainBinidng خواهد شد.
این کلاس تمامی پراپرتی ها و المان های درون لایه را برای استفاده در کلاس های جاوا یا کاتلین پیاده می کند (برای مثال متغیر user که به عنوان variable درون تگ layout مربوط به کتابخانه دیتا بایندینگ پیاده شده).

ساخت یک شی binding

یک نکته مهم درباره زمان ساخت شی binding وجود دارد که قبل از گفتن آن بهتر است درباره ماهیت خود شی binding کمی اطلاعات به دست بیاوریم.

شی binding چیست ؟
شی binding درواقع یک نمونه یا instance از همان کلاس تولید شده توسط کتابخانه data binding است که براساس لایه موردنظر ما تولید شده.

خب حال زمان آن است که ببینیم چه زمانی بهترین زمان است برای ساخت شی binding از جنس کلاس تولید شده توسط کتابخانه دیتا بایندینگ.

بهترین زمان برای ساخت شی binding درواقع زمان inflate یا چسباندن لایه به اکتیویتی ست.

چرا بهترین زمان برای ساخت شی binding درواقع زمان inflate یا چسباندن لایه به اکتیویتی ست؟

به این خاطر که مطمئن شوید سلسله مراتب لایه و یا دیتاهای بایند شده به لایه به هم نخورده و درواقع همان لایه بیس و اصلی است که باید در صفحه نمایش داده شود.
متدوال ترین راه بایند کردن لایه استفاده از متد inflate ( یک متد استاتیک از کلاس binding ) است.به مثال زیر توجه کنید:

جاوا

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    MyLayoutBinding binding = MyLayoutBinding.inflate(getLayoutInflater());
}

کاتلین

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val binding: MyLayoutBinding = MyLayoutBinding.inflate(layoutInflater)
}

همانگونه که می بینید ما شی binding مربوط به کلاس تولید شده توسط کتابخانه دیتا بایندینگ را دقیقا در متد onCreate و زمان چسباندن لایه به اکتیوتی پیاده می کنیم.
اما ساخت این شی binding می تواند به صورت های دیگری هم باشد که در ادامه آنها را بررسی خواهیم کرد.یک نمونه inflate دیگر هم هست که از شما ViewGroup گرفته و بصورت زیر خواهد بود:

جاوا

MyLayoutBinding binding = MyLayoutBinding.inflate(getLayoutInflater(), viewGroup, false);

کاتلین

val binding: MyLayoutBinding = MyLayoutBinding.inflate(getLayoutInflater(), viewGroup, false)

و اما شما می توانید یک نمونه یا instance از لایه (که آبجکتی از جنس View خواهد شد) در خطی جدا ایجاد کنید و آن را بدین صورت به کلاس bidning ارسال کنید:

جاوا

View viewRoot = LayoutInflater.from(this).inflate(layoutId, parent, attachToParent);
MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot);

کاتلین

val viewRoot = LayoutInflater.from(this).inflate(layoutId, parent, attachToParent)
val binding: MyLayoutBinding = MyLayoutBinding.bind(viewRoot)

اما در بعضی مواقع ما نمیتوانیم نوع کلاس binding را تشخیص دهیم که در این مواقع می توان از کلاس DataBindingUtil استفاده کنیم که کلاسی ارائه شده توسط کتابخانه دیتا بایندینگ است.به مثال زیر دقت کنید:

جاوا

View viewRoot = LayoutInflater.from(this).inflate(layoutId, parent, attachToParent);
ViewDataBinding binding = DataBindingUtil.bind(viewRoot);

کاتلین

val viewRoot = LayoutInflater.from(this).inflate(layoutId, parent, attachToParent)
val binding: ViewDataBinding? = DataBindingUtil.bind(viewRoot)

یک نکته کلیدی درباره شی binding

یک نکته کلیدی درباره شی binding این است که اگر شما از دیتا بایندینگ درون المان هایی نظیر Fragment ، ListView و RecyclerView adapter استفاده می کنید ممکن است که بخواهید یک شی بایندینگ جدا برای هرکدام با استفاده از inflate ایجاد کنید که شما هم میتوانید از کلاس بایندینگ خود لایه مورد نظر و هم از کلاس DataBindingUtil استفاده کنید.

جاوا

ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);
// or
ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);

کاتلین

val listItemBinding = ListItemBinding.inflate(layoutInflater, viewGroup, false)
// or
val listItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false)

فراخوانی Viewهایی که ID دارند

کتابخانه دیتا بایندینگ یک فیلد تغییر ناپذیر (final) برای هر ویویی در لایه که ID منحصر به فردی دارد ،ایجاد می کند.برای مثال در کلاس بایندینگ تولید شده برای لایه زیر درواقع برای TextView هایی که ID های آنها به ترتیب firstName و lastName است یک فیلد تغییر ناپذیر ایجاد شده.

<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"
   android:id="@+id/firstName"/>
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.lastName}"
  android:id="@+id/lastName"/>
   </LinearLayout>
</layout>

کتابخانه دیتا بایندینگ تمامی ID هارا به ترتیب از لایه استخراج کرده و درقالب یک فیلد در کلاس پیاده میکند.این مکانیزم استفاده از ویو ها را برای شما سریع تر می کند بدین صورت که دیگر نیازی نخواهید داشت که از متد findViewById برای فراخوانی view ها استفاده کنید.

Variables

کلاس های تولید شده دیتا بایندینگ متدهای دسترسی به هر variable درون لایه را هم ایجاد می کنند.برای مثال کلاس تولید شده binding برای لایه زیر ، متدهای getter و setter را برای متغیرهای user ، image و note ایجاد کرده تا هم بتوان از طریق کلاس به آنها مقدار داد و هم بتوان از مقادیر درون آنها استفاده کرد

 <data>
   <import type="android.graphics.drawable.Drawable"/>
   <variable name="user" type="com.example.User"/>
   <variable name="image" type="Drawable"/>
   <variable name="note" type="String"/>
</data>

اتصال فوری (Immediate Binding)

زمانی که شما یک variable یا یک شی observable را تغییر می دهید ، بایندینگ زمانبندی می کند که در فریم بعدی این تغییرات برروی صفحه اعمال کند.اما زمان هایی هست که شما نیاز دارید همان لحظه تغییرات بروی صفحه اعمال و نمایش داده شوند پس در این مواقع می توانید از متد ()executePendingBindings .

دقیقا بعد از دستوراتی که تغییرات را اعمال کرده استفاده کنید تا تغییرات همان لحظه در لایه به شما نمایش داده شود.

اتصال پیشرفته (Advanced Binding)

زمان هایی وجود دارد که یک کلاس بایندینگ خاص هنوز مشخص نشده و ما نمی توانیم مستقیما از همان کلاس استفاده کنیم.برای مثال در RecyclerView.Adapter کلاس بایندینگ برای هر آیتم مشخص نیست اما ما ملزم به بایند کردن داده ها به لایه با استفاده از دیتا بایندینگ در متد ()onBindViewHolder اداپتر هستیم .

پس در این مواقع چه باید کرد ؟

جاوا

public void onBindViewHolder(BindingHolder holder, int position) {
    final T item = items.get(position);
    holder.getBinding().setVariable(BR.item, item);
    holder.getBinding().executePendingBindings();
}

کاتلین

override fun onBindViewHolder(holder: BindingHolder, position: Int) {
    item: T = items.get(position)
    holder.binding.setVariable(BR.item, item);
    holder.binding.executePendingBindings();
}

همانطور که می بینید تمامی ویو هایی که ما برای آیتم های لیست درنظر گرفتیم مجهز به دیتا بایندینگ و یک variable با نام item است

نکته :
همانطور که در پست های قبل آموزش دیتا بایندینگ در تجاری اپ گفته شد ،کتابخانه دیتا بایندینگ یک کلاس با نام BR به صورت خودکار تولید میکند که شامل تمامی variable های به کار رفته در لایه هاست به همین خاطر در مثال فوق هم از BR.item استفاده شده و نشان دهنده این مسئله ست که لایه استفاده شده برای آیتم ها علاوه بر اینکه دارای دیتا بایندینگ است ، یک variable با نام item نیز دارد.

به علاوه BindingHolder یک متد getBinding دارد که مقدار ViewDataBinding را برمی گرداند که می توان با استفاده از آن مقدار variable را با setVariable به لایه پاس داد و همچنین تغییرات را بصورت آنی با استفاده از ()exucutePendingBindings به لایه متصل کرد.

Background Thread

شما می توانید مقادیر مدل خود را همچنین در پس زمینه هم ویرایش کنید بدون این که برای دیتا بایندینگ مشکلی پیش آید.چرا که دیتا بایندینگ تمامی فیلد ها و variable ها را زمان پیاده سازی localize یا به عبارتی بومی می کند تا از بروز هرگرونه مشکل همزمانی جلوگیری شود.

سفارشی کردن کلاس های binding (سفارشی سازی نام کلاس تولید شده بایندینگ برای لایه ها)

به صورت پیش فرض نام کلاس هایی که کتابخانه data binding تولید میکند از نام لایه گرفته می شود.بدین صورت که نام لایه بصورت Pascal case بدون هیچ ( ـ ) از نام لایه گرفته می شود به علاوه یک پسوند Binding که به انتهای نام کلاس چسبانده می شود همچنین محل قرارگیری کلاس های تولید شده data binding هم در پکیج databinding درون پکیج اصلی خواهد بود.

برای مثال اگر نام پکیج اصلی شما com.example.my.app و نام لایه شما contact_item.xml است کلاسی که data binding برای این لایه تولید می کند با نام ContactItemBinding خواهد بود و محل قرار گیری آن هم com.example.my.app.databinding است.

اما نام کلاس های تولیدی data binding می توانند عوض شوند و ثابت نیستند و حتی محل قرار گیری آنها می تواند جابجا شود.
برای تغییر نام آنها تنها کافی ست درون تگ data یک مقدار class تنظیم کرد و نام دلخواه خود را در آن قرار دهید.برای مثال نمونه زیر یک کلاس با نام ContactItem در پکیج databinding ایجاد میکند:

<data class="ContactItem">
    …
</data>

اما اگر می خواهید محل قرار گیری کلاس دیتا بایندینگ را هم عوض کنید می توانید به صورت زیر عمل کنید

<data class=".ContactItem">
    …
</data>

بدین صورت که نام پکیج را قبل از نام کلاس بنویسید. در مثال فوق کلاس بایندینگ با نام ContactItem درون پکیج اصلی تولید می شود.

نکته :
همانطور که می دانید علامت دات ( . ) به پکیج جاری اشاره می کند یعنی اگر نام پکیج شما com.exmple.app باشد ، علامت دات ( . ) دقیقا به com.example.app اشاره خواهد کرد.

همچنین می توانید آدرس کامل پکیج را بدین صورت بنویسید:

<data class="com.example.ContactItem">
    …
</data>

در مثال فوق کلاس ContactItem درون پکیج com.example تولید می شود.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *