Android ListView 刷新单行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2123083/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 04:38:03  来源:igfitidea点击:

Android ListView Refresh Single Row

androidperformancelistview

提问by Thizzer

After I have gotten the data for a single row of a ListView, I want to update that single row.

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

Currently I am using notifyDataSetChanged();but that makes the Viewreact very slowly. Are there any other solutions?

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

采纳答案by Daniel Velkov

One option is to manipulate the ListViewdirectly. First check if the index of the updated row is between getFirstVisiblePosition()and getLastVisiblePosition(), these two give you the first and last positions in the adapter that are visible on the screen. Then you can get the row Viewwith getChildAt(int index)and change it.

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

回答by GriffonRL

As Romain Guy explained a while backduring the Google I/O session, the most efficient way to only update one view in a list view is something like the following (this one update the whole view data):

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

Assuming targetis one item of the adapter.

假设target是适配器的一项。

This code retrieve the ListView, then browse the currently shown views, compare the targetitem you are looking for with each displayed view items, and if your target is among those, get the enclosing view and execute the adapter getViewon that view to refresh the display.

此代码检索ListView,然后浏览当前显示的视图,将target您要查找的项目与每个显示的视图项目进行比较,如果您的目标在其中,则获取封闭视图并getView在该视图上执行适配器以刷新显示。

As a side note invalidatedoesn't work like some people expect and will not refresh the view like getView does, notifyDataSetChangedwill rebuild the whole list and end up calling getviewfor every displayed items and invalidateViewswill also affect a bunch.

由于旁注invalidate不像某些人期望的那样工作,并且不会像 getView 那样刷新视图,notifyDataSetChanged将重建整个列表并最终调用getview每个显示的项目,并且invalidateViews还会影响一堆。

One last thing, one can also get extra performance if he only needs to change a child of a row view and not the whole row like getViewdoes. In that case, the following code can replace list.getAdapter().getView(i, view, list);(example to change a TextViewtext):

最后一件事,如果他只需要更改行视图的子项而不是整行,也可以获得额外的性能getView。在这种情况下,以下代码可以替换list.getAdapter().getView(i, view, list);(更改TextView文本的示例):

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

In code we trust.

在我们信任的代码中。

回答by John Starr Dewar

This simpler method works well for me, and you only need to know the position index to get ahold of the view:

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

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

回答by SkolVikingsGuy

The following code worked for me. Note when calling GetChild() you have to offset by the first item in the list since its relative to that.

以下代码对我有用。请注意,在调用 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 );
            }
        }
    }
}  

回答by vedant

There is another much more efficient thing you can do, if it fits your use-case that is.

如果它适合您的用例,您还可以做另一件更有效的事情。

If you are changing the state and can somehow call the proper (by knowing the position) mListView.getAdapter().getView()it will the most efficient of all.

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

I can demonstrate a really easy way to do it, by creating an anonymous inner class in my ListAdapter.getView()class. In this example I have a TextViewshowing a text "new" and that view is set to GONEwhen the list item is clicked:

我可以通过在我的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;
}

The framework automatically uses the correct positionand you do have to worry about fetching it again before calling getView.

框架会自动使用正确的position,您不必担心在调用getView.

回答by AnoNym

Just for the record, did anyone consider the 'View view' on the override method ?

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

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

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

                }