2010-06-25 34 views
9

Tôi đang gặp sự cố với một số mã BaseAdapter mà tôi đã thích nghi từ một cuốn sách. Tôi đã sử dụng các biến thể của mã này trên khắp nơi trong ứng dụng của tôi, nhưng chỉ mới nhận ra khi cuộn một danh sách dài các mục trong ListView trở nên lộn xộn và không phải tất cả các phần tử được hiển thị.BaseAdapter khiến ListView bị lỗi khi cuộn

Rất khó để mô tả hành vi chính xác, nhưng thật dễ dàng để xem bạn có sắp xếp danh sách 50 mục và bắt đầu cuộn lên và xuống.

class ContactAdapter extends BaseAdapter { 

    ArrayList<Contact> mContacts; 

    public ContactAdapter(ArrayList<Contact> contacts) { 
     mContacts = contacts; 
    } 

    @Override 
    public int getCount() { 
     return mContacts.size(); 
    } 

    @Override 
    public Object getItem(int position) { 
     return mContacts.get(position); 
    } 

    @Override 
    public long getItemId(int position) { 
     return position; 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     View view; 
     if(convertView == null){ 
      LayoutInflater li = getLayoutInflater(); 
      view = li.inflate(R.layout.groups_item, null); 
      TextView label = (TextView)view.findViewById(R.id.groups_item_title); 
      label.setText(mContacts.get(position).getName()); 
      label = (TextView)view.findViewById(R.id.groups_item_subtitle); 
      label.setText(mContacts.get(position).getNumber()); 
     } 
     else 
     { 
      view = convertView; 
     } 
     return view; 
    } 

} 

Trả lời

12

Bạn chỉ đang đặt dữ liệu trong các tiện ích TextView khi chúng được tạo lần đầu tiên. Bạn cần phải di chuyển bốn dòng:

 TextView label = (TextView)view.findViewById(R.id.groups_item_title); 
     label.setText(mContacts.get(position).getName()); 
     label = (TextView)view.findViewById(R.id.groups_item_subtitle); 
     label.setText(mContacts.get(position).getNumber()); 

là sau khi khối if/else và trước sự trở lại phương pháp, vì vậy bạn cập nhật các TextView widget cho dù bạn đang tái chế hàng hoặc tạo một hình mới.

+0

Ồ, tôi hiểu. Vì vậy, ListView chỉ chứa tối đa số lần xem cần thiết để lấp đầy màn hình? –

+0

@Mr. Không rõ ràng: Nhiều hay ít. Nó có thể bộ nhớ cache một cặp vợ chồng để có thể phản ứng nhanh chóng để di chuyển yêu cầu. Tuy nhiên, trong một 'ListView' với không gian giao diện người dùng cho 10 hàng và một' Bộ điều hợp' của 1.000 hàng, số lượng 'Số lần xem' sẽ đến gần hơn 10 so với 1.000. Có lẽ như 12 hoặc 14. Đó là điểm của hàng tái chế với 'convertView', do đó, Android không phải tạo (và sau này GC) một mớ hỗn độn toàn bộ các tiện ích hàng. – CommonsWare

5

Để làm rõ thêm câu trả lời của CommonsWare, đây là một số thông tin thêm:

Các li.inflate hoạt động (cần thiết vào đây để phân tích cú pháp của cách bố trí của một hàng từ XML và tạo View đối tượng thích hợp) là được bao bọc bởi nếu câu lệnh (convertView == null) cho hiệu quả, do đó, lạm phát của cùng một đối tượng sẽ không xảy ra lặp đi lặp lại mỗi khi nó xuất hiện.

BAO GIỜ, các phần khác của phương thức getView được sử dụng để đặt các tham số khác và do đó KHÔNG được bao gồm trong câu lệnh nếu (convertView == null) {} ... else {}.

Trong nhiều thi chung của phương pháp này, một số nhãn TextView, ImageView hoặc ImageButton yếu tố cần phải được dân cư bởi các giá trị trong danh sách [vị trí], sử dụng findViewById và sau đó .setText hoặc .setImageBitmap hoạt động . Các hoạt động này phải sau cả hai tạo chế độ xem từ đầu bằng cách lạm phát nhận chế độ xem hiện tại nếu không trống (ví dụ: khi làm mới).

Một ví dụ khác mà giải pháp này được áp dụng cho một ListView ArrayAdapter xuất hiện trong https://stackoverflow.com/a/3874639/978329

Các vấn đề liên quan