Lớp học lập trình này thuộc khoá học Kiến thức cơ bản về Kotlin cho Android. Bạn sẽ nhận được nhiều giá trị nhất qua khoá học này nếu thực hiện các lớp học lập trình theo trình tự. Tất cả lớp học lập trình của khoá học đều được liệt kê trên trang đích của lớp học lập trình Kiến thức cơ bản về cách tạo ứng dụng Android bằng Kotlin.
Giới thiệu
Trong lớp học lập trình này, bạn sẽ tìm hiểu cách thêm một tiêu đề trải dài theo chiều rộng của danh sách xuất hiện trong một RecyclerView
. Bạn sẽ phát triển ứng dụng theo dõi giấc ngủ từ các lớp học lập trình trước.
Kiến thức bạn cần có
- Cách tạo giao diện người dùng cơ bản bằng hoạt động, mảnh và thành phần hiển thị.
- Cách điều hướng giữa các mảnh và cách sử dụng
safeArgs
để truyền dữ liệu giữa các mảnh. - Xem các mô hình, nhà máy mô hình hiển thị, các phép biến đổi và
LiveData
cũng như các đối tượng theo dõi của chúng. - Cách tạo cơ sở dữ liệu
Room
, tạo DAO và xác định các thực thể. - Cách sử dụng coroutine cho các lượt tương tác với cơ sở dữ liệu và các tác vụ chạy trong thời gian dài khác.
- Cách triển khai một
RecyclerView
cơ bản bằngAdapter
,ViewHolder
và bố cục thành phần. - Cách triển khai liên kết dữ liệu cho
RecyclerView
. - Cách tạo và sử dụng các phương thức điều hợp liên kết để chuyển đổi dữ liệu.
- Cách sử dụng
GridLayoutManager
. - Cách ghi lại và xử lý lượt nhấp vào các mục trong
RecyclerView.
Kiến thức bạn sẽ học được
- Cách sử dụng nhiều
ViewHolder
với mộtRecyclerView
để thêm các mục có bố cục khác. Cụ thể là cách sử dụngViewHolder
thứ hai để thêm tiêu đề phía trên các mục xuất hiện trongRecyclerView
.
Bạn sẽ thực hiện
- Xây dựng trên ứng dụng TrackMySleepQuality từ lớp học lập trình trước trong loạt lớp học lập trình này.
- Thêm một tiêu đề trải dài theo chiều rộng của màn hình phía trên các đêm ngủ xuất hiện trong
RecyclerView
.
Ứng dụng theo dõi giấc ngủ mà bạn bắt đầu có 3 màn hình, được biểu thị bằng các mảnh, như minh hoạ trong hình bên dưới.
Màn hình đầu tiên (xuất hiện ở bên trái) có các nút để bắt đầu và dừng theo dõi. Màn hình này cho thấy một số dữ liệu về giấc ngủ của người dùng. Nút Xoá sẽ xoá vĩnh viễn tất cả dữ liệu mà ứng dụng đã thu thập cho người dùng. Màn hình thứ hai (ở giữa) là để chọn điểm xếp hạng chất lượng giấc ngủ. Màn hình thứ ba là một khung hiển thị chi tiết sẽ mở ra khi người dùng nhấn vào một mục trong lưới.
Ứng dụng này sử dụng một cấu trúc đơn giản với bộ điều khiển giao diện người dùng, mô hình hiển thị và LiveData
, cùng một cơ sở dữ liệu Room
để duy trì dữ liệu về giấc ngủ.
Trong lớp học lập trình này, bạn sẽ thêm một tiêu đề vào lưới các mục được hiển thị. Màn hình chính cuối cùng của bạn sẽ có dạng như sau:
Lớp học lập trình này hướng dẫn nguyên tắc chung về việc đưa các mục sử dụng nhiều bố cục vào một RecyclerView
. Một ví dụ thường gặp là có tiêu đề trong danh sách hoặc lưới. Danh sách có thể có một tiêu đề duy nhất để mô tả nội dung của mục. Một danh sách cũng có thể có nhiều tiêu đề để nhóm và tách các mục trong một danh sách.
RecyclerView
không biết gì về dữ liệu của bạn hoặc loại bố cục của từng mục. LayoutManager
sắp xếp các mục trên màn hình, nhưng trình chuyển đổi sẽ điều chỉnh dữ liệu để hiển thị và truyền trình giữ khung hiển thị đến RecyclerView
. Vì vậy, bạn sẽ thêm mã để tạo tiêu đề trong trình điều hợp.
Hai cách thêm tiêu đề
Trong RecyclerView
, mỗi mục trong danh sách tương ứng với một số chỉ mục bắt đầu từ 0. Ví dụ:
[Actual Data] -> [Adapter Views]
[0: SleepNight] -> [0: SleepNight]
[1: SleepNight] -> [1: SleepNight]
[2: SleepNight] -> [2: SleepNight]
Một cách để thêm tiêu đề vào danh sách là sửa đổi bộ chuyển đổi để sử dụng một ViewHolder
khác bằng cách kiểm tra các chỉ mục nơi tiêu đề cần xuất hiện. Adapter
sẽ chịu trách nhiệm theo dõi tiêu đề. Ví dụ: để hiện một tiêu đề ở đầu bảng, bạn cần trả về một ViewHolder
khác cho tiêu đề trong khi bố trí mục có chỉ mục bằng 0. Sau đó, tất cả các mục khác sẽ được liên kết với phần bù tiêu đề, như minh hoạ bên dưới.
[Actual Data] -> [Adapter Views]
[0: Header]
[0: SleepNight] -> [1: SleepNight]
[1: SleepNight] -> [2: SleepNight]
[2: SleepNight] -> [3: SleepNight.
Một cách khác để thêm tiêu đề là sửa đổi tập dữ liệu hỗ trợ cho lưới dữ liệu. Vì tất cả dữ liệu cần hiển thị đều được lưu trữ trong một danh sách, nên bạn có thể sửa đổi danh sách để thêm các mục đại diện cho tiêu đề. Cách này dễ hiểu hơn một chút, nhưng bạn cần phải suy nghĩ về cách thiết kế các đối tượng để có thể kết hợp nhiều loại mục vào một danh sách duy nhất. Khi được triển khai theo cách này, trình chuyển đổi sẽ hiển thị các mục được truyền đến. Vì vậy, mục ở vị trí 0 là tiêu đề và mục ở vị trí 1 là SleepNight
, được liên kết trực tiếp với nội dung trên màn hình.
[Actual Data] -> [Adapter Views]
[0: Header] -> [0: Header]
[1: SleepNight] -> [1: SleepNight]
[2: SleepNight] -> [2: SleepNight]
[3: SleepNight] -> [3: SleepNight]
Mỗi phương pháp đều có ưu điểm và nhược điểm riêng. Việc thay đổi tập dữ liệu không gây ra nhiều thay đổi cho phần còn lại của mã bộ chuyển đổi và bạn có thể thêm logic tiêu đề bằng cách thao tác với danh sách dữ liệu. Mặt khác, việc sử dụng một ViewHolder
khác bằng cách kiểm tra các chỉ mục cho tiêu đề sẽ giúp bạn có nhiều quyền tự do hơn trong việc bố trí tiêu đề. Nó cũng cho phép trình chuyển đổi xử lý cách dữ liệu được điều chỉnh cho phù hợp với khung hiển thị mà không cần sửa đổi dữ liệu sao lưu.
Trong lớp học lập trình này, bạn sẽ cập nhật RecyclerView
để hiển thị một tiêu đề ở đầu danh sách. Trong trường hợp này, ứng dụng của bạn sẽ sử dụng một ViewHolder
khác cho tiêu đề so với các mục dữ liệu. Ứng dụng sẽ kiểm tra chỉ mục của danh sách để xác định ViewHolder
nào cần sử dụng.
Bước 1: Tạo một lớp DataItem
Để trừu tượng hoá loại mục và cho phép trình chuyển đổi chỉ xử lý "các mục", bạn có thể tạo một lớp trình giữ dữ liệu đại diện cho SleepNight
hoặc Header
. Sau đó, tập dữ liệu của bạn sẽ là một danh sách các mục trình giữ dữ liệu.
Bạn có thể lấy ứng dụng khởi đầu trên GitHub hoặc tiếp tục sử dụng ứng dụng SleepTracker mà bạn đã tạo trong lớp học lập trình trước.
- Tải mã RecyclerViewHeaders-Starter xuống từ GitHub. Thư mục RecyclerViewHeaders-Starter chứa phiên bản khởi đầu của ứng dụng SleepTracker cần thiết cho lớp học lập trình này. Bạn cũng có thể tiếp tục với ứng dụng đã hoàn thành từ lớp học lập trình trước nếu muốn.
- Mở SleepNightAdapter.kt.
- Bên dưới lớp
SleepNightListener
, ở cấp cao nhất, hãy xác định một lớpsealed
có tên làDataItem
, đại diện cho một mục dữ liệu.
Lớpsealed
xác định một loại khép kín, tức là tất cả các lớp con củaDataItem
đều phải được xác định trong tệp này. Do đó, trình biên dịch sẽ biết số lượng lớp con. Một phần khác trong mã của bạn không thể xác định một loạiDataItem
mới có thể làm hỏng bộ chuyển đổi.
sealed class DataItem {
}
- Trong phần nội dung của lớp
DataItem
, hãy xác định 2 lớp đại diện cho các loại mục dữ liệu khác nhau. Đầu tiên làSleepNightItem
, đây là một trình bao bọc xung quanhSleepNight
, vì vậy, nó lấy một giá trị duy nhất có tên làsleepNight
. Để tạo thành một phần của lớp niêm phong, hãy mở rộngDataItem
.
data class SleepNightItem(val sleepNight: SleepNight): DataItem()
- Lớp thứ hai là
Header
, đại diện cho tiêu đề. Vì tiêu đề không có dữ liệu thực tế, nên bạn có thể khai báo tiêu đề đó là mộtobject
. Điều đó có nghĩa là sẽ chỉ có một thực thể củaHeader
. Một lần nữa, hãy mở rộngDataItem
.
object Header: DataItem()
- Bên trong
DataItem
, ở cấp lớp, hãy xác định một thuộc tínhabstract
Long
có tên làid
. Khi bộ chuyển đổi sử dụngDiffUtil
để xác định xem một mục có thay đổi hay không và thay đổi như thế nào,DiffItemCallback
cần biết mã nhận dạng của từng mục. Bạn sẽ thấy lỗi vìSleepNightItem
vàHeader
cần ghi đè thuộc tính trừu tượngid
.
abstract val id: Long
- Trong
SleepNightItem
, hãy ghi đèid
để trả vềnightId
.
override val id = sleepNight.nightId
- Trong
Header
, hãy ghi đèid
để trả vềLong.MIN_VALUE
, đây là một số rất nhỏ (theo đúng nghĩa đen, -2 mũ 63). Vì vậy, điều này sẽ không bao giờ xung đột với bất kỳnightId
nào hiện có.
override val id = Long.MIN_VALUE
- Mã hoàn thiện của bạn sẽ có dạng như sau và ứng dụng của bạn sẽ được tạo mà không gặp lỗi.
sealed class DataItem {
abstract val id: Long
data class SleepNightItem(val sleepNight: SleepNight): DataItem() {
override val id = sleepNight.nightId
}
object Header: DataItem() {
override val id = Long.MIN_VALUE
}
}
Bước 2: Tạo một ViewHolder cho Tiêu đề
- Tạo bố cục cho tiêu đề trong một tệp tài nguyên bố cục mới có tên là header.xml hiển thị một
TextView
. Không có gì thú vị về điều này, vì vậy đây là mã.
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Sleep Results"
android:padding="8dp" />
- Trích xuất
"Sleep Results"
thành một tài nguyên chuỗi và gọi tài nguyên đó làheader_text
.
<string name="header_text">Sleep Results</string>
- Trong SleepNightAdapter.kt, bên trong
SleepNightAdapter
, phía trên lớpViewHolder
, hãy tạo một lớpTextViewHolder
mới. Lớp này mở rộng bố cục textview.xml và trả về một thực thểTextViewHolder
. Vì bạn đã làm việc này trước đây, nên đây là mã và bạn sẽ phải nhậpView
vàR
:
class TextViewHolder(view: View): RecyclerView.ViewHolder(view) {
companion object {
fun from(parent: ViewGroup): TextViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val view = layoutInflater.inflate(R.layout.header, parent, false)
return TextViewHolder(view)
}
}
}
Bước 3: Cập nhật SleepNightAdapter
Tiếp theo, bạn cần cập nhật nội dung khai báo của SleepNightAdapter
. Thay vì chỉ hỗ trợ một loại ViewHolder
, nó cần có khả năng sử dụng mọi loại trình lưu giữ thành phần hiển thị.
Xác định các loại mặt hàng
- Trong
SleepNightAdapter.kt
, ở cấp cao nhất, bên dưới các câu lệnhimport
và phía trênSleepNightAdapter
, hãy xác định 2 hằng số cho các loại khung hiển thị.RecyclerView
sẽ cần phân biệt loại khung hiển thị của từng mục để có thể chỉ định chính xác một trình giữ khung hiển thị cho mục đó.
private val ITEM_VIEW_TYPE_HEADER = 0
private val ITEM_VIEW_TYPE_ITEM = 1
- Trong
SleepNightAdapter
, hãy tạo một hàm để ghi đègetItemViewType()
nhằm trả về hằng số tiêu đề hoặc mục phù hợp, tuỳ thuộc vào loại mục hiện tại.
override fun getItemViewType(position: Int): Int {
return when (getItem(position)) {
is DataItem.Header -> ITEM_VIEW_TYPE_HEADER
is DataItem.SleepNightItem -> ITEM_VIEW_TYPE_ITEM
}
}
Cập nhật định nghĩa SleepNightAdapter
- Trong định nghĩa của
SleepNightAdapter
, hãy cập nhật đối số đầu tiên choListAdapter
từSleepNight
thànhDataItem
. - Trong định nghĩa của
SleepNightAdapter
, hãy thay đổi đối số chung thứ hai choListAdapter
từSleepNightAdapter.ViewHolder
thànhRecyclerView.ViewHolder
. Bạn sẽ thấy một số lỗi đối với các nội dung cập nhật cần thiết và tiêu đề lớp của bạn sẽ có dạng như hình bên dưới.
class SleepNightAdapter(val clickListener: SleepNightListener):
ListAdapter<DataItem, RecyclerView.ViewHolder>(SleepNightDiffCallback()) {
Cập nhật onCreateViewHolder()
- Thay đổi chữ ký của
onCreateViewHolder()
để trả về mộtRecyclerView.ViewHolder
.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder
- Mở rộng quá trình triển khai phương thức
onCreateViewHolder()
để kiểm thử và trả về trình giữ khung hiển thị thích hợp cho từng loại mục. Phương thức đã cập nhật của bạn sẽ có dạng như mã bên dưới.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
ITEM_VIEW_TYPE_HEADER -> TextViewHolder.from(parent)
ITEM_VIEW_TYPE_ITEM -> ViewHolder.from(parent)
else -> throw ClassCastException("Unknown viewType ${viewType}")
}
}
Cập nhật onBindViewHolder()
- Thay đổi loại tham số của
onBindViewHolder()
từViewHolder
thànhRecyclerView.ViewHolder
.
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int)
- Thêm một điều kiện để chỉ chỉ định dữ liệu cho trình giữ nếu trình giữ là một
ViewHolder
.
when (holder) {
is ViewHolder -> {...}
- Truyền kiểu đối tượng do
getItem()
trả về thànhDataItem.SleepNightItem
. HàmonBindViewHolder()
hoàn chỉnh sẽ có dạng như sau.
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is ViewHolder -> {
val nightItem = getItem(position) as DataItem.SleepNightItem
holder.bind(nightItem.sleepNight, clickListener)
}
}
}
Cập nhật các lệnh gọi lại diffUtil
- Thay đổi các phương thức trong
SleepNightDiffCallback
để sử dụng lớpDataItem
mới thay vìSleepNight
. Tắt cảnh báo lint như minh hoạ trong mã bên dưới.
class SleepNightDiffCallback : DiffUtil.ItemCallback<DataItem>() {
override fun areItemsTheSame(oldItem: DataItem, newItem: DataItem): Boolean {
return oldItem.id == newItem.id
}
@SuppressLint("DiffUtilEquals")
override fun areContentsTheSame(oldItem: DataItem, newItem: DataItem): Boolean {
return oldItem == newItem
}
}
Thêm và gửi tiêu đề
- Bên trong
SleepNightAdapter
, bên dướionCreateViewHolder()
, hãy xác định một hàmaddHeaderAndSubmitList()
như minh hoạ bên dưới. Hàm này lấy một danh sáchSleepNight
. Thay vì sử dụngsubmitList()
doListAdapter
cung cấp để gửi danh sách, bạn sẽ sử dụng hàm này để thêm tiêu đề rồi gửi danh sách.
fun addHeaderAndSubmitList(list: List<SleepNight>?) {}
- Bên trong
addHeaderAndSubmitList()
, nếu danh sách được truyền vào lànull
, chỉ cần trả về một tiêu đề, nếu không, hãy đính kèm tiêu đề vào đầu danh sách, rồi gửi danh sách.
val items = when (list) {
null -> listOf(DataItem.Header)
else -> listOf(DataItem.Header) + list.map { DataItem.SleepNightItem(it) }
}
submitList(items)
- Mở SleepTrackerFragment.kt và thay đổi lệnh gọi thành
submitList()
thànhaddHeaderAndSubmitList()
.
- Chạy ứng dụng và quan sát cách tiêu đề của bạn xuất hiện dưới dạng mục đầu tiên trong danh sách các mục về giấc ngủ.
Có hai vấn đề cần được khắc phục cho ứng dụng này. Một vấn đề có thể thấy được và một vấn đề không thấy được.
- Tiêu đề xuất hiện ở góc trên cùng bên trái và không dễ phân biệt.
- Điều này không quan trọng đối với một danh sách ngắn có một tiêu đề, nhưng bạn không nên thao tác với danh sách trong
addHeaderAndSubmitList()
trên luồng giao diện người dùng. Hãy tưởng tượng một danh sách có hàng trăm mục, nhiều tiêu đề và logic để quyết định vị trí cần chèn các mục. Thao tác này thuộc về một coroutine.
Thay đổi addHeaderAndSubmitList()
để sử dụng coroutine:
- Ở cấp cao nhất bên trong lớp
SleepNightAdapter
, hãy xác định mộtCoroutineScope
bằngDispatchers.Default
.
private val adapterScope = CoroutineScope(Dispatchers.Default)
- Trong
addHeaderAndSubmitList()
, hãy chạy một coroutine trongadapterScope
để thao tác với danh sách. Sau đó, chuyển sang ngữ cảnhDispatchers.Main
để gửi danh sách, như minh hoạ trong mã bên dưới.
fun addHeaderAndSubmitList(list: List<SleepNight>?) {
adapterScope.launch {
val items = when (list) {
null -> listOf(DataItem.Header)
else -> listOf(DataItem.Header) + list.map { DataItem.SleepNightItem(it) }
}
withContext(Dispatchers.Main) {
submitList(items)
}
}
}
- Mã của bạn sẽ được tạo và chạy, đồng thời bạn sẽ không thấy bất kỳ sự khác biệt nào.
Hiện tại, tiêu đề có cùng chiều rộng với các mục khác trên lưới, chiếm một khoảng theo chiều ngang và chiều dọc. Toàn bộ lưới vừa với 3 mục có chiều rộng một khoảng theo chiều ngang, vì vậy, tiêu đề phải sử dụng 3 khoảng theo chiều ngang.
Để cố định chiều rộng tiêu đề, bạn cần cho GridLayoutManager
biết thời điểm trải rộng dữ liệu trên tất cả các cột. Bạn có thể thực hiện việc này bằng cách định cấu hình SpanSizeLookup
trên GridLayoutManager
. Đây là một đối tượng cấu hình mà GridLayoutManager
dùng để xác định số lượng khoảng cần dùng cho mỗi mục trong danh sách.
- Mở SleepTrackerFragment.kt.
- Tìm mã nơi bạn xác định
manager
, gần cuốionCreateView()
.
val manager = GridLayoutManager(activity, 3)
- Bên dưới
manager
, hãy xác địnhmanager.spanSizeLookup
như minh hoạ. Bạn cần tạo mộtobject
vìsetSpanSizeLookup
không lấy lambda. Để tạo mộtobject
trong Kotlin, hãy nhậpobject : classname
, trong trường hợp này làGridLayoutManager.SpanSizeLookup
.
manager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
}
- Bạn có thể gặp lỗi trình biên dịch khi gọi hàm khởi tạo. Nếu bạn làm như vậy, hãy mở trình đơn ý định bằng
Option+Enter
(Mac) hoặcAlt+Enter
(Windows) để áp dụng lệnh gọi hàm khởi tạo.
- Sau đó, bạn sẽ gặp lỗi trên
object
cho biết bạn cần ghi đè các phương thức. Đặt con trỏ lênobject
, nhấnOption+Enter
(Mac) hoặcAlt+Enter
(Windows) để mở trình đơn ý định, sau đó ghi đè phương thứcgetSpanSize()
.
- Trong phần nội dung của
getSpanSize()
, hãy trả về kích thước khoảng phù hợp cho từng vị trí. Vị trí 0 có kích thước khoảng là 3, còn các vị trí khác có kích thước khoảng là 1. Đoạn mã hoàn chỉnh của bạn sẽ có dạng như mã bên dưới:
manager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int) = when (position) {
0 -> 3
else -> 1
}
}
- Để cải thiện giao diện của tiêu đề, hãy mở header.xml rồi thêm mã này vào tệp bố cục header.xml.
android:textColor="@color/white_text_color"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:background="@color/colorAccent"
- Chạy ứng dụng. Ứng dụng sẽ có dạng như ảnh chụp màn hình dưới đây.
Xin chúc mừng! Bạn đã hoàn tất.
Dự án Android Studio: RecyclerViewHeaders
- Tiêu đề thường là một mục trải dài theo chiều rộng của danh sách và đóng vai trò là tiêu đề hoặc dấu phân cách. Danh sách có thể có một tiêu đề duy nhất để mô tả nội dung của mục hoặc nhiều tiêu đề để nhóm các mục và tách các mục với nhau.
RecyclerView
có thể sử dụng nhiều trình lưu giữ thành phần hiển thị để chứa một nhóm các mục không đồng nhất; ví dụ: tiêu đề và mục trong danh sách.- Một cách để thêm tiêu đề là sửa đổi bộ chuyển đổi để sử dụng một
ViewHolder
khác bằng cách kiểm tra các chỉ mục nơi tiêu đề cần xuất hiện.Adapter
chịu trách nhiệm theo dõi tiêu đề. - Một cách khác để thêm tiêu đề là sửa đổi tập dữ liệu hỗ trợ (danh sách) cho lưới dữ liệu của bạn. Đây là việc bạn đã làm trong lớp học lập trình này.
Sau đây là các bước chính để thêm tiêu đề:
- Tóm tắt dữ liệu trong danh sách bằng cách tạo một
DataItem
có thể chứa tiêu đề hoặc dữ liệu. - Tạo một ngăn chứa khung hiển thị có bố cục cho tiêu đề trong bộ chuyển đổi.
- Cập nhật trình điều hợp và các phương thức của trình điều hợp để sử dụng mọi loại
RecyclerView.ViewHolder
. - Trong
onCreateViewHolder()
, hãy trả về đúng loại trình giữ chế độ xem cho mục dữ liệu. - Cập nhật
SleepNightDiffCallback
để hoạt động với lớpDataItem
. - Tạo một hàm
addHeaderAndSubmitList()
dùng coroutine để thêm tiêu đề vào tập dữ liệu, rồi gọisubmitList()
. - Triển khai
GridLayoutManager.SpanSizeLookup()
để chỉ tạo tiêu đề có chiều rộng 3 ô.
Khoá học của Udacity:
Tài liệu dành cho nhà phát triển Android:
Phần này liệt kê các bài tập về nhà cho học viên của lớp học lập trình này trong phạm vi khoá học có người hướng dẫn. Người hướng dẫn phải thực hiện các việc sau đây:
- Giao bài tập về nhà nếu cần.
- Trao đổi với học viên về cách nộp bài tập về nhà.
- Chấm điểm bài tập về nhà.
Người hướng dẫn có thể sử dụng các đề xuất này ít hoặc nhiều tuỳ ý và nên giao cho học viên bất kỳ bài tập về nhà nào khác mà họ cảm thấy phù hợp.
Nếu bạn đang tự học các lớp học lập trình, hãy sử dụng những bài tập về nhà này để kiểm tra kiến thức của mình.
Trả lời các câu hỏi sau
Câu hỏi 1
Câu nào sau đây đúng về ViewHolder
?
▢ Bộ chuyển đổi có thể sử dụng nhiều lớp ViewHolder
để lưu giữ tiêu đề và nhiều loại dữ liệu.
▢ Bạn chỉ được có đúng một phần tử giữ khung hiển thị đối với dữ liệu và một phần tử giữ khung hiển thị đối với tiêu đề.
▢ RecyclerView
hỗ trợ nhiều loại tiêu đề, nhưng dữ liệu phải thống nhất.
▢ Khi thêm tiêu đề, bạn tạo lớp con RecyclerView
để chèn tiêu đề vào đúng vị trí.
Câu hỏi 2
Khi nào bạn nên sử dụng các coroutine với RecyclerView
? Chọn tất cả những nhận định đúng.
▢ Không bao giờ. RecyclerView
là một phần tử trên giao diện người dùng và không được dùng coroutine.
▢ Sử dụng coroutine cho các tác vụ chạy trong thời gian dài có thể làm chậm giao diện người dùng.
▢ Các thao tác trên danh sách có thể mất nhiều thời gian và bạn nên luôn thực hiện các thao tác này bằng cách sử dụng coroutine.
▢ Sử dụng coroutine với các hàm tạm ngưng để tránh chặn luồng chính.
Câu hỏi 3
Bạn KHÔNG cần làm gì trong số những việc sau đây khi sử dụng nhiều ViewHolder
?
▢ Trong ViewHolder
, hãy cung cấp nhiều tệp bố cục để tăng kích thước khi cần.
▢ Trong onCreateViewHolder()
, hãy trả về đúng loại trình giữ chế độ xem cho mục dữ liệu.
▢ Trong onBindViewHolder()
, chỉ liên kết dữ liệu nếu phần tử giữ khung hiển thị là loại phần tử giữ khung hiển thị phù hợp cho mục dữ liệu.
▢ Tổng quát hoá chữ ký lớp bộ chuyển đổi để chấp nhận mọi RecyclerView.ViewHolder
.
Bắt đầu bài học tiếp theo:
Để biết đường liên kết đến các lớp học lập trình khác trong khoá học này, hãy xem trang đích của lớp học lập trình Kiến thức cơ bản về cách tạo ứng dụng Android bằng Kotlin.