【问题标题】:Jetpack Compose - How to trigger an event when a screen is composedJetpack Compose - 如何在屏幕合成时触发事件
【发布时间】:2023-02-24 11:01:54
【问题描述】:

我的应用程序使用 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 函数,但我看不到其他方法。我错过了什么?

【问题讨论】:

    标签: android kotlin android-jetpack-compose


    【解决方案1】:

    您可以将流程与生命周期回调联系起来。您可以创建可组合的实用程序来处理生命周期事件。

    @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 -> { ... }
           }
        }
    }
    

    我实际上使用this question and its answer 作为来源

    【讨论】:

      【解决方案2】:

      您可以使用的另一种方法如下

      让我们一步一步来吧:)

      第一步 : 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
      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

      LoginViewModel.kt
       override fun onResume(owner: LifecycleOwner) {
              super.onResume(owner)
       }
      

      【讨论】:

      • 你能解释一下扩展功能吗?它只是一个全局函数吗?
      • 是的,它是一个全局函数,您可以在每个项目中使用它
      • IMO,这个答案比公认的更好。
      猜你喜欢
      • 2022-10-23
      • 2022-10-25
      • 2023-03-28
      • 1970-01-01
      • 2021-09-02
      • 2022-11-01
      • 2023-03-07
      • 2022-11-07
      • 2021-10-27
      相关资源
      最近更新 更多