Tạo danh sách động bằng RecyclerView Thuộc Android Jetpack.
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.
RecyclerView
làViewGroup
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êmRecyclerView
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ộngRecyclerView.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ộngRecyclerView.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.
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.
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ảnViewHolder
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 quanhView
và thành phần hiển thị đó doRecyclerView
quản lý.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.
- Nếu lưới được bố trí theo chiều dọc,
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 Adapter
và ViewHolder
. 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ạoViewHolder
mới. Phương thức này tạo và khởi độngViewHolder
cùng vớiView
đã 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ếtViewHolder
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ếuRecyclerView
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 íchTextView
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.