Android

ListView trong Android (Phần 2)

Giới thiệu

Trong bài viết ListView trong Android Phần 1 tôi đã hướng dẫn các bạn sử dụng ListView một cách đơn giản nhất. Tuy nhiên ứng dụng của chúng ta cần những ListView phức tạp hơn nhiều. Vậy làm sao để xây dựng được những ListView đó trong ứng dụng của chúng ta, thì bài viết này sẽ cùng các bạn tìm hiểu.

CustomAdapter

Ở bài viết trước chúng ta sử dụng ArrayAdapter rất là đơn giản (kiểu dữ liệu truyền vào là một list String và layout định nghĩa từng row cho ListView chỉ là TextView mà thôi). Và chúng ta không hiểu được cách mà Adapter sẽ lấy dữ liệu và gắn vào từng row như thế nào. Ở trong bài viết này tôi nói rõ cách mà Adapter làm việc như thế nào và cách Custom ListView với những row phức tạp.

Video Demo ListView sử dụng trong bài viết này

Trước tiên tôi tạo một project có tên là ListViewAnvanced.

File activity_main.xml được định nghĩa như sau:

Tạo file row_song.xml trong thư mục layout và design để hiển thị thông tin của một bài hát như hình dưới đây:

listview-advanced-0

Nội dung của file row_song.xml

Nếu các bạn chưa hiểu phần thiết kế bằng xml ở trên có thể xem lại bài viết Layout trong Android.

Class Song đại diện cho 1 bài hát gồm các thông tin:

  • mCode: Mã số bài hát
  • mTitle: Tên bài hát
  • mLyric: Lyric của bài hát.
  • mAstist: Tên ca sĩ

Class Song.java

Tiếp tục là phần quan trọng nhất là viết custom Adapter.

File MainActivity.java

Chạy thử ứng dụng chúng ta sẽ thấy kết quả như sau. Rất đẹp phải không các bạn.

listview-advanced-1

Đến đây các bạn có thể thấy rằng việc Custom ListView chỉ là việc các bạn tạo một Adapter mới và  row mới và xử lý trong phương thức getView của Adapter. Còn các thao thác khác đều giống như ListView cơ bản đã đề cập ở bài viết trước.

Chắc hẳn, các bạn thắc mắc phương thức getView có chức năng gì và các đối số của nó có ý nghĩa gì. Thì tôi cũng nói với các bạn rằng:

+ Phương thức getView  dùng để tạo và gắn data vào cho view trước khi add và ListView.

+ Khi bạn mở ListView lên thì getView gọi đúng n lần với n là số View hiển thị trên màn hình, và n này cũng chính là số child của ListView. Các bạn đừng nghĩa rằng ListView có 100 item thì số child của nó cũng chính là 100. Mà số child của nó chính là số item visible trên màn hình.

+ Khi bạn scoll ListView thì phương thức getView sẽ được gọi (kể cả việc scroll lên hay scroll xuống).

+ Khi bạn scroll các item bị mất đi sẽ bị remove khỏi ListView và gọi getView để tạo view mới và add vào ListView.

+ Các tham số trong phương thức getView

position: Chính là vị trí của của item trong listview.

convertView: Chính là đối tượng cache view. Đối tượng này rất quan trọng sẽ bàn luận sâu ở ngay phần dưới.

parent: Chính là đối tượng ListView.

Các bạn có thể dùng loge trong phương thức getView để kiểm tra những nhận xét đưa ra ở trên.

Cơ chế tái sử dụng View của ListView (View Recycling)

listview-advanced-2

Khi ArrayAdapter của chúng ta có 1000 item, thì thực sự ArrayAdapter binding lên ListView một số item sao sao lấp đủ ListView. Còn những item khác chưa được binding lên.

Khi chúng ta scroll ListView thì những view mất đi sẽ được cached lại ở đối tượng convertView. Sau đó sẽ remove view đó ra khỏi ListView và gọi getView để add view mới vào ListView.

Cùng nhìn lại phương thức getView của chúng ta:

Thấy rằng khi getView được gọi thì chúng ta luôn luôn tạo view mới từ row_song.xml sau đó tiếp tục findViewById để lấy rác các view khác. Như vậy mất rất nhiều thời gian và chi phí. Giả sử row của các bạn quá phức tạp ví như như row new feeds của Facebook. Thì khi chúng ta scroll sẽ có cảm giác bị giật đơ.

Để khắc phục nhược điểm này chúng ta sử dụng lại view đã cache như sau:

Như vậy chúng ta chỉ tạo View cho những item đầu tiên đề fill đủ ListView. Khi scroll chúng ta View sẽ được cache lại và chúng ta sử dụng đối tượng này để set data chứ không cần tạo inflate để tạo view mới từ row_song.xml.

Nhưng có một nhược điểm là cúng ta phải sử dụng findViewById lặp lại trong getView. Để khắc phục nhược điểm này chúng ta sử dụng một pattern gọi là ViewHolder

Sử dụng ViewHolder

Chúng ta sửa lại class SongAdapter như dưới dây:

Source code sử dụng trong bài viết: ListViewAdvanced

Kết luận

Qua bài viết này tôi hy vọng rằng các bạn có thể thiết kệ được bất cứ ListView nào và xử lý trong phương thức getView để ListView đạt được performance cao nhất. Bài viết tiếp theo về ListView tôi sẽ giới thiệu một số tính năng của ListView và thao tác với thuần thục với Adapter. Nếu có bất cứ thắc mắc nào có thể để lại bình luận ở dưới bài viết hoặc có thể liên hệ qua fanpage Eitguide để được giải đáp.

11 thoughts on “ListView trong Android (Phần 2)”

  1. Rất hay và dễ hiểu. Mong bạn làm nhiều bài hướng dẫn như thế này. Cám ơn.
    Sao bạn ko cho comment bằng facebook nhỉ

    1. LayoutFlater hiểu đơn giản thì nó parse code từ xml qua Java đó bạn. Còn phương thức getView khó hiểu tại vì nó là cơ chế cached View của ListView, và bạn cần phải hiểu được cơ chế này.

  2. Anh ơi cho em hỏi, khi mà mình scroll listview thì những cái item bị scroll có được dồn vào convertView hay không, hay là convertView chỉ chứa được 1 View thôi ạ

    1. Và cho em hỏi thêm, nếu mà ConrvertView nó có thể lưu được nhiều View thì cơ chế làm việc của nó như là Stack ạ. Nếu như mình cuộn lên thì ListView lại lấy item từ top của ConvertView để điền đầy vào ak

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.