Как иногда плохой код и антипаттерн решают

Привет %username%!

Сегодня я хотел бы рассказать о том, как мне помог в проекте плохой код :)

Кому интересно, под кат

Достался мне в наследство проект на сопровождение. Не знаю кем писался, но этому человеку икается и по сей день. Суть такая — есть приложение для сбора фотоотчетов в магазине и их отправке руководству на сервак.

Все вроде просто, но были постоянные жалобы сотрудников на падение приложения при фотографировании. Анализ кода показал, что при вызове intent приложения камеры, Android убивал приложение из-за нехватки ресурсов и по возвращению результата в активити, последняя пересоздавалась и не содержала нужных для работы данных. Пересоздание активити просто не обрабатывалось. Ну да, есть же configChanges *sarcasm*

Шаг 1. Обработка пересоздания.

Помучавшись 2 дня, поправив код, выкинув повторяющиеся фрагменты я принялся тестировать. Закинул в эмулятор taskkiller, запустил камеру, убил процесс. Фоткаю — красота!!! Все красиво, фотка есть. Нажимаю сохранить и… бабах) Приложение упало.

Шаг 2. Singleton — злое зло.

Причина падения — нет данных о текущем отчете. Оказалось, что в приложении был чудо-синглтон, который хранил в себе ВСЕ! Абсолютно все критические данные, необходимые для работы приложения и даже больше. Это и токен авторизации, и 40 полей состояния отчета и ссылки на классы, описывающие отчет и геоданные юзера и еще пару коллекций Bitmap. В одно мгновение мы лишились всего, чего только можно было лишиться.

Результат был описан заказчику. Рефакторинг оценен, но столько денег у них не оказалось. При этом слезно попросили что-то сделать и наставить костылей.

Шаг 3. Меняем Singleton.
Все, что пришло в голову — исправить синглтон так, чтобы он стал надежным и при этом абсолютно не поменялся его интерфейс. Придумано было следующее — все что только можно запихнуть в SharedPreferenses сохранялось туда.

public String getAuthToken() {
        return getStingFromPref(AUTH_TOKEN);
}
.....
// и так далее.

Грубо, тупо, зато не нужно менять код во всем проекте и наш Singleton стал более устойчив (остались коллекции Bitmap, с которыми пока ничего не сделал). Все объекты, которые только можно сериализовать были сериализованы и тоже запихнулись в SharedPreferences.

Приложение ушло на тест, в прод и падения прекратились на 70% устройств. На остальных после отправки результата с камеры, пересоздавалась не текущая, а предыдущая активити в стеке. Для меня это пока загадка. Гуру — объясните в комментах.
Суть такая — Активити А стартует Активити Б с получением результата. Активити Б запускает intent камеры с получением результата.
Когда в процессе работы камеры процесс убивался, по созданию фотки пересоздавалась активити А. У активити Б не вызывался ни onCreate, ни onActivityResult. (P.S. Android 4.4)

goggle и stackowerflow ответа не дали, пришлось идти другим путем и писать больше плохого кода.

Если пересоздать не получается, можно запретить убивать, подумал я и перешел к шагу 4.

Шаг 4. Финальный. Foreground-мусоровоз.

Как же заставить Android не убивать процесс? Мои мысли были такими: «Если сказать операционке, что у нас есть важный foreground сервис, выполняющий важные нам вычисления ровно столько времени, сколько мы фоткам товар. Это определенно может сработать».

Так родился в проекте foreground-мусоровоз. Он гонял цикл от 0 до 60 и в теле засыпал на секунду. Как только приходил результат с камеры — сервис убивался. Приложение было собрано и отдано на тестирование.
Результат — KitKat оказался умнее и прибивал процесс. То-есть не изменилось ничего.

Я уже было отчаялся, когда мне в голову пришла еще одна мысль: «А если тупо сохранить ссылку на активити в синглтоне и вызвать startActivityForResult прямо из foreground-мусоровоза?». Я никогда так не делал и, надеюсь, больше не придется.

Приложение собрано, отдано в тест и… о чудо, процесс больше не закрывался.

Вместо заключения. Заказчик предупрежден, что у него плохое приложение и я сделал его еще хуже, но оно работает так как этого ждут сотрудники компании.

Напоследок. Расскажите про свой самый «плохой код» в карьере. Давайте поднимем друг другу настроение:)

© Habrahabr.ru