我正在使用视图模型从片段调用登录方法。我一直在其他领域使用很多回调,但阅读使用MVVM,我不应该以这种方式在片段和视图模型之间进行通信。Android文档似乎也使用了LiveData。为什么可以为组件(如recyclerview的适配器)设置侦听器,而不是为从视图模型调用的其他组件设置侦听器?
签名组件在Splash片段中。我应该将其作为视图模型之外的组件调用并利用侦听器吗?
我遇到了一个错误,想给用户反馈。我:
- 将组件从视图模型中取出,并直接从片段 中调用它
- 将组件留在视图模型中,并利用livedata向片段/用户提供反馈?
- 将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 class
在viewModel
类中创建这些事件。
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
发送任何error
或success
事件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()
}
}
}