
Я хочу рассказать вам о библиотеке Chronos для Android (уровень API ›= 9), которая разработана, чтобы помочь вам выполнять длительные операции, такие как база данных или сетевые запросы.
Что мы пытаемся исправить?
Не секрет, что Android использует много асинхронных заданий. Очень немногие приложения работают исключительно в автономном режиме, без доступа к сети. И только небольшое число не требует взаимодействия с данными на устройстве - будь то база данных, настройки или файл. Однако за все время разработки платформы у нас не было ни одного готового решения для этого.

Что мы с этим сделали - краткая история
Давайте рассмотрим текущий набор инструментов в контексте задачи «завершить клик с помощью кнопки« авторизовать »». Что у нас есть?
1. Стандартная ветка
Практически все в этом коде плохо. Сложно читать, есть утечки памяти и это не отменяется. Он также не обрабатывает изменения поворота экрана или какие-либо ошибки вызова API (и если они обрабатываются, все становится действительно некрасиво).
2. AsyncTask
Это улучшение, но все еще недостаточно. AsyncTask обеспечивает понятную обработку ошибок и возможность отмены операций. Однако этот код по-прежнему не может должным образом обрабатывать изменения ориентации экрана в момент вызова API: ссылка на Activity, определяющая класс, теряется.
3. Загрузчик
Когда Google представил загрузчики, все думали, что они станут серебряной пулей для асинхронных заданий, заменив AsyncTasks, которые стали стандартным решением. К сожалению, этого не произошло. Сегодня загрузчики редко используются в коммерческих проектах, потому что их очень неудобно реализовать. Я не буду приводить пример кода в этом разделе, как это было с двумя другими. Вместо этого я призываю любопытного читателя взглянуть на официальное руководство по этому стеку, чтобы оценить объем кода, который требуется загрузчикам: developer.android.com/reference/android/content/AsyncTaskLoader.html
4. Сервис
Службы хороши для выполнения длительных задач, которые зависают в фоновом режиме в течение продолжительных периодов использования приложения. Однако сервисы имеют не идеальную структуру для запуска приложений, требующих немедленного результата. Самым большим ограничением является требование передачи данных через намерения, которые могут обрабатывать ограниченный объем информации и которые требуют, чтобы передаваемые данные имели некоторую форму итеративности. Популярная библиотека Robospice использует этот стек.
Что предлагает Chronos?

Chronos выполняет всю работу по выполнению задачи в параллельном потоке и передает результат или ошибку выполнения в основной поток. По сути, эта библиотека является контейнером для любых длительных операций. У нас есть полная вики по проекту: часть кода используется в этой статье, но ознакомьтесь с полным руководством github.com/RedMadRobot/Chronos/wiki.
Пример
Давайте рассмотрим стандартную задачу с помощью Chronos: Activity необходимо запросить определенный объект из определенного места, и доступ к нему занимает слишком много времени для обработки операции в потоке пользовательского интерфейса. Давайте сначала напишем код, а потом посмотрим, что у нас получится.
- Прежде всего, нам нужно добавить в проект Chronos. Для этого создайте зависимость в gradle:
2. Теперь опишем действие. Базовый класс ChronosActivity является одним из компонентов библиотеки, но вы можете написать свой собственный, используя примеры в документации. Вы также можете использовать тот же код Chronos для фрагментов.
3. Все, что осталось, - это описать бизнес-логику получения данных в классе MyOperation:
Вот и все! Давайте внимательно посмотрим, что происходит в коде, начиная с самого начала.
Настройка класса пользовательского интерфейса
Чтобы использовать Chronos, вы можете расширить базовый класс Activity или Fragment из библиотеки Chronos или включить определенный код в методы жизненного цикла, примеры которых можно найти в документации.
Запуск
Вызывается базовый метод класса ChronosActivity, куда передается вновь созданная операция. Затем Chronos помещает операцию в очередь и начинает выполнять ее в параллельном потоке в фоновом режиме.
Обработка результатов операции
Этот метод будет вызываться после выполнения операции или в случае возникновения исключения во время выполнения. Эти обработчики должны иметь подпись public void onOperationFinished (ResultType). Примечательно, что метод будет вызываться только между методами обратного вызова onResume () и onPause (), что означает, что вы можете возиться с пользовательским интерфейсом, не беспокоясь о том, что к этому моменту он станет недействительным. Более того, если Activity перезагружается из-за поворота экрана, перехода в фоновый режим по какой-либо другой причине, Chronos все равно будет возвращать результат (единственное исключение - если системе не хватает памяти - чтобы предотвратить OutOfMemory, Chronos может стереть старые результаты).
Откуда поступает звонок?
Вы могли заметить, что Activity не вызывает никаких конкретных интерфейсов. Так откуда же взялся этот метод? Ответ - отражение в коде. Это решение было принято с помощью TypeErasure в Java, который не позволяет одновременное выполнение одного и того же интерфейса шаблона с разными параметрами. Таким образом, мы использовали этот подход, чтобы позволить одному Activity обрабатывать результаты бесконечного числа операций.
Настройка классов операций
Класс ChronosOperation инкапсулирует бизнес-логику для получения определенного типа объекта - в данном случае BusinessObject. Все пользовательские операции должны быть расширены из ChronosOperation.
Бизнес-логика
Этот абстрактный метод класса ChronosOperation занимается бизнес-логикой получения объекта. Он выполняется в параллельном потоке, что позволяет выполнять длительные операции, не затрагивая интерфейс приложения. Более того, любые сгенерированные исключения будут переданы обратно вызывающему объекту, не вызывая сбоя приложения.
Название результата
Следующий метод и класс позволяют определить обработчик результатов для каждой конкретной операции в коде действия, используя класс в качестве типа параметра для метода onOperationFinished. Вы можете использовать один и тот же класс результатов для разных операций, если хотите, чтобы результаты обрабатывались одинаково.
Подводя итог, минимальный набор областей кода, необходимых для работы с Chronos, включает:
- Класс работы
- Код объекта пользовательского интерфейса для вызова операции
- Код объекта пользовательского интерфейса для обработки результатов
Что еще есть?
- Чтобы предотвратить потерю звонка после поворота экрана, Chronos позволяет« давать имя запускам операций»;
- Вы можете отменять операции;
- Если вам нужно, чтобы результаты операции возвращались не только объекту, который совершил вызов, а всем подписавшимся на него, вы можете создать Broadcast-запуски;
- Более того, вы можете выполнять операции синхронно с помощью класса Chronos.
Итак, где и почему вам следует использовать Chronos?
- Chronos следит за передачей данных между потоками, а это значит, что вам нужно беспокоиться только о бизнес-логике;
- Chronos соответствует нюансам жизненных циклов Activity и Fragment, возвращая результаты только тогда, когда они готовы к обработке, и сохраняя данные до тех пор.
- Chronos не создает утечек памяти. Вы не рискуете привести к сбою приложения из-за утечки слишком большого количества объектов Activity.
- Chronos покрыт юнит-тестами
- Наконец, Chronos - это проект с открытым исходным кодом. Вы всегда можете взять код и настроить его под свои нужды. Тесты позволяют легко проверять изменения кода.
Ознакомьтесь с проектом на GitHub. Он содержит полную документацию по библиотеке, примеры использования и, конечно же, исходный код.