Аннотация


В данной статье я бы хотел поделиться общими впечатлениями от использования BaaS – решения под названием Parse для разработки бэкэнда Android-приложения, рассказать о всех «подводных камнях», с которыми мне пришлось столкнуться в период разработки. Впервые эту платформу мне посоветовали коллеги по работе, когда я был юниором, и за плечами был всего 1 коммерческий проект. Мотивацией к написанию данной статьи послужили нервы и время, которые я потратил для поиска совместимых версий библиотек и обдумывание странных решений разработчиков платформы, ну или просто потому, что я до сих пор не нашел статей по этому поводу. Так же я ничего не буду рассказывать о том, что такое Parse и как его подключить и настроить, но на всякий случай я оставлю все необходимые ссылки, где можно почитать об этом.

Проблема №1: Использование Parse Server в связке с PostgreSQl


Использование данной конфигурации было обусловлено тем, что сервер был развернут на VDS-хостинге, и использование удаленной базы MLab было нецелесообразно, ибо на момент разработки Роскомнадзор пытался блокировать Telegram в России, и были проблемы с соединением без VPN. Настраивать VPN на консольной Линухе времени не было, а проект горел, поэтому решил использовать локальную базу на серваке. Я выбрал PostgreSQL, потому что с ней у меня был хороший опыт работы.

Лайфхак №1: чтобы база работала без ошибок в типах данных, при установке postgres нужно установить postgis. После чего, необходимо создать базу и сразу же после создания создать подключить все расширения postgis. О том как подключить расширения postgis к базе, можно почитать тут: После того, как все расширения подключены, можно подключать базу к серверу, открыть dashboard и посмотреть, что таблицы созданы без ошибок.

Лайфхак №2: используйте версию Parse server >= 2.7.2. Когда я скачал тестовый проект с гита, там был сервер версии 2.2.5, и вроде всё работало, но в последствии вылез один баг: при сохранении координат геолокации lat и lng менялись местами. И тут было 2 случая: если координаты были < 90 по модулю, то маркер на карте был просто в другом месте, иначе приложение ловило краш, и в консоль падал лог о том, что Lat не должен быть больше 90 по модулю. Тут у меня начался 2хдневный тупняк в поисках решений. Чего я только не находил на разнообразных форумах и в github issues: переворот координат в Cloud-функции (не работает!); переворот координат в PostgresStorageAdapter (после изменений возникла кучка ошибок, я не захотел вникать под конец рабочего дня, выключил комп и ушел). На следующий день заглянул в релизы, и увидел, что в версии 2.7.2 был пофикшен баг в PostgresStorageAdapter. Быстро исправил версию в package.json, и о чудо, всё заработало как надо. На этот момент уже была версия 3.х.х, и я попытался её использовать, но разработчики внесли много изменений, связанных с Cloud-функциями, и при запуске высыпалась еще одна кучка ошибок. Времени исправлять рабочий код не было, поэтому версия 2.7.2 мне подошла как нельзя кстати. Если же вы только начали свой проект, то конечно же лучше использовать свежую версию.

Проблема №2: Не отписываются LiveQuery


На решение данной проблемы я потратил чуть больше одного дня. И она была чертовски странной и неочевидной.

Изначально архитектура была примерно такой:

public class Subclass extends ParseObject {
    // init columns, create getters & setters
}

public class QueryHelper {
    public static ParseQuery getQuery(Param... params) {
        ParseQuery query = ParseQuery.getQuery(Subclass.class);
        // init query by params
        return query;
    }
}

public class MainActivity extends Activity {
    public void onResume() {
        ParseLiveQueryClient.getClient().subscribe(QueryHelper.getQuery(), callback);
    }

     public void onPause() {
        ParseLiveQueryClient.getClient().unsubscribe(QueryHelper.getQuery(), callback);
    }
}

И при выходе с экрана метод вызывался, но запрос не отписывался. Как известно, LiveQuery подписывается по запросу, и любое изменение данных, соответствующих запросу, можно отследить в колбэке. Отписка так же происходит по запросу. В методе подписки возвращается объект Subscriber, но этот объект абсолютно бесполезен, потому что метода «отписаться» он не содержит, и сам LiveQueryClient не содержит метода «отписаться» с параметром Subscriber. Включив дебаг, начал пошагово заходить в тот самый метод «отписаться». В самом клиенте приватно хранится лист подписок. В методе разработчики проходятся по этому листу циклом и сравнивают запрос из параметра с приватным запросом, который хранится в объекте подписки непереопределенной функцией equals, которая соответствует обычному ==, и которая сравнивает адреса у сложных объектов. И это всё объясняло, потому что в моем проекте был класс с функциями, который создавал мне нужный запрос. И так как объект запроса всегда создавался заново, следовательно, адреса у запросов были разные, equals не срабатывал, и отписка не происходила. Решил я эту проблему следующим образом: сделал singleton, и всё заработало.

Выглядеть это стало примерно так:

public class Subclass extends ParseObject {
    // init columns, create getters & setters
}

public class QueryHelper {
    public static final ParseQuery query;
    
    public static ParseQuery getQuery(Param... params) {
        if (query == null) {
            query = ParseQuery.getQuery(Subclass.class);
            // init query by params
        }
        return query;
    }
}

public class MainActivity extends Activity {
    public void onResume() {
        ParseLiveQueryClient.getClient().subscribe(QueryHelper.getQuery(), callback);
    }

     public void onPause() {
        ParseLiveQueryClient.getClient().unsubscribe(QueryHelper.getQuery(), callback);
    }
}

Спустя некоторое время пришла идея о написании собственного менеджера, который будет следить за подписками, но я это так и не реализовал.

Заключение


Надеюсь, данная статья принесет пользу. Если вы нашли какие-нибудь неточности или ошибки, напишите мне. Как и обещал, оставлю ссылки на несколько хороших источников, которые помогли мне:


Всем удачи!

Комментарии (0)