این کد لبه بخشی از دوره آموزشی Android Kotlin Fundamentals است. اگر به ترتیب روی کدها کار کنید، بیشترین ارزش را از این دوره خواهید گرفت. همه کدهای دوره در صفحه فرود کد لبه های کدهای Android Kotlin Fundamentals فهرست شده اند.
مقدمه
در کدهای قبلی در این دوره، از تابع findViewById()
برای دریافت ارجاع به view ها استفاده کردید. هنگامی که برنامه شما دارای سلسله مراتب نمای پیچیده است، findViewById()
گران است و سرعت برنامه را کاهش می دهد، زیرا Android سلسله مراتب view را از ریشه شروع می کند تا زمانی که نمای مورد نظر را پیدا کند. خوشبختانه راه بهتری وجود دارد.
برای تنظیم داده ها در نماها، از منابع رشته ای استفاده کرده اید و داده های مربوط به فعالیت را تنظیم کرده اید. اگر view از داده ها مطلع باشد کارآمدتر خواهد بود. و خوشبختانه باز هم این امکان پذیر است.
در این لبه کد، یاد می گیرید که چگونه از data binding برای حذف نیاز به findViewById()
استفاده کنید. همچنین می آموزید که چگونه از اتصال داده برای دسترسی مستقیم به داده ها از یک نما استفاده کنید.
آنچه از قبل باید بدانید
باید با:
- اکتیویتی چیست و چگونه می توان یک اکتیویتی را با طرح بندی در
onCreate()
تنظیم کرد. - ایجاد نمای متنی و تنظیم متنی که نمای متنی نمایش داده می شود.
- استفاده از
findViewById()
برای دریافت ارجاع به view. - ایجاد و ویرایش یک طرح اولیه XML برای یک نما.
چیزی که یاد خواهید گرفت
- نحوه استفاده از Data Binding Library برای حذف تماس های ناکارآمد برای
findViewById()
. - نحوه دسترسی مستقیم به داده های برنامه از XML
کاری که خواهی کرد
- یک برنامه را تغییر دهید تا به جای
findViewById()
از data binding استفاده کند و مستقیماً از فایلهای XML طرحبندی به دادهها دسترسی داشته باشد.
در این کد لبه، شما با برنامه AboutMe شروع میکنید و برنامه را برای استفاده از data binding تغییر میدهید. وقتی کارتان تمام شد، برنامه دقیقاً یکسان به نظر می رسد!
این چیزی است که برنامه AboutMe انجام می دهد:
- وقتی کاربر برنامه را باز می کند، برنامه یک نام، یک فیلد برای وارد کردن نام مستعار، یک دکمه انجام شد، یک تصویر ستاره و متن قابل پیمایش را نشان می دهد.
- کاربر می تواند یک نام مستعار وارد کرده و روی دکمه Done ضربه بزند. فیلد و دکمه قابل ویرایش با نمای متنی جایگزین می شوند که نام مستعار وارد شده را نشان می دهد.
میتوانید از کدی که در نرمافزار قبلی ایجاد کردهاید استفاده کنید، یا میتوانید کد AboutMeDataBinding-Starter را از GitHub دانلود کنید.
کدی که در لبه های کد قبلی نوشتید از تابع findViewById()
برای به دست آوردن ارجاع به view ها استفاده می کند.
هر بار که از findViewById()
برای جستجوی یک View پس از ایجاد یا ایجاد مجدد ویو استفاده میکنید، سیستم Android در زمان اجرا سلسله مراتب view را طی میکند تا آن را پیدا کند. وقتی برنامه شما فقط تعداد انگشت شماری بازدید دارد، مشکلی نیست. با این حال، برنامه های تولیدی ممکن است ده ها نمایش در یک طرح داشته باشند، و حتی با بهترین طراحی، نماهای تو در تو نیز وجود خواهد داشت.
به طرحی خطی فکر کنید که شامل نمای پیمایشی است که حاوی نمای متنی است. برای یک سلسله مراتب نمای بزرگ یا عمیق، یافتن نما می تواند زمان کافی را صرف کند که به طور قابل توجهی سرعت برنامه را برای کاربر کاهش دهد. ذخیره نماها در متغیرها می تواند کمک کننده باشد، اما همچنان باید برای هر نما، در هر فضای نام، متغیری را مقداردهی اولیه کنید. با تعداد زیادی بازدید و فعالیت های متعدد، این نیز اضافه می شود.
یک راه حل این است که یک شی ایجاد کنید که حاوی یک مرجع برای هر نما باشد. این شی که یک شی Binding
نام دارد، می تواند توسط کل برنامه شما استفاده شود. به این تکنیک داده اتصال می گویند . هنگامی که یک شیء الزام آور برای برنامه شما ایجاد شد، می توانید بدون نیاز به پیمودن سلسله مراتب view یا جستجوی داده ها، از طریق شی binding به نماها و سایر داده ها دسترسی داشته باشید.
اتصال داده ها دارای مزایای زیر است:
- کد کوتاهتر، خواندن آسانتر و نگهداری آسانتر از کدی است که از
findByView()
استفاده میکند. - داده ها و دیدگاه ها به وضوح از هم جدا شده اند. این مزیت اتصال داده ها بعداً در این دوره اهمیت فزاینده ای پیدا می کند.
- سیستم اندروید فقط یک بار سلسله مراتب نمایش را طی می کند تا هر نما را دریافت کند، و این در حین راه اندازی برنامه اتفاق می افتد، نه در زمان اجرا زمانی که کاربر در حال تعامل با برنامه است.
- برای دسترسی به نماها ایمنی نوع دریافت می کنید. ( تایپ ایمنی به این معنی است که کامپایلر در حین کامپایل انواع را تایید می کند و اگر بخواهید نوع اشتباهی را به یک متغیر اختصاص دهید با خطا مواجه می شود.)
در این کار، اتصال داده را تنظیم میکنید، و از data binding برای جایگزینی فراخوانیهای findViewById()
با تماسهای شی binding استفاده میکنید.
مرحله 1: اتصال داده را فعال کنید
برای استفاده از اتصال داده، باید اتصال داده را در فایل Gradle خود فعال کنید، زیرا به طور پیش فرض فعال نیست. این به این دلیل است که اتصال داده ها زمان کامپایل را افزایش می دهد و ممکن است بر زمان راه اندازی برنامه تأثیر بگذارد.
- اگر برنامه AboutMe را از یک Codelab قبلی ندارید، کد AboutMeDataBinding-Starter را از GitHub دریافت کنید. آن را در اندروید استودیو باز کنید.
-
build.gradle (Module: app)
را باز کنید. - در داخل بخش
android
، قبل از بستن پرانتزenabled
یک بخشdataBinding
اضافه کنید و رویtrue
تنظیم کنید.
dataBinding {
enabled = true
}
- وقتی از شما خواسته شد، پروژه را همگام سازی کنید. اگر از شما خواسته نشد، File > Sync Project with Gradle Files را انتخاب کنید.
- می توانید برنامه را اجرا کنید، اما هیچ تغییری نمی بینید.
مرحله 2: فایل طرح بندی را تغییر دهید تا با اتصال داده قابل استفاده باشد
برای کار با data binding، باید طرح XML خود را با یک برچسب <layout>
بپیچید. این به این دلیل است که کلاس ریشه دیگر یک گروه نمایش نیست، بلکه یک طرح بندی است که شامل گروهها و نماها است. سپس شی binding می تواند از طرح و نماهای موجود در آن مطلع شود.
- فایل
activity_main.xml
را باز کنید. - به تب Text بروید.
-
<layout></layout>
را به عنوان بیرونی ترین تگ در اطراف<LinearLayout>
اضافه کنید.
<layout>
<LinearLayout ... >
...
</LinearLayout>
</layout>
- برای رفع تورفتگی کد، Code > Reformat code را انتخاب کنید.
اعلانهای فضای نام برای یک طرح باید در بیرونیترین تگ باشد.
- اعلانهای فضای نام را از
<LinearLayout>
برش داده و در تگ<layout>
قرار دهید. تگ<layout>
باز شما باید مانند شکل زیر باشد و تگ<LinearLayout>
فقط باید دارای مشخصات view باشد.
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
- برنامه خود را بسازید و اجرا کنید تا مطمئن شوید که این کار را به درستی انجام داده اید.
مرحله 3: یک شی binding در اکتیویتی اصلی ایجاد کنید
یک مرجع به شی binding به اکتیویتی اصلی اضافه کنید تا بتوانید از آن برای دسترسی به نماها استفاده کنید:
- فایل
MainActivity.kt
را باز کنید. - قبل از
onCreate()
در سطح بالا یک متغیر برای شی binding ایجاد کنید. این متغیر معمولاًbinding
نامیده می شود.
نوعbinding
، کلاسActivityMainBinding
، توسط کامپایلر به طور خاص برای این فعالیت اصلی ایجاد می شود. نام از نام فایل layout گرفته شده است، یعنیactivity_main + Binding
.
private lateinit var binding: ActivityMainBinding
- اگر Android Studio از شما خواسته است،
ActivityMainBinding
را وارد کنید. اگر از شما خواسته نشد، رویActivityMainBinding
کلیک کنید وAlt+Enter
(Option+Enter
در Mac) را فشار دهید تا این کلاس از دست رفته وارد شود. (برای اطلاعات بیشتر میانبرهای صفحه کلید، به میانبرهای صفحه کلید مراجعه کنید.)
عبارتimport
باید شبیه به شکل زیر باشد.
import com.example.android.aboutme.databinding.ActivityMainBinding
در مرحله بعد، تابع setContentView()
فعلی را با دستورالعملی جایگزین می کنید که موارد زیر را انجام می دهد:
- شی binding را ایجاد می کند.
- از تابع
setContentView()
از کلاسDataBindingUtil
برای مرتبط کردن طرحبندیactivity_main
باMainActivity
استفاده میکند. این تابعsetContentView()
همچنین از تنظیمات اتصال داده برای view ها مراقبت می کند.
- در
onCreate()
) فراخوانیsetContentView()
را با خط کد زیر جایگزین کنید.
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
-
DataBindingUtil
را وارد کنید.
import androidx.databinding.DataBindingUtil
مرحله 4: از شی binding برای جایگزینی همه فراخوانی ها برای findViewById() استفاده کنید.
اکنون می توانید همه فراخوانی های findViewById()
را با ارجاع به view هایی که در شی binding هستند جایگزین کنید. هنگامی که شی binding ایجاد می شود، کامپایلر نام نماهای موجود در شی binding را از شناسه نماهای موجود در طرح تولید می کند و آنها را به camel case تبدیل می کند. بنابراین، به عنوان مثال، done_button
در doneButton
binding انجام میشود، nickname_edit
تبدیل به nicknameEdit
و nickname_text
به nicknameText
تبدیل میشود.
- در
onCreate()
، کدی را که ازfindViewById()
برای یافتن دکمهdone_button
استفاده می کند، با کدی که به دکمه موجود در شی binding اشاره می کند، جایگزین کنید.
این کد را جایگزین کنید:findViewById<Button>(R.id.
done_button
)
با:binding.doneButton
کد تمام شده شما برای تنظیم شنونده کلیک درonCreate()
باید شبیه این باشد.
binding.doneButton.setOnClickListener {
addNickname(it)
}
- همین کار را برای همه تماسهای
findViewById()
در تابعaddNickname()
انجام دهید.
همه مواردfindViewById<
View
>(R.id.
id_view
)
را باbinding.
idView
. این کار را به روش زیر انجام دهید:
- تعاریف متغیرهای
editText
وnicknameTextView
را به همراه فراخوانی آنها بهfindViewById()
حذف کنید. این به شما خطا می دهد. - با دریافت نماهای
nicknameText
،nicknameEdit
وdoneButton
از شیbinding
به جای متغیرهای (حذف شده) خطاها را برطرف کنید. -
view.visibility
باbinding.doneButton.visibility
جایگزین کنید. استفاده ازbinding.doneButton
به جایview
پاس شده، کد را سازگارتر می کند.
نتیجه کد زیر است:
binding.nicknameText.text = binding.nicknameEdit.text
binding.nicknameEdit.visibility = View.GONE
binding.doneButton.visibility = View.GONE
binding.nicknameText.visibility = View.VISIBLE
- هیچ تغییری در عملکرد وجود ندارد. به صورت اختیاری، اکنون میتوانید پارامتر
view
را حذف کنید و همه کاربردهایview
را برای استفاده ازbinding.doneButton
در داخل این تابع بهروزرسانی کنید.
-
nicknameText
به یکString
نیاز دارد وnicknameEdit.text
Editable
است. هنگام استفاده از data binding، لازم است کهEditable
را صریحاً به یکString
تبدیل کنید.
binding.nicknameText.text = binding.nicknameEdit.text.toString()
- می توانید واردات خاکستری شده را حذف کنید.
- با استفاده از application
apply{}
تابع را Kotlinize کنید.
binding.apply {
nicknameText.text = nicknameEdit.text.toString()
nicknameEdit.visibility = View.GONE
doneButton.visibility = View.GONE
nicknameText.visibility = View.VISIBLE
}
- برنامه خود را بسازید و اجرا کنید... و باید دقیقاً مانند قبل به نظر برسد و کار کند.
شما می توانید از مزایای اتصال داده استفاده کنید تا یک کلاس داده را مستقیماً در دسترس یک View قرار دهید. این تکنیک کد را ساده می کند و برای رسیدگی به موارد پیچیده تر بسیار ارزشمند است.
برای این مثال، به جای تنظیم نام و نام مستعار با استفاده از منابع رشته، یک کلاس داده برای نام و نام مستعار ایجاد می کنید. شما کلاس داده را با استفاده از data binding در دسترس view قرار می دهید.
مرحله 1: کلاس داده MyName را ایجاد کنید
- در Android Studio در فهرست
java
، فایلMyName.kt
را باز کنید. اگر این فایل را ندارید، یک فایل Kotlin جدید ایجاد کنید و آن راMyName.kt
. - یک کلاس داده برای نام و نام مستعار تعریف کنید. از رشته های خالی به عنوان مقادیر پیش فرض استفاده کنید.
data class MyName(var name: String = "", var nickname: String = "")
مرحله 2: داده ها را به طرح اضافه کنید
در فایل activity_main.xml
، نام در حال حاضر در یک TextView
از یک منبع رشته تنظیم شده است. شما باید ارجاع به نام را با ارجاع به داده در کلاس داده جایگزین کنید.
- فعالیت_
activity_main.xml
در تب Text باز کنید. - در بالای طرح، بین تگ های
<layout>
و<LinearLayout>
، یک تگ<data></data>
وارد کنید. این جایی است که نمای را با داده ها وصل خواهید کرد.
<data>
</data>
در داخل تگ های داده، می توانید متغیرهای نامگذاری شده ای را که مرجع یک کلاس هستند را اعلام کنید.
- داخل تگ
<data>
، یک تگ<variable>
اضافه کنید. - یک پارامتر
name
اضافه کنید تا به متغیر نام"myName"
بدهید. یک پارامترtype
اضافه کنید و نوع را روی یک نام کاملاً واجد شرایط کلاس دادهMyName
(نام بسته + نام متغیر) تنظیم کنید.
<variable
name="myName"
type="com.example.android.aboutme.MyName" />
اکنون به جای استفاده از منبع رشته برای نام، می توانید به متغیر myName
ارجاع دهید.
-
android:text="@string/name"
با کد زیر جایگزین کنید.
@={}
دستوری برای دریافت دادههایی است که در داخل بریسهای فرفری ارجاع میشوند.
myName
به متغیر myName
اشاره میکند که قبلاً تعریف کردهاید، که به کلاس داده myName
اشاره میکند و ویژگی name
را از کلاس واکشی میکند.
android:text="@={myName.name}"
مرحله 3: داده ها را ایجاد کنید
اکنون یک مرجع به داده های موجود در فایل طرح بندی خود دارید. بعد، داده های واقعی را ایجاد می کنید.
- فایل
MainActivity.kt
را باز کنید. - در بالای
onCreate()
یک متغیر خصوصی ایجاد کنید که طبق قراردادmyName
نیز نامیده می شود. متغیر را به عنوان نمونه ای از کلاس دادهMyName
اختصاص دهید که در نام ارسال می شود.
private val myName: MyName = MyName("Aleks Haecky")
- در
onCreate()
مقدار متغیرmyName
در فایل layout را با مقدار متغیرmyName
که به تازگی اعلام کردید تنظیم کنید. شما نمی توانید مستقیماً به متغیر در XML دسترسی داشته باشید. شما باید از طریق شی binding به آن دسترسی داشته باشید.
binding.myName = myName
- این ممکن است یک خطا را نشان دهد، زیرا باید پس از ایجاد تغییرات، شی binding را بهروزرسانی کنید. برنامه خود را بسازید و خطا برطرف می شود.
مرحله 4: از کلاس داده برای نام مستعار در TextView استفاده کنید
مرحله آخر استفاده از کلاس داده برای نام مستعار در TextView
است.
-
activity_main.xml
باز کنید. - در نمای متنی
nickname_text
، یک ویژگیtext
اضافه کنید. مطابق شکل زیر بهnickname
در کلاس داده ارجاع دهید.
android:text="@={myName.nickname}"
- در
ActivityMain
، جایگزین کنید
nicknameText.text = nicknameEdit.text.toString()
با کد برای تنظیم نام مستعار در متغیرmyName
.
myName?.nickname = nicknameEdit.text.toString()
پس از تنظیم نام مستعار، میخواهید کد شما رابط کاربری را با دادههای جدید تازهسازی کند. برای انجام این کار، باید تمام عبارات binding را باطل کنید تا با داده های صحیح دوباره ایجاد شوند.
- پس از تنظیم نام مستعار،
invalidateAll()
را اضافه کنید تا UI با مقدار موجود در شی binding به روز شود.
binding.apply {
myName?.nickname = nicknameEdit.text.toString()
invalidateAll()
...
}
- برنامه خود را بسازید و اجرا کنید، و باید دقیقاً مانند قبل کار کند.
پروژه Android Studio: AboutMeDataBinding
مراحل استفاده از data binding برای جایگزینی تماس با findViewById()
:
- اتصال داده را در بخش اندروید فایل
build.gradle
کنید:
dataBinding { enabled = true }
- از
<layout>
به عنوان نمای ریشه در طرح بندی XML خود استفاده کنید. - یک متغیر الزام آور را تعریف کنید:
private lateinit var binding: ActivityMainBinding
- یک شیء اتصال در
MainActivity
کنید، به جایsetContentView
:
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
- فراخوانی برای
findViewById()
را با ارجاع به view در شی binding جایگزین کنید. مثلا:
findViewById<Button>(R.id.done_button) ⇒ binding.doneBu
tton
(در مثال، نام view ازid
view در XML ایجاد شده است.)
مراحل اتصال نماها به داده ها:
- یک کلاس داده برای داده های خود ایجاد کنید.
- یک بلوک
<data>
داخل تگ<layout>
اضافه کنید. - یک
<variable>
را با یک نام و یک نوع کلاس داده تعریف کنید.
<data>
<variable
name="myName"
type="com.example.android.aboutme.MyName" />
</data>
- در
MainActivity
، یک متغیر با نمونه ای از کلاس داده ایجاد کنید. مثلا:
private val myName: MyName = MyName("Aleks Haecky")
- در شیء binding، متغیر را روی متغیری که به تازگی ایجاد کرده اید، تنظیم کنید:
binding.myName = myName
- در XML، محتوای view را روی متغیری که در بلوک
<data>
تعریف کرده اید، تنظیم کنید. از نماد نقطه برای دسترسی به داده های داخل کلاس داده استفاده کنید.
android:text="@={myName.name}"
دوره بی ادبی:
مستندات توسعه دهنده اندروید:
- کتابخانه صحافی داده
- کلاس های الزام آور ایجاد شده است
- با اتصال داده ها شروع کنید
- چیدمان ها و عبارات الزام آور
این بخش، تکالیف احتمالی را برای دانشآموزانی که در این آزمایشگاه کد به عنوان بخشی از دورهای که توسط یک مربی هدایت میشود، فهرست میکند. این وظیفه مربی است که موارد زیر را انجام دهد:
- در صورت نیاز تکالیف را تعیین کنید.
- نحوه ارسال تکالیف را با دانش آموزان در میان بگذارید.
- تکالیف را نمره دهید.
مربیان میتوانند از این پیشنهادات به اندازهای که میخواهند استفاده کنند، و باید با خیال راحت هر تکلیف دیگری را که فکر میکنند مناسب است به آنها اختصاص دهند.
اگر به تنهایی بر روی این کدها کار می کنید، از این تکالیف برای آزمایش دانش خود استفاده کنید.
یه این سوالات پاسخ دهید
سوال 1
چرا می خواهید فراخوانی های صریح و ضمنی را برای findViewById()
به حداقل برسانید؟
- هر بار که
findViewById()
فراخوانی می شود، از سلسله مراتب view عبور می کند. -
findViewById()
روی رشته اصلی یا UI اجرا می شود. - این تماس ها می توانند رابط کاربری را کاهش دهند.
- احتمال خرابی اپلیکیشن شما کمتر است.
سوال 2
اتصال داده را چگونه توصیف می کنید؟
به عنوان مثال، در اینجا مواردی وجود دارد که می توانید در مورد اتصال داده ها بگویید:
- ایده بزرگ در مورد اتصال داده، ایجاد یک شی است که در زمان کامپایل، دو قطعه از اطلاعات دور را به هم متصل/نقشهبرداری/پیوند میدهد، به طوری که در زمان اجرا نیازی به جستجوی دادهها نباشید.
- شیئی که این اتصالات را به شما نشان می دهد، شیء اتصال نامیده می شود.
- شی binding توسط کامپایلر ایجاد می شود.
سوال 3
کدام یک از موارد زیر از مزایای اتصال داده ها نیست؟
- کد کوتاهتر، خواندن آسانتر و نگهداری آسانتر است.
- داده ها و دیدگاه ها به وضوح از هم جدا شده اند.
- سیستم اندروید برای دریافت هر نما فقط یک بار سلسله مراتب را طی می کند.
- فراخوانی
findViewById()
یک خطای کامپایلر ایجاد می کند. - ایمنی را برای دسترسی به نماها تایپ کنید.
سوال 4
وظیفه تگ <layout>
چیست؟
- شما آن را به دور نمای ریشه خود در طرح بندی می پیچید.
- صحافی ها برای همه نماها در یک طرح ایجاد می شوند.
- نمای سطح بالا را در یک طرح XML مشخص می کند که از اتصال داده استفاده می کند.
- می توانید از تگ
<data>
در داخل<layout>
برای اتصال یک متغیر به یک کلاس داده استفاده کنید.
سوال 5
راه صحیح ارجاع داده های محدود در طرح XML کدام است؟
-
android:text="@={myDataClass.property}"
-
android:text="@={myDataClass}"
-
android:text="@={myDataClass.property.toString()}"
-
android:text="@={myDataClass.bound_data.property}"
درس بعدی را شروع کنید:
برای پیوند به دیگر کدهای این دوره، به صفحه فرود کد لبههای کد پایه Android Kotlin Fundamentals مراجعه کنید.