Jak odświeżyć widok listy Androida?

Odpowiedzi:

530

Zadzwoń notifyDataSetChanged()na Adapterobiekcie Po zmodyfikowaniu danych w tym adapterem.

Niektóre dodatkowe informacje na temat tego, jak / kiedy zadzwonić, notifyDataSetChanged()można obejrzeć w tym filmie We / Wy Google .

Christopher Orr
źródło
24
Powinieneś uruchomić go w wątku interfejsu użytkownika. Utwórz moduł obsługi w wątku interfejsu użytkownika, a następnie opublikuj w nim Runable
Kirill Kulakov
11
Jeszcze raz: powiadomienieDataSetChanged () nie działa, przynajmniej nie w przypadku praktyk użytkowania, które są zalecane (czytaj nieaktualne). Jeśli korzystasz z widoku listy, adaptera kursora i dostawcy treści, możesz spróbować czegoś podobnego: gettLoaderManager (). RestartLoader (). Zobacz: stackoverflow.com/a/19657500/1087411 Chciałbym zobaczyć co najmniej trochę dokumentacji dotyczącej notyfikacjiDataSetChanged (). Zbyt wiele w Androidzie pozostało do testowania czarnej skrzynki.
Anderson
Jeśli powiadomienieDataSetChanged nie działa, to ty robisz to źle
zdarsky.peter
4
replaceDataSetChanged nie zawsze działa. Nie jestem pewien, dlaczego tak jest. Czasami musisz wywołać listView.setAdapter (adapter), aby wyczyścić stare widoki. Zobacz także: stackoverflow.com/a/16261588/153275
1
Nigdy nie byłem w stanie uzyskać powiadomieniaDataSetChanged. Widziałem wyraźnie, że kolekcja, którą przekazuję do adaptera, uległa zmianie (elementy zostały usunięte), ale powiadomienieDataSetChanged nigdy nic nie zrobiło. Nie jesteś pewien, czy ta metoda jest po prostu zepsuta?
byemute,
204

Możesz także użyć tego:

myListView.invalidateViews();
Boby
źródło
22
To jest prawidłowa odpowiedź, jeśli wystarczy WYRÓŻNIĆ widok. Na przykład po zalogowaniu użytkownika, który musi ujawnić więcej informacji lub opcji w każdym widoku widoku listy. Właśnie to musiałem zrobić, więc oddałem głos. Jeśli podstawowe dane ulegną zmianie, prawdopodobnie lepszym pomysłem jest skorzystanie z replaceDataSetChanged ().
SBerg413,
Właściwie invalidateViews()w zestawach kodów źródłowych, mDataChanged = true;więc nie jestem pewien, czy to spowoduje lepszą wydajność w porównaniu donotifyDataSetChanged()
vovahost
Uratowałeś mi dzień, stary!
oskarko
możesz wybrać rodzaj listy, która jest „listą obserwowalną”, nie trzeba zmieniać powiadomień
Priya
153

Proszę ignorować wszystkich invalidate(), invalidateViews(), requestLayout()... odpowiedź na to pytanie.

Właściwą czynnością (i na szczęście oznaczoną również jako prawidłową odpowiedź) jest zadzwonienie do notifyDataSetChanged()adaptera .

Rozwiązywanie problemów

Jeśli wywołanie notifyDataSetChanged()nie działa, wszystkie metody układu również nie pomogą. Uwierz mi, że ListViewzostał odpowiednio zaktualizowany. Jeśli nie znajdziesz różnicy, musisz sprawdzić, skąd pochodzą dane w karcie.

Jeśli jest to tylko kolekcja, którą przechowujesz w pamięci, sprawdź, czy faktycznie ją usunąłeś lub dodałeś do kolekcji przed wywołaniem notifyDataSetChanged().

Jeśli pracujesz z bazą danych lub zapleczem usługi, musisz wywołać metodę, aby ponownie pobrać informacje (lub manipulować danymi w pamięci) przed wywołaniem notifyDataSetChanged().

Chodzi o to, że notifyDataSetChangeddziała to tylko wtedy, gdy zestaw danych się zmienił. To jest miejsce, w którym należy sprawdzić, czy nie zauważysz zmian. W razie potrzeby debuguj.

