ViewModel不用我的ViewModel初始化或问题设计

发布于 2025-01-31 08:00:29 字数 3150 浏览 3 评论 0原文

我一直在阅读有关Android中有关MVVM模式的一些问题,答案和博客,并且我已经在应用程序中实现了它。

我的应用程序由3个选项卡组成。每个选项卡的内容都是片段。

这些片段之一是存储在房间DB上的用户列表,我是我实现MVVM的地方(用RecycleView实现用户对象,ViewModel,Repository和Adapter)。

在相同的片段中,我在末尾有一个“添加用户”按钮,该按钮导致了一项新活动,其中提出了一个配方以添加新用户。在此活动中,我想确保在保存之前,我的数据库中不存在全名不存在。

我试图使用相同的ViewModel来获取完整的用户名全名,但是看来ViewModel从未初始化,我不知道为什么。

我已经阅读了有关该视图模型的一些问题,无法在不同的活动中使用(我也将其用于助推器活动中,

这是我的ViewModel:

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()

    }
}

调试,我看到日志“初始化userviewmodel”启动MainActivity的片段,但是当调用adduser活动时,我看不到

  1. 它 为什么
  2. 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
    }

忘记 “功能并开始工作:

 userViewModel.allUsersLiveData.observe(this, Observer<List<User>>{
            it?.let {
                // updates the list.
                Timber.i("Updating User Names")
                userList =userViewModel.getAllUsersNames()
            }
        })

I've been reading some questions, answers and blogs about MVVM pattern in Android, and I've implemented it in my application.

My application consists of a MainActivity with 3 Tabs. Content of each tab is a fragment.

One of these fragments, is a List of Users stored on Room DB, which is where I've implemented the MVVM (implementing User object, ViewModel, Repository and Adapter with RecycleView).

In this same fragment, I have an "add User" button at the end that leads to a new activity where a formulary is presented to add a new user. In this activity I want to be sure that the full name of user not exists in my DB before saving it.

I was trying to use the same ViewModel to get full UserNames full name, but it seems that ViewModel is never initialized and I dont' know why.

I've read some questions about that viewmodel can't be used in different activities (I use it in MainActivity also in AddUser activity

This is my ViewModel:

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}
    }

And my 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()

    }
}

Debugging, I see the log "Initializing UserViewModel" when the fragment of MainActivity is started, but I can't see it when AddUser activity is called. So it seems it's not initializing correctly.

So the questions:

  1. Is this a good approach? I'm making some design mistake?
  2. Why the VM isn't initializing?

EDIT

I forgot to add this function. Calling userViewModel here is where I get the error:

 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
    }

EDIT 2

I added this on my "onCreate" function and started to work:

 userViewModel.allUsersLiveData.observe(this, Observer<List<User>>{
            it?.let {
                // updates the list.
                Timber.i("Updating User Names")
                userList =userViewModel.getAllUsersNames()
            }
        })

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

水溶 2025-02-07 08:00:29

如果您通过ViewModels 委托来看,您会看到它是懒惰,这意味着它将在第一次访问时初始化

@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)
}

if you take a look at by viewModels delegate you will see it's lazy it means it will initialize when it is first time accessed

@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)
}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文