RecyclerView.ViewHolder - getLayoutPosition so với getAdapterPosition


87

Kể từ phiên bản thư viện hỗ trợ mới (22.x), getPosition()phương thức của RecyclerView.ViewHolderlớp đã không được chấp nhận thay cho các phương thức được đề cập trong chủ đề. Tôi không thực sự nhận được sự khác biệt từ việc đọc các tài liệu. Ai đó có thể giải thích sự khác biệt trong thuật ngữ của giáo dân không?

Tôi có trường hợp sử dụng sau - Tôi cung cấp bộ điều hợp của mình Listvà cũng muốn có thể liên kết thông tin bổ sung cho từng mục danh sách. Tôi có một ánh xạ từ vị trí đến vị trí bổ sung và ánh xạ có sẵn cho những người nắm giữ để họ có thể lấy thêm vị trí của họ và thực hiện các công việc với nó. Trong chủ sở hữu, tôi nên sử dụng phương pháp nào?

Điều gì xảy ra với các vị trí nắm giữ khi các mục danh sách ở chỉ số 0 và 1 được đổi chỗ cho nhau? Các phương thức trả về cái gì?

Câu trả lời:


114

Đây là một tình huống phức tạp, xin lỗi vì tài liệu không đủ.

Khi nội dung bộ điều hợp thay đổi (và bạn gọi notify***()) RecyclerView yêu cầu một bố cục mới. Từ thời điểm đó, cho đến khi hệ thống bố trí quyết định tính toán bố cục mới (<16 ms), vị trí bố trí và vị trí bộ điều hợp có thể không khớp vì bố cục chưa phản ánh các thay đổi của bộ điều hợp.

Trong trường hợp sử dụng của bạn, vì dữ liệu của bạn có liên quan đến nội dung bộ điều hợp của bạn (và tôi giả sử rằng dữ liệu được thay đổi đồng thời với các thay đổi bộ điều hợp), bạn nên sử dụng adapterPosition.

Tuy nhiên, hãy cẩn thận, nếu bạn đang gọi notifyDataSetChanged(), vì nó làm mất hiệu lực của mọi thứ, RecyclerView không biết rằng vị trí bộ điều hợp của ViewHolder cho đến khi bố trí tiếp theo được tính toán. Trong trường hợp đó, getAdapterPosition()sẽ trả về RecyclerView#NO_POSITION( -1).

Nhưng giả sử nếu bạn đã gọi notifyItemInserted(0), getAdapterPosition()ViewHolder trước đó đã ở vị trí 0sẽ bắt đầu quay lại 1ngay lập tức. Vì vậy, miễn là bạn đang gửi các sự kiện thông báo chi tiết, bạn luôn ở trạng thái tốt (chúng tôi biết vị trí bộ điều hợp mặc dù bố cục mới chưa được tính toán).

Một ví dụ khác, nếu bạn đang làm điều gì đó khi người dùng nhấp vào, nếu getAdapterPosition()trả về NO_POSITION, tốt nhất là bỏ qua nhấp chuột đó vì bạn không biết người dùng đã nhấp vào cái gì (trừ khi bạn có một số cơ chế khác, ví dụ: id ổn định để tra cứu mục).

Chỉnh sửa khi vị trí bố cục tốt

LinearLayoutManagerGiả sử bạn đang sử dụng và muốn truy cập ViewHolder phía trên mục hiện được nhấp. Trong trường hợp đó, bạn nên sử dụng vị trí bố trí để lấy mục ở trên.

mRecyclerView.findViewHolderForLayoutPosition(myViewHolder.getLayoutPosition() - 1)

Bạn phải sử dụng vị trí bố cục vì nó khớp với những gì người dùng hiện đang nhìn thấy trên màn hình.


