ViewModel 未初始化或问题设计与我的 viewModel
ViewModel not initializing or problem design with my viewModel
我在 Android 中阅读了一些关于 MVVM 模式的问题、答案和博客,并且我已经在我的应用程序中实现了它。
我的应用程序包含一个带有 3 个选项卡的 MainActivity。每个选项卡的内容是一个片段。
其中一个片段是存储在 Room DB 上的用户列表,这是我实现 MVVM 的地方(使用 RecycleView 实现用户对象、ViewModel、存储库和适配器)。
在同一个片段中,我在末尾有一个“添加用户”按钮,它指向一个新的 activity,其中显示了一个用于添加新用户的处方集。在此activity中,我想在保存之前确保用户的全名不存在于我的数据库中。
我试图使用相同的 ViewModel 获取完整的 UserNames 全名,但似乎 ViewModel 从未初始化,我也不知道为什么。
我读过一些关于视图模型不能在不同活动中使用的问题(我在 MainActivity 和 AddUser 中也使用它 activity
这是我的视图模型:
class UserViewModel : ViewModel() {
val allUsersLiveData: LiveData<List<User>>
private val repository: UserRepository
init {
Timber.i("Initializing UserViewModel")
repository = UserRepository(UserTrackerApplication.database!!.databaseDao())
allUsersLiveData = repository.getAllUsers()
}
fun getAllUsersFullName(): List<String> {
return allUsersLiveData.value!!.map { it.fullname}
}
还有我的 AddUser activity:
class AddUser : AppCompatActivity() {
private lateinit var userList:List<String>
private lateinit var binding: ActivityAddUserBinding
private val userViewModel: UserViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_add_user)
Timber.i("Add User OnCreate")
binding = ActivityAddUserBinding.inflate(layoutInflater)
setContentView(binding.root)
}
fun addUserClick(v : View){
//someCode
val userName = binding.constraintLayoutAddUser.etUserName!!.text.toString()
if(checkUserExistance(userName)) {
val text: String = String.format(
resources.getString(R.string.repeated_user_name),
userName
Snackbar.make(v, text, Snackbar.LENGTH_LONG).show()
{
else
{
lifecycleScope.launch {
UserTrackerApplication.database!!.databaseDao()
.insertUser(user)
Timber.i("User added!")
}
finish()
}
}
调试,MainActivity片段启动时看到日志"Initializing UserViewModel"
,调用AddUseractivity时看不到。所以它似乎没有正确初始化。
所以问题:
- 这是一个好方法吗?我犯了一些设计错误?
- 为什么 VM 没有初始化?
编辑
我忘记添加这个功能了。在这里调用 userViewModel 是我得到错误的地方:
private fun checkUserExistance(userName: String): Boolean {
var result = false
userList = userViewModel.getAllUsersNames()
for (usr in userList)
{
if(usr.uppercase() == userName.uppercase())
{
result = true
break
}
}
return result
}
编辑 2
我在我的“onCreate”函数中添加了这个并开始工作:
userViewModel.allUsersLiveData.observe(this, Observer<List<User>>{
it?.let {
// updates the list.
Timber.i("Updating User Names")
userList =userViewModel.getAllUsersNames()
}
})
如果你看一下 by viewModels delegate 你会看到它是 lazy 这意味着它将在第一次访问时初始化
@MainThread
public inline fun <reified VM : ViewModel> ComponentActivity.viewModels(
noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> {
val factoryPromise = factoryProducer ?: {
defaultViewModelProviderFactory
}
return ViewModelLazy(VM::class, { viewModelStore }, factoryPromise)
}
我在 Android 中阅读了一些关于 MVVM 模式的问题、答案和博客,并且我已经在我的应用程序中实现了它。
我的应用程序包含一个带有 3 个选项卡的 MainActivity。每个选项卡的内容是一个片段。
其中一个片段是存储在 Room DB 上的用户列表,这是我实现 MVVM 的地方(使用 RecycleView 实现用户对象、ViewModel、存储库和适配器)。
在同一个片段中,我在末尾有一个“添加用户”按钮,它指向一个新的 activity,其中显示了一个用于添加新用户的处方集。在此activity中,我想在保存之前确保用户的全名不存在于我的数据库中。
我试图使用相同的 ViewModel 获取完整的 UserNames 全名,但似乎 ViewModel 从未初始化,我也不知道为什么。
我读过一些关于视图模型不能在不同活动中使用的问题(我在 MainActivity 和 AddUser 中也使用它 activity
这是我的视图模型:
class UserViewModel : ViewModel() {
val allUsersLiveData: LiveData<List<User>>
private val repository: UserRepository
init {
Timber.i("Initializing UserViewModel")
repository = UserRepository(UserTrackerApplication.database!!.databaseDao())
allUsersLiveData = repository.getAllUsers()
}
fun getAllUsersFullName(): List<String> {
return allUsersLiveData.value!!.map { it.fullname}
}
还有我的 AddUser activity:
class AddUser : AppCompatActivity() {
private lateinit var userList:List<String>
private lateinit var binding: ActivityAddUserBinding
private val userViewModel: UserViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_add_user)
Timber.i("Add User OnCreate")
binding = ActivityAddUserBinding.inflate(layoutInflater)
setContentView(binding.root)
}
fun addUserClick(v : View){
//someCode
val userName = binding.constraintLayoutAddUser.etUserName!!.text.toString()
if(checkUserExistance(userName)) {
val text: String = String.format(
resources.getString(R.string.repeated_user_name),
userName
Snackbar.make(v, text, Snackbar.LENGTH_LONG).show()
{
else
{
lifecycleScope.launch {
UserTrackerApplication.database!!.databaseDao()
.insertUser(user)
Timber.i("User added!")
}
finish()
}
}
调试,MainActivity片段启动时看到日志"Initializing UserViewModel"
,调用AddUseractivity时看不到。所以它似乎没有正确初始化。
所以问题:
- 这是一个好方法吗?我犯了一些设计错误?
- 为什么 VM 没有初始化?
编辑
我忘记添加这个功能了。在这里调用 userViewModel 是我得到错误的地方:
private fun checkUserExistance(userName: String): Boolean {
var result = false
userList = userViewModel.getAllUsersNames()
for (usr in userList)
{
if(usr.uppercase() == userName.uppercase())
{
result = true
break
}
}
return result
}
编辑 2
我在我的“onCreate”函数中添加了这个并开始工作:
userViewModel.allUsersLiveData.observe(this, Observer<List<User>>{
it?.let {
// updates the list.
Timber.i("Updating User Names")
userList =userViewModel.getAllUsersNames()
}
})
如果你看一下 by viewModels delegate 你会看到它是 lazy 这意味着它将在第一次访问时初始化
@MainThread
public inline fun <reified VM : ViewModel> ComponentActivity.viewModels(
noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> {
val factoryPromise = factoryProducer ?: {
defaultViewModelProviderFactory
}
return ViewModelLazy(VM::class, { viewModelStore }, factoryPromise)
}