2013-07-17 8 views
20

Próbuję zaimplementować niekończący się widok listy przewijania, ale kiedy zadzwonię pod numer notifyDataSetChanged(), cała lista odświeża się, a pozycja przewijania wraca na górę.notifyDataSetChanged() sprawia, że ​​lista odświeża się, a przewijanie przeskakuje z powrotem na górę

Czy to normalne zachowanie? jak mogę po prostu dodać elementy dodane bez odświeżania i zachować pozycję przewijania?

+0

Czy możesz opublikować swój pełny kod? – yfsx

Odpowiedz

51

takie zachowanie nie jest normalne. Nie widząc Twojego kodu, mogę zasugerować:

1) Nie dzwonisz pod numer notifyDataSetChanged() z wątku interfejsu użytkownika. Prawidłowy sposób:

runOnUiThread(new Runnable() { 
    public void run() { 
     adapter.notifyDataSetChanged(); 
    } 
}); 

2) Przypadkowo lub nie wykonanie połączenia do adapter.notifyDataSetInvalidated();

3) karty przesłonić metodę adapter.notifyDataSetChanged(); i dodaje instrukcje, aby przejść do góry

4) Jeśli używasz listy do wypełnienia adaptera - za każdym razem dostarczasz nową listę, więc ustawienia adaptera są odświeżane. Powinieneś zawsze dostarczać tę samą listę. Jednak możesz go zmienić tak, jak chcesz. Jeśli resetowanie użycie listy list.clear zamiast list = new ArrayList();

Oto przykład mojego adaptera:

public class Adapter extends BaseAdapter { 

    private Activity activity; 
    private ArrayList<HashMap<String, String>> data; 
    private static LayoutInflater inflater = null; 
    public ImageLoader imageLoader; 

    public MediaItemAdapter(Activity a, ArrayList<HashMap<String, String>> d) { 
     activity = a; 
     data = d; 
     inflater = (LayoutInflater) activity 
       .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     imageLoader = new ImageLoader(activity.getApplicationContext()); 
    } 

    public int getCount() { 
     return data.size(); 
    } 

    public Object getItem(int position) { 
     return position; 
    } 

    public long getItemId(int position) { 
     return position; 
    } 

    public View getView(int position, View convertView, ViewGroup parent) { 
     View vi = convertView; 
     if (convertView == null) { 
      vi = inflater.inflate(R.layout.item_composer, null); 
     } 
     TextView title = (TextView) vi.findViewById(R.id.item_title); // title 
     TextView price = (TextView) vi.findViewById(R.id.price); 


     return vi; 
    } 


} 

Zaproszenie do adaptera:

List myList = new ArrayList<HashMap<String, String>>(); 
Adapter ma = new Adapter(this, myList); 

myList może być pusta przed inicjalizacji adaptera.

Następnie wykonać pewne działania z mojej liście:

myList.add(someElement); 
ma.notifyDataSetChanged(); 

jeśli trzeba usunąć wszystkie elementy:

myList.clear(); 
ma.notifyDataSetChanged(); 

Taka implementacja jest dość nieograniczone, widziałem więcej niż 15 tysięcy elementów bez żadnych problemów.

+0

Czy możesz spojrzeć na http: // stackoverflow.com/questions/27815882/scroll-position-jumps-to-previous-list-items-while-scrolling-up-in-custom-listvi – kittu88

+0

W moim przypadku był to trzeci problem. Zapełniłem zupełnie nową listę i przypisałem ją do zmiennej pierwotnie używanej z adapterem, ponieważ lista w adapterze nigdy nie została odświeżona. – Nashe

+0

Świetny post! Uratowałem moje zdrowie psychiczne! – siniux

6

Można to zrobić w inny sposób, jak to

int position = scrollView.getSelectedItemPosition(); 
notifyDataSetChanged(); 
scrollView.setSelection(position); 
+2

To nie jest właściwa droga, ale czasami jest bardzo przydatna! – Kasas

2

Jeśli adapter jest podklasy ArrayList, wywołanie adapter.clear() wywoła notifyDataSetChanged() powodując utratę pozycji przewijania. Rozważ najpierw wywołanie setNotifyOnChange(false), aby temu zapobiec.

Więcej informacji tutaj: https://stackoverflow.com/a/14719538/383761

5

W moim przypadku problemem było to, że za każdym razem dzwoni ListView.setAdapter(adapter) nowe dane ustalono które również przywrócić położenie i widok podskoczył do góry.

Usunięcie zbędnych połączeń setAdapter(...) naprawiono dla mnie.