1

Я расширяю ExpandableListView, чтобы создать свой собственный ListView и адаптер обратных вызовов осуществляются следующим образом:ExpandableListView обратных вызовов не синхронизированы

@Override 
public int getGroupCount() { 
    return m_FilteredSites.getSize(); 
} 

@Override 
public Object getGroup(int i) { 
    return m_FilteredSites.get(i); 
} 

@Override 
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { 
    SiteEntity site = (SiteEntity) getGroup(groupPosition); 
    //more code .... 
} 

Проблема заключается в том, что в периоде между вызовами getGroupCount и getGroupView, тем Коллекция m_FilteredSites может измениться (из-за использования фильтра в моем случае). Есть ли способ обеспечить синхронизацию или любой другой метод, который будет поддерживать соответствие данных между вызовами?

ответ

1

Проблема теперь исправлена. Проблема заключалась в том, что я менял коллекцию m_FilteredSites на рабочий поток вместо потока пользовательского интерфейса. Класс фильтра имеет 2 обратных вызова: 1. performFiltering - выполняется на рабочем потоке. 2. publishResults - выполняется в потоке пользовательского интерфейса.

Первоначально я вычислял фильтр, но также модифицировал m_FilteredSites по методу performFiltering. Исправление заключается в перемещении фактического кода, который изменяет коллекцию m_FilteredSites, на метод publishResults.

0

Вы можете синхронизировать свой собственный код доступа к нему последовательно, а не одновременно, например:

ExpandableListView elv; 

synchronized(elv) { 
    // Do whatever with elv that requires exclusive thread access 
} 
+0

Я не вижу, как поможет синхронизация моего кода. Я не контролирую поток - это системные обратные вызовы. Например, система будет: 1. вызвать getGroupCount и получить номер 3 (конец синхронизатора заканчивается). 2. Теперь я меняю данные в другом синхронизированном блоке, а число элементов меняется на 0. 3. теперь система вызывает getGroupView с номером 2, потому что все еще думает, что количество элементов - 3. стрела. – galbarm

1

Вы не должны изменять внутренние данные за пределами setAdapter() . Вместо этого вы можете создать новый адаптер, а затем изменить его с помощью этого метода, и все будет хорошо.

Это видео предназначено для ListView, но оно также работает с ExpandableListView: Google I/O 2010 - The world of ListView. Если у вас есть время, я думаю, что стоит посмотреть.


Edited

Жаль, что я не мог вспомнить, где я узнал, что. Я только что просмотрел видео выше, но не смог найти этот момент. Я думаю, что notifyDataSetChanged() используется, когда изменяются данные из элементов в списке, а не сам список. Теперь, если я правильно помню, вы должны сделать это:

public class SampleAdapter extends BaseExpandableListAdapter { 

    private List<List<String>> mData; 

    public void updateData(List<List<String>> data) { 
     mData = data; 
     notifyDataSetChanged(); 
    } 
} 

Я имею в виду, вы не должны изменять пункты mData (например, add(), remove() ...). Лучше построить новый список и назначить его mData, как и выше.

Если у вас есть content provider, вы можете использовать CursorTreeAdapter, он автоматически определит набор данных. Я настоятельно рекомендую использовать контент-провайдеров.

+0

Ваш ответ звучит разумно. однако, не показывает ли метод notifyDataSetChanged в адаптере, что «нормально» изменить внутренние данные адаптера, не воссоздавая его? – galbarm

+0

@galbarm Прошу прощения за оригинальный ответ, я его отредактировал ... – 2013-02-28 11:28:47

Смежные вопросы