این کد لبه بخشی از دوره آموزشی Android Kotlin Fundamentals است. اگر به ترتیب روی کدها کار کنید، بیشترین ارزش را از این دوره خواهید گرفت. همه کد لبه های دوره در صفحه فرود کد لبه های Android Kotlin Fundamentals فهرست شده اند.
مقدمه
در آزمایشگاه کد قبلی، یاد گرفتید که چگونه داده ها را از یک وب سرویس دریافت کنید و پاسخ را به یک شی داده تجزیه کنید. در این نرم افزار کد، شما بر اساس آن دانش برای بارگیری و نمایش عکس ها از URL وب ایجاد می کنید. همچنین میتوانید نحوه ساخت RecyclerView را مجدداً مرور کنید و از آن برای نمایش شبکهای از تصاویر در صفحه نمای کلی استفاده کنید.
آنچه از قبل باید بدانید
- نحوه ایجاد و استفاده از قطعات
- نحوه استفاده از مولفههای معماری از جمله مدلهای مشاهده، کارخانههای مشاهده مدل، تبدیلها و
LiveData. - نحوه بازیابی JSON از یک وب سرویس REST و تجزیه آن داده ها به اشیاء Kotlin با استفاده از کتابخانه های Retrofit و Moshi .
- نحوه ساخت یک طرح شبکه با
RecyclerView. -
Adapter،ViewHolderوDiffUtilچگونه کار می کنند.
چیزی که یاد خواهید گرفت
- نحوه استفاده از کتابخانه Glide برای بارگیری و نمایش تصویر از URL وب.
- نحوه استفاده از
RecyclerViewو آداپتور شبکه برای نمایش شبکه ای از تصاویر. - نحوه رسیدگی به خطاهای احتمالی هنگام دانلود و نمایش تصاویر.
کاری که خواهی کرد
- برنامه MarsRealEstate را تغییر دهید تا URL تصویر را از داده های ویژگی Mars دریافت کنید و از Glide برای بارگیری و نمایش آن تصویر استفاده کنید.
- یک انیمیشن بارگیری و نماد خطا به برنامه اضافه کنید.
- از
RecyclerViewبرای نمایش شبکه ای از تصاویر دارایی مریخ استفاده کنید. - وضعیت و رسیدگی به خطا را به
RecyclerViewاضافه کنید.
در این کد لبه (و کدهای مرتبط)، شما با اپلیکیشنی به نام MarsRealEstate کار می کنید که املاکی را برای فروش در مریخ نشان می دهد. این برنامه برای بازیابی و نمایش داده های دارایی، از جمله جزئیاتی مانند قیمت و اینکه آیا ملک برای فروش یا اجاره موجود است یا خیر، به یک سرور اینترنتی متصل می شود. تصاویری که هر ملک را نشان می دهد، عکس های واقعی از مریخ است که از مریخ نوردهای ناسا گرفته شده است.

نسخه برنامه ای که در این لبه کد می سازید، صفحه نمای کلی را پر می کند که شبکه ای از تصاویر را نمایش می دهد. تصاویر بخشی از دادههای دارایی هستند که برنامه شما از وب سرویس املاک و مستغلات Mars دریافت میکند. برنامه شما از کتابخانه Glide برای بارگیری و نمایش تصاویر و از RecyclerView برای ایجاد طرح بندی شبکه ای برای تصاویر استفاده می کند. برنامه شما همچنین خطاهای شبکه را به خوبی مدیریت می کند.
نمایش یک عکس از یک URL وب ممکن است ساده به نظر برسد، اما کمی مهندسی وجود دارد تا آن را به خوبی کار کند. تصویر باید دانلود، بافر، و از فرمت فشرده آن به تصویری که اندروید بتواند از آن استفاده کند، رمزگشایی شود. تصویر باید در حافظه پنهان، حافظه نهان مبتنی بر ذخیره سازی یا هر دو ذخیره شود. همه اینها باید در رشتههای پسزمینه با اولویت پایین اتفاق بیفتد تا رابط کاربری پاسخگو باقی بماند. همچنین، برای بهترین عملکرد شبکه و CPU، ممکن است بخواهید همزمان بیش از یک تصویر را واکشی و رمزگشایی کنید. یادگیری نحوه بارگذاری موثر تصاویر از شبکه می تواند به خودی خود یک رمز نگاری باشد.
خوشبختانه، میتوانید از یک کتابخانه توسعهیافته در جامعه به نام Glide برای دانلود، بافر، رمزگشایی و کش کردن تصاویر خود استفاده کنید. Glide کار بسیار کمتری نسبت به زمانی که مجبور بودید همه این کارها را از ابتدا انجام دهید، برای شما باقی می گذارد.
Glide اساساً به دو چیز نیاز دارد:
- نشانی اینترنتی تصویری که میخواهید بارگیری کنید و نشان دهید.
- یک شی
ImageViewبرای نمایش آن تصویر.
در این کار، نحوه استفاده از Glide را برای نمایش یک تصویر از وب سرویس املاک یاد می گیرید. شما تصویری را که نشان دهنده اولین ویژگی Mars در لیست ویژگی هایی است که وب سرویس برمی گرداند، نمایش می دهید. در اینجا اسکرین شات های قبل و بعد آمده است:


