Redraw a single row in a listview

android, android-arrayadapter, listview, redraw, view

Solution

As Romain Guy explained a while back during 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):

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 `target` is one item of the adapter.

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

As a side note `invalidate()` doesn't work like some people expect and will not refresh the view like `getView()` does, `notifyDataSetChanged()` will rebuild the whole list and end up calling `getview()` for every displayed items and `invalidateViews()` will also affect a bunch.

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 `getView` does. In that case, the following code can replace `list.getAdapter().getView(i, view, list);` (example to change a `TextView` text):

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

In code we trust.

Problem

Is it possible to redraw a single row in a `ListView`? I have a `ListView` with rows that are `LinearLayout`s. I listen to a preference change and sometimes I need to change just one `View` inside the `LinearLayout` of a single row. Is there a way to make it redraw that row without calling `listview.notifyDatasetChanged()`? I've tried calling view.invalidate() on the view (inside the `LinearLayout`) but it doesn't redraw the row.

Original source

Related problems