1
Tôi đã chơi xung quanh một chút và hóa ra phương thức getAdapterPosition () luôn trả về -1 cho tôi. Tôi đã gỡ lỗi nó và lý do là mã trong phương thức (Final ViewParent parent = itemView.getParent (); if (! (Parent instanceof RecyclerView)) {return -1;} luôn đi vào khối if, tức là chế độ xem trình tái chế không phải là cha của chế độ xem ô của tôi. Làm thế nào nó có thể được? Mã của tôi để tạo trình giữ là: return MyViewHolder (LayoutInflater.from (viewGroup.getContext ()). phồng lên (R.layout.test_list_item, viewGroup, false)); (Tiếp tục trong một bình luận khác.)
wujek

Khi tôi thay đổi mã để gọi giá trị (R.layout.test_list_item, viewGroup, true); (lưu ý đúng với 'đính kèm vào gốc), Android ném: java.lang.IllegalStateException: Con được chỉ định đã có cha mẹ. Trước tiên, bạn phải gọi removeView () trên cha mẹ của đứa trẻ. Vì vậy, cách chính xác để tạo một khung nhìn với một khung nhìn được gắn chính xác vào khung nhìn tái chế là gì? Thật kỳ lạ, ngay cả khi getAdapterPosition () trả về -1 vì giá trị gốc là null, mọi thứ khác đều hoạt động tốt.
wujek

1
Tham số boolean trong bộ thổi bố cục là "addToParent". Nó phải là false vì LayoutManager có trách nhiệm thêm nó vào. Tôi nghĩ rằng bạn đang gọi getAdapterPosition trong onBind, nơi bạn đã được thông qua vị trí. Về mặt kỹ thuật, người giữ chế độ xem đại diện cho vị trí đó sau khi onBind trở lại. Btw, chúng tôi đã cập nhật vị trí getAdapter để trả lại vị trí hợp lệ (nếu có thể) ngay cả khi nó bị tách ra, nó sẽ sớm được phát hành.
yigit

Bạn nói đúng, tôi đang gọi getAdapterPosition trong onBind. Thay vào đó, tôi nên làm gì trong trường hợp này, tôi cần vị trí để lấy một số thông tin ảnh hưởng đến trạng thái của một số chế độ xem. Gọi getLayoutPosition trong trường hợp này có ổn không?
wujek

5
Bạn nên sử dụng tham số vị trí được truyền cho phương thức onBind.
yigit

2


Để tranh luận sự khác biệt (s) của getAdapterPosition(), getLayoutPosition()và cũng position; chúng tôi sẽ nhận thấy các trường hợp dưới đây:

1. positionđối số trong onBindViewHolder()phương pháp:

Chúng tôi có thể sử dụng đối số positionđể liên kết dữ liệu với chế độ xem và bạn có thể sử dụng positionđối số để thực hiện việc này, nhưng không được sử dụng positionđối số để xử lý các nhấp chuột của người dùng và nếu bạn đã sử dụng nó, bạn sẽ thấy một cảnh báo cho bạn biết "không được coi positionlà đã sửa và sử dụng holder.getAdapterPosition()thay thế ”.

2 getAdapterPosition().:

Phương thức này luôn bao gồm vị trí bộ điều hợp được cập nhật của holder. Nó có nghĩa là bất cứ khi nào bạn nhấp vào một mục, bạn sẽ hỏi bộ điều hợp về nó position. vì vậy bạn sẽ nhận được vị trí mới nhất của mục này theo logic của Bộ điều hợp.

3 getLayoutPosition().:

Đôi khi, cần phải tìm các positionđiều khoản của bố cục được cập nhật (bố cục được chuyển lần cuối mà người dùng đang nhìn thấy bây giờ), ví dụ: Nếu người dùng yêu cầu thứ ba position, họ có thể xem và bạn sử dụng swipe/ dismisscho các mục hoặc áp dụng bất kỳ hoạt ảnh nào hoặc đồ trang trí cho các vật phẩm sẽ tốt hơn nếu sử dụng getLayoutPosition()thay vì getAdapterPosition(), vì bạn sẽ luôn chắc chắn rằng bạn đang xử lý vị trí của các vật phẩm theo bố cục được thông qua mới nhất.


Để biết thêm thông tin về điều này; xem tại đây . . .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.