مرحله 1: وابستگی Glide را اضافه کنید
- برنامه MarsRealEstate را از آخرین کد لبه باز کنید. (اگر برنامه را ندارید می توانید MarsRealEstateNetwork را از اینجا دانلود کنید.)
- برنامه را اجرا کنید تا ببینید چه کاری انجام می دهد. (جزئیات متنی یک ویژگی را نشان می دهد که به طور فرضی در مریخ موجود است.)
- build.gradle (ماژول: برنامه) را باز کنید.
- در بخش
dependencies، این خط را برای کتابخانه Glide اضافه کنید:
implementation "com.github.bumptech.glide:glide:$version_glide"
توجه داشته باشید که شماره نسخه قبلاً به طور جداگانه در فایل Gradle پروژه تعریف شده است.
- روی Sync Now کلیک کنید تا پروژه را با وابستگی جدید بازسازی کنید.
مرحله 2: مدل view را به روز کنید
سپس کلاس OverviewViewModel را بهروزرسانی میکنید تا دادههای زنده برای یک ویژگی مریخ را شامل شود.
-
overview/OverviewViewModel.ktباز کنید. درست در زیرLiveDataبرای_response، دادههای زنده داخلی (قابل تغییر) و خارجی (غیرقابل تغییر) را برای یک شیMarsPropertyاضافه کنید.
کلاسMarsProperty(com.example.android.marsrealestate.network.MarsProperty) را در صورت درخواست وارد کنید.
private val _property = MutableLiveData<MarsProperty>()
val property: LiveData<MarsProperty>
get() = _property- در متد
getMarsRealEstateProperties()، خطی را در داخل بلوکtry/catch {}بیابید که_response.valueرا با تعداد ویژگی ها تنظیم می کند. آزمایش نشان داده شده در زیر را اضافه کنید. اگر اشیاءMarsPropertyدر دسترس باشند، این تست مقدار_propertyLiveDataبه اولین ویژگی درlistResultتنظیم می کند.
if (listResult.size > 0) {
_property.value = listResult[0]
} بلوک کامل try/catch {} اکنون به شکل زیر است:
try {
var listResult = getPropertiesDeferred.await()
_response.value = "Success: ${listResult.size} Mars properties retrieved"
if (listResult.size > 0) {
_property.value = listResult[0]
}
} catch (e: Exception) {
_response.value = "Failure: ${e.message}"
}- فایل
res/layout/fragment_overview.xmlباز کنید. در عنصر<TextView>،android:textتغییر دهید تا به مولفهimgSrcUrlازpropertyLiveDataمتصل شود:
android:text="@{viewModel.property.imgSrcUrl}"- برنامه را اجرا کنید.
TextViewفقط URL تصویر را در اولین ویژگی Mars نمایش می دهد. تمام کاری که تاکنون انجام داده اید این است که مدل view و داده های زنده را برای آن URL تنظیم کرده اید.

