Android调用组件w/listener或让视图模型调用组件与片段通信



我正在使用视图模型从片段调用登录方法。我一直在其他领域使用很多回调,但阅读使用MVVM,我不应该以这种方式在片段和视图模型之间进行通信。Android文档似乎也使用了LiveData。为什么可以为组件(如recyclerview的适配器)设置侦听器,而不是为从视图模型调用的其他组件设置侦听器?

签名组件在Splash片段中。我应该将其作为视图模型之外的组件调用并利用侦听器吗?

我遇到了一个错误,想给用户反馈。我:

  1. 将组件从视图模型中取出,并直接从片段
  2. 中调用它
  3. 将组件留在视图模型中,并利用livedata向片段/用户提供反馈?
  4. 将signin组件留在视图模型中,只使用回调/监听器

更新

谢谢你的反馈。我将提供更多细节。我正在使用Java,仅供参考。我关注的是第一次运行的过程,它不同于显示列表或详细数据。所以,我需要做很多事情来让应用为第一次使用做好准备,我还需要很多反馈,以防出现问题。我创建了一个启动屏幕,并有一种方法来记录过程中的步骤,这样我就可以知道什么时候出了问题,哪里出了问题。用户最终看到最后一条消息,但保存完整的消息。

我一直在向调用添加侦听器和向组件添加接口。如果你还没有猜到,我有点像一个新手,但这似乎真的是一个很好的模式,但我一直在阅读这不是片段和ViewModel之间通信的正确方式。

示例,来自SplashFragment.java:

viewModel.signIn(getActivity(), getAuthHelperSignInCallback());

SplashViewModel.java:

public void signIn (Activity activity, AuthHelper.AuthHelperSignInListener listener) {

AuthHelper authHelper = new AuthHelper(activity.getApplication());
authHelper.signIn(activity,listener);
}

在AuthHelper.java中我有一个接口:

public interface AuthHelperSignInListener {
void onSuccess(IAuthenticationResult iAuthenticationResult);
void onCancel();
void onError(MsalException e);
}

使用这个方法,我可以得到我需要的信息,所以如果我不应该在这样的片段中使用回调/侦听器,替代方案是什么?

您可以使用channel将这些事件发送到您的活动或片段,并相应地触发UI操作。Channel属于kotlinx.coroutines.channels.Channel

首先,使用sealed classviewModel类中创建这些事件。

sealed class SignInEvent{
data class ShowError(val message: String) : SignInEvent()
data class ShowLoginSuccess(val message: String) : SignInEvent()
}

viewModel中定义一个channel变量

private val signInEventChannel = Channel<SignInEvent>()

// below flow will be used to collect these events inside activity/fragment
val signInEvent = signInEventChannel.receiveAsFlow()

现在您可以使用定义的事件通道

viewModel发送任何errorsuccess事件
fun onSignIn() {
try {
//your sign in logic

// on success
signInEventChannel.send(SignInEvent.ShowLoginSuccess("Login successful"))
} catch(e: Exception){
//on getting an error.
signInEventChannel.send(SignInEvent.ShowError("There is an error logging in"))
}         
}

现在您可以监听这些事件并相应地触发任何UI操作,例如显示toast或零食栏

活动

lifecycleScope.launchWhenStarted {
activityViewModel.signInEvent.collect { event ->
when (event) {
//ActivityViewModel is your viewmodel's class name
is ActivityViewModel.SignInEvent.ShowError-> {
Snackbar.make(binding.root, event.message, Snackbar.LENGTH_SHORT)
.show()
}
is ActivityViewModel.SignInEvent.ShowLoginSuccess-> {
Snackbar.make(binding.root, event.message, Snackbar.LENGTH_SHORT)
.show()
}
}
}

片段中

viewLifecycleOwner.lifecycleScope.launchWhenStarted {
fragmentViewModel.signInEvent.collect { event ->
when (event) {
is FragmentViewModel.SignInEvent.ShowError-> {
Snackbar.make(requireView(), event.message, Snackbar.LENGTH_SHORT)
.show()
}
is FragmentViewModel.SignInEvent.ShowLoginSuccess-> {
Snackbar.make(requireView(), event.message, Snackbar.LENGTH_SHORT)
.show()
}
}
}

最新更新