【问题标题】:Android ListView Refresh Single RowAndroid ListView 刷新单行
【发布时间】:2011-01-08 13:08:51
【问题描述】:

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

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

【问题讨论】:

    标签: android performance listview


    【解决方案1】:

    作为 Google I/O session 期间的 Romain Guy 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 和 @987654332 @ 也会影响一堆。

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

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

    在我们信任的代码中。

    【讨论】:

    • 您可能应该只链接您的其他答案stackoverflow.com/a/9987616/1026132,而不是在此处复制和粘贴。这将有助于减少 SO 中重复内容的数量。
    • 如何用不同的视图类型实现这个?
    • 答案中指向“Google I/O 会话”的链接已失效。
    • 看起来棒极了!我今天要试试这个
    • 也许有时你需要使用“list.getAdapter().getView(i - list.getHeaderviewCount, view, list);”而不是“list.getAdapter().getView(i, view, list);”
    【解决方案2】:

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

    【讨论】:

    • 谢谢。如果我正在编辑孩子的当前布局,这将起作用。但是,如果我想完全更改布局(通过膨胀不同的 xml)怎么办?如果我在适配器上调用newView(...),它会给我一个不同的视图,但是不会放在listView 中。
    • @hadi 你应该看看这个答案:stackoverflow.com/a/11568271/858626
    【解决方案3】:

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

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

    【讨论】:

    • 像魅力一样工作,+1
    • 如果用户在该详细信息页面上更改如何更新回列表,我会将更新后的值发送到 detailview 另一个页面
    【解决方案4】:

    以下代码对我有用。请注意,在调用 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 表示您要更新的行的位置
    【解决方案5】:

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

    如果您正在更改状态并且可以以某种方式调用正确的(通过知道位置)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 之前再次获取它。

    【讨论】:

      【解决方案6】:

      对我来说,下面的线路工作:

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

      Adapter.notifyDataSetChanged();

      【讨论】:

        【解决方案7】:

        仅作记录,是否有人考虑过覆盖方法上的“查看视图”?

           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 仅在用户单击项目时调用,因此不够
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-18
        • 2016-01-17
        相关资源
        最近更新 更多