مرحله 3: یک آداپتور اتصال ایجاد کنید و با Glide تماس بگیرید
اکنون URL یک تصویر را برای نمایش دارید، و زمان آن رسیده است که برای بارگذاری آن تصویر، کار با Glide را شروع کنید. در این مرحله، از یک آداپتور binding برای گرفتن URL از یک ویژگی XML مرتبط با ImageView استفاده میکنید و از Glide برای بارگیری تصویر استفاده میکنید. آداپتورهای اتصال روشهای توسعهای هستند که بین نما و دادههای محدود قرار میگیرند تا رفتار سفارشی را هنگام تغییر داده ارائه دهند. در این مورد، رفتار سفارشی فراخوانی Glide برای بارگیری تصویر از URL در ImageView است.
-
BindingAdapters.ktرا باز کنید. این فایل آداپتورهای اتصالی را که در سرتاسر برنامه استفاده میکنید نگه میدارد. - یک تابع
bindImage()ایجاد کنید که یکImageViewو یکStringبه عنوان پارامتر می گیرد. تابع را با@BindingAdapterحاشیه نویسی کنید. حاشیه نویسی@BindingAdapterبه binding داده می گوید که می خواهید این آداپتور binding زمانی که یک مورد XML دارای ویژگیimageUrlباشد، اجرا شود.
در صورت درخواستandroidx.databinding.BindingAdapterوandroid.widget.ImageViewرا وارد کنید.
@BindingAdapter("imageUrl")
fun bindImage(imgView: ImageView, imgUrl: String?) {
}- در تابع
bindImage()یک بلوکlet {}برای آرگومانimgUrlاضافه کنید:
imgUrl?.let {
}- در داخل بلوک
let {}، خط نشان داده شده در زیر را اضافه کنید تا رشته URL (از XML) به یک شیUriتبدیل شود. در صورت درخواستandroidx.core.net.toUriرا وارد کنید.
شما میخواهید که شی نهاییUriاز طرح HTTPS استفاده کند، زیرا سروری که تصاویر را از آن میکشید به آن طرح نیاز دارد. برای استفاده از طرح HTTPS،buildUpon.scheme("https")را به سازندهtoUriاضافه کنید. متدtoUri()یک تابع پسوند Kotlin از کتابخانه هسته Android KTX است، بنابراین به نظر می رسد که بخشی از کلاسStringاست.
val imgUri = imgUrl.toUri().buildUpon().scheme("https").build()- همچنان در داخل
let {}،Glide.with()را فراخوانی کند تا تصویر را از شیUriدرImageViewبارگیری کند. در صورت درخواست،com.bumptech.glide.Glideرا وارد کنید.
Glide.with(imgView.context)
.load(imgUri)
.into(imgView)مرحله 4: طرح و قطعات را به روز کنید
اگرچه Glide تصویر را بارگذاری کرده است، هنوز چیزی برای دیدن وجود ندارد. گام بعدی این است که طرح و قطعات را با ImageView به روز کنید تا تصویر نمایش داده شود.
-
res/layout/gridview_item.xmlباز کنید. این فایل منبع طرح بندی است که برای هر آیتم درRecyclerViewبعداً در Codelab استفاده خواهید کرد. شما در اینجا به طور موقت از آن برای نشان دادن تنها یک تصویر استفاده می کنید. - در بالای عنصر
<ImageView>، یک عنصر<data>برای اتصال داده اضافه کنید و به کلاسOverviewViewModelمتصل شوید:
<data>
<variable
name="viewModel"
type="com.example.android.marsrealestate.overview.OverviewViewModel" />
</data>- برای استفاده از آداپتور اتصال بارگذاری تصویر جدید، یک ویژگی
app:imageUrlبه عنصرImageViewاضافه کنید:
app:imageUrl="@{viewModel.property.imgSrcUrl}"-
overview/OverviewFragment.ktباز کنید. در متدonCreateView()خطی را که کلاسFragmentOverviewBindingباد می کند و آن را به متغیر binding اختصاص می دهد، نظر دهید. این فقط موقتی است. شما بعداً به آن باز خواهید گشت
//val binding = FragmentOverviewBinding.inflate(inflater)- به جای آن یک خط برای افزایش کلاس
GridViewItemBindingاضافه کنید.com.example.android.marsrealestate. databinding.GridViewItemBindingدر صورت درخواست.
val binding = GridViewItemBinding.inflate(inflater)- برنامه را اجرا کنید. اکنون باید عکس تصویر اولین
MarsPropertyرا در لیست نتایج ببینید.
مرحله 5: تصاویر بارگیری و خطای ساده را اضافه کنید
Glide میتواند تجربه کاربر را با نشان دادن یک تصویر نگهدارنده حین بارگیری تصویر و یک تصویر خطا در صورت عدم بارگیری، به عنوان مثال اگر تصویر گم شده یا خراب باشد، بهبود بخشد. در این مرحله، این قابلیت را به آداپتور صحافی و طرح بندی اضافه می کنید.
-
res/drawable/ic_broken_image.xmlرا باز کنید و روی برگه Preview در سمت راست کلیک کنید. برای تصویر خطا، از نماد تصویر شکسته استفاده میکنید که در کتابخانه نماد داخلی موجود است. این رسم برداری از ویژگیandroid:tintبرای رنگ کردن آیکون خاکستری استفاده می کند.

-
res/drawable/loading_animation.xmlباز کنید. این drawable یک انیمیشن است که با تگ<animate-rotate>تعریف شده است. انیمیشن یک تصویر قابل ترسیم،loading_img.xmlدر اطراف نقطه مرکزی می چرخاند. (شما انیمیشن را در پیش نمایش نمی بینید.)

