Tạo danh sách động bằng RecyclerView   Thuộc Android Jetpack.

Thử cách dùng Compose
Jetpack Compose là bộ công cụ giao diện người dùng được đề xuất cho Android. Tìm hiểu cách sử dụng bố cục trong ứng dụng Compose.

RecyclerView giúp dễ dàng hiển thị hiệu quả các tập dữ liệu lớn. Bạn chỉ cần cung cấp dữ liệu và xác định giao diện của từng mục, thư viện RecyclerView sẽ linh động tạo các phần tử khi cần.

Đúng như tên gọi, RecyclerView tái chế các phần tử riêng lẻ đó. Khi một mục cuộn ra khỏi màn hình, RecyclerView sẽ không huỷ bỏ thành phần hiển thị của mục đó. Thay vào đó, RecyclerView sử dụng lại thành phần hiển thị này cho các mục mới đã cuộn trên màn hình. RecyclerView cải thiện hiệu suất và khả năng phản hồi của ứng dụng, đồng thời giảm mức tiêu thụ điện năng.

Các lớp chính

Một số lớp sẽ phối hợp với nhau để tạo danh sách động.

  • RecyclerViewViewGroup chứa các thành phần hiển thị tương ứng với dữ liệu của bạn. Bản thân đây là một thành phần hiển thị, nên hãy thêm RecyclerView vào bố cục theo cách tương tự khi bạn thêm bất kỳ thành phần nào khác trên giao diện người dùng.

  • Mỗi phần tử riêng lẻ trong danh sách được xác định bởi một đối tượng ngăn chứa thành phần hiển thị. Khi được tạo, ngăn chứa thành phần hiển thị không có bất kỳ dữ liệu liên kết nào. Sau khi ngăn chứa thành phần hiển thị được tạo, RecyclerView sẽ liên kết thành phần hiển thị với dữ liệu tương ứng. Bạn xác định ngăn chứa thành phần hiển thị bằng cách mở rộng RecyclerView.ViewHolder.

  • RecyclerView yêu cầu các thành phần hiển thị và liên kết các thành phần hiển thị với dữ liệu tương ứng, bằng cách gọi các phương thức trong bộ chuyển đổi. Bạn xác định bộ chuyển đổi bằng cách mở rộng RecyclerView.Adapter.

  • Trình quản lý bố cục sắp xếp các thành phần riêng lẻ trong danh sách của bạn. Bạn có thể sử dụng một trong các trình quản lý bố cục do thư viện RecyclerView cung cấp hoặc bạn có thể tự xác định. Tất cả trình quản lý bố cục đều dựa trên lớp trừu tượng LayoutManager của thư viện.

Bạn có thể xem cách tất cả các thành phần khớp với nhau trong ứng dụng mẫu RecyclerView (Kotlin) hoặc ứng dụng mẫu RecyclerView (Java).

Các bước triển khai RecyclerView

Nếu định sử dụng RecyclerView thì bạn sẽ có một vài việc cần làm. Những việc này sẽ được giải thích chi tiết trong các phần sau.

  1. Quyết định giao diện của danh sách hoặc lưới. Thông thường, bạn có thể sử dụng một trong những trình quản lý bố cục chuẩn của thư viện RecyclerView.

  2. Thiết kế giao diện và hoạt động của từng phần tử trong danh sách. Dựa trên thiết kế này, hãy mở rộng lớp ViewHolder. Phiên bản ViewHolder của bạn cung cấp toàn bộ chức năng cho các mục trong danh sách. Ngăn chứa thành phần hiển thị của bạn là trình bao bọc xung quanh View và thành phần hiển thị đó do RecyclerView quản lý.

  3. Xác định Adapter liên kết dữ liệu của bạn với các thành phần hiển thị ViewHolder.

Ngoài ra, bạn cũng có thể sử dụng các tuỳ chọn tuỳ chỉnh nâng cao để điều chỉnh RecyclerView phù hợp theo đúng nhu cầu của mình.

Lên kế hoạch về bố cục

Các mục trong RecyclerView của bạn được một lớp LayoutManager sắp xếp. Thư viện RecyclerView cung cấp ba trình quản lý bố cục, giúp xử lý các trường hợp bố cục phổ biến nhất:

  • LinearLayoutManager sắp xếp các mục theo danh sách một chiều.
  • GridLayoutManager sắp xếp các mục theo dạng lưới hai chiều:
    • Nếu lưới được bố trí theo chiều dọc, GridLayoutManager sẽ cố gắng điều chỉnh sao cho mọi phần tử trong mỗi hàng có cùng độ rộng và chiều cao, nhưng chiều cao có thể tuỳ theo hàng.
    • Nếu lưới được bố trí theo chiều ngang, GridLayoutManager sẽ cố gắng điều chỉnh sao cho mọi phần tử trong mỗi cột có cùng độ rộng và chiều cao, nhưng độ rộng có thể tuỳ theo cột.
  • StaggeredGridLayoutManager tương tự như GridLayoutManager, nhưng không yêu cầu các mục trong cùng một hàng có cùng chiều cao (đối với lưới dọc) hoặc các mục trong cùng một cột có cùng độ rộng (đối với lưới ngang). Do đó, các mục trong cùng một hàng hoặc cột có thể bù trừ cho nhau.

Bạn cũng cần thiết kế bố cục của từng mục riêng lẻ. Bạn cần bố cục này khi thiết kế ngăn chứa thành phần hiển thị như mô tả trong phần tiếp theo.

Triển khai bộ chuyển đổi và ngăn chứa thành phần hiển thị

