2010-01-23 33 views
72

Sau khi tôi đã nhận dữ liệu cho một hàng duy nhất của ListView, tôi muốn cập nhật hàng đơn đó.Android ListView Làm mới hàng đơn

Hiện tại tôi đang sử dụng notifyDataSetChanged(); nhưng điều đó khiến cho View phản ứng rất chậm. Có bất kỳ giải pháp khác?

Trả lời

29

Một tùy chọn là thao tác trực tiếp ListView. Trước tiên hãy kiểm tra xem chỉ mục của hàng được cập nhật có nằm giữa getFirstVisiblePosition()getLastVisiblePosition(), hai chỉ số này cung cấp cho bạn vị trí đầu tiên và cuối cùng trong bộ điều hợp hiển thị trên màn hình. Sau đó, bạn có thể nhận hàng View với getChildAt(int index) và thay đổi nó.

+3

Cảm ơn. Điều này sẽ làm việc nếu tôi ** chỉnh sửa ** bố trí hiện tại của đứa trẻ. Nhưng nếu tôi muốn ** thay đổi bố cục hoàn toàn ** (bằng cách tăng một xml khác)? Nếu tôi gọi 'newView (...)' trên bộ điều hợp, nó mang lại cho tôi một cái nhìn khác mà tuy nhiên không được đặt trong 'listView'. – hadi

+1

@hadi bạn nên xem câu trả lời này: http://stackoverflow.com/a/11568271/858626 –

6

Mã sau đây đã hoạt động đối với tôi. Lưu ý khi gọi GetChild() bạn phải bù đắp bằng mục đầu tiên trong danh sách kể từ khi nó liên quan đến nó.

int iFirst = getFirstVisiblePosition(); 
int iLast = getLastVisiblePosition(); 

if (indexToChange >= numberOfRowsInSection()) { 
    Log.i("MyApp", "Invalid index. Row Count = " + numberOfRowsInSection()); 
} 
else {  
    if ((index >= iFirst) && (index <= iLast)) { 
     // get the view at the position being updated - need to adjust index based on first in the list 
     View vw = getChildAt(sysvar_index - iFirst); 
     if (null != vw) { 
      // get the text view for the view 
      TextView tv = (TextView) vw.findViewById(com.android.myapp.R.id.scrollingListRowTextView); 
      if (tv != null) { 
       // update the text, invalidation seems to be automatic 
       tv.setText("Item = " + myAppGetItem(index) + ". Index = " + index + ". First = " + iFirst + ". Last = " + iLast); 
      } 
     } 
    } 
} 
87

Như Romain Guy explained a while back trong Google I/O session, cách hiệu quả nhất để chỉ cập nhật một cái nhìn trong một danh sách xem là một cái gì đó như sau (cái này cập nhật xem dữ liệu toàn bộ):

ListView list = getListView(); 
int start = list.getFirstVisiblePosition(); 
for(int i=start, j=list.getLastVisiblePosition();i<=j;i++) 
    if(target==list.getItemAtPosition(i)){ 
     View view = list.getChildAt(i-start); 
     list.getAdapter().getView(i, view, list); 
     break; 
    } 

Giả sử target là một mục của bộ điều hợp.

Mã này lấy ListView, sau đó duyệt các quan điểm hiện nay cho thấy, so sánh target mục mà bạn đang tìm kiếm với mỗi hiển thị xem mặt hàng, và nếu mục tiêu của bạn là một trong số đó, có được cái nhìn kèm theo và thực hiện adapter getView vào đó xem để làm mới màn hình.

Như một mặt lưu ý invalidate không hoạt động giống như một số người mong đợi và sẽ không làm mới xem như getView không, notifyDataSetChanged sẽ xây dựng lại toàn bộ danh sách và kết thúc gọi getview cho mỗi mặt hàng trưng bày và invalidateViews cũng sẽ ảnh hưởng đến một bó.

Một điều cuối cùng, bạn cũng có thể nhận được hiệu suất bổ sung nếu chỉ cần thay đổi con của chế độ xem hàng và không phải toàn bộ hàng như getView. Trong trường hợp đó, các mã sau đây có thể thay thế list.getAdapter().getView(i, view, list); (ví dụ để thay đổi một văn bản TextView):

((TextView)view.findViewById(R.id.myid)).setText("some new text"); 

trong mã chúng tôi tin tưởng.

+15

Có lẽ bạn chỉ cần liên kết câu trả lời khác của mình http://stackoverflow.com/a/9987616/1026132 thay vì sao chép và dán ở đây. Điều này sẽ giúp giảm lượng nội dung trùng lặp trong SO. –

+2

cách triển khai tính năng này với các loại chế độ xem khác nhau? – Zyoo

+1

Liên kết tới "phiên Google I/O" trong câu trả lời đã chết. – Pang

26

phương pháp đơn giản này hoạt động tốt đối với tôi, và bạn chỉ cần phải biết chỉ số vị trí để có được Ahold của quan điểm:

// mListView is an instance variable 

private void updateItemAtPosition(int position) { 
    int visiblePosition = mListView.getFirstVisiblePosition(); 
    View view = mListView.getChildAt(position - visiblePosition); 
    mListView.getAdapter().getView(position, view, mListView); 
} 
+2

Làm việc như một nét duyên dáng, +1 – Rutger

+0

tôi sẽ gửi các giá trị cập nhật đó để xem chi tiết một trang khác nếu người dùng thực hiện thay đổi trên trang chi tiết đó cách cập nhật lại danh sách, vui lòng – Harsha

2

Có một điều nhiều hiệu quả hơn bạn có thể làm, nếu nó phù hợp với bạn trường hợp sử dụng.

Nếu bạn đang thay đổi trạng thái và bằng cách nào đó có thể gọi đúng (bằng cách biết vị trí) mListView.getAdapter().getView(), nó sẽ hiệu quả nhất trong tất cả.

Tôi có thể chứng minh một cách thực sự dễ dàng để thực hiện điều đó, bằng cách tạo một lớp bên trong vô danh trong lớp học ListAdapter.getView() của tôi.Trong ví dụ này tôi có một TextView thấy một văn bản "mới" và xem đó là thiết lập để GONE khi mục danh sách được nhấp:

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    // assign the view we are converting to a local variable 
    View view = convertView; 

    Object quotation = getItem(position); 
    // first check to see if the view is null. if so, we have to inflate it. 
    if (view == null) 
     view = mInflater.inflate(R.layout.list_item_quotation, parent, false); 

    final TextView newTextView = (TextView) view.findViewById(R.id.newTextView); 

    view.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      if (mCallbacks != null) 
       mCallbacks.onItemSelected(quotation.id); 
      if (!quotation.isRead()) { 
       servicesSingleton.setQuotationStatusReadRequest(quotation.id); 
       quotation.setStatusRead(); 
       newTextView.setVisibility(View.GONE); 
      } 
     } 
    }); 

    if(quotation.isRead()) 
     newTextView.setVisibility(View.GONE); 
    else 
     newTextView.setVisibility(View.VISIBLE); 

    return view; 
} 

Khung tự động sử dụng đúng position và bạn không phải lo lắng về lấy nó một lần nữa trước khi gọi getView.

-1

Chỉ để lưu nội dung, có ai xem 'Chế độ xem' trên phương pháp ghi đè không?

public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 

        //Update the selected item 
        ((TextView)view.findViewById(R.id.cardText2)).setText("done!"); 

       } 
+0

Câu hỏi là cách làm mới một hàng trong ListView tại bất kỳ chốc lát. onItemClick chỉ được gọi khi người dùng nhấp vào một mục và do đó không đủ – Thys

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