Parse & Android: рекомендации начинающим разработчикам

В данной статье Android-разработчик BytePace, Андрей Ващенко, хотел бы поделиться общими впечатлениями от использования BaaS — решения под названием Parse для разработки бэкэнда Android-приложения, рассказать о всех «подводных камнях», с которыми пришлось столкнуться в период разработки.

Впервые эту платформу мне посоветовали коллеги по работе, когда я был юниором, и за плечами был всего один коммерческий проект. Мотивацией к написанию данной статьи послужило большое количество потраченного времени для поиска совместимых версий библиотек и обдумывание странных решений разработчиков платформы. На всякий случай в конце оставлю все необходимые ссылки о том, что такое Parse.

Андрей Ващенко, Android-разработчик

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

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

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

Лайфхак № 2: используйте версию Parse server >= 2.7.2. Когда я скачал тестовый проект с Git, там был сервер версии 2.2.5, и вроде всё работало, но впоследствии вылез один баг: при сохранении координат геолокации lat и lng менялись местами.

И здесь было 2 случая: если координаты были <90 по модулю, то маркер на карте был просто в другом месте, иначе приложение ловило краш, и в консоль падал лог о том, что Lat не должен быть больше 90 по модулю.

В течение двух суток я искал решения. Чего я только не находил на разнообразных форумах и в 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); } }

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

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

Больше статей на:

22
Начать дискуссию