- به فایل
BindingAdapters.ktبرگردید. در متدbindImage()، فراخوانی را بهGlide.with()به روز کنید تا تابعapply()بینload()وinto()فراخوانی شود. در صورت درخواستcom.bumptech.glide.request.RequestOptionsرا وارد کنید.
این کد تصویر بارگیری مکاننما را برای استفاده در حین بارگذاری تنظیم میکند (قابلیت ترسیمloading_animation). کد همچنین یک تصویر را تنظیم می کند تا در صورت عدم بارگیری تصویر از آن استفاده کند (broken_imageقابل ترسیم). متد کاملbindImage()اکنون به شکل زیر است:
@BindingAdapter("imageUrl")
fun bindImage(imgView: ImageView, imgUrl: String?) {
imgUrl?.let {
val imgUri =
imgUrl.toUri().buildUpon().scheme("https").build()
Glide.with(imgView.context)
.load(imgUri)
.apply(RequestOptions()
.placeholder(R.drawable.loading_animation)
.error(R.drawable.ic_broken_image))
.into(imgView)
}
}
- برنامه را اجرا کنید. بسته به سرعت اتصال شبکه خود، ممکن است به طور خلاصه تصویر بارگیری را به عنوان Glide مشاهده کنید و تصویر ویژگی را نمایش دهد. اما شما هنوز آیکون تصویر شکسته را نخواهید دید، حتی اگر شبکه خود را خاموش کنید - این مشکل را در آخرین قسمت از Codelab حل می کنید.
اکنون برنامه شما اطلاعات دارایی را از اینترنت بارگیری می کند. با استفاده از دادههای اولین مورد فهرست MarsProperty ، یک ویژگی LiveData در مدل view ایجاد کردهاید، و از URL تصویر از دادههای ویژگی برای پر کردن ImageView استفاده کردهاید. اما هدف این است که برنامه شما شبکهای از تصاویر را نمایش دهد، بنابراین میخواهید از RecyclerView با GridLayoutManager استفاده کنید.
مرحله 1: مدل view را به روز کنید
در حال حاضر مدل view دارای یک _property LiveData است که یک شی MarsProperty در خود نگه می دارد—اولین مورد در لیست پاسخ از سرویس وب. در این مرحله، LiveData را تغییر می دهید تا کل لیست اشیاء MarsProperty را در خود نگه دارد.
-
overview/OverviewViewModel.ktباز کنید. - متغیر private
_propertyرا به_propertiesتغییر دهید. نوع را به لیستی از اشیاءMarsPropertyتغییر دهید.
private val _properties = MutableLiveData<List<MarsProperty>>()- داده های زنده
propertyخارجی را باpropertiesجایگزین کنید. لیست را در اینجا نیز به نوعLiveDataاضافه کنید:
val properties: LiveData<List<MarsProperty>>
get() = _properties- به سمت پایین به متد
getMarsRealEstateProperties()بروید. در داخل بلوکtry {}، کل آزمایشی را که در کار قبلی اضافه کردید با خط زیر جایگزین کنید. از آنجایی که متغیرlistResultلیستی از اشیاءMarsPropertyرا در خود دارد، میتوانید به جای آزمایش برای پاسخ موفقیتآمیز، آن را به_properties.valueاختصاص دهید.
_properties.value = listResultکل بلوک try/catch اکنون به شکل زیر است:
try {
var listResult = getPropertiesDeferred.await()
_response.value = "Success: ${listResult.size} Mars properties retrieved"
_properties.value = listResult
} catch (e: Exception) {
_response.value = "Failure: ${e.message}"
}مرحله 2: چیدمان ها و قطعات را به روز کنید
گام بعدی این است که طرحبندی و قطعات برنامه را تغییر دهید تا از نمای بازیافتکننده و طرحبندی شبکهای استفاده کنید، نه از نمای تک تصویر.
-
res/layout/gridview_item.xmlباز کنید. اتصال داده را ازOverviewViewModelبهMarsPropertyتغییر دهید و نام متغیر را به"property"تغییر دهید.
<variable
name="property"
type="com.example.android.marsrealestate.network.MarsProperty" />- در
<ImageView>، ویژگیapp:imageUrlرا تغییر دهید تا به URL تصویر در شیءMarsPropertyاشاره شود:
app:imageUrl="@{property.imgSrcUrl}"-
overview/OverviewFragment.ktباز کنید. درonCreateview()خطی را کهFragmentOverviewBindingافزایش میدهد از نظر خارج کنید. خطی را کهGridViewBindingافزایش میدهد، حذف یا نظر دهید. این تغییرات تغییرات موقتی را که در آخرین کار انجام داده اید، خنثی می کند.
val binding = FragmentOverviewBinding.inflate(inflater)
// val binding = GridViewItemBinding.inflate(inflater)-
res/layout/fragment_overview.xmlباز کنید. کل عنصر<TextView>را حذف کنید. - به جای آن این عنصر
<RecyclerView>اضافه کنید، که از یکGridLayoutManagerو طرحgrid_view_itemبرای یک مورد استفاده می کند:
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/photos_grid"
android:layout_width="0dp"
android:layout_height="0dp"
android:padding="6dp"
android:clipToPadding="false"
app:layoutManager=
"androidx.recyclerview.widget.GridLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:spanCount="2"
tools:itemCount="16"
tools:listitem="@layout/grid_view_item" />مرحله 3: آداپتور شبکه عکس را اضافه کنید
اکنون طرح fragment_overview دارای یک RecyclerView است در حالی که طرح بندی grid_view_item دارای یک ImageView است. در این مرحله، داده ها را از طریق یک آداپتور RecyclerView به RecyclerView متصل می کنید.
-
overview/PhotoGridAdapter.ktباز کنید. - کلاس
PhotoGridAdapterبا پارامترهای سازنده نشان داده شده در زیر ایجاد کنید. کلاسPhotoGridAdapterListAdapterگسترش می دهد که سازنده آن به نوع آیتم لیست، نگهدارنده view و اجرایDiffUtil.ItemCallbackنیاز دارد.
در صورت درخواست، کلاسهایandroidx.recyclerview.widget.ListAdapterوcom.example.android.marsrealestate.network.MarsPropertyرا وارد کنید. در مراحل زیر، سایر قسمت های گمشده این سازنده که خطا تولید می کنند را پیاده سازی می کنید.
class PhotoGridAdapter : ListAdapter<MarsProperty,
PhotoGridAdapter.MarsPropertyViewHolder>(DiffCallback) {
}- روی هر نقطه از کلاس
PhotoGridAdapterکلیک کنید وControl+iرا فشار دهید تا متدهایListAdapterپیاده سازی کنید، که عبارتند ازonCreateViewHolder()وonBindViewHolder().
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PhotoGridAdapter.MarsPropertyViewHolder {
TODO("not implemented")
}
override fun onBindViewHolder(holder: PhotoGridAdapter.MarsPropertyViewHolder, position: Int) {
TODO("not implemented")
}- در پایان تعریف کلاس
PhotoGridAdapter، پس از متدهایی که به تازگی اضافه کرده اید، یک تعریف شی همراه برایDiffCallbackاضافه کنید، همانطور که در زیر نشان داده شده است.
در صورت درخواستandroidx.recyclerview.widget.DiffUtilرا وارد کنید.
شیDiffCallbackDiffUtil.ItemCallbackرا با نوع شی ای که می خواهید مقایسه کنید گسترش می دهد -MarsProperty.
companion object DiffCallback : DiffUtil.ItemCallback<MarsProperty>() {
}-
Control+iرا فشار دهید تا متدهای مقایسهکننده برای این شیء اجرا شود که عبارتند ازareItemsTheSame()وareContentsTheSame().
override fun areItemsTheSame(oldItem: MarsProperty, newItem: MarsProperty): Boolean {
TODO("not implemented")
}
override fun areContentsTheSame(oldItem: MarsProperty, newItem: MarsProperty): Boolean {
TODO("not implemented") }- برای متد
areItemsTheSame()، TODO را حذف کنید. از عملگر برابری ارجاعی کاتلین (===) استفاده کنید، که اگر ارجاعات شیءoldItemوnewItemیکسان باشد،trueبرمی گرداند.
override fun areItemsTheSame(oldItem: MarsProperty,
newItem: MarsProperty): Boolean {
return oldItem === newItem
}- برای
areContentsTheSame()از عملگر برابری استاندارد فقط روی شناسهoldItemوnewItemاستفاده کنید.
override fun areContentsTheSame(oldItem: MarsProperty,
newItem: MarsProperty): Boolean {
return oldItem.id == newItem.id
}- هنوز در داخل کلاس
PhotoGridAdapter، در زیر شیء همراه، یک تعریف کلاس داخلی برایMarsPropertyViewHolderاضافه کنید، کهRecyclerView.ViewHolderگسترش می دهد.
androidx.recyclerview.widget.RecyclerViewوcom.example.android.marsrealestate.databinding.GridViewItemBindingرا در صورت درخواست وارد کنید.
برای اتصالMarsPropertyبه چیدمان به متغیرGridViewItemBindingنیاز دارید، بنابراین متغیر را بهMarsPropertyViewHolderمنتقل کنید. از آنجا که کلاسViewHolderپایه به یک view در سازنده خود نیاز دارد، شما به آن نمای ریشه binding ارسال می کنید.
class MarsPropertyViewHolder(private var binding:
GridViewItemBinding):
RecyclerView.ViewHolder(binding.root) {
}- در
MarsPropertyViewHolder، یک متدbind()ایجاد کنید که یک شیMarsPropertyرا به عنوان آرگومان می گیرد وbinding.propertyبرای آن شی تنظیم می کند. پس از تنظیم ویژگی،executePendingBindings()را فراخوانی کنید، که باعث می شود به روز رسانی بلافاصله اجرا شود.
fun bind(marsProperty: MarsProperty) {
binding.property = marsProperty
binding.executePendingBindings()
}- در
onCreateViewHolder()TODO را حذف کرده و خط زیر را اضافه کنید. در صورت درخواستandroid.view.LayoutInflaterرا وارد کنید.
متدonCreateViewHolder()باید یکMarsPropertyViewHolderجدید را برگرداند که با باد کردنGridViewItemBindingو استفاده ازLayoutInflaterاز زمینهViewGroupوالدین شما ایجاد شده است.
return MarsPropertyViewHolder(GridViewItemBinding.inflate(
LayoutInflater.from(parent.context)))- در متد
onBindViewHolder()TODO را حذف کرده و خطوط زیر را اضافه کنید. در اینجا شماgetItem()را فراخوانی می کنید تا شیMarsPropertyمرتبط با موقعیت فعلیRecyclerViewرا دریافت کنید و سپس آن ویژگی را به متدbind()درMarsPropertyViewHolderمنتقل کنید.
val marsProperty = getItem(position)
holder.bind(marsProperty)مرحله 4: آداپتور صحافی را اضافه کنید و قطعات را وصل کنید
در نهایت، از BindingAdapter برای مقداردهی اولیه PhotoGridAdapter با لیست اشیاء MarsProperty استفاده کنید. استفاده از BindingAdapter برای تنظیم داده های RecyclerView باعث می شود که اتصال داده ها به طور خودکار LiveData برای لیست اشیاء MarsProperty مشاهده کند. سپس با تغییر لیست MarsProperty ، آداپتور binding به طور خودکار فراخوانی می شود.
-
BindingAdapters.ktرا باز کنید. - در انتهای فایل، یک متد
bindRecyclerView()اضافه کنید که یکRecyclerViewو لیستی از اشیاءMarsPropertyرا به عنوان آرگومان می گیرد. آن روش را با@BindingAdapterحاشیه نویسی کنید.
androidx.recyclerview.widget.RecyclerViewوcom.example.android.marsrealestate.network.MarsPropertyرا در صورت درخواست وارد کنید.
@BindingAdapter("listData")
fun bindRecyclerView(recyclerView: RecyclerView,
data: List<MarsProperty>?) {
}- در تابع
bindRecyclerView()recyclerView.adapterرا بهPhotoGridAdapterفرستاده و با داده هاadapter.submitList()فراخوانی کنید. این بهRecyclerViewمی گوید که یک لیست جدید در دسترس است.
در صورت درخواست، com.example.android.marsrealestate.overview.PhotoGridAdapter را وارد کنید.
val adapter = recyclerView.adapter as PhotoGridAdapter
adapter.submitList(data)-
res/layout/fragment_overview.xmlباز کنید. ویژگیapp:listDataرا به عنصرRecyclerViewاضافه کنید و با استفاده از data binding آن را رویviewmodel.propertiesتنظیم کنید.
app:listData="@{viewModel.properties}"-
overview/OverviewFragment.ktباز کنید. درonCreateView()، درست قبل از فراخوانیsetHasOptionsMenu()، آداپتورRecyclerViewرا درbinding.photosGridبه یک شیPhotoGridAdapterراه اندازی کنید.
binding.photosGrid.adapter = PhotoGridAdapter()- برنامه را اجرا کنید. شما باید شبکه ای از تصاویر
MarsPropertyرا ببینید. همانطور که برای دیدن تصاویر جدید پیمایش می کنید، برنامه قبل از نمایش خود تصویر، نماد پیشرفت بارگیری را نشان می دهد. اگر حالت هواپیما را روشن کنید، تصاویری که هنوز بارگذاری نشده اند به عنوان نمادهای تصویر شکسته ظاهر می شوند.

