این کد لبه بخشی از دوره آموزشی Android Kotlin Fundamentals است. اگر به ترتیب روی کدها کار کنید، بیشترین ارزش را از این دوره خواهید گرفت. همه کد لبه های دوره در صفحه فرود کد لبه های Android Kotlin Fundamentals فهرست شده اند.
مقدمه
در آزمایشگاه کد قبلی، برنامه TrackMySleepQuality را برای نمایش دادههای مربوط به کیفیت خواب در RecyclerView بهروزرسانی کردید. تکنیک هایی که هنگام ساختن اولین RecyclerView خود یاد گرفتید برای اکثر RecyclerViews که لیست های ساده ای را نمایش می دهند که خیلی بزرگ نیستند کافی است. با این حال، تعدادی تکنیک وجود دارد که RecyclerView برای لیستهای بزرگ کارآمدتر میکند و حفظ و گسترش کد شما را برای لیستها و شبکههای پیچیده آسانتر میکند.
در این کد لبه، شما بر اساس برنامه ردیاب خواب از کد لبه قبلی ایجاد می کنید. روش موثرتری برای بهروزرسانی فهرست دادههای خواب را یاد میگیرید و نحوه استفاده از اتصال داده با RecyclerView را یاد میگیرید. (اگر برنامه نسخه قبلی را ندارید، می توانید کد شروع را برای این کد لبه دانلود کنید.)
آنچه از قبل باید بدانید
- ساخت یک رابط کاربری پایه با استفاده از یک فعالیت، قطعات و نماها.
- پیمایش بین قطعات و استفاده از
safeArgsبرای انتقال داده ها بین قطعات. - مشاهده مدلها، مشاهده کارخانههای مدل، تبدیلها، و
LiveDataو ناظران آنها. - چگونه یک پایگاه داده
Roomایجاد کنیم، یک DAO ایجاد کنیم و موجودیت ها را تعریف کنیم. - نحوه استفاده از کوروتین ها برای پایگاه داده و سایر کارهای طولانی مدت.
- نحوه پیاده سازی
RecyclerViewاولیه باAdapter،ViewHolderو طرح بندی آیتم.
چیزی که یاد خواهید گرفت
- نحوه استفاده از
DiffUtilبرای به روز رسانی موثر لیست نمایش داده شده توسطRecyclerView. - نحوه استفاده از data binding با
RecyclerView. - نحوه استفاده از آداپتورهای اتصال برای تبدیل داده ها
کاری که خواهی کرد
- بر اساس برنامه TrackMySleepQuality از کدهای قبلی در این سری ساخته شده است.
-
SleepNightAdapterبهروزرسانی کنید تا لیست را با استفاده ازDiffUtilبهروز کنید. - اجرای اتصال داده برای
RecyclerView، با استفاده از آداپتورهای اتصال برای تبدیل داده ها.
برنامه ردیاب خواب دارای دو صفحه است که با قطعات نشان داده شده است، همانطور که در شکل زیر نشان داده شده است.
|
|
اولین صفحه نمایش داده شده در سمت چپ دارای دکمه هایی برای شروع و توقف ردیابی است. صفحه نمایش برخی از داده های خواب کاربر را نشان می دهد. دکمه Clear تمام داده هایی را که برنامه برای کاربر جمع آوری کرده است برای همیشه حذف می کند. صفحه دوم، نشان داده شده در سمت راست، برای انتخاب رتبه بندی کیفیت خواب است.
این برنامه به گونهای طراحی شده است که از کنترلر رابط کاربری، ViewModel و LiveData و پایگاه داده Room برای تداوم دادههای خواب استفاده کند.

