Pull to refresh

Comments 8

Спасибо за статью! Интересно читать опыт других людей.

Мы для работы с json используем AndroidAnnotations Rest API (для получения с сервиса json) + Jackson (парсинг). Тоже работает отлично, падений по памяти замечено не было. Ну это, так сказать, может кому-то пригодится наш опыт :)
Захотелось придраться :)

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

Во-вторых, раз уж вы грузите такие объемы, пихать их все распаршенными в память в любом случае неправильно, т.к. даже если вы сначала запишите весь ответ от сервера в файл или распарсите его целиком налету, то вы же все равно можете выпасть с OutOfMemoryError после его парсинга, решение с файлом и потоковым парсингом всех записей просто сократило вам потребление памяти ~ в 2 раза. Так что, смею заявить, что все предложенные способы упадут с OutOfMemoryError на еще более больших объемах данных.

Как бы сделал я (надеюсь не придется с таким апи работать), я бы последовательно парсил элементы прямо из InputStream от сервера и писал их в БД, зачем? Чтобы минимизировать расходы по памяти, т.к. InputStream освобождается при чтении, а все элементы в памяти мы не храним, пишем все в БД. Соответственно, потом надо будет просто извлекать их уже из БД при отображении в списке.

Естественно, писать в БД можно не прямо последовательно, а накапливая небольшой буфер в памяти. Так же и с чтением из БД при отображении в списке, можно подгружать следующие паки данных из БД пока пользователь не докрутил список до них, можно держать небольшой кеш данных в SoftHashMap чтобы не дергать БД постоянно. Вот как то так :)
В целом согласен (правда я замерял, разница не в 2 раза, а даже больше, и тем не менее).

Но, если мне нужно скачать за один раз не пачку однотипных объектов, а 5-6 разных типов? Сделать 5 отдельных запросов, а далее парсить каждый… я пробовал, получается медленнее и дольше.

Это первая загрузка данных, последующие тянут только диффы. Так что не всё так страшно. Устанавливая 2Гис тоже первый раз скачиваешь карту, но работа в оффлайне того стоит. ;-)
В свое время решил данную проблему с помощью
 JsonReader reader = new JsonReader(new InputStreamReader(is, "UTF-8"));

это аналог SAX парсера для XML, только в отношении Json.
Определяешь какие секции тебе нужны и итеративно их пробегаешь и парсишь.
Метод геморойный, так как это почти ручной парсинг, но самый лучший по использованию памяти,
так как сам определяешь что оставить, а что взять в обработку.
Совместно с описанным выше импортом в базу, самое оптимальное решение.
Да, я об этом методе упомянул. На него есть резон переходить, если текущий не срабатывает, скажем разница в скорости будет большой или в потреблении памяти. Так что кому-нибудь пригодится, безусловно)
Минус – не удастся контролировать процесс скачивания (прервать его адекватным способом), а так же – неизвестно, сколько уже скачано данных. Красивый прогресс-бар не нарисуешь.

Ошиаетесь. Вполне себе стандартный трюк — написать врапер стрима который бы подсчитывал сколько байт через него прошло. Писал и использовал на практике. Начните копать с FilterInputStream, но можно и без него, главное понимание стримов вообще. И прервать его можно вполне адекватно если знать матчасть.
Как оказалось Swing уже содержит образец тыц
Sign up to leave a comment.

Articles