Android ListView не обновляется после notifyDataSetChanged

android android-listview notifydatasetchanged

180950 просмотра

11 ответа

Мой код ListFragment

public class ItemFragment extends ListFragment {

    private DatabaseHandler dbHelper;
    private static final String TITLE = "Items";
    private static final String LOG_TAG = "debugger";
    private ItemAdapter adapter;
    private List<Item> items;


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.item_fragment_list, container, false);        
        return view;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.setHasOptionsMenu(true);
        super.onCreate(savedInstanceState);
        getActivity().setTitle(TITLE);
        dbHelper = new DatabaseHandler(getActivity());
        items = dbHelper.getItems(); 
        adapter = new ItemAdapter(getActivity().getApplicationContext(), items);
        this.setListAdapter(adapter);

    }



    @Override
    public void onResume() {
        super.onResume();
        items.clear();
        items = dbHelper.getItems(); //reload the items from database
        adapter.notifyDataSetChanged();
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
        if(dbHelper != null) { //item is edited
            Item item = (Item) this.getListAdapter().getItem(position);
            Intent intent = new Intent(getActivity(), AddItemActivity.class);
            intent.putExtra(IntentConstants.ITEM, item);
            startActivity(intent);
        }
    }
}

Мой ListView

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <ListView
        android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

Но это не освежает ListView. Даже после перезапуска приложения обновленные элементы не отображаются. Мой ItemAdapterрасширяетсяBaseAdapter

public class ItemAdapter extends BaseAdapter{

    private LayoutInflater inflater;
    private List<Item> items;
    private Context context;

    public ProjectListItemAdapter(Context context, List<Item> items) {
        super();
        inflater = LayoutInflater.from(context);
        this.context = context;
        this.items = items;

    }

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

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

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ItemViewHolder holder = null;
        if(convertView == null) {
            holder = new ItemViewHolder();
            convertView = inflater.inflate(R.layout.list_item, parent,false);
            holder.itemName = (TextView) convertView.findViewById(R.id.topText);
            holder.itemLocation = (TextView) convertView.findViewById(R.id.bottomText);
            convertView.setTag(holder);
        } else {
            holder = (ItemViewHolder) convertView.getTag();
        }
        holder.itemName.setText("Name: " + items.get(position).getName());
        holder.itemLocation.setText("Location: " + items.get(position).getLocation());
        if(position % 2 == 0) {                                                                                 
            convertView.setBackgroundColor(context.getResources().getColor(R.color.evenRowColor));
        } else {    
            convertView.setBackgroundColor(context.getResources().getColor(R.color.oddRowColor));
        }
        return convertView;
    }

    private static class ItemViewHolder {
        TextView itemName;
        TextView itemLocation;
    }
}

Может кто-нибудь помочь, пожалуйста?

Автор: Coder Источник Размещён: 12.11.2019 09:18

Ответы (11)


224 плюса

Решение

Посмотрите на ваш onResumeметод в ItemFragment:

@Override
public void onResume() {
    super.onResume();
    items.clear();
    items = dbHelper.getItems(); // reload the items from database
    adapter.notifyDataSetChanged();
}

то, что вы только что обновили перед вызовом, notifyDataSetChanged()это не поле адаптера, private List<Item> items;а идентично объявленное поле фрагмента. Адаптер по-прежнему хранит ссылку на список элементов, которые вы передали при создании адаптера (например, в фрагменте onCreate). Самый короткий (в смысле количества изменений), но не элегантный способ заставить ваш код вести себя так, как вы ожидаете, - это просто заменить строку:

    items = dbHelper.getItems(); // reload the items from database

с участием

    items.addAll(dbHelper.getItems()); // reload the items from database

Более элегантное решение:

1) удалить элементы private List<Item> items;из ItemFragment- нам нужно хранить ссылки на них только в адаптере

2) изменить наСоздать на:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    super.setHasOptionsMenu(true);
    getActivity().setTitle(TITLE);
    dbHelper = new DatabaseHandler(getActivity());
    adapter = new ItemAdapter(getActivity(), dbHelper.getItems());
    setListAdapter(adapter);
}

3) добавить метод в ItemAdapter:

public void swapItems(List<Item> items) {
    this.items = items;
    notifyDataSetChanged();
}

4) измените свой onResume на:

@Override
public void onResume() {
    super.onResume();
    adapter.swapItems(dbHelper.getItems());
}
Автор: Tomasz Gawel Размещён: 03.02.2013 01:52

22 плюса

Вы назначаете перезагруженные элементы в элементы глобальной переменной onResume(), но это не будет отражаться в ItemAdapterклассе, потому что у него есть собственная переменная экземпляра, называемая «элементы».

Для обновления ListViewдобавьте refresh () в ItemAdapterкласс, который принимает данные списка, т.е. элементы

class ItemAdapter
{
    .....

    public void refresh(List<Item> items)
    {
        this.items = items;
        notifyDataSetChanged();
    } 
}

обновить onResume()с помощью следующего кода

@Override
public void onResume()
{
    super.onResume();
    items.clear();
    items = dbHelper.getItems(); //reload the items from database
    **adapter.refresh(items);**
}
Автор: Santhosh Размещён: 30.01.2013 01:46

