Перейти к основному содержанию
`Ctrl`+`K`

# Введение

## Ключевые возможности

- Перенос вычислений в серверный поток
  Главный поток никогда не блокируется: фрейм-рендер выполнился — задача ушла в очередь, анимация пользовательского интерфейса не зависит от бизнес-логики.

- Хранение данных

- Транзакционная обработка данных GsSession:

  - SQLite, файлы, сетевые отклики — коммитятся или откатываются одним вызовом.

  - Встроенный генератор ID и горячий кэш сущностей.

- Автоматизация работы с инъекциями зависимостей

- Адаптированный MVVM-паттерн

- Навигация между представлениями

- Планирование серверных команд
  Позволяет избавиться от сложных асинхронных запусков.

- Observable-слой данных
  `RecordSet`, `SingleRecord`, `RecordValue<T>` передают изменения сразу в Compose-дерево, без необходимости писать адаптеры.

- Плагин-подход к железу
  `ActivityPlugin` регистрируется в `GsBaseActivity`; доступ к NFC или камере получаем без Dagger/Hilt.

- Горячий офлайн
  Легко настраивать работу, копить данные и синхронизировать по необходимости
  за счёт встроенной поддержки БД.

- Простое тестирование
  `State`/`VCI` можно запустить с `database = null`, логика тестируется без Android-эмулятора, при этом транзакционная модель сохраняется.

## Архитектура

### Взаимодействие слоев

### Основные понятия

- Главный поток (`mainThread`) — поток взаимодействия с пользователем; этот поток не должен блокироваться. Рендерит Compose, обрабатывает жесты и никогда не исполняет длительных операций.

- Серверный поток (`serverThread`) — поток для выполнения синхронной бизнес-логики и синхронизации с асинхронными задачами. Последовательно выполняет SQL, операции с файлами, трансформации стека и любые другие долгие операции. Все вызовы VCI к тяжёлым ресурсам отправляются сюда через `postSharedTask` или `postAsyncTask` (минуют карусель событий).

- Сессия (GsSession) — сессия работы с данными.
  Содержит контекст для хранения и управления компонентами, необходимыми для обработки данных.

- Состояние (`State`) — содержит данные и бизнес-логику представления, работающую в серверном потоке.

- Стек состояний — хранит историю открытых представлений. Верхнее представление отображается на экране.
  Позволяет пользователю возвращаться на предыдущее представление.

- Контроллер представления (`VCI`) — содержит данные и бизнес-логику представления в главном потоке.

- Представление (`VcpScreen`) — декларация правил отрисовки представления с использованием библиотеки Compose.

- Контроллер сессии (`Api`, `Pkg`) — контроллер сессии обрабатывает бизнес-логику в серверном потоке в разрезе сущностей базы данных или их групп.

- Навигатор (`Navigator`) — занимается компоновкой и управлением представлениями приложения.

- Главная активность (`MainActivity`) — точка входа Android-приложения, подробнее смотрите руководство по разработке на платформе Android.

### Отдельный серверный поток

Отдельный серверный поток для выполнения бизнес-логики лучше, чем рассыпанные потоки `launch(Dispatchers.IO)`, так как позволяет достичь:

- более высокой производительности на последовательных вычислениях за счёт отсутствия необходимости
  межпотоковой синхронизации;

- более простой разработки и отладки за счёт:

  - последовательного выполнения, что позволяет использовать классические принципы структурного программирования;

  - полностью воспроизводимого stack trace —
    нет прыжков между диспатчерами;

  - декларативной двусторонней синхронизации между главным и серверным потоком;

  - контролируемой отмены:
    `InterruptingLock.validate()` бросит исключение на любой стадии, стек откатится, а UI мирно вернётся к последнему стабильному экрану.

### Адаптированный MVVM-паттерн

Обеспечивает:

- Предсказуемый интерфейс
  Стабильный FPS даже на сложных формах.

- Единый стиль
  Все экраны одинаково устроены, code review смотрит в основном на логику, а не на повторяющиеся слои.

Детализация принципа view–viewmodel–model:

- `View` — декларация интерфейса на Compose-UI, объявляется в VCI.

- `viewmodel` — разбит на 2 слоя для отделения бизнес-логики главного и серверного потоков:

  - VCI — бизнес-логика для работы в главном потоке, а также подписка на данные `state`.

  - State — бизнес-логика для работы в серверном потоке, а также сбор данных для представления.

- `model`:

  - Api — контроллер таблицы для обработки хранимых данных;

  - Entity — модель хранимых данных.

#### Жизненный цикл экранов

Таблица ниже отображает карусель событий, которые произойдут при открытии и закрытии экрана.

Событие | Когда вызывается | Что делать
--- | --- | ---
`onInit`(State, VCI) | Сразу после создания, синхронно | Подготовить запросы к БД, инициализировать `RecordSet`
`afterPush`(State) | State помещён в стек | Подписаться на шину, запустить лёгкие preload-задачи
`onVisit() : SmTrans`(State) | Сразу после push, но до `afterEnter` | Вернуть `SmTrans` для мгновенного перенаправления (например Splash → Login) или `null`
`afterEnter`(State) | Каждый раз, когда State стал активным | Обновить данные, запустить `postSharedTask`; триггерится на каждую фоновую задачу
`afterEnter`(VCI) | UI создан и синхронизирован с главным потоком | Восстановить scroll-позицию, открыть диалоги, получить данные из State — главная точка синхронизации перед показом экрана
`beforeExit`(VCI) | UI ещё на экране, но пользователь уходит | Сохранить scroll, закрыть диалоги, очистить временные данные
`beforeExit`(State) | UI уже закрыт, транзакция ещё открыта | `flush()` RecordSet, финальные изменения в БД, подготовка к уходу
`onError(e)`(State) | Любая необработанная ошибка внутри State | Вернуть `SmTrans` на экран ошибки или кастомизировать обработку
`onClose`(State) | State удалён из стека окончательно | Отписаться от шины, освободить ресурсы

### Дополнительные понятия

- Менеджер состояний(`StateManager`) - отвечает за обработку очереди событий для серверного потока и транзакционной логики обработки переходов между состояниями. StateManager обращается к UI из серверного потока безопасно через блокировки, поэтому состояние стека остаётся консистентным.

## Тестирование и масштабирование

- Любой `State` и `VCI` можно запустить с `database = null` логика тестируется без эмулятора, транзакционная модель при этом сохраняется.

- Новый экран требует три файла — `State`, `VCI`, `Compose-View` — и не затрагивает существующий код; команда растёт линейно, не переписывая инфраструктуру.