ArrayAdapter vs BaseAdapter

Odkryłem, że praca z adapterem, który pozwala zarządzać kolekcją, tak jak BaseAdapter działa lepiej. Niektóre adaptery, takie jak ArrayAdapter, już zarządzają własną kolekcją, co utrudnia dostęp do odpowiedniej kolekcji w celu aktualizacji. W większości przypadków jest to po prostu niepotrzebna dodatkowa warstwa trudności.

Wątek interfejsu użytkownika

Prawdą jest, że należy to wywołać z wątku interfejsu użytkownika. Inne odpowiedzi zawierają przykłady, jak to osiągnąć. Jest to jednak wymagane tylko w przypadku pracy z tymi informacjami spoza wątku interfejsu użytkownika. To jest z usługi lub wątku innego niż interfejs użytkownika. W prostych przypadkach będziesz aktualizować swoje dane za pomocą kliknięcia przycisku lub innej aktywności / fragmentu. Więc nadal w wątku interfejsu użytkownika. Nie trzeba zawsze otwierać tego runOnUiTrhead.

Szybki przykładowy projekt

Można znaleźć na https://github.com/hanscappelle/so-2250770.git . Wystarczy sklonować i otworzyć projekt w Android Studio (stopień). Ten projekt ma MainAciency budujący ListViewwszystkie losowe dane. Tę listę można odświeżyć za pomocą menu akcji.

Implementacja adaptera utworzona dla tego przykładu ModelObject udostępnia kolekcję danych

public class MyListAdapter extends BaseAdapter {

    /**
     * this is our own collection of data, can be anything we 
     * want it to be as long as we get the abstract methods 
     * implemented using this data and work on this data 
     * (see getter) you should be fine
     */
    private List<ModelObject> mData;

    /**
     * our ctor for this adapter, we'll accept all the things 
     * we need here
     *
     * @param mData
     */
    public MyListAdapter(final Context context, final List<ModelObject> mData) {
        this.mData = mData;
        this.mContext = context;
    }

    public List<ModelObject> getData() {
        return mData;
    }

    // implement all abstract methods here
}

Kod z MainActivity

public class MainActivity extends Activity {

    private MyListAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ListView list = (ListView) findViewById(R.id.list);

        // create some dummy data here
        List<ModelObject> objects = getRandomData();
        // and put it into an adapter for the list
        mAdapter = new MyListAdapter(this, objects);
        list.setAdapter(mAdapter);

        // mAdapter is available in the helper methods below and the 
        // data will be updated based on action menu interactions

        // you could also keep the reference to the android ListView 
        // object instead and use the {@link ListView#getAdapter()} 
        // method instead. However you would have to cast that adapter 
        // to your own instance every time
    }

    /**
     * helper to show what happens when all data is new
     */
    private void reloadAllData(){
        // get new modified random data
        List<ModelObject> objects = getRandomData();
        // update data in our adapter
        mAdapter.getData().clear();
        mAdapter.getData().addAll(objects);
        // fire the event
        mAdapter.notifyDataSetChanged();
    }

    /**
     * helper to show how only changing properties of data 
     * elements also works
     */
    private void scrambleChecked(){
        Random random = new Random();
        // update data in our adapter, iterate all objects and 
        // resetting the checked option
        for( ModelObject mo : mAdapter.getData()) {
            mo.setChecked(random.nextBoolean());
        }
        // fire the event
        mAdapter.notifyDataSetChanged();
    }
}

Więcej informacji

Kolejny fajny post o sile listViews znajduje się tutaj: http://www.vogella.com/articles/AndroidListView/article.html

