Android viewmodel函数具有接收片段的参数可以吗?
我有一个用于用户输入的片段和一个用于处理验证和IO的viewmodel。在插入信息后,我让UI导航到“成功”对话框。现在,此导航是从viewmodel的 使用对片段的引用插入方法。这一切似乎都是可行的,但我记得viewmodel不应该包含对片段或活动的引用。我的问题是,这是否适用于viewmodel函数的局部参数?它是否会以某种方式保留这一参照物 视图模型代码Android viewmodel函数具有接收片段的参数可以吗?,android,android-fragments,android-viewmodel,Android,Android Fragments,Android Viewmodel,我有一个用于用户输入的片段和一个用于处理验证和IO的viewmodel。在插入信息后,我让UI导航到“成功”对话框。现在,此导航是从viewmodel的 使用对片段的引用插入方法。这一切似乎都是可行的,但我记得viewmodel不应该包含对片段或活动的引用。我的问题是,这是否适用于viewmodel函数的局部参数?它是否会以某种方式保留这一参照物 视图模型代码 suspend fun insertNewCustomer(name: String?,address: String?, city:
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应该分开,不应该将片段作为参数传递给ViewModel。如果希望通过ViewModel触发片段操作,则应在片段中使用观察者。我将发布一些我自己的代码片段来解释我的意思。应该注意的是,我在这里使用的是一个活动,而不是一个片段,但概念保持不变 在ViewModel中,我创建了以下变量:
val closeInCall: LiveData<EmptyEvent>
get() = _closeInCall
private val _closeInCall = MutableLiveData<EmptyEvent>()
在我的活动中,我观察到closeInCall
如下:
viewModel.closeInCall.observe(this, EventObserver {
// Do stuff
})
我使用的EmptyEvent和EventObserver是MVVM帮助器类,当我不需要在片段/活动中接收任何值时,我喜欢使用它们,您不必使用它们
清空事件:
/**
* 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)
}
}
}
导入androidx.lifecycle.Observer
/**
*[Event]的[Observer],简化了检查
[事件]的内容已被删除
*已经处理好了。
*
*[OneEventHandleContent]仅在[Event]的
内容尚未处理。
*/
内部类事件观察者(
private val onEventUnhandledContent:(T)->单位
):观察员{
更改后覆盖乐趣(事件:事件?){
事件?.getContentIfNotHandled()?.let{value->
onEventUnhandledContent(值)
}
}
}
您可以尝试使用lambda
函数处理活动/片段中的回调
,从ViewModel
。如下图所示:
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
}
}
不要从ViewModel显示/导航到对话框,只需将此信息传递给活动或片段并从那里处理它。这是一个糟糕的解决方案。insertNewCustomer肯定是需要在ViewModel中发生的事情。活动/片段应该只包含控制UI的代码,ViewModel应该处理逻辑。还是说viewModel.insertNewCustomer?是的,它必须是viewModel.insertNewCustomer。
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
}
}