viewmodel 函数可以有一个接收片段的参数吗?
Is it ok for a viewmodel function to have a parameter that receives a fragment?
我有一个用于用户输入的片段和一个用于处理验证和 IO 的视图模型。插入信息后,我 UI 导航到 'success' 对话框。现在这个导航发生在视图模型的
使用对片段的引用插入方法。这一切似乎都有效,但后来我想起视图模型不应该包含对片段或 activity 的引用。我的问题是这是否适用于视图模型函数的局部参数?它会以某种方式保留该参考吗?
ViewModel代码
suspend fun insertNewCustomer(name: String?,address: String?, city: String?, state: String?,
phoneNumber: String?, emailAddress: String?, frag: ManualAddCustomerFrag
){
if ( (validateName(name)
&& validateAddress(address)
&& validateCity(city)
&& validateState()
&& validateServiceDays())
&& isAddressTaken(address) == false
){
val customer = CustomerEntity(address!!,name,city,state,phoneNumber, emailAddress)
viewModelScope.launch {
customerRepo.insertCustomer(customer)
val days = convertSelectedDaysToStrings()
for (i in days.indices){
val serviceDay = ServiceDayEntity(0,customer.address,days[i])
customerRepo.addServiceDay(serviceDay)
}
withContext(Dispatchers.Main){
val dialogFragment = SuccessfullyAddedDialog()
val action = ManualAddCustomerFragDirections.
actionManualAddCustomerFragToSuccessfullyAddedDialog()
frag.findNavController().navigate(action)
}
}
}
}
ViewModel 和 Fragment 应该分开,永远不要将 Fragment 作为参数传递给 ViewModel。如果你想通过 ViewModel 触发 Fragment 动作,你应该在 Fragment 中使用 Observer。我将 post 一些我自己的代码片段来解释我的意思。应该注意的是,我在这里使用的是 Activity 而不是 Fragment,但概念保持不变。
在 ViewModel 中我创建了这些变量:
val closeInCall: LiveData<EmptyEvent>
get() = _closeInCall
private val _closeInCall = MutableLiveData<EmptyEvent>()
当 ViewModel 中的某个方法被触发时,会发生这种情况:
_closeInCall.postValue(EmptyEvent())
在我的 Activity 中,我观察到 closeInCall
是这样的:
viewModel.closeInCall.observe(this, EventObserver {
// Do stuff
})
我正在使用的 EmptyEvent 和 EventObserver 是 MVVM 助手 类 我喜欢在不需要接收 Fragment/Activity 中的任何值时使用,你不一定必须使用它们。
空事件:
/**
* An [Event] without content.
*/
class EmptyEvent : Event<Unit>(Unit)
事件观察者:
import androidx.lifecycle.Observer
/**
* An [Observer] for [Event]s, simplifying the pattern of checking if
the [Event]'s content has
* already been handled.
*
* [onEventUnhandledContent] is *only* called if the [Event]'s
contents has not been handled.
*/
internal class EventObserver<T>(
private val onEventUnhandledContent: (T) -> Unit
) : Observer<Event<T>> {
override fun onChanged(event: Event<T>?) {
event?.getContentIfNotHandled()?.let { value ->
onEventUnhandledContent(value)
}
}
}
您可以尝试使用 lambda
函数来处理 ViewModel
中的 Activity/Fragment
中的 callback
。如下所示:
fun insertNewCustomer(name: String?,address: String?, city: String?, state: String?,
phoneNumber: String?, emailAddress: String?, callBack: () -> Unit
){
if ( (validateName(name)
&& validateAddress(address)
&& validateCity(city)
&& validateState()
&& validateServiceDays())
&& isAddressTaken(address) == false
){
val customer = CustomerEntity(address!!,name,city,state,phoneNumber, emailAddress)
viewModelScope.launch {
customerRepo.insertCustomer(customer)
val days = convertSelectedDaysToStrings()
for (i in days.indices){
val serviceDay = ServiceDayEntity(0,customer.address,days[i])
customerRepo.addServiceDay(serviceDay)
}
callBack()
/* withContext(Dispatchers.Main){
val dialogFragment = SuccessfullyAddedDialog()
val action = ManualAddCustomerFragDirections.
actionManualAddCustomerFragToSuccessfullyAddedDialog()
frag.findNavController().navigate(action)
}*/
}
}
}
添加从 Activity/Fragment
调用上述方法,如下所示:
lifecycleScope.launch {
yourViewModel.insertNewCustomer("name","address","city","state","phone","email"){
val dialogFragment = SuccessfullyAddedDialog()
val action = ManualAddCustomerFragDirections.
actionManualAddCustomerFragToSuccessfullyAddedDialog()
// If you are using binding, then use binding.root where binding is an instance variable instantiated in onCreateView() of Fragment
binding.root.findNavController().navigate(action)
// Or else you can get NavController from View
}
}
我有一个用于用户输入的片段和一个用于处理验证和 IO 的视图模型。插入信息后,我 UI 导航到 'success' 对话框。现在这个导航发生在视图模型的 使用对片段的引用插入方法。这一切似乎都有效,但后来我想起视图模型不应该包含对片段或 activity 的引用。我的问题是这是否适用于视图模型函数的局部参数?它会以某种方式保留该参考吗?
ViewModel代码
suspend fun insertNewCustomer(name: String?,address: String?, city: String?, state: String?,
phoneNumber: String?, emailAddress: String?, frag: ManualAddCustomerFrag
){
if ( (validateName(name)
&& validateAddress(address)
&& validateCity(city)
&& validateState()
&& validateServiceDays())
&& isAddressTaken(address) == false
){
val customer = CustomerEntity(address!!,name,city,state,phoneNumber, emailAddress)
viewModelScope.launch {
customerRepo.insertCustomer(customer)
val days = convertSelectedDaysToStrings()
for (i in days.indices){
val serviceDay = ServiceDayEntity(0,customer.address,days[i])
customerRepo.addServiceDay(serviceDay)
}
withContext(Dispatchers.Main){
val dialogFragment = SuccessfullyAddedDialog()
val action = ManualAddCustomerFragDirections.
actionManualAddCustomerFragToSuccessfullyAddedDialog()
frag.findNavController().navigate(action)
}
}
}
}
ViewModel 和 Fragment 应该分开,永远不要将 Fragment 作为参数传递给 ViewModel。如果你想通过 ViewModel 触发 Fragment 动作,你应该在 Fragment 中使用 Observer。我将 post 一些我自己的代码片段来解释我的意思。应该注意的是,我在这里使用的是 Activity 而不是 Fragment,但概念保持不变。
在 ViewModel 中我创建了这些变量:
val closeInCall: LiveData<EmptyEvent>
get() = _closeInCall
private val _closeInCall = MutableLiveData<EmptyEvent>()
当 ViewModel 中的某个方法被触发时,会发生这种情况:
_closeInCall.postValue(EmptyEvent())
在我的 Activity 中,我观察到 closeInCall
是这样的:
viewModel.closeInCall.observe(this, EventObserver {
// Do stuff
})
我正在使用的 EmptyEvent 和 EventObserver 是 MVVM 助手 类 我喜欢在不需要接收 Fragment/Activity 中的任何值时使用,你不一定必须使用它们。
空事件:
/**
* An [Event] without content.
*/
class EmptyEvent : Event<Unit>(Unit)
事件观察者:
import androidx.lifecycle.Observer
/**
* An [Observer] for [Event]s, simplifying the pattern of checking if
the [Event]'s content has
* already been handled.
*
* [onEventUnhandledContent] is *only* called if the [Event]'s
contents has not been handled.
*/
internal class EventObserver<T>(
private val onEventUnhandledContent: (T) -> Unit
) : Observer<Event<T>> {
override fun onChanged(event: Event<T>?) {
event?.getContentIfNotHandled()?.let { value ->
onEventUnhandledContent(value)
}
}
}
您可以尝试使用 lambda
函数来处理 ViewModel
中的 Activity/Fragment
中的 callback
。如下所示:
fun insertNewCustomer(name: String?,address: String?, city: String?, state: String?,
phoneNumber: String?, emailAddress: String?, callBack: () -> Unit
){
if ( (validateName(name)
&& validateAddress(address)
&& validateCity(city)
&& validateState()
&& validateServiceDays())
&& isAddressTaken(address) == false
){
val customer = CustomerEntity(address!!,name,city,state,phoneNumber, emailAddress)
viewModelScope.launch {
customerRepo.insertCustomer(customer)
val days = convertSelectedDaysToStrings()
for (i in days.indices){
val serviceDay = ServiceDayEntity(0,customer.address,days[i])
customerRepo.addServiceDay(serviceDay)
}
callBack()
/* withContext(Dispatchers.Main){
val dialogFragment = SuccessfullyAddedDialog()
val action = ManualAddCustomerFragDirections.
actionManualAddCustomerFragToSuccessfullyAddedDialog()
frag.findNavController().navigate(action)
}*/
}
}
}
添加从 Activity/Fragment
调用上述方法,如下所示:
lifecycleScope.launch {
yourViewModel.insertNewCustomer("name","address","city","state","phone","email"){
val dialogFragment = SuccessfullyAddedDialog()
val action = ManualAddCustomerFragDirections.
actionManualAddCustomerFragToSuccessfullyAddedDialog()
// If you are using binding, then use binding.root where binding is an instance variable instantiated in onCreateView() of Fragment
binding.root.findNavController().navigate(action)
// Or else you can get NavController from View
}
}