hcpl
źródło
16
jesteś w błędzie. powiadomienieDataSetChanged () nie działało dla mnie, ale funkcja validateViews () zrobiła to poprawnie.
babay
6
Mam problem polegający na tym, że rzeczywiste elementy na liście się nie zmieniają, np. Ta sama ilość elementów. Problem polega jednak na tym, że sposób ich prezentacji musi ulec zmianie. Oznacza to, że kod mojego adaptera do zbudowania interfejsu użytkownika musi zostać ponownie uruchomiony, a następnie poprawnie ukryć jakiś element w wierszach listy. powiadomienieDataSetChanged () nie działa ...
Sven Haiges
9
Ta odpowiedź naprawdę mi pomogła. Trzymałem tablicę w pamięci z pewnych powodów. Aby to naprawić, teraz dzwonię adapter.clear(), a adapter.addAll(Array<T>)przed dzwonieniemnotifyDataSetChanged()
Michael DePhillips
2
@hcpl, jak powinienem wywołać powiadomienieDataSetChanged, jeśli jestem w OnClickListener adaptera dla CheckBox? invalidateViews właśnie wykonuje zadanie. Dlaczego unieważnia Wyświetla niewłaściwą metodę wywołania?
ściągnął
1
Nigdy nie byłem w stanie uzyskać powiadomieniaDataSetChanged. Widziałem wyraźnie, że kolekcja, którą przekazuję do adaptera, uległa zmianie (elementy zostały usunięte), ale powiadomienieDataSetChanged nigdy nic nie zrobiło. Nie jesteś pewien, czy ta metoda jest po prostu zepsuta?
byemute,
42

Dzwoń w dowolnym momencie:

runOnUiThread(run);

OnCreate(), ustawiasz wątek uruchamialny:

