Android ListView刷新单行
在获取ListView
的单行数据后,我想更新该单行。
目前我正在使用notifyDataSetChanged();
但是这使得View
反应非常缓慢。 还有其他解决scheme吗?
一个select是直接操作ListView
。 首先检查更新行的索引是否在getFirstVisiblePosition()
和getLastVisiblePosition()
,这两个参数给出了适配器中第一个和最后一个在屏幕上可见的位置。 然后你可以用getChildAt(int index)
得到行View
并改变它。
正如罗曼·盖伊(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; }
假设target
是适配器的一个项目。
这段代码检索ListView
,然后浏览当前显示的视图,将你正在寻找的target
项目与每个显示的视图项目进行比较,如果你的目标是在这些视图项目之间,则获取包含视图并在该视图上执行适配器getView
以刷新显示。
作为一个附注invalidate
不工作像一些人所期望的,并不会像getView那样刷新视图, notifyDataSetChanged
将重build整个列表并最终为每个显示的项目调用getview
, invalidateViews
也会影响一堆。
最后一件事情是,如果他只需要改变一个行视图的子项而不是像getView
那样的整行,也可以获得额外的性能。 在这种情况下,下面的代码可以替代list.getAdapter().getView(i, view, list);
(例如更改TextView
文本):
((TextView)view.findViewById(R.id.myid)).setText("some new text");
在我们信任的代码中。
这个更简单的方法适用于我,您只需要知道位置索引就可以了解视图:
// 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); }
下面的代码为我工作。 注意调用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 ); } } } }
如果它符合你的用例,那么你可以做另一个更有效率的事情。
如果你正在改变状态,并可以以某种方式调用适当的(通过了解位置) mListView.getAdapter().getView()
它将是最有效的。
我可以通过在ListAdapter.getView()
类中创build一个匿名内部类来演示一个非常简单的方法。 在这个例子中,我有一个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
之前,您不必担心再次获取它。
只是为了logging,有没有人考虑覆盖方法的“查看视图”?
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //Update the selected item ((TextView)view.findViewById(R.id.cardText2)).setText("done!"); }