Подтвердить что ты не робот

Только в некоторых телефонах ListView не обновляется после notifyDataSetChanged()

Это странно, потому что это происходит только в некоторых телефонах, разрешение которых является FHD.

Когда отображается пользовательский интерфейс, все выглядит нормально. Когда я нажимаю элементы и вызываю notifyDataSetChanged(), элемент не обновляет его. Мне нужно снова щелкнуть по списку ListView, элемент обновит макет до правильного внешнего вида.

Если listview изменяет размер (например: функция поиска перепроектирует весь макет), все становится ОК.

Вот код ListView:

public final class MyListView extends ListView implements AdapterView.OnItemClickListener
{

    ArrayList<SELECT_ITEM> selectList;
    ArrayList<ID_ITEM> idList;
    ShowItemAdapter showAdapter;

    public MyListView(Context context) 
    {
        selectList = new ArrayList<SELECT_ITEM>();
        idList = new ArrayList<ID_ITEM>();

        readIdList(mIdList);
        showAdapter = new ShowItemAdapter(context, idList, selectList);
        setAdapter(showAdapter);        

        ...
    }

    @Override
    protected void onFinishInflate() {
        setOnItemClickListener(this);
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long ID) {
        boolean itemIsSelected = true;
        int size = selectList.size();

        // remove if click item in selectList
        for(int i=0 ; i<size ; i++) {
            int selectID = selectList.get(i).id;
            if (idList.get(position).id == selectID) {  
                itemIsSelected = false;
                selectList.remove(i);
                showAdapter.notifyDataSetChanged();
                break;
            }
        }

        if (itemIsSelected) {
            SELECT_ITEM item = new SELECT_ITEM();
            item.id = idList.get(position);
            selectList.add(item);
            // Here
            showAdapter.notifyDataSetChanged();
        }
    ...
    }

    ....
}

И вот код адаптера,

    public final class ShowItemAdapter extends BaseAdapter{

    public ArrayList<ID_ITEM>   mIdList;
    public ArrayList<SELECT_ITEM>   mSelectList;

    public ShowItemAdapter(Context context,
        ArrayList<ID_ITEM> idList,
        ArrayList<SELECT_ITEM> selectList)
    {
        mIdList = idList;
        mSelectList = selectList;
    }

    @Override
    public int getCount() {
        int ret = mIdList.size();
        return ret;
    }

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

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

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

        ...

        for(int i=0 ; i<size ; i++)
        {
            // is selected
            if (mIdList.get(position).id == 
                selectList.get(i).id)
            {
                mIsSelected = true;
                break;
            }
        }

        if (mIsSelected)
        {
            textView.setBackgroundColor(Color.red);
        }
        else
        {
            textView.setBackgroundColor(Color.white);
        }
    }
}

Кто-нибудь даст мне руку?

Я нашел, что эти телефоны работают правильно, вызовет такую ​​же проблему при отладке паузы в getView(). Я думаю.. это похоже на то, что "Views обновлен, поэтому он не обновляет представления". Но просмотр обновлений во время отладки делает ui не обновляться на самом деле, а затем работает не так.

Я думаю, что речь идет о освежающих представлениях.

4b9b3361

Ответ 1

Я вижу возможный конфликт кода и проблему времени между getView() адаптера и onItemClick().

Позвольте мне объяснить. В getView() есть код

if (mIdList.get(position).id == selectList.get(i).id)

Примечание. Здесь проверяется значение selectList, которое даже не объявлено в этом классе адаптера. Я предполагаю, что вы имели в виду mSelectList. Но пусть двигаться дальше...

В onItemClick() есть код