run = new Runnable() {
    public void run() {
        //reload content
        arraylist.clear();
        arraylist.addAll(db.readAll());
        adapter.notifyDataSetChanged();
        listview.invalidateViews();
        listview.refreshDrawableState();
    }
};
Marckaraujo
źródło
1
Działa również w moim przypadku, w którym muszę zaktualizować widok listy na podstawie danych pochodzących z połączenia TCP (z wątku „nonUI”). Jedynym sposobem na odświeżenie listy było wyczyszczenie i ponowne dodanie wszystkich elementów ArrayList. W każdym razie, jeśli jesteś już w wątku interfejsu, nie musisz wywoływać kodu za pomocą runOnUiThread()funkcji.
Andre
Dzięki! Mi to pasuje. Dla wszystkich ludzi, którzy chcą uruchomić to z fragmentu, powinieneś użyć getActivity (). RunOnUiThread (nowy Runnable ... aby upewnić się, że kod działa w wątku interfejsu użytkownika
codingpuss
Nie widzę celu run = new Runnable()i po prostu nadałem mojej funkcji public void refreshUIThread()metodę, która modeluje twoją run()metodę (która też działa).
T.Woody,
11

Mam problemy z dynamicznym odświeżaniem widoku listy.

Wywołaj powiadomienieDataSetChanged () na karcie.

Niektóre dodatkowe informacje na temat tego, jak / kiedy wywołać powiadomienieDataSetChanged () można obejrzeć w tym filmie Google I / O.

powiadomienieDataSetChanged () nie działało poprawnie w moim przypadku [wywołałem powiadomienieDataSetChanged z innej klasy]. Właśnie w przypadku, gdy edytowałem ListView w działającym działaniu (wątku). Ten film dzięki Christopherowi dał ostatnią wskazówkę.

W mojej drugiej klasie korzystałem

Runnable run = new Runnable(){
     public void run(){
         contactsActivity.update();
     }
};
contactsActivity.runOnUiThread(run);

aby uzyskać dostęp do aktualizacji () z mojej Aktywności. Ta aktualizacja obejmuje

myAdapter.notifyDataSetChanged();

powiedzieć adapterowi, aby odświeżył widok. Działało dobrze, o ile mogę powiedzieć.

Wille
źródło
9

Jeśli używasz SimpleCursorAdapter, spróbuj wywołać requery () na obiekcie Cursor.

freehacker
źródło
13
Ta metoda jest przestarzała.
AndroidGecko
5

jeśli nadal nie jesteś zadowolony z ListView Refreshment, możesz spojrzeć na ten fragment kodu, służy on do wczytywania listView z bazy danych. Właściwie to po prostu przeładuj ListView po wykonaniu jakiejkolwiek operacji CRUD. Nie jest to najlepszy sposób na kod, ale odświeży ListView, jak chcesz ..

Działa dla mnie .... jeśli znajdziesz lepsze rozwiązanie, udostępnij ...

.......
......
wykonaj swoje operacje CRUD ..
......
.....
DBAdapter.open ();
DBAdapter.insert_into_SingleList ();
// Przynieś wyniki DB_result i dodaj go do listy jako jego zawartość ....
                                            ls2.setAdapter (nowy ArrayAdapter (DynTABSample.this,
    android.R.layout.simple_list_item_1, DBAdapter.DB_ListView));
                                            DBAdapter.close ();
Nandagopal T.
źródło
2

Rozwiązania zaproponowane przez ludzi w tym poście działają lub nie, głównie w zależności od wersji Androida urządzenia. Na przykład, aby użyć metody AddAll, musisz umieścić Androida: minSdkVersion = "10" na urządzeniu z Androidem.

Aby rozwiązać te pytania dla wszystkich urządzeń, utworzyłem własną metodę w adapterze i używam wewnątrz metody dodawania i usuwania dziedziczenia z ArrayAdapter, które aktualizują dane bez problemów.

Mój kod: Używając własnej klasy danych RaceResult, korzystasz z własnego modelu danych.

ResultGpRowAdapter.java

public class ResultGpRowAdapter extends ArrayAdapter<RaceResult> {

    Context context;
    int resource;
    List<RaceResult> data=null;

        public ResultGpRowAdapter(Context context, int resource, List<RaceResult> objects)           {
        super(context, resource, objects);

        this.context = context;
        this.resource = resource;
        this.data = objects;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        ........
        }

        //my own method to populate data           
        public void myAddAll(List<RaceResult> items) {

        for (RaceResult item:items){
            super.add(item);
        }
    }

ResultsGp.java

public class ResultsGp extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {

    ...........
    ...........
    ListView list = (ListView)findViewById(R.id.resultsGpList); 

    ResultGpRowAdapter adapter = new ResultGpRowAdapter(this,  R.layout.activity_result_gp_row, new ArrayList<RaceResult>()); //Empty data

   list.setAdapter(adapter);

   .... 
   ....
   ....
   //LOAD a ArrayList<RaceResult> with data

   ArrayList<RaceResult> data = new ArrayList<RaceResult>();
   data.add(new RaceResult(....));
   data.add(new RaceResult(....));
   .......

   adapter.myAddAll(data); //Your list will be udpdated!!!
AntuanSoft
źródło
1

Jeśli chcesz zachować pozycję przewijania podczas odświeżania i możesz to zrobić:

if (mEventListView.getAdapter() == null) {
    EventLogAdapter eventLogAdapter = new EventLogAdapter(mContext, events);
    mEventListView.setAdapter(eventLogAdapter);
} else {
    ((EventLogAdapter)mEventListView.getAdapter()).refill(events);
}

public void refill(List<EventLog> events) {
    mEvents.clear();
    mEvents.addAll(events);
    notifyDataSetChanged();
}

Aby uzyskać szczegółowe informacje, zobacz Android ListView: Utrzymaj pozycję przewijania podczas odświeżania .

Brandon Yang
źródło
1

Wystarczy użyć myArrayList.remove(position);wewnątrz detektora:

  myListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override public void onItemClick(AdapterView<?> parent, android.view.View view, int position, long id) {
           myArrayList.remove(position);
           myArrayAdapter.notifyDataSetChanged();
        }
    });
Steffo Dimfelt
źródło
1

Musisz użyć jednego obiektu z tej listy, do którego danych chcesz nadmuchać ListView. Jeśli odwołanie jest zmieniane, to notifyDataSetChanged()nie działa. Za każdym razem, gdy usuwasz elementy z widoku listy, usuwaj je również z używanej listy, niezależnie od tego, czy jest to ArrayList <>, czy coś innego niż Wywołaj notifyDataSetChanged()obiekt klasy adaptera.

Zobacz więc, jak zarządzałem w mojej przejściówce, patrz poniżej

public class CountryCodeListAdapter extends BaseAdapter implements OnItemClickListener{

private Context context;
private ArrayList<CountryDataObject> dObj;
private ViewHolder holder;
private Typeface itemFont;
private int selectedPosition=-1;
private ArrayList<CountryDataObject> completeList;

public CountryCodeListAdapter(Context context, ArrayList<CountryDataObject> dObj) {
    this.context = context;
    this.dObj=dObj;
    completeList=new  ArrayList<CountryDataObject>();
    completeList.addAll(dObj);
    itemFont=Typeface.createFromAsset(context.getAssets(), "CaviarDreams.ttf");
}

@Override
public int getCount() {
    return dObj.size();
}

@Override
public Object getItem(int position) {
    return dObj.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}
@Override
public View getView(int position, View view, ViewGroup parent) {
    if(view==null){
        holder = new ViewHolder();
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = inflater.inflate(R.layout.states_inflator_layout, null);
        holder.textView = ((TextView)view.findViewById(R.id.stateNameInflator));
        holder.checkImg=(ImageView)view.findViewById(R.id.checkBoxState);
        view.setTag(holder);
    }else{
        holder = (ViewHolder) view.getTag();
    }
    holder.textView.setText(dObj.get(position).getCountryName());
    holder.textView.setTypeface(itemFont);

    if(position==selectedPosition)
     {
         holder.checkImg.setImageResource(R.drawable.check);
     }
     else
     {
         holder.checkImg.setImageResource(R.drawable.uncheck);
     }
    return view;
}
private class ViewHolder{
    private TextView textView;
    private ImageView checkImg;
}

public void getFilter(String name) {
    dObj.clear();
    if(!name.equals("")){
    for (CountryDataObject item : completeList) {
        if(item.getCountryName().toLowerCase().startsWith(name.toLowerCase(),0)){
            dObj.add(item);
        }
    }
    }
    else {
        dObj.addAll(completeList);
    }
    selectedPosition=-1;
    notifyDataSetChanged();
    notifyDataSetInvalidated(); 
}

@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
        long id) {
    Registration reg=(Registration)context;
    selectedPosition=position;
    reg.setSelectedCountryCode("+"+dObj.get(position).getCountryCode());
    notifyDataSetChanged();
}
}
ADM
źródło
1
twoje wyjaśnienia są niedoceniane, ale naprawdę dają mi zrozumienie na temat arraylist. dziękuję
Abraham Putra Prakasa
0

