2011-02-04 3 views
38

My ListView использует расширение BaseAdapter, я не могу получить его для правильного обновления. Когда я обновляюсь, кажется, что старые данные берут верх над новыми данными, пока не произойдет событие прокрутки. Старые строки рисуются поверх новых строк, но старые строки исчезают, когда я начинаю прокрутку.Android: как обновить содержимое ListView?

Я попытался позвонить invalidateViews(), notifyDataSetChanged() и notifyDataSetInvalidated(). Мой код выглядит примерно так:

private void updateData() 
{ 
    List<DataItems> newList = getNewList(); 

    MyAdapter adapter = new MyAdapter(getContext()); 
    //my adapter holds an internal list of DataItems 
    adapter.setList(newList); 
    mList.setAdapter(adapter); 
    adapter.notifyDataSetChanged(); 
    mList.invalidateViews(); 
} 
+0

ли вы когда-нибудь найти ответ на этот вопрос? У меня точно такая же проблема. – CjS

+0

У меня тоже такая же проблема, кто ее решил? – dexxtr

+0

любой pls помогите мне как обновить новый listdata с существующими данными onscrolllistener – Harsha

ответ

60

Для тех все еще возникают проблемы, я решил это так:

List<Item> newItems = databaseHandler.getItems(); 
ListArrayAdapter.clear(); 
ListArrayAdapter.addAll(newItems); 
ListArrayAdapter.notifyDataSetChanged(); 
databaseHandler.close(); 

Я первый очищенный данные из адаптера, а затем добавил новую коллекцию предметов, и только затем установить notifyDataSetChanged(); Это для меня не было ясно, поэтому я хотел бы указать на это. Обратите внимание, что без вызова notifyDataSetChanged() представление не будет обновляться.

+1

это очень помогло! Моя проблема заключалась в том, что вместо 'ListArrayAdapter.clear();' я снова создавал новый пустой ListAdapter, и, таким образом, ни один из других решений не работал. – TheBronx

+3

что это за 'dbh'? – akhyar

+0

Я думаю, что dbh является экземпляром обработчика базы данных @akhyar – Odin

2

Я делаю то же самое, используя invalidateViews(), и это работает для меня. Если вы хотите, чтобы он немедленно недействителен, вы можете попробовать вызвать postInvalidate после вызова invalidateView.

+0

Спасибо, я пробовал это без успеха. Любые другие предложения? – ab11

11

Вам не нужно создавать новый адаптер для обновления содержимого ListView. Просто храните адаптер в поле и обновить список с помощью следующего кода:

mAdapter.setList(yourNewList); 
mAdapter.notifyDataSetChanged(); 

Чтобы выяснить, что ваша деятельность должна выглядеть так:

private YourAdapter mAdapter; 

protected void onCreate(...) { 

    ... 

    mAdapter = new YourAdapter(this); 
    setListAdapter(mAdapter); 

    updateData(); 
} 

private void updateData() { 
    List<Data> newData = getYourNewData(); 
    mAdapter.setList(yourNewList); 
    mAdapter.notifyDataSetChanged(); 
} 
+0

Спасибо, я пробовал это без успеха. Любые другие предложения? – ab11

+1

Хм этот код должен работать, не могли бы вы разместить часть, где вы устанавливаете свой адаптер и метод setList()? – Gubbel

+0

Итак, если мой ListActivity установлен на полный экран (style/Theme.NoBackground), у него есть проблемы, которые я описал. Но если я настрою его на тему диалога, он обновится правильно. – ab11

3

Я тоже пытался Invalidate (), invalidateViews(), notifyDataSetChanged(). Все они могут работать в определенных контекстах, но в моем случае это не помогло.

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

Во время отладки я понял, что данные были там, но просто не отображены. Если invalidate() или invalidateViews() не отображает (что он должен), я не знаю, что бы это сделал.

Создание нового объекта адаптера для обновления измененных данных не представляет собой плохую идею. Это определенно работает. Единственным недостатком может быть время, затрачиваемое на выделение новой памяти для вашего адаптера, но это должно быть хорошо, если система Android достаточно умен и позаботится об этом, чтобы она была эффективной.

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

Таким образом, мы не теряем много, но набираем много.

+1

Я обнаружил, что установка цвета фона для списка исключает многие проблемы с обновлением. – ab11

