این کد لبه بخشی از دوره آموزشی 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
می تواند استفاده کند و نمایش دهد. - آداپتور
SleepNightAdapter
ViewHolders
را تولید می کند که حاوی نماها، داده ها و اطلاعات متا برای نمای 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()
فراخوانی کنید و سپسtext
TextView
را روی متن فرمت شده تنظیم کنید. (از آنجا که این یک تابع افزونه در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
شما فقط دارای یک نمای است.
درس بعدی را شروع کنید: