مشخصات مقاله
آموزش Data Binding در اندروید،اندروید استودیو
بر کسی پوشیده نیست که اپلیکیشن های اندروید دائما با داده سروکار دارند. این داده ها قاعدتا باید یا از یک منبع داده همچون دیتابیس خوانده شوند یا از اینترنت گرفته شده و در اپلیکیشن مورد نظر برای کاربر به نمایش در آیند.
طبیعتا داده های برنامه باید با نما و ظاهر خاصی در نمایشگر دستگاه نشان داده شوند. همان طور که می دانید در اندروید توسعه دهنده اغلب با آبجکت های activity، fragment و لایه ها سروکار دارد و ظاهر برنامه را با آیتم های ذکر شده طراحی می کند. در مرحله ی بعدی توسعه دهنده این با جاوا این آبجکت ها را مقداردهی می کند. نا گفته مشخص است که این کار بسیار تکراری است و در فایل های XML انجام می شود. به این دلیل Google کتابخانه ای ارائه داد که به واسطه ی آن برنامه نویس قادر است به راحتی مقداردهی را در فایل های layout و با همان تگ های XML انجام دهد و سپس مقادیر به view های مربوطه متصل شوند. این کتابخانه یک support library هست که با وجود جدید بودن، به راحتی برای ویرایش های قبلی، البته از 2.1 به بالا قابل استفاده می شود.
این مبحث به شما آموزش می دهد چگونه با استفاده از کتابخانه ی Data Binding فایل های layout با فرمت XML بسازید و کد لازم برای متصل کردن منطق اپلیکیشن و فایل های layout (glue code) را به حداقل برسانید.

