Android (Kotlin)MVVM中片段之间的通信
我试图理解MVVM的概念,但在本例中,我很难理解如何在模型类和UI(片段)之间进行通信 以下是(糟糕的,请注意)代码: LoginFragment.ktAndroid (Kotlin)MVVM中片段之间的通信,android,android-studio,kotlin,mvvm,Android,Android Studio,Kotlin,Mvvm,我试图理解MVVM的概念,但在本例中,我很难理解如何在模型类和UI(片段)之间进行通信 以下是(糟糕的,请注意)代码: LoginFragment.kt class LoginFragment: Fragment(), AuthListener { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View?
class LoginFragment: Fragment(), AuthListener {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding = DataBindingUtil.inflate<CredentialsLoginFragmentBinding>(
inflater,
R.layout.credentials_login_fragment,
container,
false
)
val viewModel = ViewModelProviders.of(this).get(LoginViewModel::class.java)
val view: View = binding.root
val registerButton: Button = view.findViewById(R.id.register_button)
binding.viewModel = viewModel
viewModel.authListener = this
registerButton.setOnClickListener {
val transaction: FragmentTransaction? = fragmentManager?.beginTransaction()
transaction?.replace(R.id.fragment_container, SignupFragment())?.commit()
}
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val constraintRoot: MotionLayout = view.findViewById(R.id.sign_in_root)
ActivityUtils().switchLayoutAnimationKeyboard(constraintRoot = constraintRoot)
}
override fun onStarted() {
Toast.makeText(context, "Started", Toast.LENGTH_SHORT).show()
}
override fun onSuccess() {
Toast.makeText(context, "Success", Toast.LENGTH_SHORT).show()
}
override fun onError(message: String) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}}
class LoginViewModel: ViewModel(){
var username: String? = null
var password: String? = null
var isCredentialsValid: Boolean = false
var authListener: AuthListener? = null
private val context: Context? = null
fun onLoginButtonClicked(view: View){
if(username.isNullOrEmpty() || password.isNullOrEmpty()){
authListener?.onError("Invalid username or password")
isCredentialsValid = false
return
}
if(!username.isNullOrEmpty() && password!!.length >= 8){
isCredentialsValid = true
authListener?.onSuccess()
}else{
authListener?.onError("Invalid")
}
}}
现在假设我输入了用户名和密码,并且两者都符合条件。现在我想,当我点击“登录”按钮时,当前片段会被一个菜单片段替换,例如
我怎样才能做到这样?我尝试从ViewModel类中替换,但不起作用。
我是否应该从VM类中获取“isCredentialsValid”的结果,并在LoginFragment类中做出相应的响应
谢谢。从视图模型返回UI的一种典型通信方式是使用。在LoginView模型中,您可以将livedata设置为
true
或false
。在视图LoginFragment.kt
中,您将有一个观察者。此任务是在livedata的值发生更改时触发。这样,视图中的逻辑可以显示错误消息liveData=false或启动菜单fragment=true
下面是一个很好的例子,使用livedata将数据传递到视图(片段)文档中的这一部分:您必须使用livedata将数据从viewModel更新到视图。我将发布代码,但请确保您需要理解LiveData的概念 LoginViewModel.kt
class LoginViewModel: ViewModel(){
var username: String? = null
var password: String? = null
var isCredentialsValid: Boolean = false
var authListener: AuthListener? = null
private val context: Context? = null
// LiveData to udpate the UI
private val _isValidCredential = MutableLiveData<Boolean>()
val isValidCredential: LiveData<Boolean> = _isValidCredential
fun onLoginButtonClicked(view: View){
if(username.isNullOrEmpty() || password.isNullOrEmpty()){
authListener?.onError("Invalid username or password")
isCredentialsValid = false
return
}
if(!username.isNullOrEmpty() && password!!.length >= 8){
isCredentialsValid = true
// to update the value of live data wherever you need
_isValidCredential.value = true
authListener?.onSuccess()
}else{
authListener?.onError("Invalid")
// to update the value of live data wherever you need
_isValidCredential.value = false
}
}
}
classloginviewmodel:ViewModel(){
变量用户名:字符串?=null
var密码:字符串?=null
var isCredentialsValid:Boolean=false
var authListener:authListener?=null
私有val上下文:上下文?=null
//使用LiveData对UI进行自定义
private val_isValidCredential=MutableLiveData()
val isValidCredential:LiveData=_isValidCredential
乐趣onLoginButtonClicked(视图:视图){
if(username.isNullOrEmpty()| | password.isNullOrEmpty()){
authListener?.onError(“无效的用户名或密码”)
isCredentialsValid=false
返回
}
如果(!username.isNullOrEmpty()&&password!!.length>=8){
isCredentialsValid=true
//随时随地更新实时数据的价值
_isValidCredential.value=true
authListener?.onSuccess()
}否则{
authListener?.onError(“无效”)
//随时随地更新实时数据的价值
_isValidCredential.value=false
}
}
}
你的碎片应该是
LoginFragment.kt
class LoginFragment: Fragment(), AuthListener {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding = DataBindingUtil.inflate<CredentialsLoginFragmentBinding>(
inflater,
R.layout.credentials_login_fragment,
container,
false
)
val viewModel = ViewModelProviders.of(this).get(LoginViewModel::class.java)
val view: View = binding.root
val registerButton: Button = view.findViewById(R.id.register_button)
binding.viewModel = viewModel
viewModel.authListener = this
// This is the way you need to observe the value
viewModel.isValidCredential.observe(viewLifecycleOwner, Observer {
if(it){
// do your navigation stuff here
}else{
// do your stuff if not valid credential
}
})
registerButton.setOnClickListener {
val transaction: FragmentTransaction? =
fragmentManager?.beginTransaction()
transaction?.replace(R.id.fragment_container, SignupFragment())?.commit()
}
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val constraintRoot: MotionLayout = view.findViewById(R.id.sign_in_root)
ActivityUtils().switchLayoutAnimationKeyboard(constraintRoot = constraintRoot)
}
override fun onStarted() {
Toast.makeText(context, "Started", Toast.LENGTH_SHORT).show()
}
override fun onSuccess() {
Toast.makeText(context, "Success", Toast.LENGTH_SHORT).show()
}
override fun onError(message: String) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}}
class-LoginFragment:Fragment(),AuthListener{
覆盖创建视图(
充气机,
容器:视图组?,
savedInstanceState:捆绑?
):查看{
val binding=DataBindingUtil.inflate(
充气机,
R.layout.credentials\u login\u片段,
集装箱,
假的
)
val viewModel=ViewModelProviders.of(this.get)(LoginViewModel::class.java)
val view:view=binding.root
val registerButton:Button=view.findViewById(R.id.register_按钮)
binding.viewModel=viewModel
viewModel.authListener=此
//这是您需要观察值的方式
viewModel.isValidCredential.observe(viewLifecycleOwner,Observer{
如果(它){
//在这里做你的导航工作
}否则{
//如果不是有效的凭证,请执行您的操作
}
})
registerButton.setOnClickListener{
val事务:碎片事务?=
碎片管理器?.beginTransaction()
事务?.replace(R.id.fragment_容器,SignupFragment())?.commit()
}
返回视图
}
覆盖已创建的视图(视图:视图,保存状态:捆绑?){
super.onViewCreated(视图,savedInstanceState)
val constraintRoot:MotionLayout=view.findViewById(R.id.sign\u in\u root)
ActivityUtils().SwitchLayoutImationKeyboard(constraintRoot=constraintRoot)
}
覆盖启动时的乐趣(){
Toast.makeText(上下文“开始”,Toast.LENGTH\u SHORT.show())
}
覆盖成功的乐趣(){
Toast.makeText(上下文,“Success”,Toast.LENGTH\u SHORT.show())
}
重写错误(消息:字符串){
Toast.makeText(上下文、消息、Toast.LENGTH\u SHORT).show()
}}
@BenAndJerrys upvoting这个答案可能对其他人有用,我相信我太新了