برنامه MarsRealEstate زمانی که تصویری قابل واکشی نیست، نماد تصویر شکسته را نمایش می دهد. اما وقتی شبکه وجود ندارد، برنامه یک صفحه خالی را نشان می دهد.

این یک تجربه کاربری عالی نیست. در این کار، مدیریت خطای اولیه را اضافه میکنید تا به کاربر ایده بهتری از آنچه اتفاق میافتد ارائه دهید. اگر اینترنت در دسترس نباشد، برنامه نماد خطای اتصال را نشان می دهد. در حالی که برنامه در حال دریافت لیست MarsProperty است، برنامه انیمیشن بارگیری را نشان می دهد.
مرحله 1: اضافه کردن وضعیت به مدل view
برای شروع، شما یک LiveData در مدل view ایجاد می کنید تا وضعیت درخواست وب را نشان دهد. سه حالت وجود دارد که باید در نظر گرفت: بارگیری، موفقیت و شکست. حالت بارگیری زمانی اتفاق میافتد که منتظر دادههای موجود در فراخوانی await() هستید.
-
overview/OverviewViewModel.ktباز کنید. در بالای فایل (بعد از وارد کردن، قبل از تعریف کلاس)، یکenumاضافه کنید تا تمام وضعیت های موجود را نشان دهد:
enum class MarsApiStatus { LOADING, ERROR, DONE }- تعاریف دادههای زنده داخلی و خارجی
_responseدر کلاسOverviewViewModelرا به_statusتغییر نام دهید. از آنجایی که قبلاً در این کد لبه از_propertiesLiveDataپشتیبانی کردید، پاسخ سرویس وب کامل استفاده نشده است. برای پیگیری وضعیت فعلی بهLiveDataدر اینجا نیاز دارید، بنابراین می توانید نام متغیرهای موجود را تغییر دهید.
همچنین انواع را از String به MarsApiStatus.
private val _status = MutableLiveData<MarsApiStatus>()
val status: LiveData<MarsApiStatus>
get() = _status- به سمت پایین به متد
getMarsRealEstateProperties()بروید و_responseبه_statusرا در اینجا نیز به روز کنید. رشته"Success"را به حالتMarsApiStatus.DONEو رشته"Failure"را بهMarsApiStatus.ERRORتغییر دهید. - یک وضعیت
MarsApiStatus.LOADINGرا به بالای بلوکtry {}، قبل از تماس toawait()اضافه کنید. این وضعیت اولیه در زمانی است که کوروتین در حال اجرا است و شما منتظر داده هستید. بلوک کاملtry/catch {}اکنون به شکل زیر است:
try {
_status.value = MarsApiStatus.LOADING
var listResult = getPropertiesDeferred.await()
_status.value = MarsApiStatus.DONE
_properties.value = listResult
} catch (e: Exception) {
_status.value = MarsApiStatus.ERROR
}- پس از حالت خطا در بلوک
catch {}،_propertiesLiveDataروی یک لیست خالی تنظیم کنید. اینRecyclerViewرا پاک می کند.
} catch (e: Exception) {
_status.value = MarsApiStatus.ERROR
_properties.value = ArrayList()
}مرحله 2: یک آداپتور اتصال برای وضعیت ImageView اضافه کنید
اکنون شما یک وضعیت در مدل view دارید، اما این فقط مجموعه ای از حالت ها است. چگونه آن را در خود برنامه نشان می دهید؟ در این مرحله، از ImageView ، متصل به دادههای اتصال، برای نمایش نمادها برای حالتهای بارگیری و خطا استفاده میکنید. هنگامی که برنامه در حالت بارگیری یا خطا است، ImageView باید قابل مشاهده باشد. وقتی بارگیری برنامه تمام شد، ImageView باید نامرئی باشد.
-
BindingAdapters.ktرا باز کنید. یک آداپتور اتصال جدید به نامbindStatus()اضافه کنید که یکImageViewو یک مقدارMarsApiStatusرا به عنوان آرگومان می گیرد.com.example.android.marsrealestate.overview.MarsApiStatusرا در صورت درخواست وارد کنید.
@BindingAdapter("marsApiStatus")
fun bindStatus(statusImageView: ImageView,
status: MarsApiStatus?) {
}- برای جابجایی بین وضعیتهای مختلف، یک
when {}در متدbindStatus()اضافه کنید.
when (status) {
}- در داخل
when {}، یک مورد برای وضعیت بارگیری اضافه کنید (MarsApiStatus.LOADING). برای این حالت،ImageViewروی قابل مشاهده تنظیم کنید و انیمیشن بارگیری را به آن اختصاص دهید. این همان انیمیشن قابل ترسیمی است که برای Glide در کار قبلی استفاده کردید. در صورت درخواستandroid.view.Viewرا وارد کنید.
when (status) {
MarsApiStatus.LOADING -> {
statusImageView.visibility = View.VISIBLE
statusImageView.setImageResource(R.drawable.loading_animation)
}
}- یک مورد برای حالت خطا اضافه کنید که
MarsApiStatus.ERRORاست. مشابه کاری که برای حالتLOADINGانجام دادید، وضعیتImageViewرا روی قابل مشاهده تنظیم کنید و از ترسیم خطای اتصال مجدد استفاده کنید.
MarsApiStatus.ERROR -> {
statusImageView.visibility = View.VISIBLE
statusImageView.setImageResource(R.drawable.ic_connection_error)
}- یک مورد برای حالت انجام شده اضافه کنید که
MarsApiStatus.DONEاست. در اینجا شما یک پاسخ موفق دارید، بنابراین نمایان بودن وضعیتImageViewرا خاموش کنید تا آن را پنهان کنید.
MarsApiStatus.DONE -> {
statusImageView.visibility = View.GONE
}مرحله 3: وضعیت ImageView را به طرح اضافه کنید
-
res/layout/fragment_overview.xmlباز کنید. در زیر عنصرRecyclerView، داخلConstraintLayout،ImageViewرا که در زیر نشان داده شده است اضافه کنید.
اینImageViewدارای محدودیت های مشابه باRecyclerViewاست. با این حال، عرض و ارتفاع ازwrap_contentبرای وسط تصویر استفاده میکنند تا اینکه تصویر را کشیده و نمای را پر کند. همچنین به صفتapp:marsApiStatusتوجه کنید که وقتی ویژگی وضعیت در مدل view تغییر میکند، نمایBindingAdapterشما را فراخوانی میکند.
<ImageView
android:id="@+id/status_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:marsApiStatus="@{viewModel.status}" />- برای شبیه سازی اتصال شبکه از دست رفته، حالت هواپیما را در شبیه ساز یا دستگاه خود روشن کنید. برنامه را کامپایل و اجرا کنید و متوجه شوید که تصویر خطا ظاهر می شود:

