Jetpack Compose — как инициировать событие при составлении экрана

Мое приложение использует 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, но я не вижу другого пути. Что мне не хватает?

3
0
660
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете связать свой поток с обратными вызовами жизненного цикла. Вы можете создать компонуемую утилиту для обработки событий жизненного цикла.

@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)
 }

Можете ли вы объяснить больше о функции расширения? Это просто глобальная функция?

Ne0 11.11.2022 12:37

Да, это глобальная функция, которую вы можете использовать в каждом проекте.

Vahid Garousi 11.11.2022 13:21

Другие вопросы по теме