Android ListView aktualisiert eine einzelne Zeile

Nachdem ich die Daten für eine einzelne Zeile einer ListView , möchte ich diese einzelne Zeile aktualisieren.

Derzeit verwende ich notifyDataSetChanged(); aber das lässt die View sehr langsam reagieren. Gibt es andere Lösungen?

Eine Möglichkeit besteht darin, den ListView direkt zu manipulieren. Überprüfen Sie zuerst, ob der Index der aktualisierten Zeile zwischen getFirstVisiblePosition() und getLastVisiblePosition() liegt. Diese beiden geben Ihnen die erste und letzte Position im Adapter, die auf dem Bildschirm sichtbar sind. Dann können Sie die Zeile View mit getChildAt(int index) und ändern.

Wie Romain Guy vor einiger Zeit während der Google I / O-Sitzung erklärt hat , ist der effizienteste Weg, nur eine Ansicht in einer Listenansicht zu aktualisieren, etwa Folgendes (diese aktualisiert die gesamten Ansichtsdaten):

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

Angenommen, target ist ein Element des Adapters.

Dieser Code ruft die ListView , durchsucht dann die aktuell angezeigten Ansichten, vergleicht das ListView mit den einzelnen angezeigten Ansichtselementen. Wenn Ihr Ziel unter diesen Elementen ist, getView Sie die umschließende Ansicht ab und führen den Adapter getView für diese Ansicht aus Anzeige.

Als eine Nebenbemerkung funktioniert notifyDataSetChanged nicht wie einige Leute erwarten und wird die Ansicht nicht wie getView aktualisieren, notifyDataSetChanged wird die gesamte Liste neu aufbauen und am Ende ruft getview für jedes angezeigte Element auf und getview wirken sich auch auf ein Bündel aus.

Eine letzte Sache, man kann auch zusätzliche performance bekommen, wenn er nur ein Kind einer getView muss und nicht die ganze Zeile wie getView . In diesem Fall kann der folgende Code list.getAdapter().getView(i, view, list); ersetzen list.getAdapter().getView(i, view, list); (Beispiel um einen TextView Text zu ändern):

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

Im Code vertrauen wir.

Diese einfachere Methode funktioniert gut für mich, und Sie müssen nur den Positionsindex kennen, um die Ansicht zu erhalten:

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

Der folgende Code funktionierte für mich. Beachten Sie beim Aufruf von GetChild (), dass Sie um das erste Element in der Liste versetzt werden müssen, da es relativ dazu ist.

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

Es gibt noch eine viel effizientere Sache, die Sie tun können, wenn es zu Ihrem Anwendungsfall passt.

Wenn Sie den Status ändern und die richtige (durch die Kenntnis der Position) mListView.getAdapter().getView() , wird es am effizientesten von allen.

Ich kann eine wirklich einfache Möglichkeit demonstrieren, indem ich eine anonyme innere class in meiner ListAdapter.getView() class ListAdapter.getView() . In diesem Beispiel habe ich eine TextView mit dem Text “new” und diese Ansicht wird auf GONE gesetzt, wenn auf das Listenelement geklickt wird:

 @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; } 

Das Framework verwendet automatisch die korrekte position und Sie müssen sich sorgen, dass Sie es erneut getView müssen, bevor Sie getView aufrufen.

Nur für den Rekord, hat jemand die “View View” auf die Override-Methode?

  public void onItemClick(AdapterView< ?> parent, View view, int position, long id) { //Update the selected item ((TextView)view.findViewById(R.id.cardText2)).setText("done!"); }