3

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

public void refill(ArrayList<BeanDatabase> names) { 
    list.clear(); 
    list.addAll(names); 
    list.notifyDataSetChanged(); 
} 

Если вы изменяете адаптер или устанавливаете адаптер снова и снова при обновлении списка, то принудительная ошибка закрытия, несомненно, вызовет проблемы в какой-то момент. (Ошибка: данные списка обновлены, но адаптер не уведомляет о представлении списка)

11

В моем понимании, если вы хотите обновить ListView сразу же после изменения данных, вы должны позвонить notifyDataSetChanged() в RunOnUiThread().

private void updateData() { 
    List<Data> newData = getYourNewData(); 
    mAdapter.setList(yourNewList); 

    runOnUiThread(new Runnable() { 
     @Override 
     public void run() { 
       mAdapter.notifyDataSetChanged(); 
     } 
    }); 
} 
+1

Я расчесывал StackOverflow в течение двух часов и нашел только сотни бесполезных советов «call notifyDataSetChanged» и тому подобное. Однако ваш ответ действительно работает. Благодаря! – Nevermind

+0

Говорят, что mAdapter должен быть окончательным? –

+0

@FarazAhmad Если mAdapter является локальной переменной, он должен быть окончательным, но если mAdapter является экземпляром экземпляра (из Activity), он не обязательно должен быть :) – Aigori

1
содержание

Update ListView в по ниже код:

private ListView listViewBuddy; 
private BuddyAdapter mBuddyAdapter; 
private ArrayList<BuddyModel> buddyList = new ArrayList<BuddyModel>(); 

OnCreate():

listViewBuddy = (ListView)findViewById(R.id.listViewBuddy); 
mBuddyAdapter = new BuddyAdapter(); 
listViewBuddy.setAdapter(mBuddyAdapter); 

onDataGet (После WebService вызова или из локальной базы данных или otherelse):

mBuddyAdapter.setData(buddyList); 
mBuddyAdapter.notifyDataSetChanged(); 

BaseAdapter:

private class BuddyAdapter extends BaseAdapter { 

    private ArrayList<BuddyModel> mArrayList = new ArrayList<BuddyModel>(); 
    private LayoutInflater mLayoutInflater= (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    private ViewHolder holder; 

    public void setData(ArrayList<BuddyModel> list){ 
     mArrayList = list; 
    } 

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

    @Override 
    public BuddyModel getItem(int position) { 
     return mArrayList.get(position); 
    } 

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

    private class ViewHolder { 
     private TextView txtBuddyName, txtBuddyBadge; 

    } 
    @SuppressLint("InflateParams") 
    @Override 
    public View getView(final int position, View convertView, ViewGroup parent) { 
     if (convertView == null) { 
      holder = new ViewHolder(); 
      convertView = mLayoutInflater.inflate(R.layout.row_buddy, null); 
      // bind views 
      holder.txtBuddyName = (TextView) convertView.findViewById(R.id.txtBuddyName); 
      holder.txtBuddyBadge = (TextView) convertView.findViewById(R.id.txtBuddyBadge); 

      // set tag 
      convertView.setTag(holder); 
     } else { 
      // get tag 
      holder = (ViewHolder) convertView.getTag(); 
     } 

     holder.txtBuddyName.setText(mArrayList.get(position).getFriendId()); 

     int badge = mArrayList.get(position).getCount(); 
     if(badge!=0){ 
      holder.txtBuddyBadge.setVisibility(View.VISIBLE); 
      holder.txtBuddyBadge.setText(""+badge); 
     }else{ 
      holder.txtBuddyBadge.setVisibility(View.GONE); 
     } 

     return convertView; 
    } 
} 

Когда вы хотите Update Listview просто позвоните ниже две строки кода:

mBuddyAdapter.setData(Your_Updated_ArrayList); 
mBuddyAdapter.notifyDataSetChanged(); 

Совершено

1

Только это работает для меня каждый раз, обратите внимание, что я не знаю, вызывает какие-либо другие осложнения или проблемы с производительностью:

private void updateListView(){ 
     listview.setAdapter(adapter); 
    } 
0

Еще один простой способ:

//In your ListViewActivity: 
public void refreshListView() { 
    listAdapter = new ListAdapter(this); 
    setListAdapter(listAdapter); 
}