Android ListView Refresh Single Row
Solution 1
One option is to manipulate the ListView
directly. 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 View
with getChildAt(int index)
and change it.
Solution 2
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.
Solution 3
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);
}
Solution 4
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.
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 );
}
}
}
}
Solution 5
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.
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 TextView
showing a text "new" and that view is set to GONE
when the list item is clicked:
@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 position
and you do have to worry about fetching it again before calling getView
.
Related videos on Youtube
Thizzer
Software developer at heart. Interested in all things Tech.
Updated on July 05, 2022Comments
-
Thizzer almost 2 years
After I have gotten the data for a single row of a
ListView
, I want to update that single row.Currently I am using
notifyDataSetChanged();
but that makes theView
react very slowly. Are there any other solutions? -
Nacho Coloma almost 11 yearsYou should probably just link your other answer stackoverflow.com/a/9987616/1026132 instead of copying and pasting here. This would help to reduce the amount of duplicate content in SO.
-
hadi over 10 yearsThanks. This would work if I am editing the current layout of the child. But what if I want to change the layout altogether (by inflating a different xml)? If I call
newView(...)
on the adapter, it gives me a different view which however is not put in thelistView
. -
Zyoo over 10 yearshow to implement this with different view type?
-
Rutger over 10 yearsWorks like a charm, +1
-
Jose_GD over 9 years@hadi you should take a look at this answer: stackoverflow.com/a/11568271/858626
-
Pang almost 9 yearsLink to "Google I/O session" in answer is dead.
-
Rakesh Patil about 8 yearsseems awesome! I'm gonna try this today
-
QuinnChen almost 8 yearsmaybe sometimes you need to use "list.getAdapter().getView(i - list.getHeaderviewCount, view, list);" instead of "list.getAdapter().getView(i, view, list);"
-
Thizzer over 7 yearsThe question was how to refresh a single row in the ListView at any given moment. onItemClick is only called when the users click an item and so does not suffice
-
Harsha over 7 yearsi will send that updated values to detailview another page if user do changes on that details page how to update back to list please
-
Someone Somewhere almost 6 yearsin this example
sysvar_index
means the position of the row you want to update