این کد لبه بخشی از دوره آموزشی 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 اساساً به دو چیز نیاز دارد:
- نشانی اینترنتی تصویری که میخواهید بارگیری کنید و نشان دهید.
- یک شی
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
در دسترس باشند، این تست مقدار_property
LiveData
را به اولین ویژگی در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
ازproperty
LiveData
متصل شود:
android:text="@{viewModel.property.imgSrcUrl}"
- برنامه را اجرا کنید.
TextView
فقط URL تصویر را در اولین ویژگی Mars نمایش می دهد. تنها کاری که تاکنون انجام داده اید تنظیم مدل view و داده های زنده برای آن URL است.
مرحله 3: یک آداپتور اتصال ایجاد کنید و با Glide تماس بگیرید
اکنون URL یک تصویر را برای نمایش دارید و زمان آن رسیده است که برای بارگیری آن تصویر با Glide کار کنید. در این مرحله، از یک آداپتور binding برای گرفتن URL از یک ویژگی XML مرتبط با ImageView
استفاده میکنید و از Glide برای بارگیری تصویر استفاده میکنید. آداپتورهای اتصال روشهای توسعهای هستند که بین یک view و دادههای محدود قرار میگیرند تا رفتار سفارشی را هنگام تغییر داده ارائه دهند. در این مورد، رفتار سفارشی فراخوانی Glide برای بارگیری تصویر از URL در ImageView
است.
-
BindingAdapters.kt
باز کنید. این فایل آداپتورهای اتصالی را که در سراسر برنامه استفاده میکنید نگه میدارد. - یک
bindImage()
ایجاد کنید که یکImageView
و یکString
را به عنوان پارامتر می گیرد. تابع را با@BindingAdapter
حاشیه نویسی کنید. حاشیهنویسی@BindingAdapter
به دادههای binding میگوید که میخواهید زمانی که یک آیتم XML دارای ویژگیimageUrl
باشد، این آداپتور binding اجرا شود.
در صورت درخواست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()
به روز کنید تا تابع application() بینload()
وinto()
فراخوانیapply()
. در صورت درخواست،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 مشاهده کنید و تصویر ویژگی را نمایش دهید. اما شما هنوز نماد تصویر شکسته را نخواهید دید، حتی اگر شبکه خود را خاموش کنید - این مشکل را در آخرین قسمت از لبه کد رفع می کنید.
اکنون برنامه شما اطلاعات دارایی را از اینترنت بارگیری می کند. با استفاده از دادههای اولین مورد فهرست 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
را با پارامترهای سازنده نشان داده شده در زیر ایجاد کنید. کلاسPhotoGridAdapter
ListAdapter
را گسترش می دهد که سازنده آن به نوع آیتم لیست، نگهدارنده 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
وارد کنید.
شیDiffCallback
DiffUtil.ItemCallback
را با نوع شی ای که می خواهید مقایسه کنید گسترش می دهد -MarsProperty
.
companion object DiffCallback : DiffUtil.ItemCallback<MarsProperty>() {
}
- برای پیاده سازی متدهای مقایسه کننده برای این شیء، که عبارتند از
areItemsTheSame()
وareContentsTheSame()
،Control+i
را فشار دهید.
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
. از آنجایی که قبلاً در این کد لبه از_properties
LiveData
پشتیبانی کردهاید، پاسخ سرویس وب کامل استفاده نشده است. برای پیگیری وضعیت فعلی به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 {}
،_properties
LiveData
را روی یک لیست خالی تنظیم کنید. با این کار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 قرار میگیرند. آداپتورهای اتصال رفتار سفارشی را هنگام تغییر داده ها ارائه می دهند، به عنوان مثال، برای بارگیری تصویر از URL در
ImageView
، Glide را فراخوانی کنید. - آداپتورهای صحافی روشهای پسوندی هستند که با حاشیهنویسی
@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 setBindingAdapter()
را در LiveData
فراخوانی کنید.
▢ متد را در یک فایل Kotlin به نام BindingAdapters.kt
قرار دهید.
▢ از ویژگی android:adapter
در طرح XML استفاده کنید.
▢ روش را با @BindingAdapter
حاشیه نویسی کنید.
درس بعدی را شروع کنید:
برای پیوند به دیگر کدهای این دوره، به صفحه فرود کد لبههای کد پایه Android Kotlin Fundamentals مراجعه کنید.