if (idList.get(position).id == selectID) {  
   ...
   selectList.remove(i);
   ...

Примечание. Этот код удаляет элемент из selectList, а в getView() он проверяет один и тот же объект. Мы не можем знать, какой код будет работать в первую очередь. Но у меня есть идея... getView() - это метод виртуального обратного вызова, в котором BaseAdapter может инициировать метод, когда для его отображения требуется строка или элемент. Поэтому, когда вы удаляете элемент из списка, адаптер может не запрашивать обновление, независимо от того, что вы делаете в коде. А адаптер ShowItemAdapter отвечает за обновление всех строк/просмотров.

Предложение. Поместите тот же код (для удаления/добавления элемента) в getView(), чтобы избежать подобных конфликтов кода.

Дайте нам знать и удачи в этой нечетной аномалии.
Томми Кви

Ответ 2

Вам нужно вызвать методы super в функциях constructor и onFinishInflate класса MyListView. Возможно, это вызвало проблему.

public MyListView(Context context) 
 {
    super(context);
    selectList = new ArrayList<SELECT_ITEM>();
    ..
    ..
}

и

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        setOnItemClickListener(this);
    }

Ответ 3

Это ошибка на Android 4.0.3, notifyDataSetChanged не работает с onItemClickListener.

Итак, решение будет примерно таким:

  • Установить onItemClickListener отдельно для каждого вида в адаптере
  • Отправляйте его туда, где бы вы ни хотели его обрабатывать.
  • Сделайте то, что вы хотите, и позвоните notifyDataSetChanged оттуда

Ответ 4

Обычно я обновляю данные на своем адаптере, и у меня нет такой проблемы, я считаю, что она более прочная. Поскольку вы обновляете данные (selectList) в Listview, обновление/обновление немного косвенно, я думаю. Сначала я предложил бы попробовать.

Образцы кода после кода ниже:

selectList.remove(i);
showAdapter.notifyDataSetChanged();

ADD

  • invalidate() ИЛИ
  • invalidateViews()

Примечание. Я замечаю ваше решение call onInit(), которое я не знаю, что это такое. Кажется, что есть проблема с синхронизацией, то есть вам не нужно запускать код в новом/отдельном потоке.

Ответ 5

Ниже может помочь. У меня была аналогичная проблема в 4.4.2, и это помогло:

//clear the adapter    
showAdapter.clear();
//add all the data in your list to adapter again
showAdapter.addAll(selectList);

Вам не нужно вызывать notifyDataSetChanged, поскольку он будет делать это в addAll. Надеюсь, что это поможет.

Ответ 6

Вы должны обновлять свой ListView синхронно.

 public final class ShowItemAdapter extends BaseAdapter{

public ArrayList<ID_ITEM>   mIdList;
public ArrayList<SELECT_ITEM>   mSelectList;

public ShowItemAdapter(Context context,
    ArrayList<ID_ITEM> idList,
    ArrayList<SELECT_ITEM> selectList)
{
    mIdList = idList;
    mSelectList = selectList;
}

 public synchronized void refreshData(ArrayList<SELECT_ITEM> items) {
    this.mSelectList = items;
    notifyDataSetChanged();
}

Затем вызовите метод refreshData() всякий раз, когда вы вносите изменения в список

 selectList.remove(i);
 refreshData(selectList);

или

 selectList.add(i);
 refreshData(selectList);

Это обязательно обновит список пользователей с обновленным списком элементов

Ответ 7

Я нашел решение, хотя оно по-прежнему работает с некоторыми проблемами.
Я вызываю ниже на Activity.onCreate(), и только в onInit() MyListView будет инициализирован:

    postDelayed(new Runnable()
    {
        public void run()
        {
            onInit(icicle); // initial ui
        }
    }, 100);

Это делает просмотр более медленным, но отлично работает.
Если отложить около 100 миллисекунд, это может привести к тому, что эти тонкие телефоны станут плохими. Задержка около 350 миллисекунд заставляет оба телефона работать хорошо. Есть ли лучшие ответы?

Ответ 8

Вместо использования showAdapter.notifyDataSetChanged(); просто обновите свой источник данных, я имею в виду selectList и повторно инициализую ваш адаптер и присоединяю его к ListView.

замените это

selectList.remove(i);
showAdapter.notifyDataSetChanged();

и

selectList.add(item);
showAdapter.notifyDataSetChanged();

с этим соответственно

selectList.remove(i);
// or selectList.add(item);
  showAdapter = new ShowItemAdapter(context, idList, selectList);
        setAdapter(showAdapter);