获取ListView
的单行数据后,我想更新该行。
目前我正在使用notifyDataSetChanged();
,但这会使View
反应非常缓慢。还有其他解决方案吗?
答案 0 :(得分:88)
在explained a while back期间,作为Romain Guy Google I/O session,仅在列表视图中更新一个视图的最有效方法如下(此更新整个视图数据):
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");
在我们信任的代码中。
答案 1 :(得分:30)
一种选择是直接操纵ListView
。首先检查更新行的索引是否在getFirstVisiblePosition()
和getLastVisiblePosition()
之间,这两个给出了适配器中屏幕上可见的第一个和最后一个位置。然后,您可以使用View
获取行getChildAt(int index)
并进行更改。
答案 2 :(得分:27)
这个更简单的方法对我来说效果很好,你只需要知道位置索引来获得视图:
// 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);
}
答案 3 :(得分: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 );
}
}
}
}
答案 4 :(得分:2)
如果它适合您的用例,那么还有另一种更有效的方法。
如果你正在改变状态并且可以某种方式调用正确的(通过知道位置)mListView.getAdapter().getView()
它将是最有效的。
通过在我的ListAdapter.getView()
类中创建一个匿名内部类,我可以演示一种非常简单的方法。在这个例子中,我有TextView
显示文本&#34; new&#34;单击列表项时该视图设置为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
之前再次获取它。
答案 5 :(得分:0)
对我来说,下面这行有效:
Arraylist.set(位置,新ModelClass(值));
Adapter.notifyDataSetChanged();
答案 6 :(得分:-1)
仅仅是为了记录,有没有人考虑覆盖方法的“查看视图”?
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//Update the selected item
((TextView)view.findViewById(R.id.cardText2)).setText("done!");
}