Sau khi xác định bố cục, bạn cần triển khai AdapterViewHolder. Hai lớp này phối hợp với nhau để xác định cách hiển thị dữ liệu của bạn. ViewHolder là trình bao bọc xung quanh một View chứa bố cục cho từng mục riêng lẻ trong danh sách. Adapter sẽ tạo các đối tượng ViewHolder nếu cần, đồng thời đặt dữ liệu cho các thành phần hiển thị đó. Quá trình gắn thành phần hiển thị với dữ liệu tương ứng được gọi là liên kết.

Khi xác định bộ chuyển đổi, bạn sẽ ghi đè ba phương thức chính:

  • onCreateViewHolder(): RecyclerView gọi phương thức này bất cứ khi nào cần tạo ViewHolder mới. Phương thức này tạo và khởi động ViewHolder cùng với View đã liên kết, nhưng không điền vào nội dung của thành phần hiển thị – ViewHolder chưa liên kết với dữ liệu cụ thể.

  • onBindViewHolder(): RecyclerView gọi phương thức này để liên kết ViewHolder với dữ liệu. Phương thức này tìm nạp dữ liệu thích hợp và sử dụng dữ liệu đó để điền vào bố cục của ngăn chứa thành phần hiển thị. Ví dụ: nếu RecyclerView hiển thị một danh sách tên, phương thức này có thể tìm tên thích hợp trong danh sách và điền vào tiện ích TextView của ngăn chứa thành phần hiển thị.

  • getItemCount(): RecyclerView gọi phương thức này để lấy kích thước của tập dữ liệu. Ví dụ: trong một ứng dụng sổ địa chỉ, đây có thể là tổng số địa chỉ. RecyclerView sử dụng phương thức này để xác định thời điểm không thể hiển thị thêm mục nào.

Dưới đây là ví dụ điển hình về bộ chuyển đổi đơn giản có ViewHolder lồng ghép, hiển thị danh sách dữ liệu. Trong trường hợp này, RecyclerView hiển thị một danh sách đơn giản các thành phần văn bản. Bộ chuyển đổi nhận được một loạt chuỗi chứa văn bản cho các phần tử ViewHolder.

Kotlin

class CustomAdapter(private val dataSet: Array<String>) :
        RecyclerView.Adapter<CustomAdapter.ViewHolder>() {

    /**
     * Provide a reference to the type of views that you are using
     * (custom ViewHolder)
     */
    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val textView: TextView

        init {
            // Define click listener for the ViewHolder's View
            textView = view.findViewById(R.id.textView)
        }
    }

    // Create new views (invoked by the layout manager)
    override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
        // Create a new view, which defines the UI of the list item
        val view = LayoutInflater.from(viewGroup.context)
                .inflate(R.layout.text_row_item, viewGroup, false)

        return ViewHolder(view)
    }

    // Replace the contents of a view (invoked by the layout manager)
    override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {

        // Get element from your dataset at this position and replace the
        // contents of the view with that element
        viewHolder.textView.text = dataSet[position]
    }

    // Return the size of your dataset (invoked by the layout manager)
    override fun getItemCount() = dataSet.size

}

Java

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {

    private String[] localDataSet;

    /**
     * Provide a reference to the type of views that you are using
     * (custom ViewHolder)
     */
    public static class ViewHolder extends RecyclerView.ViewHolder {
        private final TextView textView;

        public ViewHolder(View view) {
            super(view);
            // Define click listener for the ViewHolder's View

            textView = (TextView) view.findViewById(R.id.textView);
        }

        public TextView getTextView() {
            return textView;
        }
    }

    /**
     * Initialize the dataset of the Adapter
     *
     * @param dataSet String[] containing the data to populate views to be used
     * by RecyclerView
     */
    public CustomAdapter(String[] dataSet) {
        localDataSet = dataSet;
    }

    // Create new views (invoked by the layout manager)
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        // Create a new view, which defines the UI of the list item
        View view = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.text_row_item, viewGroup, false);

        return new ViewHolder(view);
    }

    // Replace the contents of a view (invoked by the layout manager)
    @Override
    public void onBindViewHolder(ViewHolder viewHolder, final int position) {

        // Get element from your dataset at this position and replace the
        // contents of the view with that element
        viewHolder.getTextView().setText(localDataSet[position]);
    }

    // Return the size of your dataset (invoked by the layout manager)
    @Override
    public int getItemCount() {
        return localDataSet.length;
    }
}

Thông thường, bố cục của mỗi mục thành phần hiển thị sẽ được xác định trong tệp bố cục XML. Trong trường hợp này, ứng dụng có tệp text_row_item.xml như sau:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="@dimen/list_item_height"
    android:layout_marginLeft="@dimen/margin_medium"
    android:layout_marginRight="@dimen/margin_medium"
    android:gravity="center_vertical">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/element_text"/>
</FrameLayout>

Các bước tiếp theo

Đoạn mã sau đây cho biết cách bạn có thể sử dụng RecyclerView.

Kotlin

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val dataset = arrayOf("January", "February", "March")
        val customAdapter = CustomAdapter(dataset)

        val recyclerView: RecyclerView = findViewById(R.id.recycler_view)
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.adapter = customAdapter

    }

}

Java

RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.layoutManager = new LinearLayoutManager(this)
recyclerView.setAdapter(customAdapter);

Thư viện này cũng cung cấp nhiều cách để tuỳ chỉnh quá trình triển khai của bạn. Để biết thêm thông tin, hãy xem phần Tuỳ chỉnh RecyclerView nâng cao.

Tài nguyên khác

Để biết thêm thông tin về quy trình kiểm thử trên Android, hãy tham khảo các tài nguyên sau.

Ứng dụng mẫu