Как я могу обновить адаптер действия от другого действия? - PullRequest
0 голосов
/ 17 февраля 2012

Проблема: Задание A - это ListView, содержащее ListAdapter, и нажатие на любом элементе адаптера приводит к заданию B. На задании B есть кнопка, которая выбирает новый (или несколько) элемент из Интернета (используя AsyncTask) и добавляет его в список, отображаемый действием A при нажатии.Эта операция из B не блокируется ProgressDialog, поэтому пользователь может вернуться к A до того, как AsyncTask, который B начал, заканчивает выборку данных.

Так что мне нужен способ обновления адаптера A из B.

У меня есть класс C со статическими данными, отображаемыми в ListView от A. Когда нажата кнопка в B, он добавляет это значение к C. Этот класс также имеет адаптер от A в качестве статического поля, но я думаю, что это приводит к утечке памяти из Context, и это плохо.Моей первой идеей исправить это было удаление статического адаптера из C и каждый раз, когда A onResume() (и если данные на адаптере отличаются от данных в C), я снова загружаю данные из C в адаптер и notifyDatasetChanged().Хорошо, это работает большую часть времени, но если пользователь возвращается к A из B до того, как B извлекает данные из Интернета, то адаптер не обновляется, поскольку onResume() пришел до того, как данные были извлечены.

Вопрос: есть ли лучший способ обновления адаптера A от B?

Ответы [ 2 ]

0 голосов
/ 18 февраля 2012

попробуйте позвонить mListView.invalidate();

** Java-документ

Недействительно весь вид. Если представление является видимым, onDraw (android.graphics.Canvas) будет вызван в определенный момент в будущем. Это должно быть вызвано из потока пользовательского интерфейса. Для вызова из не-пользовательского потока вызовите postInvalidate () .

0 голосов
/ 17 февраля 2012

Не сохранять статические ссылки на адаптер.Это действительно приведет к утечке памяти и плохому поведению.

Кажется, я неправильно понял первый раз.Вот обновленный ответ:

Первое решение

Самое красивое решение - реализовать поставщик контента для хранения данных и запросить этого поставщика контента как в А, так и в В.Обновите данные в B с помощью contentProvider.insert () и прочитайте данные с помощью contentProvider.query (), возвращая, например, SQLiteCursor, если он поддерживается базой данных, или MatrixCursor, если вы просто сохраняете их в памяти в поставщике контента.

Основные шаги (без CursorLoader):

  1. В onCreate of A вы регистрируетесь как contentobserver, используя ContentResolver.registerContentObserver(uri, true, this), где uri - это URI, используя некоторую заданную вами схему.
  2. В onCreate of A вы получаете данные, запрашивая контент-провайдер, используя ContentResolver.query(uri, projection, selection, selectionArgs, sortOrder), где projection, selection, selectionArgs и sortOrder могут быть тем, что подходит вашему контент-провайдеру (может быть, null).Uri относится к данным, которые вы хотите запросить, и является вашим выбором.
  3. Когда данные загружаются в B, вы звоните ContentResolver.insert()insert вашего контент-провайдера вы вызываете ContentResolver.notifyChange (Uri uri, null, null), где uri - это URI, который вы использовали на шаге 1.
  4. Реализация onChange (логическое selfChange) в A и запрос к поставщику контента при его вызове.

Обратите внимание, что вам вообще не понадобится вызывать registerContentObserver, если вы используете CursorLoaders!Он получит новый курсор в загрузчике, так как при уведомлении об изменении он автоматически запрашивает.

Второе решение Менее привлекательное решение - реализовать одноэлементный объект, который обрабатывает данные.Что-то вроде:

  1. Реализация класса

    public class DataHolder {
        private static DataHolder sDataHolder;
    
        private String data = ""; // Data represented by string.
        public DataHolder getInstance() {
            if (sDataHolder == null) {
                sDataHolder = new DataHolder()
            }
            return sDataHolder;
        }
    
        private DataHolder() {} // Hidden constructor
    
        public void setData(final String data) {
            mData = data;
    
            for (DataListener listener: mDataListeners) {
                listener.onDataChanged(mData);
            }
        }
    
        public void registerListener(DataListener listener) {
           mDataListeners.add(listener);
        }
    
        public String unregisterListener(DataListener listener) {
           mDataListeners.remove(listener);
        }
    
        public String getData() {
           return mData;
        }
    
        public static interface DataListener {
            public void onDataChanged(String data);
        }
    }
    
  2. Создание A реализует DataListener
  3. Чтение и обновление данных в onStart() изDataListener, чтобы убедиться, что он установлен, если изменение было сделано, когда B был жив, используя DataHolder.getInstance().getData().
  4. Зарегистрируйте слушателя в onCreate / onStart A, используя DataHolder.getInstance().registerListener(this); Позвольте слушателю обновить данные.
  5. Отмените регистрацию слушателя в onDestroy / onStop A, используя DataHolder.getInstance().unregisterListener(this)
  6. Установите данные и подайте сигнал любому слушателю в B, используя DataHolder.getInstance().setData(data)

Также обратите внимание, что вы можете сделать второе решениеполностью поточно-ориентированный, изменив void registerListener() на synchronized String registerListenerAndGetValue(), если вы также синхронизируете setValue.

Старый ответ, основанный на недоразумении

Мой старый ответ для общей обработки результатовне совсем ответил на вопрос, но это было:

Если вы хотите отправить данные обратно в упражнение A, вы должны сделать следующее:

  1. Всегда начинать B с startActivityForResult (Intent intent, int requestCode)
  2. Установить результат, когда сделано в B, используя setResult (int resultCode)
  3. Обработайте результат, когда вы вернетесь к A, выполнив onActivityResult (int requestCode, int resultCode, Intent data)

В качестве дополнения вы можете добавить, чтобы вы только в первый раз выбирали данные в A, выполняя это.только если savedInstanceState == null в, например, onCreate ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...