Po usunięciu danych z widoku listy musisz zadzwonić refreshDrawableState(). Oto przykład:

final DatabaseHelper db = new DatabaseHelper (ActivityName.this);

db.open();

db.deleteContact(arg3);

mListView.refreshDrawableState();

db.close();

i deleteContactmetoda w DatabaseHelperklasie będzie wyglądać nieco

public boolean deleteContact(long rowId) {

   return db.delete(TABLE_NAME, BaseColumns._ID + "=" + rowId, null) > 0;

}
użytkownik1031852
źródło
0

Nie byłem w stanie uzyskać powiadomieniaDataSetChanged () do pracy nad aktualizacją mojego SimpleAdapter, więc zamiast tego próbowałem najpierw usunąć wszystkie widoki, które zostały dołączone do układu nadrzędnego za pomocą removeAllViews (), a następnie dodać ListView i działało, pozwalając mi zaktualizować Interfejs użytkownika:

LinearLayout results = (LinearLayout)findViewById(R.id.results);
ListView lv = new ListView(this);
ArrayList<HashMap<String,String>> list = new ArrayList<HashMap<String,String>>();
SimpleAdapter adapter = new SimpleAdapter( this, list, R.layout.directory_row, 
                new String[] { "name", "dept" }, new int[] { R.id.name, R.id.dept } );

for (...) { 
    HashMap<String, String> map = new HashMap<String, String>();
    map.put("name", name);
    map.put("dept", dept);
    list.add(map);
}

lv.setAdapter(adapter);
results.removeAllViews();     
results.addView(lv);
Chasden
źródło
0

Dla mnie po zmianie informacji w bazie danych SQL nic nie może odświeżyć widoku listy (a konkretnie rozwijanego widoku listy), więc jeśli powiadomienieataDataSetChanged () nie pomoże, możesz spróbować wyczyścić listę i dodać ją ponownie po tym wywołaniu powiadomićDataSetChanged (). Na przykład

private List<List<SomeNewArray>> arrayList;
List<SomeNewArray> array1= getArrayList(...);
List<SomeNewArray> array2= getArrayList(...);
arrayList.clear();
arrayList.add(array1);
arrayList.add(array2);
notifyDataSetChanged();

