Android ListView刷新单行

时间:2010-01-23 12:10:23

标签: android performance listview

获取ListView的单行数据后,我想更新该行。

目前我正在使用notifyDataSetChanged();,但这会使View反应非常缓慢。还有其他解决方案吗?

7 个答案:

答案 0 :(得分:88)

explained a while back期间,作为Romain Guy Google I/O session,仅在列表视图中更新一个视图的最有效方法如下(此更新整个视图数据):

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");

在我们信任的代码中。

答案 1 :(得分:30)

一种选择是直接操纵ListView。首先检查更新行的索引是否在getFirstVisiblePosition()getLastVisiblePosition()之间,这两个给出了适配器中屏幕上可见的第一个和最后一个位置。然后,您可以使用View获取行getChildAt(int index)并进行更改。

答案 2 :(得分:27)

这个更简单的方法对我来说效果很好,你只需要知道位置索引来获得视图:

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

答案 3 :(得分: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 );
            }
        }
    }
}  

答案 4 :(得分:2)

如果它适合您的用例,那么还有另一种更有效的方法。

如果你正在改变状态并且可以某种方式调用正确的(通过知道位置)mListView.getAdapter().getView()它将是最有效的。

通过在我的ListAdapter.getView()类中创建一个匿名内部类,我可以演示一种非常简单的方法。在这个例子中,我有TextView显示文本&#34; new&#34;单击列表项时该视图设置为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之前再次获取它。

答案 5 :(得分:0)

对我来说,下面这行有效:

Arraylist.set(位置,新ModelClass(值));

Adapter.notifyDataSetChanged();

答案 6 :(得分:-1)

仅仅是为了记录,有没有人考虑覆盖方法的“查看视图”?

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

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

                }