8 плюса

В onResume () измени эту строку

items = dbHelper.getItems(); //reload the items from database

в

items.addAll(dbHelper.getItems()); //reload the items from database

Проблема в том, что вы никогда не говорите своему адаптеру о списке новых предметов. Если вы не хотите передавать новый список вашему адаптеру (как вам кажется, нет), просто используйте items.addAllпосле clear(). Это гарантирует, что вы изменяете тот же список, на который ссылается адаптер.

Автор: Justin Breitfeller Размещён: 01.02.2013 08:20

4 плюса

Если адаптер уже установлен, его повторная установка не обновит представление списка. Вместо этого сначала проверьте, есть ли у listview адаптер, а затем вызовите соответствующий метод.

Я думаю, что это не очень хорошая идея, чтобы создать новый экземпляр адаптера при настройке представления списка. Вместо этого создайте объект.

BuildingAdapter adapter = new BuildingAdapter(context);

    if(getListView().getAdapter() == null){ //Adapter not set yet.
     setListAdapter(adapter);
    }
    else{ //Already has an adapter
    adapter.notifyDataSetChanged();
    }

Также вы можете попробовать запустить список обновления в потоке пользовательского интерфейса:

activity.runOnUiThread(new Runnable() {         
        public void run() {
              //do your modifications here

              // for example    
              adapter.add(new Object());
              adapter.notifyDataSetChanged()  
        }
});
Автор: AlexGo Размещён: 24.01.2013 02:52

4 плюса

Если вы хотите обновить ваш ListView не имеет значения , если вы хотите сделать это на onResume(), onCreate()или в какой - либо другой функции, первое , что вы должны понимать, что вам не нужно будет создать новый экземпляр адаптера, просто Заселите массивы с вашими данными снова. Идея примерно такая:

private ArrayList<String> titles;
private MyListAdapter adapter;
private ListView myListView;

@Override
public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_activity);

    myListView = (ListView) findViewById(R.id.my_list);

    titles = new ArrayList<String>()

    for(int i =0; i<20;i++){
        titles.add("Title "+i);
    }

    adapter = new MyListAdapter(this, titles);
    myListView.setAdapter(adapter);
}


@Override
public void onResume(){
    super.onResume();
    // first clear the items and populate the new items
    titles.clear();
    for(int i =0; i<20;i++){
        titles.add("New Title "+i);
    }
    adapter.notifySetDataChanged();
}

Таким образом, в зависимости от этого ответа вы должны использовать то же самое List<Item>в вашем Fragment. При первой инициализации адаптера вы заполняете свой список элементами и устанавливаете адаптер в свой список. После этого при каждом изменении ваших предметов вы должны очищать значения из основного, List<Item> itemsа затем снова заполнять его новыми элементами и вызывать notifySetDataChanged();.

Вот как это работает:).

Автор: hardartcore Размещён: 27.01.2013 10:14

3 плюса

Ответ от AlexGo помог мне:

getActivity().runOnUiThread(new Runnable() {
        @Override
        public void run() {
         messages.add(m);
         adapter.notifyDataSetChanged();
         getListView().setSelection(messages.size()-1);
        }
});

Обновление списка работало для меня раньше, когда обновление было запущено из события GUI, таким образом находясь в потоке пользовательского интерфейса.

Однако, когда я обновляю список из другого события / потока - то есть вызова из-за пределов приложения, обновление не будет в потоке пользовательского интерфейса, и оно игнорирует вызов getListView. Вызов обновления с runOnUiThread, как указано выше, помог мне. Спасибо!!

Автор: user2996950 Размещён: 20.11.2013 06:54

3 плюса

Попробуй это

@Override
public void onResume() {
super.onResume();
items.clear();
items = dbHelper.getItems(); //reload the items from database
adapter = new ItemAdapter(getActivity(), items);//reload the items from database
adapter.notifyDataSetChanged();
}
Автор: Gautami Размещён: 22.04.2014 11:31

2 плюса

adpter.notifyDataSetInvalidated();

Попробуйте это в onPause()методе класса Activity.

Автор: Som Размещён: 01.02.2013 01:01

1 плюс

adapter.setNotifyDataChanged()

должен сделать свое дело.

Автор: Hitman Размещён: 20.11.2013 07:16

0 плюса

Попробуйте вот так:

this.notifyDataSetChanged();

вместо:

adapter.notifyDataSetChanged();

Вы должны notifyDataSetChanged()в ListViewне к классу адаптера.

Автор: Jachu Размещён: 31.01.2013 11:02

0 плюса

Если ваш список содержится в самом адаптере, вызов функции, которая обновляет список, также должен вызываться notifyDataSetChanged().

Запуск этой функции из потока пользовательского интерфейса помог мне:

refresh()Функции внутри адаптера

public void refresh(){
    //manipulate list
    notifyDataSetChanged();
}

Затем, в свою очередь, запустите эту функцию из потока пользовательского интерфейса

getActivity().runOnUiThread(new Runnable() { 
    @Override
    public void run() {
          adapter.refresh()  
    }
});
Автор: Dévan Coetzee Размещён: 22.06.2017 10:51
Вопросы из категории :
32x32