Mam nadzieję, że ma to dla ciebie sens.

Aivus
źródło
0

podczas korzystania z SimpleCursorAdapter może wywoływać changeCursor (newCursor) na adapterze.

Vihaan Verma
źródło
0

Byłem taki sam, gdy fragmentem chciałem wypełnić ListView (w pojedynczym TextView) adresem MAC urządzeń BLE skanowanych przez pewien czas.

Zrobiłem to:

public class Fragment01 extends android.support.v4.app.Fragment implements ...
{
    private ListView                listView;
    private ArrayAdapter<String>    arrayAdapter_string;

...

@Override
public void onActivityCreated(Bundle savedInstanceState)
{
    ...
    this.listView= (ListView) super.getActivity().findViewById(R.id.fragment01_listView);
    ...
    this.arrayAdapter_string= new ArrayAdapter<String>(super.getActivity(), R.layout.dispositivo_ble_item, R.id.fragment01_item_textView_titulo);
    this.listView.setAdapter(this.arrayAdapter_string);
}


@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord)
{
    ...
    super.getActivity().runOnUiThread(new RefreshListView(device));
}


private class RefreshListView implements Runnable
{
    private BluetoothDevice bluetoothDevice;

    public RefreshListView(BluetoothDevice bluetoothDevice)
    {
        this.bluetoothDevice= bluetoothDevice;
    }

    @Override
    public void run()
    {
        Fragment01.this.arrayAdapter_string.add(new String(bluetoothDevice.toString()));
        Fragment01.this.arrayAdapter_string.notifyDataSetChanged();
    }
}

Następnie ListView zaczął dynamicznie wypełniać adres mac znalezionych urządzeń.

jsanmarb
źródło
0

Myślę, że to zależy od tego, co masz na myśli przez odświeżenie. Czy masz na myśli, że ekran GUI powinien zostać odświeżony, czy masz na myśli, że widoki potomne powinny zostać odświeżone, abyś mógł programowo wywołać getChildAt (int) i uzyskać widok odpowiadający temu, co jest w adapterze.

Jeśli chcesz odświeżyć ekran GUI, wywołaj powiadomienieataDataSetChanged () na adapterze. GUI zostanie odświeżony przy następnym przerysowaniu.

Jeśli chcesz mieć możliwość wywołania getChildAt (int) i uzyskania widoku odzwierciedlającego to, co jest w adapterze, to wywołaj layoutChildren (). Spowoduje to zrekonstruowanie widoku potomnego na podstawie danych adaptera.

oszołomiony
źródło
0

Miałem ArrayList, który chciałem wyświetlić w widoku listy. ArrayList zawierał elementy z mysql. Przesłoniłem metodę onRefresh iw tej metodzie użyłem tablelayout.removeAllViews (); a następnie powtórzył proces ponownego pobierania danych z bazy danych. Ale przed tym upewnij się, że wyczyściłeś ArrayList lub jakąkolwiek strukturę danych, albo nowe dane zostaną dołączone do starej.

Kshitij G.
źródło
0

Jeśli chcesz zaktualizować widok listy interfejsu użytkownika z usługi, ustaw statyczny adapter w działaniu głównym i wykonaj następujące czynności:

@Override
public void onDestroy() {
    if (MainActivity.isInFront == true) {
        if (MainActivity.adapter != null) {
            MainActivity.adapter.notifyDataSetChanged();
        }

        MainActivity.listView.setAdapter(MainActivity.adapter);
    }
}    
Mayank Saini
źródło
0

Jeśli korzystasz z linii prowadzących Androida i używasz ContentProvidersdo pobierania danych Databasei wyświetlasz je za ListViewpomocą CursorLoaderiCursorAdapters , wtedy wszystkie zmiany w powiązanych danych zostaną automatycznie odzwierciedlone w ListView.

Twój getContext().getContentResolver().notifyChange(uri, null);kursor wContentProvider będzie wystarczający, aby odzwierciedlić zmiany. Nie musisz wykonywać dodatkowej pracy.

