Android 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:

我有一个用于用户输入的片段和一个用于处理验证和IO的viewmodel。在插入信息后,我让UI导航到“成功”对话框。现在,此导航是从viewmodel的 使用对片段的引用插入方法。这一切似乎都是可行的,但我记得viewmodel不应该包含对片段或活动的引用。我的问题是,这是否适用于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应该分开,不应该将片段作为参数传递给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
            
        }
    }