我有一个看起来像这样的数据类:
@Parcelize
data class Profile(
val firstName: String = "",
val lastName: String = "",
val description: String = "",
val imageUri: String = ""
) : Parcelable
单击后,我从 ViewModel 类中调用一个方法,并向其传递当前输入值,然后使用 Repository 类保存该值:
viewModel.createProfile(
etFirstName.text.toString(),
etLastName.text.toString(),
etProfileDescription.text.toString(),
profileImageUri.toString()
)
// The createProfile function itself
fun createProfile(
firstName: String = "John",
lastName: String = "Doe",
description: String = "Default Description",
imageUri: String = ""
) {
val profile = Profile(firstName, lastName, description, imageUri)
// Persist data
}
在另一个片段中,我使用此持久数据设置一些 UI 数据,如下所示:
private fun observeProfile() {
viewModel.getProfile()
viewModel.profile.observe(viewLifecycleOwner, Observer {
val profile = it
tvName.text = getString(R.string.profile_name, profile.firstName, profile.lastName)
tvDescription.text = profile.description
ivProfileImage.setImageURI(Uri.parse(profile.imageUri))
})
}
createProfile
需要 4 个参数。我可以传递更少的参数,因为我有可选参数,但是如何根据值是否为非 null 或空有条件地将参数传递给
createProfile
。我当然可以为每个值创建检查,但是解决这个问题的最佳方法是什么?
更新
我认为我原来的问题不够清楚,因为我不仅将文本输入中的值传递到createProfile
。
profileImageUri
是类型为
Uri?
的类变量,最初设置为
null
。用户可以选择图像,并且该变量将使用图像数据进行更新。我将图像数据传递并存储为字符串的原因是因为所有配置文件数据也会持久保存到 Firestore,因此字符串更易于使用。
fun CharSequence?.ifNullOrEmpty(default: String) = if (this.isNullOrEmpty()) default else this.toString()
并将其用作
viewModel.createProfile(
etFirstName.text.ifNullOrEmpty("John"),
etLastName.text.ifNullOrEmpty("Doe"),
etProfileDescription.text.ifNullOrEmpty("Default Description"),
profileImageUri.ifNullOrEmpty("Default Uri")
)
编辑:考虑到更新,我会考虑
fun Any?.ifNullOrEmpty(default: String) =
if (this == null || (this is CharSequence && this.isEmpty()))
default
else
this.toString()
编辑2:为了处理@Gabriel Furstenheim的评论,将createProfile
定义为
fun createProfile(
firstName: String? = null,
lastName: String? = null,
description: String? = null,
imageUri: String? = null
) {
val profile = Profile(
firstName.ifNullOrEmpty("John"),
lastName.ifNullOrEmpty("Doe"),
description.ifNullOrEmpty("Default Description"),
imageUri.ifNullOrEmpty("")
)
// Persist data
}
或者如果您需要使用例如firstName
两次,
fun createProfile(
firstName: String? = null,
lastName: String? = null,
description: String? = null,
imageUri: String? = null
) {
val firstNameFinal = firstName.ifNullOrEmpty("John")
val profile = Profile(
firstNameFinal,
...
)
// Persist data
}
事实证明,可以将
if-else
语句作为参数传递,因为
if
语句是 Kotlin 中的表达式:
viewModel.createProfile(
if (!etFirstName.text.isNullOrEmpty()) etFirstName.text.toString() else "John",
if (!etLastName.text.isNullOrEmpty()) etLastName.text.toString() else "Doe",
if (!etProfileDescription.text.isNullOrEmpty()) etProfileDescription.text.toString() else "Default Description",
if (profileImageUri != null) profileImageUri.toString() else ""
)
使用这种方法,我也不必为我的 data class
变量和我的
createProfile
函数参数设置默认值。我还在我的
observeProfile
函数中添加了一个检查,因此如果
profileImageUri
为空,它不会尝试设置图像:
// ...
if (profile.imageUri.isNotEmpty()) {
ivProfileImage.setImageURI(Uri.parse(profile.imageUri))
}
// ...
varargs
但它有问题:
@Parcelize
class Profile(
vararg val params: String
) : Parcelable
...
val params = arrayOfValues.filter{ !it.isNullOrBlank() } // filter out all unwanted data
val profile = Profile(*params) // pass every param separately using spread operator
这里的主要问题是参数本身被混淆了。我仍然可以使用索引获取对各个参数的引用并使用它们进行操作,但效果不太好。
Elvis Operator:?:
。
val test = exampleExpression ?: "alternative value"
如果
?:
左侧的表达式为not null,则 elvis 运算符返回它,否则返回右侧的表达式。请注意,仅当左侧表达式为空时,才会计算右侧表达式。
viewModel.createProfile(
etFirstName.text.toString() ?: "John",
etLastName.text.toString() ?: "Doe",
etProfileDescription.text.toString() ?: "Default Description",
profileImageUri.toString() ?: "Default Uri"
)