Ale jeśli nie używasz ich wszystkich, musisz poinformować adapter o zmianie zestawu danych. Musisz również ponownie wypełnić / ponownie załadować zestaw danych (powiedzmy listę), a następnie musisz zadzwonićnotifyDataSetChanged() adapter.

notifyDataSetChanged()nie będzie działać, jeśli nie ma zmian w zestawie danych. Oto komentarz nad metodą w dokumentach

/**
 * Notifies the attached observers that the underlying data has been changed
 * and any View reflecting the data set should refresh itself.
 */
Sanjeet A.
źródło
0

Byłem w stanie uzyskać powiadomienieDataSetChanged tylko poprzez pobranie nowych danych adaptera, a następnie zresetowanie adaptera do widoku listy, a następnie wykonanie połączenia w następujący sposób:

    expandableAdapter = baseFragmentParent.setupEXLVAdapter();
    baseFragmentParent.setAdapter(expandableAdapter);
    expandableAdapter.notifyDataSetChanged(); 
Kristy Welsh
źródło
0

drugą opcją jest onWindowFocusChangedmetoda, ale pewna, że ​​jest wrażliwa i wymaga dodatkowego kodowania dla kogo jest zainteresowana

 override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)

       // some controls needed
        programList = usersDBHelper.readProgram(model.title!!)
        notesAdapter = DailyAdapter(this, programList)
        notesAdapter.notifyDataSetChanged()
        listview_act_daily.adapter = notesAdapter
    }
Sam
źródło
0

Rozważ, że przekazałeś listę do adaptera.
Posługiwać się:

list.getAdapter().notifyDataSetChanged()

zaktualizować listę.

Mahdi-Malv
źródło
0

Jeśli mówiłem tutaj o moim scenariuszu, żadne z powyższych odpowiedzi nie zadziałałoby, ponieważ miałem aktywność, która pokazuje listę wartości db wraz z przyciskiem usuwania, a kiedy przycisk usuwania jest naciśnięty, chciałem usunąć ten element z listy.

Fajne było to, że nie użyłem widoku programu do recyklingu, ale prosty widok listy i ten widok listy zainicjowano w klasie adaptera. Więc dzwoniąc donotifyDataSetChanged() nie spowoduje nic wewnątrz klasy adaptera, a nawet w klasie aktywności, w której inicjowany jest obiekt adaptera, ponieważ metoda usuwania była w klasie adaptera.

Rozwiązaniem było więc usunięcie obiektu z adaptera w getViewmetodzie klasy adaptera (aby usunąć tylko ten konkretny obiekt, ale jeśli chcesz usunąć wszystko, wywołajclear() ).

Aby dowiedzieć się, jak wyglądał mój kod,

public class WordAdapter extends ArrayAdapter<Word> {
  Context context;

  public WordAdapter(Activity context, ArrayList<Word> words) {}
    //.......

    @NonNull
    @Override
    public View getView(final int position, View convertView, ViewGroup group) {
      //.......
     ImageButton deleteBt = listItemView.findViewById(R.id.word_delete_bt);
     deleteBt.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View v) {
             if (vocabDb.deleteWord(currentWord.id)) {
                //.....
             } else{
                //.....
             }
             remove(getItem(position)); // <---- here is the trick ---<
             //clear() // if you want to clear everything
         }
    });
 //....

Uwaga: tutaj remove()i getItem()metody są dziedziczone z klasy Adapter.

  • remove() - aby usunąć konkretny kliknięty element
  • getItem(position) - ma pobrać element (tutaj, to mój obiekt Word, który dodałem do listy) z klikniętej pozycji.

W ten sposób ustawiam adapter na widok listy w klasie aktywności,

    ArrayList<Word> wordList = new ArrayList();
    WordAdapter adapter = new WordAdapter(this, wordList);

    ListView list_view = (ListView) findViewById(R.id.activity_view_words);
    list_view.setAdapter(adapter);
Blasanka
źródło
-1

Najłatwiej jest po prostu zrobić nowego Adapera i upuścić starego:

myListView.setAdapter(new MyListAdapter(...));
użytkownik1712200
źródło
To zużywa więcej pamięci.
Gracz 1
śmieci zostaną zebrane
użytkownik1712200