Android ListView刷新单行


77

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

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

Answers:


30

一种选择是ListView直接操纵。首先检查更新的行的索引是否在getFirstVisiblePosition()和之间getLastVisiblePosition(),这两个给您提供了适配器在屏幕上可见的第一个和最后一个位置。然后你就可以得到该行ViewgetChildAt(int index)和改变它。


3
谢谢。如果我正在编辑孩子的当前布局,这将起作用。但是,如果我想完全更改布局(通过填充不同的xml)怎么办?如果我调用newView(...)适配器,它会给我一个不同的视图,但是视图中没有放置listView
哈迪

1
@hadi,您应该看一下以下答案:stackoverflow.com/a/11568271/858626
Jose_GD 2014年

90

正如罗曼·盖伊(Romain Guy)在Google I / O会话中解释的那样,仅更新列表视图中的一个视图的最有效方法是如下所示(此更新整个视图数据):

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

我们相信代码。


17
您可能应该只链接其他答案stackoverflow.com/a/9987616/1026132,而不是在此处复制和粘贴。这将有助于减少SO中重复内容的数量。
Nacho Coloma

2
如何用不同的视图类型实现呢?
Zyoo

1
答案中的“ Google I / O会话”链接已死。

看起来很棒!我今天要试试
Rakesh Patil

也许有时您需要使用“ list.getAdapter()。getView(i-list.getHeaderviewCount,view,list);” 而不是“ list.getAdapter()。getView(i,view,list);”
QuinnChen

28

这个简单的方法对我来说效果很好,您只需要知道位置索引即可掌握视图:

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

如果用户在该详细信息页面上进行了更改,我将把更新后的值发送到detailview另一个页面,如何更新回列表
Harsha

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

在此示例中sysvar_index表示您要更新的行的位置
某处某人

2

如果适合您的用例,则可以执行另一项更有效的操作。

如果您要更改状态,并且可以通过某种方式调用适当的状态(通过知道位置)mListView.getAdapter().getView(),则将是最有效的。

通过在类中创建一个匿名内部类,我可以演示一种非常简单的方法ListAdapter.getView()。在此示例中,我TextView显示了一个文本“ new”,并且该视图设置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


0

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

Arraylist.set(position,new ModelClass(value));

Adapter.notifyDataSetChanged();


-2

仅作记录,是否有人考虑过重写方法的“视图”?

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

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

                }

问题是如何在任何给定时刻刷新ListView中的一行。仅当用户单击某个项目时onItemClick才被调用,因此不够用
Thizzer
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.