Руководства
Самостоятельный менеджер состояния приложения
Использование Ark MVP без UseCase Forge и предоставление стабильного ModelBinding через BuildContext.
Самостоятельный менеджер состояния приложения
В этом сценарии используется обычный неизменяемый ApplicationState и широковещательный Stream. В реализации функции нет ни одного типа UseCase Forge.
Такой вариант подходит для состояния уровня приложения: авторизованной сессии, выбранного языка или набора возможностей среды выполнения. Менеджер владеет бизнес-состоянием, а MVP адаптирует нужную одному экрану часть.
1. Предоставьте состояние и сигналы изменений
Менеджер владеет актуальным ApplicationState, публикует сигналы и предоставляет именованные операции, например toggleTheme() или selectLanguage().
final class ApplicationStateManager {
final StreamController<ApplicationState> _changes =
StreamController<ApplicationState>.broadcast();
ApplicationState _state = const ApplicationState(
userName: null,
language: 'en',
);
ApplicationState get state => _state;
Stream<ApplicationState> get changes => _changes.stream;
void toggleSession() {
_state = ApplicationState(
userName: _state.userName == null ? 'Ada' : null,
language: _state.language,
);
_changes.add(_state);
}
Future<void> close() => _changes.close();
}
2. Соберите ModelBinding
Композиция читает актуальное состояние приложения и захватывает только необходимые экрану операции. ModelBinding наблюдает Stream менеджера.
final ModelBinding<ApplicationModel> binding =
ModelBinding<ApplicationModel>(
read: () => ApplicationModel(
state: manager.state,
toggleSession: manager.toggleSession,
toggleLanguage: manager.toggleLanguage,
),
changes: <Stream<Object?>>[manager.changes],
);
Model не предоставляет сам менеджер. Контракт экрана остаётся небольшим, а Presenter не получает доступ к посторонним операциям уровня приложения.
3. Предоставьте ModelBinding через контекст
MvpModelProvider<ApplicationModel>.value(
binding: applicationBinding,
child: const ApplicationScreen(),
)
Вложенный MvpView<ApplicationModel, ...> не передаёт прямой аргумент model. Поиск определяется точным типом Model; её интерфейсы не регистрируются автоматически.
MvpView<ApplicationModel, ApplicationViewState, Never,
ApplicationPresenter>(
createPresenter: ApplicationPresenter.new,
builder: (context, viewState, presenter) => ApplicationScreenBody(
greeting: viewState.greeting,
environmentLabel: viewState.environmentLabel,
sessionAction: viewState.sessionAction,
languageAction: viewState.languageAction,
onSessionPressed: presenter.toggleSession,
onLanguagePressed: presenter.toggleLanguage,
),
)
Тип эффекта Never выбран потому, что экран не создаёт одноразовых событий
представления. Это не означает, что эффектов следует избегать на всех экранах.
4. Безопасно используйте окружение представления
FlutterPresenter.buildViewState(context) может читать Theme, локаль и направление текста при формировании ViewState. Контекст нельзя сохранять. Публичные действия принимают явные параметры или вызывают разрешённые операции Model.
@override
ApplicationViewState buildViewState(BuildContext context) {
final bool russian = model.state.language == 'ru';
final Brightness brightness = Theme.of(context).brightness;
final TextDirection direction = Directionality.of(context);
return ApplicationViewState(
greeting: model.state.userName == null
? (russian ? 'Гость' : 'Guest')
: (russian
? 'Здравствуйте, ${model.state.userName}'
: 'Hello, ${model.state.userName}'),
sessionAction: model.state.userName == null
? (russian ? 'Войти' : 'Sign in')
: (russian ? 'Выйти' : 'Sign out'),
languageAction: russian ? 'Switch to English' : 'Переключить на русский',
environmentLabel:
'Theme: ${brightness.name}; direction: ${direction.name}',
);
}
BuildContext читается во время преобразования, потому что Theme и направление текста относятся к окружению Flutter-представления. Model не зависит от Flutter, а Presenter не сохраняет контекст.
5. Сохраните явное владение
Внешний виджет создаёт и закрывает менеджер. MvpModelProvider.value предоставляет ModelBinding, но не становится владельцем менеджера. MvpView создаёт и закрывает Presenter.
@override
void dispose() {
unawaited(manager.close());
super.dispose();
}
Этот пример показывает область универсальности Ark MVP: пакет задаёт границу представления, а приложение самостоятельно выбирает механизм бизнес-состояния.