Kiến thức cơ bản về Kotlin cho Android 07.5: Tiêu đề trong RecyclerView

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ằng Adapter, 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ột RecyclerView để thêm các mục có bố cục khác. Cụ thể là cách sử dụng ViewHolder thứ hai để thêm tiêu đề phía trên các mục xuất hiện trong RecyclerView.

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.

  1. 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.
  2. Mở SleepNightAdapter.kt.
  3. Bên dưới lớp SleepNightListener, ở cấp cao nhất, hãy xác định một lớp sealed có tên là DataItem, đại diện cho một mục dữ liệu.

    Lớp sealed xác định một loại khép kín, tức là tất cả các lớp con của DataItem đề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ại DataItem mới có thể làm hỏng bộ chuyển đổi.
sealed class DataItem {

 }
  1. 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 quanh SleepNight, 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ộng DataItem.
data class SleepNightItem(val sleepNight: SleepNight): DataItem()
  1. 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ột object. Điều đó có nghĩa là sẽ chỉ có một thực thể của Header. Một lần nữa, hãy mở rộng DataItem.
object Header: DataItem()
  1. Bên trong DataItem, ở cấp lớp, hãy xác định một thuộc tính abstract Long có tên là id. Khi bộ chuyển đổi sử dụng DiffUtil để 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ì SleepNightItemHeader cần ghi đè thuộc tính trừu tượng id.
abstract val id: Long
  1. Trong SleepNightItem, hãy ghi đè id để trả về nightId.
override val id = sleepNight.nightId
  1. 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
  1. 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 đề

  1. 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" />
  1. 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>
  1. Trong SleepNightAdapter.kt, bên trong SleepNightAdapter, phía trên lớp ViewHolder, hãy tạo một lớp TextViewHolder 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ập ViewR:
    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

  1. Trong SleepNightAdapter.kt, ở cấp cao nhất, bên dưới các câu lệnh import và phía trên SleepNightAdapter, 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
  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

  1. Trong định nghĩa của SleepNightAdapter, hãy cập nhật đối số đầu tiên cho ListAdapter từ SleepNight thành DataItem.
  2. Trong định nghĩa của SleepNightAdapter, hãy thay đổi đối số chung thứ hai cho ListAdapter từ SleepNightAdapter.ViewHolder thành RecyclerView.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()

  1. Thay đổi chữ ký của onCreateViewHolder() để trả về một RecyclerView.ViewHolder.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder
  1. 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()

  1. Thay đổi loại tham số của onBindViewHolder() từ ViewHolder thành RecyclerView.ViewHolder.
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int)
  1. 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 -> {...}
  1. Truyền kiểu đối tượng do getItem() trả về thành DataItem.SleepNightItem. Hàm onBindViewHolder() 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

  1. Thay đổi các phương thức trong SleepNightDiffCallback để sử dụng lớp DataItem 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 đề

  1. Bên trong SleepNightAdapter, bên dưới onCreateViewHolder(), hãy xác định một hàm addHeaderAndSubmitList() như minh hoạ bên dưới. Hàm này lấy một danh sách SleepNight. Thay vì sử dụng submitList() do ListAdapter 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>?) {}
  1. 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)
  1. Mở SleepTrackerFragment.kt và thay đổi lệnh gọi thành submitList() thành addHeaderAndSubmitList().
  1. 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:

  1. Ở cấp cao nhất bên trong lớp SleepNightAdapter, hãy xác định một CoroutineScope bằng Dispatchers.Default.
private val adapterScope = CoroutineScope(Dispatchers.Default)
  1. Trong addHeaderAndSubmitList(), hãy chạy một coroutine trong adapterScope để thao tác với danh sách. Sau đó, chuyển sang ngữ cảnh Dispatchers.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)
            }
        }
    }
  1. 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.

  1. Mở SleepTrackerFragment.kt.
  2. Tìm mã nơi bạn xác định manager, gần cuối onCreateView().
val manager = GridLayoutManager(activity, 3)
  1. Bên dưới manager, hãy xác định manager.spanSizeLookup như minh hoạ. Bạn cần tạo một objectsetSpanSizeLookup không lấy lambda. Để tạo một object trong Kotlin, hãy nhập object : classname, trong trường hợp này là GridLayoutManager.SpanSizeLookup.
manager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
}
  1. 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ặc Alt+Enter (Windows) để áp dụng lệnh gọi hàm khởi tạo.
  1. 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ên object, nhấn Option+Enter (Mac) hoặc Alt+Enter (Windows) để mở trình đơn ý định, sau đó ghi đè phương thức getSpanSize().
  1. 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
            }
        }
  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"
  1. 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ớp DataItem.
  • Tạo một hàm addHeaderAndSubmitList() dùng coroutine để thêm tiêu đề vào tập dữ liệu, rồi gọi submitList().
  • 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: 8.1 Lấy dữ liệu từ Internet

Để 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.