Как исправить задачи notifydatasetchanged/listview в динамической адаптерной обертке Android

StackOverflow https://stackoverflow.com/questions/4566101

Вопрос

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

Я хотел бы динамически добавить элементы в список на основе значений в курсораптере, на несколько позиций опережают то, что пользователь в настоящее время просматривает. Для этого у меня есть адаптер, который завершает курсорад и держит новый контент, индексированный в SpareEarray. ListView должен быть обновлен, когда элементы добавляются в пользовательский адаптер, но я встретил много подводных камней, пытающихся заставить это работать, и мне понравятся некоторые советы.

Демо -проект можно скачать здесь: DynamicsectedList.zip

В демонстрации заголовки добавляются динамично, заглядывая в будущее 10 мест, чтобы найти правильную позицию, где элементы списка переходят на следующую букву. Каждая реализация notifydatasetchanged имеет проблемы, как описано:

Демонстрация 1Эта демонстрация показывает важность notifydatasetchanged (). Нажав что угодно, приложение будет сбой. Это связано с некоторой проверкой здравомыслия в ListView ... mItemCount != adapter.getItemCount(). Анкет Мораль, мы должны уведомить список, что данные изменились.

Демо 2Естественным следующим шагом является уведомление о списке изменений, когда происходят изменения. К сожалению, это, в то время как ListView прокручивает прокрутку, твердо ломает все сенсорные взаимодействия, пока приложение не переключается из режима сенсорного режима. Вам нужно будет «бросить свиток» достаточно далеко, чтобы генерировать новые заголовки, чтобы заметить это. Постукивание экрана не приведет к остановке свитка, и после остановки ни один из элементов списка не будет кликом. Это связано с некоторыми if (!mDataChanged) { /* do very important stuff */ } Код в abslistview.ontouchevent ().

Демо 3Чтобы исправить это, Demo 3 представляет флаг PendingChanges, а пользовательский адаптер получает notifydatasetchAngedifneededededed (), который можно вызвать ListView, как только он введет «безопасное» состояние для изменений. Первая точка, в которой должны быть уведомлены об изменениях, находится в listview.layoutchildren (), поэтому я отверг этот метод, чтобы сначала уведомлять об изменениях, если это необходимо, а затем вызовите. Пропустите хотя бы один заголовок, затем нажмите на элемент списка.

Это не совсем работает правильно, хотя я не совсем уверен, почему. Нажатие или выбор элемента с помощью клавиатуры/трекбола приводит к обновлению списка без должного синхронизации старой позиции. Он прокручивается в верхнюю часть списка, который неприемлемен.

Демо 4Проблема прокрутки в Demo 3 может быть завоевана, по крайней мере, в сенсорном режиме. Добавив призыв к NotifyDatAsetchAngedIfneedededededed () на Touch Down, изменение данных происходит в такое время, что все прикоснительные взаимодействия работают, как и ожидалось, и позиция списка должным образом синхронизируется.

Тем не менее, я не могу найти аналог для этого, когда устройство не в режиме сенсорного режима, не говоря уже о том, что это определенно кажется взломом. Список почти всегда прокручивается вверх, я не могу выяснить, что заставляет его иногда сохранять правильную позицию.

Поскольку Android борется со мной на каждом этапе пути, я чувствую, что должен быть лучший подход. Пожалуйста, попробуйте демонстрацию, если какие -либо исправления могут быть применены, чтобы работать, это было бы здорово!

Большое спасибо всем, кто может изучить это, надеюсь, если мы сможем получить работу, он будет полезен для других, пытающихся выполнить ту же оптимизацию для списков с заголовками.

Это было полезно?

Решение

Основная проблема с подходом, представленным выше, заключалась в том, что набор данных изменялся непосредственно из кода, выполненного суперклассами. Заполняя заголовки в getView (), я менял данные в том, что может быть серединой операции или «небезопасного» состояния в суперклассах. Вот почему все взаимодействие прикосновения сломалось, когда во время свитка была вызвана onnotifydatasetchanged. Данные должны быть добавлены из внешнего источника, а не из методов адаптера.

Это можно сделать, используя обработчик или Asynctask, чтобы добавить заголовки к адаптеру и назвать его notifydatasetchanged. Они будут запущены в потоке пользовательского интерфейса и не будут мешать состоянию Superclass. Благодаря примеру Commonsware endlessAdapter для представления концепции Asynctask для добавления данных в список.

Взлом ontouchevent () и layoutchildren () больше не нужны после внесения этих изменений.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top