У нас было 500 страниц спецификаций, 40000 строк кода, 2 офиса, полдюжины разработчиков, а также целое множество андроидов всех сортов и расцветок. Не то, чтобы это был необходимый запас для приложения крупной торговой сети. Но если начал собирать софт, становится трудно остановиться. Единственное, что вызвало у меня опасение — это сетевая библиотека. Нет ничего более беспомощного, безответственного и испорченного, чем писать AsyncTask на каждый вызов. Я знал, что рано или поздно мы перейдём на Event Bus.
Август 2014, DevDay, Новосибирск
6. МАГАЗИНЧИК
• 500 страниц документации.
• В том числе 200 страниц
описания API.
• Большое количество сложных
use-cases.
• Разветвлённая логика и схема
зависимостей.
7. МАГАЗИНЧИК
• 4 человеко-года на каждую платформу (iOS,Android).
• 6 разработчиков в команде Android.
• Общий размер команды — до 27 человек.
• ≈40000 строк кода.
8. ОСОБЕННОСТИ
• Android 4.0+
• Одно действие — один запрос.
• Настройками кэширования занимается сервер.
• Ссылки для последующих запросов приходят с сервера.
9. ПРОБЛЕМЫ
• Много разнородных запросов (около 100 в последней
версии API).
• Компонент-инициатор != компонент-получатель.
• Инициаторов может быть несколько.
• Получателей тоже!
10. КАК ДЕЛАТЬ ЗАПРОСЫ
• In-place AsyncTask.
• AQuery и иже с ними.
• Сервисы, контент-провайдеры, броадкасты…
• Реактивное программирование.
11. ЧЕМ ПЛОХИ ASYNCTASK
• Очень сложно переиспользовать.
• Очень много boilerplate-кода.
• Гроб, гроб, кладбище, утечка контекста.
requestDataTask = new AsyncTask<Void, Void, JSONObject>() {
@Override
protected JSONObject doInBackground(Void... params) {
final String requestResult = apiService.getData();
final JSONObject json = JsonUtils.parse(requestResult);
lruCache.cacheJson(json);
return json;
}
};
13. ПОЧЕМУ НЕ КАТИТ AQUERY
• Слишком локальное применение.
• Опять же — много повторяющегося кода.
• Сложно прикручивать другие библиотеки.
aq.ajax("http://example.com", String.class, CACHE_TIME, new AjaxCallback<String>() {
@Override
public void callback(String url, String object, AjaxStatus status) {
Type listType = new TypeToken<List<User>>() {}.getType();
List<User> list = new Gson().fromJson(object, listType);
listener.onResponse(list);
}
});
16. ЧТО НЕ ТАК С CP
• Дважды конструируем
объект (при разборе
результата запроса и
при десериализации из
БД).
• Нужно инвалидировать
данные. Зачем нам SQL?
Нам SQL не нужен
25. OTTO
• Подписка на события через
аннотации.
• Подписались на то, что не
приходит — не страшно.
• Приходит то, на что не
подписывались — не беда!
public class BaseFragment extends Fragment {
protected Bus bus = AzbukaApplication.getBus();
@Override
public void onResume() {
super.onResume();
bus.register(this);
NetworkFacade.cancelOldRequests(this);
}
@Override
public void onPause() {
super.onPause();
bus.unregister(this);
NetworkFacade.markToCancel(this);
}
26. ЧЕМ МАНИПУЛИРУЕМ
• BaseRequest — инкапсулирует парсинг и рассылку
сообщений
• BaseResponse — bean + id
public static class PutUserNickRequest extends BaseRequest<PutUserNickResponse, NewUserNick,
PutUserNickError> {
/**
* API v0.36 p. 74, Change user password (4.10.4)
* @param url - POST /user/<user-id>/phone
* @param nick - typed nick
*/
public PutUserNickRequest(String url, String nick) {
super(Method.PUT, url, PutUserNickResponse.class, PutUserNickError.class, new
NewUserNick(nick));
}
}
27. ПОДПИСКА
• Нам не важно, кто отправил.
• Нам нужно лишь уметь обрабатывать данный тип ответа.
• Кто на экране — тот и главный!
@Subscribe
public void onResponse(BasketRequest.BasketContentResponse basketContentResponse) {
loadWelcome();
}
@Subscribe
public void onError(OtherError error) {
if (TextUtils.isEmpty(error.getMessage())) {
Toast.makeText(getActivity(), getString(R.string.failed), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getActivity(), error.getMessage(), Toast.LENGTH_LONG).show();
}
}
28.
29. LET IT CRASH
• Есть одна точка получения данных об ошибке.
• Есть один общий workflow обработки ошибки.
• При особой надобности — можем подписаться на
ошибки конкретного класса.
31. ПЛЮСЫ И ПЛЮШКИ
• Лёгкая проверка работоспособности back-end.
• Часть приложения сделана как конечный автомат на
основе Event Bus.
• Архитектура «непривязанных запросов» отлично ложится
почти на любое приложение.
32. СПАСИБО ЗА ВНИМАНИЕ
А ещё я в твиттере есть,
меня @0leGG зовут,
там 0 как нолик,
а не как Олежка.