- برای بستن برنامه روی دکمه برگشت ضربه بزنید و حالت هواپیما را خاموش کنید. برای بازگرداندن برنامه از صفحه نمایش اخیر استفاده کنید. بسته به سرعت اتصال شبکه شما، ممکن است زمانی که برنامه قبل از شروع بارگیری تصاویر، سرویس وب را درخواست می کند، یک چرخش بارگذاری بسیار مختصر مشاهده کنید.
پروژه اندروید استودیو: MarsRealEstateGrid
- برای سادهسازی فرآیند مدیریت تصاویر، از کتابخانه Glide برای دانلود، بافر، رمزگشایی و ذخیرهسازی تصاویر در برنامه خود استفاده کنید.
- Glide برای بارگذاری یک تصویر از اینترنت به دو چیز نیاز دارد: URL یک تصویر، و یک شی
ImageViewبرای قرار دادن تصویر. برای مشخص کردن این گزینهها، از متدهایload()وinto()با Glide استفاده کنید. - آداپتورهای صحافی روشهای توسعهای هستند که بین یک view و دادههای محدود آن view قرار میگیرند. آداپتورهای اتصال رفتار سفارشی را هنگام تغییر دادهها ارائه میکنند، به عنوان مثال، برای فراخوانی Glide برای بارگیری تصویر از URL در
ImageView. - آداپتورهای صحافی روشهای افزودنی هستند که با حاشیهنویسی
@BindingAdapterحاشیهنویسی میشوند. - برای افزودن گزینه به درخواست Glide، از متد
apply()استفاده کنید. به عنوان مثال، ازapply()باplaceholder()برای تعیین یک drawable در حال بارگذاری و ازapply()باerror()برای تعیین خطایی قابل ترسیم استفاده کنید. - برای تولید شبکه ای از تصاویر، از
RecyclerViewباGridLayoutManagerاستفاده کنید. - برای بهروزرسانی لیست ویژگیها هنگام تغییر، از یک آداپتور اتصال بین
RecyclerViewو طرحبندی استفاده کنید.
دوره بی ادبی:
مستندات توسعه دهنده اندروید:
دیگر:
این بخش، تکالیف احتمالی را برای دانشآموزانی که در این آزمایشگاه کد به عنوان بخشی از دورهای که توسط یک مربی هدایت میشود، کار میکنند، فهرست میکند. این وظیفه مربی است که موارد زیر را انجام دهد:
- در صورت نیاز تکالیف را تعیین کنید.
- نحوه ارسال تکالیف را با دانش آموزان در میان بگذارید.
- تکالیف را نمره دهید.
مربیان میتوانند از این پیشنهادات به اندازهای که میخواهند استفاده کنند، و باید با خیال راحت هر تکلیف دیگری را که فکر میکنند مناسب است، محول کنند.
اگر به تنهایی از طریق این کدها کار می کنید، از این تکالیف برای آزمایش دانش خود استفاده کنید.
به این سوالات پاسخ دهید
سوال 1
از کدام روش Glide برای نشان دادن ImageView که حاوی تصویر بارگذاری شده است استفاده می کنید؟
▢ into()
▢ with()
▢ imageview()
▢ apply()
سوال 2
چگونه میتوانید یک تصویر مکاننما را مشخص کنید تا هنگام بارگیری Glide نشان داده شود؟
▢ از متد into() با یک drawable استفاده کنید.
▢ از RequestOptions() استفاده کنید و متد placeholder() را با یک drawable فراخوانی کنید.
▢ ویژگی Glide.placeholder را به یک drawable اختصاص دهید.
▢ از RequestOptions() استفاده کنید و متد loadingImage() با یک drawable فراخوانی کنید.
سوال 3
چگونه نشان می دهید که یک روش یک آداپتور اتصال است؟
▢ متد setBindingAdapter() را در LiveData فراخوانی کنید.
▢ متد را در یک فایل Kotlin به نام BindingAdapters.kt قرار دهید.
▢ از ویژگی android:adapter در طرح XML استفاده کنید.
▢ روش را با @BindingAdapter حاشیه نویسی کنید.
درس بعدی را شروع کنید:
برای پیوند به سایر کدهای این دوره، به صفحه فرود کد لبههای کد پایه Android Kotlin Fundamentals مراجعه کنید.