داده های خواب در یک RecyclerView نمایش داده می شود. در این کد لبه، شما بخش DiffUtil و data-binding را برای RecyclerView میسازید. بعد از این کد، برنامه شما دقیقاً یکسان به نظر می رسد، اما کارآمدتر و آسان تر مقیاس و نگهداری خواهد بود.
میتوانید به استفاده از برنامه SleepTracker از آزمایشگاه کد قبلی ادامه دهید، یا میتوانید برنامه RecyclerViewDiffUtilDataBinding-Starter را از GitHub دانلود کنید.
- در صورت نیاز، برنامه RecyclerViewDiffUtilDataBinding-Starter را از GitHub دانلود کنید و پروژه را در Android Studio باز کنید.
- برنامه را اجرا کنید.
- فایل
SleepNightAdapter.ktرا باز کنید. - کد را بررسی کنید تا با ساختار برنامه آشنا شوید. برای خلاصه ای از استفاده از
RecyclerViewبا الگوی آداپتور برای نمایش داده های خواب به کاربر، به نمودار زیر مراجعه کنید.

- از ورودی کاربر، برنامه لیستی از اشیاء
SleepNightایجاد می کند. هر شیءSleepNightنشان دهنده یک شب خواب، مدت زمان و کیفیت آن است. -
SleepNightAdapterلیست اشیاءSleepNightرا با چیزی تطبیق می دهد کهRecyclerViewمی تواند استفاده کند و نمایش دهد. - آداپتور
SleepNightAdapterViewHoldersرا تولید می کند که حاوی نماها، داده ها و اطلاعات متا برای نمای Recycler برای نمایش داده ها است. -
RecyclerViewازSleepNightAdapterبرای تعیین تعداد آیتم برای نمایش (getItemCount()) استفاده می کند.RecyclerViewازonCreateViewHolder()وonBindViewHolder()برای اتصال دارندگان view به داده ها برای نمایش استفاده می کند.
متد notifyDataSetChanged() ناکارآمد است
برای اینکه RecyclerView بگوییم که یک آیتم در لیست تغییر کرده و باید بهروزرسانی شود، کد فعلی notifyDataSetChanged() در SleepNightAdapter فراخوانی میکند، همانطور که در زیر نشان داده شده است.
var data = listOf<SleepNight>()
set(value) {
field = value
notifyDataSetChanged()
} با این حال، notifyDataSetChanged() به RecyclerView می گوید که کل لیست به طور بالقوه نامعتبر است. در نتیجه، RecyclerView همه موارد موجود در لیست، از جمله مواردی را که روی صفحه قابل مشاهده نیستند، مجدداً باند می کند و دوباره ترسیم می کند. این خیلی کار غیر ضروری است. برای لیستهای بزرگ یا پیچیده، این فرآیند ممکن است به اندازهای طول بکشد که هنگام حرکت کاربر در لیست، صفحه نمایش سوسو بزند یا دچار لکنت شود.
برای رفع این مشکل، میتوانید به RecyclerView بگویید دقیقاً چه چیزی تغییر کرده است. سپس RecyclerView می تواند تنها نماهایی را که روی صفحه تغییر کرده اند به روز کند.
RecyclerView یک API غنی برای به روز رسانی یک عنصر دارد. می توانید از notifyItemChanged() استفاده کنید تا به RecyclerView بگویید که یک مورد تغییر کرده است، و می توانید از توابع مشابه برای مواردی که اضافه، حذف یا جابجا شده اند استفاده کنید. شما می توانید همه این کارها را به صورت دستی انجام دهید، اما این کار بی اهمیت است و ممکن است شامل مقدار زیادی کد باشد.
خوشبختانه راه بهتری وجود دارد.
DiffUtil کارآمد است و کار سخت را برای شما انجام می دهد
RecyclerView یک کلاس به نام DiffUtil دارد که برای محاسبه تفاوت بین دو لیست است. DiffUtil یک لیست قدیمی و یک لیست جدید را می گیرد و متوجه می شود که چه چیزی متفاوت است. موارد اضافه، حذف یا تغییر یافته را پیدا می کند. سپس از الگوریتمی به نام الگوریتم تفاوت یوجین دبلیو مایرز استفاده می کند تا حداقل تعداد تغییراتی را که باید از لیست قدیمی ایجاد شود تا لیست جدید ایجاد کند، مشخص کند.
هنگامی که DiffUtil متوجه شد چه چیزی تغییر کرده است، RecyclerView می تواند از آن اطلاعات برای به روز رسانی فقط مواردی که تغییر، اضافه، حذف یا جابجا شده اند استفاده کند، که بسیار کارآمدتر از انجام مجدد کل لیست است.
در این کار، SleepNightAdapter را ارتقا می دهید تا از DiffUtil برای بهینه سازی RecyclerView برای تغییرات داده ها استفاده کند.
مرحله 1: اجرای SleepNightDiffCallback
به منظور استفاده از عملکرد کلاس DiffUtil ، DiffUtil.ItemCallback گسترش دهید.
-
SleepNightAdapter.ktرا باز کنید. - در زیر تعریف کامل کلاس برای
SleepNightAdapter، یک کلاس سطح بالای جدید به نامSleepNightDiffCallbackبسازید کهDiffUtil.ItemCallbackگسترش می دهد.SleepNightبه عنوان یک پارامتر عمومی بگذرانید.
class SleepNightDiffCallback : DiffUtil.ItemCallback<SleepNight>() {
}- مکان نما را در نام کلاس
SleepNightDiffCallbackقرار دهید. -
Alt+Enterرا فشار دهید (Option+Enterدر Mac) و Implement Members را انتخاب کنید. - در محاوره ای که باز می شود، برای انتخاب متدهای
areItemsTheSame()وareContentsTheSame()شیفت چپ کلیک کنید، سپس روی OK کلیک کنید.
همانطور که در زیر نشان داده شده است، این کار در داخلSleepNightDiffCallbackبرای دو روش ایجاد می کند.DiffUtilاز این دو روش استفاده می کند تا بفهمد لیست و آیتم ها چگونه تغییر کرده اند.
override fun areItemsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun areContentsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}- در داخل
areItemsTheSame()، کدTODOبا کدی جایگزین کنید که آزمایش می کند آیا دو آیتمSleepNight،oldItemوnewItemیکسان هستند یا خیر. اگر موارد دارایnightIdیکسان هستند، آنها همان آیتم هستند، بنابراینtrueرا برگردانید. در غیر این صورت،falseرا برگردانید.DiffUtilاز این تست برای کمک به کشف اینکه آیا یک مورد اضافه، حذف یا منتقل شده است استفاده می کند.
override fun areItemsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
return oldItem.nightId == newItem.nightId
}- در داخل
areContentsTheSame()، بررسی کنید که آیاoldItemوnewItemدارای داده های یکسان هستند یا خیر. یعنی برابرند یا نه. این بررسی برابری همه فیلدها را بررسی می کند، زیراSleepNightیک کلاس داده است. کلاس هایDataبه طور خودکارequalsو چند روش دیگر را برای شما تعریف می کنند. اگر بینoldItemوnewItemتفاوت هایی وجود داشته باشد، این کد بهDiffUtilمی گوید که مورد به روز شده است.
override fun areContentsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
return oldItem == newItem
} استفاده از RecyclerView برای نمایش لیستی که تغییر می کند یک الگوی رایج است. RecyclerView یک کلاس آداپتور به ListAdapter ارائه می دهد که به شما کمک می کند یک آداپتور RecyclerView بسازید که توسط یک لیست پشتیبانی می شود.
ListAdapter لیست را برای شما پیگیری می کند و هنگامی که لیست به روز می شود به آداپتور اطلاع می دهد.
مرحله 1: آداپتور خود را برای گسترش ListAdapter تغییر دهید
- در فایل
SleepNightAdapter.kt، امضای کلاسSleepNightAdapterرا به گسترشListAdapterتغییر دهید. - اگر از شما خواسته شد،
androidx.recyclerview.widget.ListAdapterرا وارد کنید. -
SleepNightبه عنوان اولین آرگومان بهListAdapterقبل ازSleepNightAdapter.ViewHolderاضافه کنید. -
SleepNightDiffCallback()را به عنوان یک پارامتر به سازنده اضافه کنید.ListAdapterاز این استفاده می کند تا بفهمد چه چیزی در لیست تغییر کرده است. امضای کلاسSleepNightAdapterتمام شده شما باید مطابق شکل زیر باشد.
class SleepNightAdapter : ListAdapter<SleepNight, SleepNightAdapter.ViewHolder>(SleepNightDiffCallback()) {- در داخل کلاس
SleepNightAdapter، فیلدdata، از جمله تنظیم کننده را حذف کنید. شما دیگر به آن نیاز ندارید، زیراListAdapterلیست را برای شما پیگیری می کند. - نادیده گرفتن
getItemCount()را حذف کنید، زیراListAdapterاین روش را برای شما پیاده سازی می کند. - برای خلاص شدن از خطای
onBindViewHolder()متغیرitemرا تغییر دهید. به جای استفاده ازdataبرای دریافت یکitem، متدgetItem(position)را کهListAdapterارائه می دهد فراخوانی کنید.
val item = getItem(position)مرحله 2: برای به روز نگه داشتن لیست از submitList() استفاده کنید
کد شما باید به ListAdapter اطلاع دهد که لیست تغییر یافته در دسترس است. ListAdapter متدی به نام submitList() ارائه می کند تا به ListAdapter بگوید که نسخه جدیدی از لیست موجود است. هنگامی که این روش فراخوانی می شود، ListAdapter لیست جدید را با لیست قدیمی متفاوت می کند و موارد اضافه، حذف، جابجایی یا تغییر را تشخیص می دهد. سپس ListAdapter موارد نشان داده شده توسط RecyclerView به روز می کند.
-
SleepTrackerFragment.ktرا باز کنید. - در
onCreateView()، در مشاهدهگر درsleepTrackerViewModel، خطا را پیدا کنید که در آن متغیرdataکه حذف کرده اید ارجاع داده شده است. - جایگزین
adapter.data = itبا یک فراخوانی بهadapter.submitList(it)جایگزین کنید. کد به روز شده در زیر نشان داده شده است.
sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
it?.let {
adapter.submitList(it)
}
})- برنامه خود را اجرا کنید سریعتر اجرا میشود، شاید اگر لیست شما کوچک باشد، بهطور محسوسی کار نمیکند.
در این کار، از همان تکنیکی که در codelab های قبلی وجود داشت برای تنظیم اتصال داده ها استفاده می کنید و تماس های findViewById() را حذف می کنید.
مرحله 1: اتصال داده را به فایل طرح بندی اضافه کنید
- فایل طرح بندی
list_item_sleep_night.xmlرا در تب Text باز کنید. - مکان نما را روی تگ
ConstraintLayoutقرار دهید وAlt+Enterرا فشار دهید (Option+Enterدر مک). منوی قصد (منوی "رفع سریع") باز می شود. - Convert to data binding layout را انتخاب کنید. این طرح را در
<layout>می پیچد و یک تگ<data>در داخل آن اضافه می کند. - در صورت لزوم به بالا برگردید و در داخل تگ
<data>، متغیری به نامsleepرا اعلام کنید. -
typeآن را به نام کاملاً واجد شرایطSleepNight،com.example.android.trackmysleepquality.database.SleepNightتبدیل کنید. تگ<data>تمام شده شما باید مانند شکل زیر باشد.
<data>
<variable
name="sleep"
type="com.example.android.trackmysleepquality.database.SleepNight"/>
</data>- برای اجبار ایجاد شی
Binding، Build > Clean Project و سپس Build > Rebuild Project را انتخاب کنید. (اگر همچنان مشکل دارید، File > Invalidate Caches / Restart را انتخاب کنید.) شیء اتصالListItemSleepNightBindingبه همراه کد مربوطه به فایل های تولید شده پروژه اضافه می شود.
مرحله 2: طرح بندی مورد را با استفاده از اتصال داده باد کنید
-
SleepNightAdapter.ktرا باز کنید. - در کلاس
ViewHolderمتدfrom()را پیدا کنید. - اعلان متغیر
viewرا حذف کنید.
کد برای حذف :
val view = layoutInflater
.inflate(R.layout.list_item_sleep_night, parent, false)- در جایی که متغیر
viewبود، یک متغیر جدید به نامbindingتعریف کنید که شیء اتصالListItemSleepNightBindingمانند شکل زیر باد می کند. وارد کردن لازم شیء binding را انجام دهید.
val binding =
ListItemSleepNightBinding.inflate(layoutInflater, parent, false)- در پایان تابع، به جای برگرداندن
view،bindingبرگردانید.
return ViewHolder(binding)- برای خلاص شدن از خطا، مکان نما را روی کلمه
bindingقرار دهید.Alt+Enter(Option+Enterدر مک) را فشار دهید تا منوی قصد باز شود.
- تغییر پارامتر «itemView» نوع سازنده اصلی کلاس «ViewHolder» به «ListItemSleepNightBinding» را انتخاب کنید. این نوع پارامتر کلاس
ViewHolderرا به روز می کند.

- برای مشاهده تغییر در امضا، به سمت تعریف کلاس
ViewHolderبروید. شما یک خطا برایitemViewمی بینید، زیرا در متدfrom()itemViewبهbindingتغییر داده اید.
در تعریف کلاسViewHolder، روی یکی از رخدادهایitemViewکلیک راست کرده و Refactor > Rename را انتخاب کنید. نام را بهbindingتغییر دهید. - پیشوند
bindingپارامتر سازنده را باvalقرار دهید تا به یک ویژگی تبدیل شود. - در فراخوانی کلاس والد،
RecyclerView.ViewHolder، پارامتر را ازbindingبهbinding.rootتغییر دهید. شما باید یکViewرا ارسال کنید وbinding.rootریشهConstraintLayoutدر طرح بندی آیتم شما است. - اعلان کلاس تمام شده شما باید مانند کد زیر باشد.
class ViewHolder private constructor(val binding: ListItemSleepNightBinding) : RecyclerView.ViewHolder(binding.root){همچنین یک خطا برای فراخوانی برای findViewById() می بینید و بعداً این مشکل را برطرف می کنید.
مرحله 3: جایگزین findViewById()
اکنون میتوانید ویژگیهای sleepLength ، quality ، و qualityImage را بهروزرسانی کنید تا از شی binding به جای findViewById() استفاده کنید.
- مقداردهی اولیه
sleepLength،qualityString، وqualityImageرا برای استفاده از نماهای شیbinding، مطابق شکل زیر تغییر دهید. پس از این، کد شما نباید دیگر خطا نشان دهد.
val sleepLength: TextView = binding.sleepLength
val quality: TextView = binding.qualityString
val qualityImage: ImageView = binding.qualityImageبا قرار دادن شی binding، دیگر نیازی به تعریف خصوصیات sleepLength ، quality و qualityImage ندارید. DataBinding جستجوها را کش می کند، بنابراین نیازی به اعلام این ویژگی ها نیست.
- روی نام ویژگیهای
sleepLength،qualityوqualityImageراست کلیک کنید. Refactor > Inline را انتخاب کنید یاControl+Command+N(Option+Command+Nدر Mac) را فشار دهید.
- برنامه خود را اجرا کنید (ممکن است لازم باشد پروژه خود را در صورت وجود خطا پاکسازی و بازسازی کنید .)
در این کار، برنامه خود را ارتقا می دهید تا از اتصال داده با آداپتورهای اتصال برای تنظیم داده ها در نماهای خود استفاده کند.
در یک کد لبه قبلی، از کلاس Transformations برای گرفتن LiveData و تولید رشته های فرمت شده برای نمایش در نمای متن استفاده می کردید. با این حال، اگر نیاز به اتصال انواع مختلف یا انواع پیچیده دارید، میتوانید آداپتورهای اتصال را برای کمک به اتصال دادهها در استفاده از آن انواع ارائه کنید. آداپتورهای صحافی، آداپتورهایی هستند که دادههای شما را میگیرند و آنها را به چیزی تطبیق میدهند که با اتصال داده میتواند برای پیوند دادن یک نما، مانند متن یا تصویر، استفاده کند.
شما می خواهید سه آداپتور صحافی را پیاده سازی کنید، یکی برای تصویر با کیفیت و یکی برای هر فیلد متنی. به طور خلاصه، برای اعلام یک آداپتور binding، روشی را تعریف میکنید که یک آیتم و یک view را میگیرد و آن را با @BindingAdapter حاشیهنویسی میکند. در بدنه روش، تبدیل را اجرا می کنید. در Kotlin، میتوانید یک آداپتور binding را به عنوان یک تابع افزونه روی کلاس view که دادهها را دریافت میکند، بنویسید.
مرحله 1: آداپتورهای اتصال ایجاد کنید
توجه داشته باشید که در مرحله باید تعدادی کلاس وارد کنید و به صورت جداگانه فراخوانی نمی شود.
-
SleepNightAdapater.ktرا باز کنید. - در داخل کلاس
ViewHolder، متدbind()پیدا کنید و به خود یادآوری کنید که این متد چه کاری انجام می دهد. کدی را که مقادیرbinding.sleepLength،binding.qualityوbinding.qualityImageرا محاسبه میکند، دریافت کرده و به جای آن در آداپتور استفاده کنید. (در حال حاضر، کد را همانطور که هست بگذارید، در مرحله بعد آن را منتقل کنید.) - در بسته
sleeptracker، فایلی به نامBindingUtils.ktایجاد و باز کنید. - یک تابع افزونه در
TextViewبه نامsetSleepDurationFormattedاعلام کنید و در یکSleepNightعبور دهید. این تابع آداپتور شما برای محاسبه و قالب بندی مدت زمان خواب خواهد بود.
fun TextView.setSleepDurationFormatted(item: SleepNight) {}- در بدنه
setSleepDurationFormatted، داده ها را به view متصل کنید، همانطور که درViewHolder.bind()انجام دادید.convertDurationToFormatted()فراخوانی کنید و سپسtextTextViewرا روی متن فرمت شده تنظیم کنید. (از آنجا که این یک تابع افزونه درTextViewاست، می توانید مستقیماً به ویژگیtextدسترسی داشته باشید.)
text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, context.resources)- برای اطلاع از اتصال دادهها در مورد این آداپتور اتصال، تابع را با
@BindingAdapterحاشیهنویسی کنید. - این تابع آداپتور ویژگی
sleepDurationFormattedاست، بنابراینsleepDurationFormattedبه عنوان آرگومان به@BindingAdapterمنتقل کنید.
@BindingAdapter("sleepDurationFormatted")- آداپتور دوم کیفیت خواب را بر اساس مقدار موجود در یک شی
SleepNightتنظیم می کند. یک تابع افزونه به نامsetSleepQualityString()درTextViewایجاد کنید و در یکSleepNightارسال کنید. - در بدنه، دادهها را مانند
ViewHolder.bind()به view متصل کنید.convertNumericQualityToStringرا فراخوانی کرده وtextرا تنظیم کنید. - تابع را با
@BindingAdapter("sleepQualityString")حاشیه نویسی کنید.
@BindingAdapter("sleepQualityString")
fun TextView.setSleepQualityString(item: SleepNight) {
text = convertNumericQualityToString(item.sleepQuality, context.resources)
}- سومین آداپتور صحافی تصویر را در نمای تصویر تنظیم می کند. تابع افزونه را در
ImageViewایجاد کنید،setSleepImageفراخوانی کنید و از کدViewHolder.bind()استفاده کنید، همانطور که در زیر نشان داده شده است.
@BindingAdapter("sleepImage")
fun ImageView.setSleepImage(item: SleepNight) {
setImageResource(when (item.sleepQuality) {
0 -> R.drawable.ic_sleep_0
1 -> R.drawable.ic_sleep_1
2 -> R.drawable.ic_sleep_2
3 -> R.drawable.ic_sleep_3
4 -> R.drawable.ic_sleep_4
5 -> R.drawable.ic_sleep_5
else -> R.drawable.ic_sleep_active
})
}مرحله ۲: SleepNightAdapter را بهروزرسانی کنید
-
SleepNightAdapter.ktرا باز کنید. - همه موارد موجود در متد
bind()حذف کنید، زیرا اکنون می توانید از binding داده و آداپتورهای جدید خود برای انجام این کار برای شما استفاده کنید.
fun bind(item: SleepNight) {
}- Inside
bind()، خواب را بهitemاختصاص دهید، زیرا باید به شی binding در موردSleepNightجدید خود بگویید.
binding.sleep = item- در زیر آن خط،
binding.executePendingBindings()اضافه کنید. این فراخوانی یک بهینهسازی است که از binding دادهها میخواهد تا هر اتصال معلق را فوراً اجرا کند. هنگامی که از آداپتورهای binding درRecyclerViewاستفاده می کنید، همیشه ایده خوبی است کهexecutePendingBindings()را فراخوانی کنید، زیرا می تواند اندازه نماها را کمی افزایش دهد.
binding.executePendingBindings()مرحله 3: پیوندها را به طرح XML اضافه کنید
-
list_item_sleep_night.xmlرا باز کنید. - در
ImageView، یک ویژگیappبا همان نام آداپتور صحافی که تصویر را تنظیم میکند، اضافه کنید. مطابق شکل زیر متغیرsleepرا پاس کنید.
این ویژگی از طریق آداپتور، ارتباط بین view و شی binding را ایجاد می کند. هر زمان که بهsleepImageارجاع داده شود، آداپتور داده هایSleepNightرا تطبیق می دهد.
app:sleepImage="@{sleep}"- همین کار را برای نماهای متنی
sleep_lengthوquality_stringانجام دهید. هر زمان کهsleepDurationFormattedیاsleepQualityStringارجاع داده شود، آداپتورها دادههایSleepNightرا تطبیق میدهند.
app:sleepDurationFormatted="@{sleep}"app:sleepQualityString="@{sleep}"- برنامه خود را اجرا کنید دقیقاً مانند قبل عمل می کند. آداپتورهای صحافی تمام کارهای قالببندی و بهروزرسانی نماها را با تغییر دادهها انجام میدهند،
ViewHolderساده میکنند و به کد ساختار بسیار بهتری نسبت به قبل میدهند.
شما همان لیست را برای چند تمرین آخر نمایش داده اید. این طراحی به شما نشان می دهد که رابط Adapter به شما امکان می دهد کد خود را به روش های مختلف معماری کنید. هرچه کد شما پیچیدهتر باشد، معماری خوب آن اهمیت بیشتری پیدا میکند. در برنامههای تولیدی، این الگوها و سایر الگوها با RecyclerView استفاده میشوند. الگوها همه کار می کنند و هر کدام مزایای خود را دارند. کدام یک را انتخاب می کنید بستگی به چیزی دارد که می سازید.
تبریک میگم در این مرحله شما به خوبی در راه تسلط بر RecyclerView در اندروید هستید.
پروژه Android Studio: RecyclerViewDiffUtilDataBinding .
DiffUtil :
-
RecyclerViewیک کلاس به نامDiffUtilدارد که برای محاسبه تفاوت بین دو لیست است. -
DiffUtilیک کلاس به نامItemCallBackدارد که شما آن را گسترش می دهید تا تفاوت بین دو لیست را بفهمید. - در کلاس
ItemCallback، باید متدهایareItemsTheSame()وareContentsTheSame()را لغو کنید.
ListAdapter :
- برای دریافت مدیریت لیست به صورت رایگان، می توانید از کلاس
ListAdapterبه جایRecyclerView.Adapterاستفاده کنید. با این حال، اگر ازListAdapterاستفاده میکنید، باید آداپتور خود را برای طرحبندیهای دیگر بنویسید، به همین دلیل است که این کد لبه به شما نشان میدهد که چگونه این کار را انجام دهید. - برای باز کردن منوی قصد در Android Studio، مکان نما را روی هر کدی از کد قرار دهید و
Alt+Enter(Option+Enterدر مک) را فشار دهید. این منو به ویژه برای بازآفرینی کد و ایجاد خرد برای پیاده سازی روش ها مفید است. منو به زمینه حساس است، بنابراین برای دریافت منوی صحیح باید مکان نما را دقیقاً قرار دهید.
اتصال داده ها:
- برای اتصال داده ها به نماها، در چیدمان مورد استفاده کنید.
آداپتورهای اتصال:
- شما قبلاً از
Transformationsبرای ایجاد رشته ها از داده ها استفاده کرده اید. اگر نیاز به اتصال دادهها از انواع مختلف یا پیچیده دارید، آداپتورهای اتصال را برای کمک به اتصال دادهها در استفاده از آنها فراهم کنید. - برای اعلام یک آداپتور binding، متدی را تعریف کنید که یک آیتم و یک view را می گیرد و روی روش را با
@BindingAdapterحاشیه نویسی کنید. در Kotlin، می توانید آداپتور binding را به عنوان یک تابع افزونه درViewبنویسید. به نام ویژگی که آداپتور تطبیق می دهد، عبور دهید. به عنوان مثال:
@BindingAdapter("sleepDurationFormatted")- در طرح XML، یک ویژگی
appرا با همان نام آداپتور binding تنظیم کنید. یک متغیر را با داده ارسال کنید. به عنوان مثال:
.app:sleepDurationFormatted="@{sleep}"دوره های بی ادبی:
مستندات توسعه دهنده اندروید:
- یک لیست با RecyclerView ایجاد کنید
-
RecyclerView -
DiffUtil - کتابخانه صحافی داده
- آداپتورهای صحافی
-
notifyDataSetChanged() -
Transformations
سایر منابع:
این بخش، تکالیف احتمالی را برای دانشآموزانی که در این آزمایشگاه کد به عنوان بخشی از دورهای که توسط یک مربی هدایت میشود، کار میکنند، فهرست میکند. این وظیفه مربی است که موارد زیر را انجام دهد:
- در صورت نیاز تکالیف را تعیین کنید.
- نحوه ارسال تکالیف را با دانش آموزان در میان بگذارید.
- تکالیف را نمره دهید.
مربیان میتوانند از این پیشنهادات به اندازهای که میخواهند استفاده کنند، و باید با خیال راحت هر تکلیف دیگری را که فکر میکنند مناسب است، محول کنند.
اگر به تنهایی از طریق این کدها کار می کنید، از این تکالیف برای آزمایش دانش خود استفاده کنید.
به این سوالات پاسخ دهید
سوال 1
کدام یک از موارد زیر برای استفاده DiffUtil ضروری است؟ همه موارد کاربردی را انتخاب کنید.
▢ کلاس ItemCallBack را گسترش دهید.
▢ areItemsTheSame() لغو کنید.
▢ areContentsTheSame() لغو کنید.
▢ برای ردیابی تفاوت بین موارد از اتصال داده استفاده کنید.
سوال 2
کدام یک از موارد زیر در مورد آداپتورهای اتصال درست است؟
▢ آداپتور binding تابعی است که با @BindingAdapter مشروح شده است.
▢ استفاده از یک آداپتور صحافی به شما امکان می دهد قالب بندی داده ها را از نگهدارنده نمایش جدا کنید.
▢ اگر میخواهید از آداپتورهای اتصال استفاده کنید، باید از RecyclerViewAdapter استفاده کنید.
▢ آداپتورهای صحافی راه حل خوبی برای زمانی است که شما نیاز به تبدیل داده های پیچیده دارید.
سوال 3
چه زمانی باید از Transformations به جای آداپتور اتصال استفاده کنید؟ همه موارد کاربردی را انتخاب کنید.
▢ داده های شما ساده است.
▢ شما در حال قالب بندی یک رشته هستید.
▢ لیست شما بسیار طولانی است.
▢ ViewHolder شما فقط دارای یک نمای است.
درس بعدی را شروع کنید:

