2010-01-23 148 views
72

當我得到一行ListView的數據後,我想更新該單行。Android ListView刷新單行

目前我正在使用notifyDataSetChanged();但這使得View反應非常緩慢。還有其他解決方案嗎?

回答

29

一個選項是直接操作ListView。首先檢查更新行的索引是否在getFirstVisiblePosition()getLastVisiblePosition()之間,這兩個參數給出了適配器中屏幕上可見的第一個和最後一個位置。然後你可以通過getChildAt(int index)得到View並改變它。

+3

謝謝。如果我正在**編輯孩子的當前佈局,這將起作用。但是,如果我想**改變佈局**(通過膨脹一個不同的XML)?如果我在適配器上調用'newView(...)',它會給我一個不同的視圖,但不會放入'listView'中。 – hadi 2013-08-15 20:30:03

+1

@hadi你應該看看這個答案:http://stackoverflow.com/a/11568271/858626 – 2014-09-24 12:56:02

6

以下代碼適用於我。請注意,調用GetChild()時,必須由列表中的第一項進行偏移,因爲它與之相關。

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

由於羅曼蓋伊的Google I/O session,最有效的辦法只能更新列表視圖一個視圖中explained a while back是類似如下(這個更新整個視圖的數據):

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; 
    } 

假設target是適配器的一項。

此代碼檢索ListView,然後瀏覽當前顯示的看法,比較target項目你正在尋找與每個顯示的視圖中的項目,如果你的目標是那些中,得到封閉看法和對執行適配器getView查看刷新顯示。

作爲一個側面說明invalidate不起作用像一些人期望並不會刷新像getView這個視圖,notifyDataSetChanged將重建整個列表,並最終調用getview爲每個顯示的項目和invalidateViews也會影響了一堆。

最後一件事,如果他只需要改變行視圖的子項而不是像getView那樣的整行,就可以獲得額外的性能。在這種情況下,下面的代碼可以取代list.getAdapter().getView(i, view, list);(例如更改TextView文本):

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

在代碼中我們信任。

+15

你應該可能只是鏈接你的其他答案http://stackoverflow.com/a/9987616/1026132而不是複製並粘貼在這裏。這將有助於減少SO中重複內容的數量。 – 2013-06-13 07:59:23

+2

如何實現這與不​​同的視圖類型? – Zyoo 2013-11-22 10:39:45

+1

回答「Google I/O session」的鏈接已經死機。 – Pang 2015-06-07 08:52:27

26

這更簡單的方法很適合我,你只需要知道位置索引得到阿霍德的看法:

// 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

工程就像一個魅力,+1 – Rutger 2013-11-23 11:51:27

+0

如果用戶在該詳細信息頁面上做了更改,請將更新後的值發送到detailview另一個頁面如何更新回到列表 – Harsha 2016-09-09 13:47:34

2

還有另一種更有效的事情可以做,如果它適合你用例就是這樣。

如果你正在改變狀態,並可以以某種方式調用適當的(通過了解位置)mListView.getAdapter().getView()它將是最有效的。

我可以通過在我的ListAdapter.getView()類中創建一個匿名內部類來演示一個非常簡單的方法。在這個例子中,我有一個TextView出「新」一文,並單擊列表項時視圖設置爲GONE

@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; 
} 

框架自動使用正確的position,你也不用擔心取它再次致電getView

-1

只是爲了記錄,有沒有人考慮覆蓋方法的'查看視圖'?

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

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

       } 
+0

問題是如何在任何給定的ListView中刷新單行時刻。 onItemClick僅在用戶單擊某個項目時纔會調用,因此不夠用 – Thys 2016-09-07 11:24:20