Мое приложение использует OpenID для аутентификации пользователя.
Первая страница больше похожа на экран-заставку, которая перенаправляет пользователя на веб-страницу для авторизации, если это необходимо, или просто выполняет фоновое обновление токена для перехода к главному экрану.
Я не знаю, как запустить процесс аутентификации без нажатия кнопки
@Composable
fun LoginScreen(viewModel: LoginViewModel) {
val ctx = LocalContext.current
AppTheme {
Screen()
}
viewModel.performLogin(ctx)
}
Выполнение вышеуказанного работает, но затем оно снова вызывается, когда приложение переходит на главный экран.
fun loginComplete(navController: NavHostController) {
navController.navigate("main")
}
@Composable
fun MyApp(viewModel: LoginViewModel) {
val navController = rememberNavController()
viewModel.setOnLoginCompete(navController, ::loginComplete)
NavHost(navController, startDestination = "login") {
composable(route = "login") {
LoginScreen(viewModel)
}
composable(route = "main") {
MainScreen()
}
}
}
Я не думаю, что должен вызывать функцию PerformLogin, как в функции Composable, но я не вижу другого пути. Что мне не хватает?
Вы можете связать свой поток с обратными вызовами жизненного цикла. Вы можете создать компонуемую утилиту для обработки событий жизненного цикла.
@Composable
fun OnLifecycleEvent(onEvent: (owner: LifecycleOwner, event:Lifecycle.Event) -> Unit) {
val eventHandler = rememberUpdatedState(onEvent)
val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current)
DisposableEffect(lifecycleOwner.value) {
val lifecycle = lifecycleOwner.value.lifecycle
val observer = LifecycleEventObserver { owner, event ->
eventHandler.value(owner, event)
}
lifecycle.addObserver(observer)
onDispose {
lifecycle.removeObserver(observer)
}
}
}
И используйте это так, если вы хотите начать ведение журнала, когда ваше приложение выходит на передний план:
@Composable
fun MyApp(viewModel: LoginViewModel) {
...
OnLifecycleEvent { owner, event ->
when (event) {
Lifecycle.Event.ON_RESUME -> { viewModel.performLogin(ctx) }
else -> { ... }
}
}
}
На самом деле я использовал этот вопрос и ответ на него в качестве источника
Другой способ, который вы можете использовать, заключается в следующем
Давайте пошагово :)
Первый шаг : ViewModel должен реализовать интерфейс DefaultLifecycleObserver.
@HiltViewModel
class LoginViewModel @Inject constructor(
private val savedStateHandle: SavedStateHandle
) : ViewModel(), DefaultLifecycleObserver {
}
таким образом вы можете получить доступ к этим методам:
public interface DefaultLifecycleObserver extends FullLifecycleObserver {
/**
* Notifies that {@code ON_CREATE} event occurred.
* <p>
* This method will be called after the {@link LifecycleOwner}'s {@code onCreate}
* method returns.
*
* @param owner the component, whose state was changed
*/
@Override
default void onCreate(@NonNull LifecycleOwner owner) {
}
/**
* Notifies that {@code ON_START} event occurred.
* <p>
* This method will be called after the {@link LifecycleOwner}'s {@code onStart} method returns.
*
* @param owner the component, whose state was changed
*/
@Override
default void onStart(@NonNull LifecycleOwner owner) {
}
/**
* Notifies that {@code ON_RESUME} event occurred.
* <p>
* This method will be called after the {@link LifecycleOwner}'s {@code onResume}
* method returns.
*
* @param owner the component, whose state was changed
*/
@Override
default void onResume(@NonNull LifecycleOwner owner) {
}
/**
* Notifies that {@code ON_PAUSE} event occurred.
* <p>
* This method will be called before the {@link LifecycleOwner}'s {@code onPause} method
* is called.
*
* @param owner the component, whose state was changed
*/
@Override
default void onPause(@NonNull LifecycleOwner owner) {
}
/**
* Notifies that {@code ON_STOP} event occurred.
* <p>
* This method will be called before the {@link LifecycleOwner}'s {@code onStop} method
* is called.
*
* @param owner the component, whose state was changed
*/
@Override
default void onStop(@NonNull LifecycleOwner owner) {
}
/**
* Notifies that {@code ON_DESTROY} event occurred.
* <p>
* This method will be called before the {@link LifecycleOwner}'s {@code onDestroy} method
* is called.
*
* @param owner the component, whose state was changed
*/
@Override
default void onDestroy(@NonNull LifecycleOwner owner) {
}
}
Второй шаг: В Composable вызовите метод, который я отправил во вложение, как показано ниже.
создайте функцию расширения следующим образом:
@Composable
fun <LO : LifecycleObserver> LO.ObserveLifecycle(lifecycle: Lifecycle) {
DisposableEffect(lifecycle) {
lifecycle.addObserver(this@ObserveLifecycle)
onDispose {
lifecycle.removeObserver(this@ObserveLifecycle)
}
}
}
Назовите это в своем компоновщике следующим образом
@Composable
fun LoginScreen(viewModel: LoginViewModel) {
viewModel.observeLifecycle(LocalLifecycleOwner.current.lifecycle)
}
Третий шаг: Реализуйте свою логику во ViewModel и если вы собираетесь перейти на другую страницу, сообщите Composable by Event
LoginViewModel.kt
override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
}
Да, это глобальная функция, которую вы можете использовать в каждом проекте.
Можете ли вы объяснить больше о функции расширения? Это просто глобальная функция?