جهت استفاده از این کتابخانه، لازم است افزونه ی اندروید ویرایش 1.5.0 سیستم کامپایل Gradle یا بالاتر را نصب نمایید.
به منظور استفاده از این کتابخانه برای اتصال داده، می بایست تکه کد زیر را به فایل app/build.gradle اضافه نمایید:
1 2 3 4 5 6 7 | android { .... dataBinding { enabled = true } } <button></button> |
آموزش فایل های layout اتصال داده از model به UI (Data Binding Layout Files)
فایل های layout ای که data binding انجام می دهند، با تگ layout آغاز شده و المان data را به صورت تودرتو در خود دارند و سپس المان آغازین و میزبان view را شامل می شود. این تگ view در واقع المانی است که در یک فایل non-binding، ریشه یا root در آن قرار می گرفت.در زیر نمونه ای از یک فایل binding layout را مشاهده می کنید:
1 2 3 4 5 6 7 8 9 10 11 | <!--?xml version="1.0" encoding="utf-8" ?--> < data > < variable name = "user" type = "com.vogella.android.databinding.User" ></ variable > </ 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}" ></ textview > < textview android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:text = "@{user.lastName}" ></ textview > </ linearlayout > </ layout > < button ></ button > |
اطلاعات data-binding به فایل های layout پروژه ی شما اضافه می شود. در طول پروسه ی build پروژه، کلاس های binding بر اساس اطلاعات این فایل تولید می شوند. به صورت پیش فرض، اسم کلاس binding بر اساس اسم فایل layout ساخته می شود. در واقع اسم فایل با سیستم نوشتاری Pascal نگارش شده و سپس پسوند "Binding" به انتهای آن الصاق می شود. برای مثال اگر اسم فایل layout شما activity_main.xml باشد، اسم کلاس متعاقبا ActivityMainBinding خواهد بود. این کلاس تمامی binding ها از متغیرهای فایل layout (تگ variable که در نمونه فایل فوق مشاهده می کنید) که اشاره گری به View های فایل layout هستند را شامل می شود و همچنین دقیقا می داند چگونه مقادیر را به view ها متصل (bind) کند. المان data که در فایل بالا مشاهده می کنید، داده هایی را توصیف می کند که قرار است به صورت دو طرفه متصل شوند. Expression ها یا عبارات داخل فایل های layout با دستور نگارشی “@{}” در attribute property ها نوشته می شوند.
در این فایل همچنین تگ variable با نام user را می بینید که یک متغیر (property) تعریف می کند و این متغیر می تواند در layout جاری بکار گرفته شود. در واقع این المان اسم یک آبجکت را مشخص می کند که property های آن در این فایل layout مورد دسترسی قرار می گیرد. برای مثال "@{user.lastName}" بیانگر مقدار فیلد lastName از کلاس User می باشد.
آموزش data binding و مدیریت event ها
data binding در اندروید به شما اجازه می دهد تا عبارت هایی بنویسید که event های ارسالی و فعال شده از view ها را مدیریت می کنند (برای مثال می توان به onClick اشاره کرد). اسم attribute های مربوط به event ها بر اساس اسم متد گوش فراخوان آن رخداد (listener method) مشخص می شود. به طور مثال، View.OnLongClickListener یک متد listener به نام onLongClick() دارد و از اینرو attribute مرتبط با این event به این صورت نام گذاری می شود: android:onLongClick.
Event ها می توانند به طور مستقیم به متدهای handler متناظر آن ها متصل باشند، همان طور که android:onClick می تواند به یک متد در activity چسبانده شود.
به منظور تخصیص یک event به handler مربوطه، کافی است از یک عبارت اتصال ساده (binding expression) استفاده کنید. به طوری که مقدار اسم همان متدی باشد که باید با فعال شدن رخداد صدا خورده شود. این عبارت اتصال سپس می تواند listener یا گوش فرادهنده به رخداد کلیک را به view بچسباند.
آموزش بروز رسانی رابط کاربری با تغییر رخ داده در data model
به منظور اتصال داده از model به UI می توان از هر آبجکت ساده ی جاوایی بهره گرفت که در اصطلاح POJO خوانده می شوند. اما متاسفانه تغییر این آبجکت ساده ی جاوا به صورت خودکار سبب بروز رسانی UI نمی شود. به منظور فراهم آوردن بروز رسانی UIهمراه با تغییر در model، آبجکت حاوی داده ها (data object) باید بتوانند بخش UI مربوطه را از تغییراتی که در داده ها رخ می دهد، مطلع کنند. در کل سه مکانیزم جهت اطلاع رسانی view ها از تغییرات در model وجود دارد: 1. Observable objects 2. Observable fields 3. Observable collections.
برای روش اول، اندروید کلاس BaseObservable را ارائه می دهد که شما می توانید از آن ارث بری کنید. این کلاس که داده ها را در خود نگه می دارد، موظف است به محض اینکه مقادیر property ها تغییر کردند، view ها از این تغییرات با خبر کند. جهت اعطا نمودن این امکان، کافی است دستور (annotation) @Bindable را در بالای تابعی که داده را می خواند درج نموده و مطلع ساختن view از تغییرات را در تابعی که مقدار را تنظیم می کند (setter)، از طریق تابعnotifyPropertyChanged(BR.celsius); انجام دهید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package com.vogella.android.databinding; import android.databinding.BaseObservable; import android.databinding.Bindable; import java.util.Observable; public class TemperatureData extends BaseObservable { private String celsius; public TemperatureData(String celsius) { this .celsius = celsius; } @Bindable 1 public String getCelsius() { return celsius; } public void setCelsius(String celsius) { this .celsius = celsius; 2 notifyPropertyChanged(BR.celsius); } } <button></button> |
- یک getter جهت خواندن داده ی مربوطه
- توسط این بخش از کد تمامی listener ها را از تغییرات با خبر می سازید. BR.celsius یک کلاس تولید شده توسط Android studio می باشد.
این listener به محض رخداد هر گونه بروز رسانی و تغییر در داده، فراخوانی می شود و view های متناظر را به تناسب با تغییر رخ داده ویرایش می کند. با این مکانیزم برنامه نویس اطمینان حاصل می کند که هرگاه مقادیر model تغییر کردند، بخش UI مربوطه نیز بروز رسانی می شود.
آموزش پیاده سازی data binding و نمونه ای از کاربرد آن
همان طور که در بالا نیز گفته شد، فایل های layout ای که از data binding پشتیبانی می کنند با تگ layout آغاز شده و یک المان data را شامل می شود که تعریف کننده ی داده ای است که قرار است bind یا دوطرفه متصل شوند. پس از المان data، تگ view میزبان و root را داریم که در یک فایل layout ساده و non-binding همان root و عنصر آغازین محسوب می شد. عبارت های اتصال دو طرفه ی داده ها (binding expressions) با دستور نگارشی “@{}” در فایل مزبور نوشته می شوند.
یک فایل نمونه به صورت زیر نوشته می شود.
1 2 3 4 5 6 7 8 9 10 11 | <!--?xml version="1.0" encoding="utf-8" ?--> < data > < variable name = "user" type = "com.vogella.android.databinding.User" ></ variable > </ 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}" ></ textview > < textview android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:text = "@{user.lastName}" ></ textview > </ linearlayout > </ layout > < button ></ button > |
متغیر user در المان data، در واقع یک property تعریف می کند که می تواند داخل این layout مورد استفاده قرار گیرد.
آبجکتی که داده ها را در خود کپسوله کرده است (data object) و همراه این layout بکار می رود، می تواند ظاهری مشابه نمونه ی زیر داشته باشد.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | package com.vogella.android.databinding; public class User { public final String firstName; public final String lastName; public User(String firstName, String lastName) { this .firstName = firstName; this .lastName = lastName; } } package com.vogella.android.databinding; import android.app.Activity; import android.databinding.DataBindingUtil; import android.databinding.ViewDataBinding; import android.os.Bundle; import com.vogella.android.databinding.databinding.ActivityMainBinding; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); ActivityMainBinding binding = DataBindingUtil.setContentView( this , R.layout.activity_main); User user = new User( "Test" , "User" ); binding.setUser(user); } } <button></button> |
در طی این پروژه ساده خواهید آموخت چگونه بین المان های رابط کاربری (UI widget) به وسیله ی data binding تعامل بر قرار نمایید. ابتدا یک اپلیکیشن جدید اندرویدی با اسم پکیج com.vogella.android.databinding ایجاد نمایید.
افزودن کتابخانه ی data binding به پروژه
فایل app/build.gradle را باز نموده و با افزودن تکه کد زیر به بخش مربوطه در این فایل، قابلیت data binding را فعال نمایید. توجه کنید که باید build file مناسب را انتخاب نمایید (آن فایلی که نود application را دارد).
1 2 3 4 5 6 7 | apply plugin: 'com.android.application' android { dataBinding { enabled = true } .... [REST AS BEFORE...] <button></button> |
آموزش ساخت کلاس جهت مطلع ساختن view از تغییرات در model
کلاس های زیر را تعریف نمایید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | package com.vogella.android.databinding; import android.databinding.BaseObservable; import android.databinding.Bindable; import android.databinding.ObservableField; import java.util.Observable; public class TemperatureData extends BaseObservable{ private String celsius; public TemperatureData(String celsius) { this .celsius = celsius; } private String fahrenheit; @Bindable public String getCelsius() { return celsius; } public void setCelsius(String celsius) { this .celsius = celsius; notifyPropertyChanged(BR.celsius); } } package com.vogella.android.databinding; public interface MainActivityContract { public interface Presenter { void onShowData(TemperatureData temperatureData); } public interface View { void showData(TemperatureData temperatureData); } } package com.vogella.android.databinding; import android.util.Log; import android.view.View; import android.widget.Toast; public class MainActivityPresenter { private MainActivityContract.View view; public MainActivityPresenter(MainActivityContract.View view) { this .view = view; } public void onShowData(TemperatureData temperatureData) { view.showData(temperatureData); } } <button></button> |
آموزش تنظیم و ویرایش فایل ها برای استفاده از قابلیت data binding
فایل layout را به صورت زیر ویرایش نمایید.
1 2 3 4 5 6 7 8 9 10 11 12 13 | <!--?xml version="1.0" encoding="utf-8" ?--> < data > < variable name = "temp" type = "com.vogella.android.databinding.TemperatureData" ></ variable > < variable name = "presenter" type = "com.vogella.android.databinding.MainActivityPresenter" ></ variable > </ data > < linearlayout android:layout_width = "match_parent" android:layout_height = "match_parent" android:orientation = "vertical" android:paddingbottom = "@dimen/activity_vertical_margin" android:paddingleft = "@dimen/activity_horizontal_margin" android:paddingright = "@dimen/activity_horizontal_margin" android:paddingtop = "@dimen/activity_vertical_margin" > < textview android:layout_width = "match_parent" android:layout_height = "wrap_content" android:text = "@={temp.celsius}" android:id = "@+id/textView" ></ textview > < edittext android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_margintop = "8dp" android:text = "@={temp.celsius}" ></ edittext > < button android:text = "Show data model" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:onclick="@{() -> presenter.onShowData(temp)}" android:id="@+id/button"></ button > </ linearlayout > </ layout > < button ></ button > |
ممکن است تعدادی پیغام هشدار در ویرایشگر مشاهده نمایید. برای مثال ممکن است پیغامی مبنی بر اینکه رشته های hard-code شده در پروژه استفاده شده است دریافت نمایید. در بخش های آتی برای شما شرح می دهیم چگونه این پیغام ها را برطرف نمایید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | package com.vogella.android.databinding; import android.app.Activity; import android.databinding.DataBindingUtil; import android.os.Bundle; import android.widget.Toast; import com.vogella.android.databinding.databinding.ActivityMainBinding; public class MainActivity extends Activity implements MainActivityContract.View { @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); ActivityMainBinding binding = DataBindingUtil.setContentView( this , R.layout.activity_main); MainActivityPresenter mainActivityPresenter = new MainActivityPresenter( this ); TemperatureData temperatureData = new TemperatureData( "10" ); binding.setTemp(temperatureData); binding.setPresenter(mainActivityPresenter); } @Override public void showData(TemperatureData temperatureData) { String celsius = temperatureData.getCelsius(); Toast.makeText( this , celsius, Toast.LENGTH_SHORT).show(); } } <button></button> |
کد کلاس MainActivity را برای فعال سازی data binding تنظیم نمایید.
تست اپلیکیشن
می توانید اپلیکیشن خود را در محیط شبیه ساز راه اندازی نمایید. با کلیک بر روی دکمه، یک popup حامل داده های مرتبط به نمایش در می آید.
با تایپ کردن در فیلد EditText، می بینید که مقادیر المان TextViewبه صورت خودکار بروز رسانی می شود.